aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.cc
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-11-07 08:24:48 +0100
committerMartin Liska <mliska@suse.cz>2022-11-07 08:24:48 +0100
commit1b09b78ee61bd921ae78ebd0f7905b95b9e1c903 (patch)
tree9c04b59cdd2cd460f0727501d15402d31ffcf5a4 /gcc/cp/lambda.cc
parent1eb021edb27e26f95cda63df121f6bc951647599 (diff)
parentc4f8f8afd07680f9e718de1331cd09607bdd9ac8 (diff)
downloadgcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.zip
gcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.tar.gz
gcc-1b09b78ee61bd921ae78ebd0f7905b95b9e1c903.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/cp/lambda.cc')
-rw-r--r--gcc/cp/lambda.cc236
1 files changed, 192 insertions, 44 deletions
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index e9d5d4d..c7a9268 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -1444,79 +1444,223 @@ 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. In ABI <= 17, there is a single per-scope sequence
+ number. In ABI >= 18, there are per-scope per-signature sequence
+ numbers. */
+struct GTY(()) lambda_sig_count
{
- tree t;
- int i;
+ tree fn; // The lambda fn whose sig this is.
+ unsigned count;
+};
+struct GTY(()) lambda_discriminator
+{
+ tree scope;
+ unsigned nesting; // Inside a function, VAR_DECLs get the function
+ // as scope. This counts that nesting.
+ unsigned count; // The per-scope counter.
+ vec<lambda_sig_count, va_gc> *discriminators; // Per-signature counters
};
-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
+ {
+ vec_safe_push (lambda_scope_stack, lambda_scope);
+ lambda_scope.scope = decl;
+ lambda_scope.nesting = 0;
+ lambda_scope.count = 0;
+ lambda_scope.discriminators = nullptr;
+ }
+}
+
+// Pop from the current lambda extra scope.
+
+void
+finish_lambda_scope (void)
+{
+ if (!lambda_scope.nesting--)
{
- /* Don't reset the count if we're still in the same function. */
- lambda_scope = decl;
- lambda_count = 0;
+ lambda_scope = lambda_scope_stack->last ();
+ lambda_scope_stack->pop ();
}
}
+// Record the current lambda scope into LAMBDA
+
void
record_lambda_scope (tree lambda)
{
- LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
- LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
- if (lambda_scope)
+ LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope.scope;
+ if (lambda_scope.scope)
{
tree closure = LAMBDA_EXPR_CLOSURE (lambda);
gcc_checking_assert (closure);
- maybe_key_decl (lambda_scope, TYPE_NAME (closure));
+ maybe_key_decl (lambda_scope.scope, TYPE_NAME (closure));
}
}
-/* 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. */
+// Compare lambda template heads TMPL_A and TMPL_B, used for both
+// templated lambdas, and template template parameters of said lambda.
-void
-record_null_lambda_scope (tree lambda)
+static bool
+compare_lambda_template_head (tree tmpl_a, tree tmpl_b)
{
- if (vec_safe_is_empty (lambda_scope_stack))
- record_lambda_scope (lambda);
- else
+ // We only need one level of template parms
+ tree inner_a = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl_a));
+ tree inner_b = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl_b));
+
+ // We only compare explicit template parms, ignoring trailing
+ // synthetic ones.
+ int len_a = TREE_VEC_LENGTH (inner_a);
+ int len_b = TREE_VEC_LENGTH (inner_b);
+
+ for (int ix = 0, len = MAX (len_a, len_b); ix != len; ix++)
{
- tree_int *p = lambda_scope_stack->begin();
- LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t;
- LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++;
+ tree parm_a = NULL_TREE;
+ if (ix < len_a)
+ {
+ parm_a = TREE_VEC_ELT (inner_a, ix);
+ if (parm_a == error_mark_node)
+ return false;
+ parm_a = TREE_VALUE (parm_a);
+ if (DECL_VIRTUAL_P (parm_a))
+ parm_a = NULL_TREE;
+ }
+
+ tree parm_b = NULL_TREE;
+ if (ix < len_b)
+ {
+ parm_b = TREE_VEC_ELT (inner_b, ix);
+ if (parm_b == error_mark_node)
+ return false;
+ parm_b = TREE_VALUE (parm_b);
+ if (DECL_VIRTUAL_P (parm_b))
+ parm_b = NULL_TREE;
+ }
+
+ if (!parm_a && !parm_b)
+ // we're done
+ break;
+
+ if (!(parm_a && parm_b))
+ return false;
+
+ if (TREE_CODE (parm_a) != TREE_CODE (parm_b))
+ return false;
+
+ if (TREE_CODE (parm_a) == PARM_DECL)
+ {
+ if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm_a))
+ != TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm_b)))
+ return false;
+
+ if (!same_type_p (TREE_TYPE (parm_a), TREE_TYPE (parm_b)))
+ return false;
+ }
+ else
+ {
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm_a))
+ != TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm_b)))
+ return false;
+
+ if (TREE_CODE (parm_a) != TEMPLATE_DECL)
+ gcc_checking_assert (TREE_CODE (parm_a) == TYPE_DECL);
+ else if (!compare_lambda_template_head (parm_a, parm_b))
+ return false;
+ }
}
- gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE);
+
+ return true;
}
-void
-finish_lambda_scope (void)
+// Compare lambda signatures FN_A and FN_B, they may be TEMPLATE_DECLs too.
+
+static bool
+compare_lambda_sig (tree fn_a, tree fn_b)
{
- tree_int *p = &lambda_scope_stack->last ();
- if (lambda_scope != p->t)
+ if (TREE_CODE (fn_a) == TEMPLATE_DECL
+ && TREE_CODE (fn_b) == TEMPLATE_DECL)
+ {
+ if (!compare_lambda_template_head (fn_a, fn_b))
+ return false;
+ fn_a = DECL_TEMPLATE_RESULT (fn_a);
+ fn_b = DECL_TEMPLATE_RESULT (fn_b);
+ }
+ else if (TREE_CODE (fn_a) == TEMPLATE_DECL
+ || TREE_CODE (fn_b) == TEMPLATE_DECL)
+ return false;
+
+ if (fn_a == error_mark_node
+ || fn_b == error_mark_node)
+ return false;
+
+ for (tree args_a = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_a))),
+ args_b = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_b)));
+ args_a || args_b;
+ args_a = TREE_CHAIN (args_a), args_b = TREE_CHAIN (args_b))
{
- lambda_scope = p->t;
- lambda_count = p->i;
+ if (!args_a || !args_b)
+ return false;
+ // This check also deals with differing varadicness
+ if (!same_type_p (TREE_VALUE (args_a), TREE_VALUE (args_b)))
+ return false;
}
- lambda_scope_stack->pop ();
+
+ return true;
+}
+
+// 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
+record_lambda_scope_discriminator (tree lambda)
+{
+ 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++;
+}
+
+// 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
+record_lambda_scope_sig_discriminator (tree lambda, tree fn)
+{
+ auto *slot = (vec_safe_is_empty (lambda_scope_stack)
+ || LAMBDA_EXPR_EXTRA_SCOPE (lambda)
+ ? &lambda_scope : lambda_scope_stack->begin ());
+ gcc_checking_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == slot->scope);
+
+ // A linear search, we're not expecting this to be a big list, and
+ // this avoids needing a signature hash function.
+ lambda_sig_count *sig;
+ if (unsigned ix = vec_safe_length (slot->discriminators))
+ for (sig = slot->discriminators->begin (); ix--; sig++)
+ if (compare_lambda_sig (fn, sig->fn))
+ goto found;
+ {
+ lambda_sig_count init = {fn, 0};
+ sig = vec_safe_push (slot->discriminators, init);
+ }
+ found:
+ LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda) = sig->count++;
}
tree
@@ -1648,6 +1792,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)
{