diff options
author | Nathan Sidwell <nathan@acm.org> | 2022-10-31 06:11:28 -0400 |
---|---|---|
committer | Nathan Sidwell <nathan@acm.org> | 2022-11-01 06:04:48 -0400 |
commit | 0122faae30fe1ad1dfa8c69f3d3f0428b996b600 (patch) | |
tree | b22a5db786c232d8636ce81e8898afc4a66c7340 /gcc/cp/lambda.cc | |
parent | 4acc4c2be84d66075d60736623c3a7134d129eaa (diff) | |
download | gcc-0122faae30fe1ad1dfa8c69f3d3f0428b996b600.zip gcc-0122faae30fe1ad1dfa8c69f3d3f0428b996b600.tar.gz gcc-0122faae30fe1ad1dfa8c69f3d3f0428b996b600.tar.bz2 |
c++: Reorganize per-scope lambda discriminators
We currently use a per-extra-scope counter to discriminate multiple
lambdas in a particular such scope. This is not ABI compliant. This
patch merely refactors the existing code to make it easier to drop in
a conformant mangling -- there's no functional change here. I rename
the LAMBDA_EXPR_DISCIMINATOR to LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR,
foreshadowing that there'll be a new discriminator. To provide ABI
warnings we'll need to calculate both, and that requires some
repacking of the lambda_expr's fields. Finally, although we end up
calling the discriminator setter and the scope recorder (nearly)
always consecutively, it's clearer to handle it as two separate
operations. That also allows us to remove the instantiation
special-case for a null extra-scope.
gcc/cp/
* cp-tree.h (LAMBDA_EXPR_DISCRIMINATOR): Rename to ...
(LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR): ... here.
(struct tree_lambda_expr): Make default_capture_mode &
discriminator_scope bitfields.
(record_null_lambda_scope) Delete.
(record_lambda_scope_discriminator): Declare.
* lambda.cc (struct lambda_discriminator): New struct.
(lambda_scope, lambda_scope_stack): Adjust types.
(lambda_count): Delete.
(struct tree_int): Delete.
(start_lambda_scope, finish_lambda_scope): Adjust.
(record_lambda_scope): Only record the scope.
(record_lambda_scope_discriminator): New.
* mangle.cc (write_closure_type_name): Adjust.
* module.cc (trees_out::core_vals): Likewise,
(trees_in::core_vals): Likewise.
* parser.cc (cp_parser_lambda_expression): Call
record_lambda_scope_discriminator.
* pt.cc (tsubst_lambda_expr): Adjust record_lambda_scope caling. Call
record_lambda_scope_discriminator. Commonize control flow on tsubsting
the operator function.
libcc1/
* libcp1plugin.cc (plugin_start_closure): Adjust.
gcc/testsuite/
* g++.dg/abi/lambda-sig1-17.C: New.
* g++.dg/abi/lambda-sig1.h: New.
* g++.dg/cpp1y/lambda-mangle-1.C: Extracted to ...
* g++.dg/cpp1y/lambda-mangle-1.h: ... here.
* g++.dg/cpp1y/lambda-mangle-1-11.C: New
* g++.dg/cpp1y/lambda-mangle-1-17.C
Diffstat (limited to 'gcc/cp/lambda.cc')
-rw-r--r-- | gcc/cp/lambda.cc | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index e9d5d4d..d2673e2 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -1444,79 +1444,77 @@ is_lambda_ignored_entity (tree val) return false; } -/* Lambdas that appear in variable initializer or default argument scope - get that in their mangling, so we need to record it. We might as well - use the count for function and namespace scopes as well. */ -static GTY(()) tree lambda_scope; -static GTY(()) int lambda_count; -struct GTY(()) tree_int +/* Lambdas that appear in variable initializer or default argument + scope get that in their mangling, so we need to record it. Also, + multiple lambdas in the same scope may need a mangling + discriminator. Record in the same data structure. */ +struct GTY(()) lambda_discriminator { - tree t; - int i; + tree scope; + unsigned nesting; // Inside a function, VAR_DECLs get the function + // as scope. This counts that nesting. + unsigned count; // The per-scope counter. }; -static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack; +// The current scope. +static GTY(()) lambda_discriminator lambda_scope; +// Stack of previous scopes. +static GTY(()) vec<lambda_discriminator, va_gc> *lambda_scope_stack; + +// Push DECL as lambda extra scope, also new discriminator counters. void start_lambda_scope (tree decl) { - tree_int ti; - gcc_assert (decl); - /* Once we're inside a function, we ignore variable scope and just push - the function again so that popping works properly. */ + gcc_checking_assert (decl); if (current_function_decl && TREE_CODE (decl) == VAR_DECL) - decl = current_function_decl; - ti.t = lambda_scope; - ti.i = lambda_count; - vec_safe_push (lambda_scope_stack, ti); - if (lambda_scope != decl) + // If we're inside a function, we ignore variable scope. Don't push. + lambda_scope.nesting++; + else { - /* Don't reset the count if we're still in the same function. */ - lambda_scope = decl; - lambda_count = 0; + vec_safe_push (lambda_scope_stack, lambda_scope); + lambda_scope.scope = decl; + lambda_scope.nesting = 0; + lambda_scope.count = 0; } } +// Pop from the current lambda extra scope. + void -record_lambda_scope (tree lambda) +finish_lambda_scope (void) { - LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope; - LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; - if (lambda_scope) + if (!lambda_scope.nesting--) { - tree closure = LAMBDA_EXPR_CLOSURE (lambda); - gcc_checking_assert (closure); - maybe_key_decl (lambda_scope, TYPE_NAME (closure)); + lambda_scope = lambda_scope_stack->last (); + lambda_scope_stack->pop (); } } -/* This lambda is an instantiation of a lambda in a template default argument - that got no LAMBDA_EXPR_EXTRA_SCOPE, so this shouldn't either. But we do - need to use and increment the global count to avoid collisions. */ +// Record the current lambda scope into LAMBDA void -record_null_lambda_scope (tree lambda) +record_lambda_scope (tree lambda) { - if (vec_safe_is_empty (lambda_scope_stack)) - record_lambda_scope (lambda); - else + LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope.scope; + if (lambda_scope.scope) { - tree_int *p = lambda_scope_stack->begin(); - LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t; - LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++; + tree closure = LAMBDA_EXPR_CLOSURE (lambda); + gcc_checking_assert (closure); + maybe_key_decl (lambda_scope.scope, TYPE_NAME (closure)); } - gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE); } +// Record the per-scope discriminator of LAMBDA. If the extra scope +// is empty, we must use the empty scope counter, which might not be +// the live one. + void -finish_lambda_scope (void) +record_lambda_scope_discriminator (tree lambda) { - tree_int *p = &lambda_scope_stack->last (); - if (lambda_scope != p->t) - { - lambda_scope = p->t; - lambda_count = p->i; - } - lambda_scope_stack->pop (); + auto *slot = (vec_safe_is_empty (lambda_scope_stack) + || LAMBDA_EXPR_EXTRA_SCOPE (lambda) + ? &lambda_scope : lambda_scope_stack->begin ()); + LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda) = slot->count++; } tree @@ -1648,6 +1646,10 @@ prune_lambda_captures (tree body) } } +// Record the per-scope per-signature discriminator of LAMBDA. If the +// extra scope is empty, we must use the empty scope counter, which +// might not be the live one. + void finish_lambda_function (tree body) { |