Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: tools/gn/functions.cc

Issue 2509333003: Change GN to disallow reading args defined in the same declare_args() call. (Closed)
Patch Set: add tests Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/functions.h" 5 #include "tools/gn/functions.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <iostream> 8 #include <iostream>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 27 matching lines...) Expand all
38 return true; 38 return true;
39 39
40 *err = Err(block, "Unexpected '{'.", 40 *err = Err(block, "Unexpected '{'.",
41 "This function call doesn't take a {} block following it, and you\n" 41 "This function call doesn't take a {} block following it, and you\n"
42 "can't have a {} block that's not connected to something like an if\n" 42 "can't have a {} block that's not connected to something like an if\n"
43 "statement or a target declaration."); 43 "statement or a target declaration.");
44 err->AppendRange(function->function().range()); 44 err->AppendRange(function->function().range());
45 return false; 45 return false;
46 } 46 }
47 47
48 // This key is set as a scope property on the scope of a declare_args() block,
49 // in order to prevent reading a variable defined earlier in the same call
50 // (see `gn help declare_args` for more).
51 const void *kInDeclareArgsKey = nullptr;
52
48 } // namespace 53 } // namespace
49 54
55
56 bool EnsureNotReadingFromSameDeclareArgs(const ParseNode* node,
57 const Scope* cur_scope,
58 const Scope* val_scope,
59 Err* err) {
60 // If the value didn't come from a scope at all, we're safe.
61 if (!val_scope)
62 return true;
63
64 const Scope* val_args_scope = nullptr;
65 val_scope->GetProperty(&kInDeclareArgsKey, &val_args_scope);
66
67 const Scope* cur_args_scope = nullptr;
68 cur_scope->GetProperty(&kInDeclareArgsKey, &cur_args_scope);
69 if (!val_args_scope || !cur_args_scope || (val_args_scope != cur_args_scope))
70 return true;
71
72 *err = Err(node,
73 "Reading a variable defined in the same declare_args() call.");
brettw 2016/11/21 17:23:39 Can you put an extended help message here explaini
Dirk Pranke 2016/11/21 17:39:48 Will do.
74 return false;
75 }
76
50 bool EnsureNotProcessingImport(const ParseNode* node, 77 bool EnsureNotProcessingImport(const ParseNode* node,
51 const Scope* scope, 78 const Scope* scope,
52 Err* err) { 79 Err* err) {
53 if (scope->IsProcessingImport()) { 80 if (scope->IsProcessingImport()) {
54 *err = Err(node, "Not valid from an import.", 81 *err = Err(node, "Not valid from an import.",
55 "Imports are for defining defaults, variables, and rules. The\n" 82 "Imports are for defining defaults, variables, and rules. The\n"
56 "appropriate place for this kind of thing is really in a normal\n" 83 "appropriate place for this kind of thing is really in a normal\n"
57 "BUILD file."); 84 "BUILD file.");
58 return false; 85 return false;
59 } 86 }
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 377
351 Introduces the given arguments into the current scope. If they are not 378 Introduces the given arguments into the current scope. If they are not
352 specified on the command line or in a toolchain's arguments, the default 379 specified on the command line or in a toolchain's arguments, the default
353 values given in the declare_args block will be used. However, these defaults 380 values given in the declare_args block will be used. However, these defaults
354 will not override command-line values. 381 will not override command-line values.
355 382
356 See also "gn help buildargs" for an overview. 383 See also "gn help buildargs" for an overview.
357 384
358 The precise behavior of declare args is: 385 The precise behavior of declare args is:
359 386
360 1. The declare_arg block executes. Any variables in the enclosing scope are 387 1. The declare_args() block executes. Any variable defined in the enclosing
361 available for reading. 388 scope is available for reading, but any variable defined earlier in
389 the current scope is not (since the overrides haven't been applied yet).
362 390
363 2. At the end of executing the block, any variables set within that scope 391 2. At the end of executing the block, any variables set within that scope
364 are saved globally as build arguments, with their current values being 392 are saved globally as build arguments, with their current values being
365 saved as the "default value" for that argument. 393 saved as the "default value" for that argument.
366 394
367 3. User-defined overrides are applied. Anything set in "gn args" now 395 3. User-defined overrides are applied. Anything set in "gn args" now
368 overrides any default values. The resulting set of variables is promoted 396 overrides any default values. The resulting set of variables is promoted
369 to be readable from the following code in the file. 397 to be readable from the following code in the file.
370 398
371 This has some ramifications that may not be obvious: 399 This has some ramifications that may not be obvious:
372 400
373 - You should not perform difficult work inside a declare_args block since 401 - You should not perform difficult work inside a declare_args block since
374 this only sets a default value that may be discarded. In particular, 402 this only sets a default value that may be discarded. In particular,
375 don't use the result of exec_script() to set the default value. If you 403 don't use the result of exec_script() to set the default value. If you
376 want to have a script-defined default, set some default "undefined" value 404 want to have a script-defined default, set some default "undefined" value
377 like [], "", or -1, and after the declare_args block, call exec_script if 405 like [], "", or -1, and after the declare_args block, call exec_script if
378 the value is unset by the user. 406 the value is unset by the user.
379 407
380 - Any code inside of the declare_args block will see the default values of 408 - Because you cannot read the value of a variable defined in the same
381 previous variables defined in the block rather than the user-overridden 409 block, if you need to make the default value of one arg depend
382 value. This can be surprising because you will be used to seeing the 410 on the possibly-overridden value of another, write two separate
383 overridden value. If you need to make the default value of one arg 411 declare_args() blocks:
384 dependent on the possibly-overridden value of another, write two separate
385 declare_args blocks:
386 412
387 declare_args() { 413 declare_args() {
388 enable_foo = true 414 enable_foo = true
389 } 415 }
390 declare_args() { 416 declare_args() {
391 # Bar defaults to same user-overridden state as foo. 417 # Bar defaults to same user-overridden state as foo.
392 enable_bar = enable_foo 418 enable_bar = enable_foo
393 } 419 }
394 420
395 Example 421 Example
(...skipping 12 matching lines...) Expand all
408 Value RunDeclareArgs(Scope* scope, 434 Value RunDeclareArgs(Scope* scope,
409 const FunctionCallNode* function, 435 const FunctionCallNode* function,
410 const std::vector<Value>& args, 436 const std::vector<Value>& args,
411 BlockNode* block, 437 BlockNode* block,
412 Err* err) { 438 Err* err) {
413 NonNestableBlock non_nestable(scope, function, "declare_args"); 439 NonNestableBlock non_nestable(scope, function, "declare_args");
414 if (!non_nestable.Enter(err)) 440 if (!non_nestable.Enter(err))
415 return Value(); 441 return Value();
416 442
417 Scope block_scope(scope); 443 Scope block_scope(scope);
444 block_scope.SetProperty(&kInDeclareArgsKey, &block_scope);
418 block->Execute(&block_scope, err); 445 block->Execute(&block_scope, err);
419 if (err->has_error()) 446 if (err->has_error())
420 return Value(); 447 return Value();
421 448
422 // Pass the values from our scope into the Args object for adding to the 449 // Pass the values from our scope into the Args object for adding to the
423 // scope with the proper values (taking into account the defaults given in 450 // scope with the proper values (taking into account the defaults given in
424 // the block_scope, and arguments passed into the build). 451 // the block_scope, and arguments passed into the build).
425 Scope::KeyValueMap values; 452 Scope::KeyValueMap values;
426 block_scope.GetCurrentScopeValues(&values); 453 block_scope.GetCurrentScopeValues(&values);
427 scope->settings()->build_settings()->build_args().DeclareArgs( 454 scope->settings()->build_settings()->build_args().DeclareArgs(
(...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after
1107 } 1134 }
1108 1135
1109 // Otherwise it's a no-block function. 1136 // Otherwise it's a no-block function.
1110 if (!VerifyNoBlockForFunctionCall(function, block, err)) 1137 if (!VerifyNoBlockForFunctionCall(function, block, err))
1111 return Value(); 1138 return Value();
1112 return found_function->second.no_block_runner(scope, function, 1139 return found_function->second.no_block_runner(scope, function,
1113 args.list_value(), err); 1140 args.list_value(), err);
1114 } 1141 }
1115 1142
1116 } // namespace functions 1143 } // namespace functions
OLDNEW
« no previous file with comments | « tools/gn/functions.h ('k') | tools/gn/functions_unittest.cc » ('j') | tools/gn/scope.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698