diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6d84514e4c0..4c0bacb91da 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1500,9 +1500,10 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_EXTRA_SCOPE(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_scope) -/* If EXTRA_SCOPE, this is the number of the lambda within that scope. */ -#define LAMBDA_EXPR_DISCRIMINATOR(NODE) \ - (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator) +/* Lambdas in the same extra scope might need a discriminating count. + This is a single per-scope count. */ +#define LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator_scope) /* During parsing of the lambda, a vector of capture proxies which need to be pushed once we're done processing a nested lambda. */ @@ -1530,8 +1531,8 @@ struct GTY (()) tree_lambda_expr tree regen_info; vec *pending_proxies; location_t locus; - enum cp_lambda_default_capture_mode_type default_capture_mode : 8; - short int discriminator; + enum cp_lambda_default_capture_mode_type default_capture_mode : 2; + unsigned discriminator_scope : 15; // Per-scope discriminator }; /* Non-zero if this template specialization has access violations that @@ -7778,10 +7779,10 @@ extern tree cp_build_vec_convert (tree, location_t, tree, tsubst_flags_t); extern tree cp_build_bit_cast (location_t, tree, tree, tsubst_flags_t); -extern void start_lambda_scope (tree); -extern void record_lambda_scope (tree); -extern void record_null_lambda_scope (tree); +extern void start_lambda_scope (tree decl); extern void finish_lambda_scope (void); +extern void record_lambda_scope (tree lambda); +extern void record_lambda_scope_discriminator (tree lambda); extern tree start_lambda_function (tree fn, tree lambda_expr); extern void finish_lambda_function (tree body); extern bool regenerated_lambda_fn_p (tree); diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index e9d5d4dc1c5..d2673e2ceeb 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 *lambda_scope_stack; +// The current scope. +static GTY(()) lambda_discriminator lambda_scope; +// Stack of previous scopes. +static GTY(()) vec *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) - { - /* Don't reset the count if we're still in the same function. */ - lambda_scope = decl; - lambda_count = 0; - } -} - -void -record_lambda_scope (tree lambda) -{ - LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope; - LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++; - if (lambda_scope) - { - tree closure = LAMBDA_EXPR_CLOSURE (lambda); - gcc_checking_assert (closure); - maybe_key_decl (lambda_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. */ - -void -record_null_lambda_scope (tree lambda) -{ - if (vec_safe_is_empty (lambda_scope_stack)) - record_lambda_scope (lambda); + // If we're inside a function, we ignore variable scope. Don't push. + lambda_scope.nesting++; else { - tree_int *p = lambda_scope_stack->begin(); - LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t; - LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++; + vec_safe_push (lambda_scope_stack, lambda_scope); + lambda_scope.scope = decl; + lambda_scope.nesting = 0; + lambda_scope.count = 0; } - gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE); } +// Pop from the current lambda extra scope. + void finish_lambda_scope (void) { - tree_int *p = &lambda_scope_stack->last (); - if (lambda_scope != p->t) + if (!lambda_scope.nesting--) { - lambda_scope = p->t; - lambda_count = p->i; + lambda_scope = lambda_scope_stack->last (); + lambda_scope_stack->pop (); } - lambda_scope_stack->pop (); +} + +// Record the current lambda scope into LAMBDA + +void +record_lambda_scope (tree lambda) +{ + 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.scope, TYPE_NAME (closure)); + } +} + +// 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++; } 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) { diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index e39621876ef..a62c9756c91 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1810,7 +1810,7 @@ write_closure_type_name (const tree type) write_method_parms (parms, /*method_p=*/1, fn); write_char ('E'); - write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); + write_compact_number (LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda)); } /* Convert NUMBER to ascii using base BASE and generating at least diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 9957df510e6..df05b524136 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -6327,7 +6327,7 @@ trees_out::core_vals (tree t) if (streaming_p ()) { WU (((lang_tree_node *)t)->lambda_expression.default_capture_mode); - WU (((lang_tree_node *)t)->lambda_expression.discriminator); + WU (((lang_tree_node *)t)->lambda_expression.discriminator_scope); } break; @@ -6819,7 +6819,7 @@ trees_in::core_vals (tree t) = state->read_location (*this); RUC (cp_lambda_default_capture_mode_type, ((lang_tree_node *)t)->lambda_expression.default_capture_mode); - RU (((lang_tree_node *)t)->lambda_expression.discriminator); + RU (((lang_tree_node *)t)->lambda_expression.discriminator_scope); break; case OVERLOAD: diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 6da32801bab..e0e3cf3eaf6 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -11035,6 +11035,7 @@ cp_parser_lambda_expression (cp_parser* parser) return error_mark_node; record_lambda_scope (lambda_expr); + record_lambda_scope_discriminator (lambda_expr); /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ determine_visibility (TYPE_NAME (type)); @@ -11085,9 +11086,7 @@ cp_parser_lambda_expression (cp_parser* parser) ok = false; if (ok) - { - cp_parser_lambda_body (parser, lambda_expr); - } + cp_parser_lambda_body (parser, lambda_expr); else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) { if (cp_parser_skip_to_closing_brace (parser)) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 51bfbbcd36d..fc6279c00a3 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19866,21 +19866,13 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (type == error_mark_node) return error_mark_node; - if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE) - { - /* A lambda in a default argument outside a class gets no - LAMBDA_EXPR_EXTRA_SCOPE, as specified by the ABI. But - tsubst_default_argument calls start_lambda_scope, so we need to - specifically ignore it here, and use the global scope. */ - record_null_lambda_scope (r); - - /* If we're pushed into another scope (PR105652), fix it. */ - if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t))) - TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type)) - = TYPE_CONTEXT (TREE_TYPE (t)); - } - else + if (LAMBDA_EXPR_EXTRA_SCOPE (t)) record_lambda_scope (r); + else if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t))) + /* If we're pushed into another scope (PR105652), fix it. */ + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type)) + = TYPE_CONTEXT (TREE_TYPE (t)); + record_lambda_scope_discriminator (r); /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ determine_visibility (TYPE_NAME (type)); @@ -19911,29 +19903,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) fntype = build_memfn_type (fntype, type, type_memfn_quals (fntype), type_memfn_rqual (fntype)); - tree fn, tmpl; - if (oldtmpl) + tree inst = (oldtmpl + ? tsubst_template_decl (oldtmpl, args, complain, fntype) + : tsubst_function_decl (oldfn, args, complain, fntype)); + if (inst == error_mark_node) { - tmpl = tsubst_template_decl (oldtmpl, args, complain, fntype); - if (tmpl == error_mark_node) - { - r = error_mark_node; - goto out; - } - fn = DECL_TEMPLATE_RESULT (tmpl); - finish_member_declaration (tmpl); - } - else - { - tmpl = NULL_TREE; - fn = tsubst_function_decl (oldfn, args, complain, fntype); - if (fn == error_mark_node) - { - r = error_mark_node; - goto out; - } - finish_member_declaration (fn); + r = error_mark_node; + goto out; } + finish_member_declaration (inst); + + tree fn = oldtmpl ? DECL_TEMPLATE_RESULT (inst) : inst; /* Let finish_function set this. */ DECL_DECLARED_CONSTEXPR_P (fn) = false; diff --git a/gcc/testsuite/g++.dg/abi/lambda-sig1-17.C b/gcc/testsuite/g++.dg/abi/lambda-sig1-17.C new file mode 100644 index 00000000000..cb71209f957 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-sig1-17.C @@ -0,0 +1,26 @@ +// { dg-do compile { target c++20 } } +// { dg-options -fabi-version=17 } + +#include "lambda-sig1.h" + +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfE0_clEf:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfE3_clEf:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfT_E1_clIiEEDafS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlfT_E4_clIiEEDafS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlT_E2_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj0EE2FnEvENKUlT_E_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE0_clEf:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE3_clEf:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfE6_clEf:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfT_E1_clIiEEDafS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfT_E4_clIiEEDafS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlfT_E7_clIiEEDafS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlT_E2_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlT_E5_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIfLj1EE2FnEvENKUlT_E_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliE0_clEi:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliE3_clEi:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliT_E1_clIiEEDaiS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUliT_E4_clIiEEDaiS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlT_E2_clIiEEDaS1_:} } } +// { dg-final { scan-assembler {_ZZN1XIiLj0EE2FnEvENKUlT_E_clIiEEDaS1_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-sig1.h b/gcc/testsuite/g++.dg/abi/lambda-sig1.h new file mode 100644 index 00000000000..a8b77ae0ebf --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-sig1.h @@ -0,0 +1,42 @@ +template struct X +{ + void Fn () + { + { + auto v1 = [] (U) {}; + auto v2 = [] (T) {}; + auto v3 = [] (T, U) {}; + + v1 (1); + v2 (1); + v3 (1, 2); + } + if constexpr (I) + { + auto v1 = [] (U) {}; + auto v2 = [] (T) {}; + auto v3 = [] (T, U) {}; + + v1 (1); + v2 (1); + v3 (1, 2); + } + { + auto v1 = [] (U) {}; + auto v2 = [] (T) {}; + auto v3 = [] (T, U) {}; + + v1 (1); + v2 (1); + v3 (1, 2); + } + + }; +}; + +void f (X &x, X &y, X &z) +{ + x.Fn (); + y.Fn (); + z.Fn (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-11.C b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-11.C new file mode 100644 index 00000000000..9847587950c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-11.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++14 } } +// { dg-additional-options -fabi-version=11 } + +// PRs 78621 + +#include "lambda-mangle-1.h" + +// We erroneously mangled lambda auto parms as-if template parameters (T_), +// rather than auto (Da). Fixed in abi version 11 + + +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E0_EOS1_S2_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE1_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E2_EOS0_RS0_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E0_EvS2_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE1_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E2_EvRS0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPT_PT0_E4_EvRS1_RS3_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPT_PT0_E4_Z3FoovEUlS1_S3_E5_EvRS0_RS2_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsDpPT_E1_EvRT_RT0_:" } } diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-17.C b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-17.C new file mode 100644 index 00000000000..31af5b89bfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1-17.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++14 } } +// { dg-additional-options -fabi-version=17 } + +// PRs 78621 + +#include "lambda-mangle-1.h" + +// We erroneously mangled lambda auto parms as-if template parameters (T_), +// rather than auto (Da). Fixed in abi version 11 +// Up to abi version 17 we had a single per-scope discriminator + +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E0_EOS1_S2_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE1_EOS0_S1_:" } } +// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E2_EOS0_RS0_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E0_EvS2_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE1_EvS1_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E2_EvRS0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPT_PT0_E4_EvRS1_RS3_:" } } +// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPT_PT0_E4_Z3FoovEUlS1_S3_E5_EvRS0_RS2_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_:" } } +// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsDpPT_E1_EvRT_RT0_:" } } diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.h similarity index 98% rename from gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C rename to gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.h index 8f135358465..c91ce0186d8 100644 --- a/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.h @@ -23,7 +23,7 @@ template { } -void Foo () +inline void Foo () { auto lam = [](auto &) { }; auto lam_1 = [](int &, auto &) { }; @@ -70,6 +70,7 @@ template void Bar () void Baz () { Bar (); + Foo (); } // { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } } diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index e2d5039a0a1..b0f0cb96626 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -1655,7 +1655,7 @@ plugin_start_closure_class_type (cc1_plugin::connection *self, /* Instead of calling record_lambda_scope, do this: */ LAMBDA_EXPR_EXTRA_SCOPE (lambda_expr) = extra_scope; - LAMBDA_EXPR_DISCRIMINATOR (lambda_expr) = discriminator; + LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda_expr) = discriminator; tree decl = TYPE_NAME (type); determine_visibility (decl);