diff options
author | Martin Liska <mliska@suse.cz> | 2022-11-07 08:24:48 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-11-07 08:24:48 +0100 |
commit | 1b09b78ee61bd921ae78ebd0f7905b95b9e1c903 (patch) | |
tree | 9c04b59cdd2cd460f0727501d15402d31ffcf5a4 /gcc/cp/lambda.cc | |
parent | 1eb021edb27e26f95cda63df121f6bc951647599 (diff) | |
parent | c4f8f8afd07680f9e718de1331cd09607bdd9ac8 (diff) | |
download | gcc-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.cc | 236 |
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) { |