aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.cc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2022-10-31 06:11:28 -0400
committerNathan Sidwell <nathan@acm.org>2022-11-01 06:04:48 -0400
commit0122faae30fe1ad1dfa8c69f3d3f0428b996b600 (patch)
treeb22a5db786c232d8636ce81e8898afc4a66c7340 /gcc/cp/lambda.cc
parent4acc4c2be84d66075d60736623c3a7134d129eaa (diff)
downloadgcc-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.cc96
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)
{