| Index: tools/gn/template.cc
|
| diff --git a/tools/gn/template.cc b/tools/gn/template.cc
|
| index cae5e0c2d092c4439fa1028624d79fc286e2dd5c..fa0ccf31c64c4e3a43b5a4a8b1e24d51e87deea6 100644
|
| --- a/tools/gn/template.cc
|
| +++ b/tools/gn/template.cc
|
| @@ -39,22 +39,33 @@ Value Template::Invoke(Scope* scope,
|
| if (!EnsureNotProcessingImport(invocation, scope, err))
|
| return Value();
|
|
|
| - // First run the invocation's block.
|
| - Scope invocation_scope(scope);
|
| + // First run the invocation's block. Need to allocate the scope on the heap
|
| + // so we can pass ownership to the template.
|
| + scoped_ptr<Scope> invocation_scope(new Scope(scope));
|
| if (!FillTargetBlockScope(scope, invocation,
|
| invocation->function().value().as_string(),
|
| - block, args, &invocation_scope, err))
|
| + block, args, invocation_scope.get(), err))
|
| return Value();
|
| - block->ExecuteBlockInScope(&invocation_scope, err);
|
| + block->ExecuteBlockInScope(invocation_scope.get(), err);
|
| if (err->has_error())
|
| return Value();
|
|
|
| // Set up the scope to run the template. This should be dependent on the
|
| // closure, but have the "invoker" and "target_name" values injected, and the
|
| - // current dir matching the invoker.
|
| + // current dir matching the invoker. We jump through some hoops to avoid
|
| + // copying the invocation scope when setting it in the template scope (since
|
| + // the invocation scope may have large lists of source files in it and could
|
| + // be expensive to copy).
|
| + //
|
| + // Scope.SetValue will copy the value which will in turn copy the scope, but
|
| + // if we instead create a value and then set the scope on it, the copy can
|
| + // be avoided.
|
| Scope template_scope(closure_.get());
|
| - template_scope.SetValue("invoker", Value(NULL, &invocation_scope),
|
| + const char kInvoker[] = "invoker";
|
| + template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()),
|
| invocation);
|
| + Value* invoker_value = template_scope.GetMutableValue(kInvoker, false);
|
| + invoker_value->SetScopeValue(invocation_scope.Pass());
|
| template_scope.set_source_dir(scope->GetSourceDir());
|
|
|
| const base::StringPiece target_name("target_name");
|
| @@ -65,7 +76,28 @@ Value Template::Invoke(Scope* scope,
|
| // Run the template code. Don't check for unused variables since the
|
| // template could be executed in many different ways and it could be that
|
| // not all executions use all values in the closure.
|
| - return definition_->block()->ExecuteBlockInScope(&template_scope, err);
|
| + Value result =
|
| + definition_->block()->ExecuteBlockInScope(&template_scope, err);
|
| +
|
| + // Check for unused variables in the invocation scope. This will find typos
|
| + // of things the caller meant to pass to the template but the template didn't
|
| + // read out.
|
| + //
|
| + // This is a bit tricky because it's theoretically possible for the template
|
| + // to overwrite the value of "invoker" and free the Scope owned by the
|
| + // value. So we need to look it up again and don't do anything if it doesn't
|
| + // exist.
|
| + invoker_value = template_scope.GetMutableValue(kInvoker, false);
|
| + if (invoker_value && invoker_value->type() == Value::SCOPE) {
|
| + if (!invoker_value->scope_value()->CheckForUnusedVars(err))
|
| + return Value();
|
| + }
|
| +
|
| + // Check for unused variables in the template itself.
|
| + if (!template_scope.CheckForUnusedVars(err))
|
| + return Value();
|
| +
|
| + return result;
|
| }
|
|
|
| LocationRange Template::GetDefinitionRange() const {
|
|
|