diff options
-rw-r--r-- | gcc/cp/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cp/parser.c | 20 | ||||
-rw-r--r-- | gcc/cp/tree.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/lambda-vis.C | 23 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle74.C | 30 |
5 files changed, 92 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 938504b..bb5f77f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2020-03-18 Nathan Sidwell <nathan@acm.org> + + PR c++/94147 - mangling of lambdas assigned to globals + * parser.c (cp_parser_init_declarator): Namespace-scope variables + provide a lambda scope. + * tree.c (no_linkage_check): Lambdas with a variable for extra + scope have a linkage from the variable. + 2020-03-18 Jakub Jelinek <jakub@redhat.com> * constraint.cc (resolve_function_concept_check, subsumes_constraints, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 26e0236..198ab97 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20761,16 +20761,24 @@ cp_parser_init_declarator (cp_parser* parser, else { /* We want to record the extra mangling scope for in-class - initializers of class members and initializers of static data - member templates. The former involves deferring - parsing of the initializer until end of class as with default - arguments. So right here we only handle the latter. */ - if (!member_p && processing_template_decl && decl != error_mark_node) + initializers of class members and initializers of static + data member templates and namespace-scope initializers. + The former involves deferring parsing of the initializer + until end of class as with default arguments. So right + here we only handle the latter two. */ + bool has_lambda_scope = false; + + if (decl != error_mark_node + && !member_p + && (processing_template_decl || DECL_NAMESPACE_SCOPE_P (decl))) + has_lambda_scope = true; + + if (has_lambda_scope) start_lambda_scope (decl); initializer = cp_parser_initializer (parser, &is_direct_init, &is_non_constant_init); - if (!member_p && processing_template_decl && decl != error_mark_node) + if (has_lambda_scope) finish_lambda_scope (); if (initializer == error_mark_node) cp_parser_skip_to_end_of_statement (parser); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index a412345..da2e7fd 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2794,9 +2794,23 @@ no_linkage_check (tree t, bool relaxed_p) fix it up later if not. We need to check this even in templates so that we properly handle a lambda-expression in the signature. */ if (LAMBDA_TYPE_P (t) - && CLASSTYPE_LAMBDA_EXPR (t) != error_mark_node - && LAMBDA_TYPE_EXTRA_SCOPE (t) == NULL_TREE) - return t; + && CLASSTYPE_LAMBDA_EXPR (t) != error_mark_node) + { + tree extra = LAMBDA_TYPE_EXTRA_SCOPE (t); + if (!extra) + return t; + + /* If the mangling scope is internal-linkage or not repeatable + elsewhere, the lambda effectively has no linkage. (Sadly + we're not very careful with the linkages of types.) */ + if (TREE_CODE (extra) == VAR_DECL + && !(TREE_PUBLIC (extra) + && (processing_template_decl + || (DECL_LANG_SPECIFIC (extra) && DECL_USE_TEMPLATE (extra)) + /* DECL_COMDAT is set too late for us to check. */ + || DECL_VAR_DECLARED_INLINE_P (extra)))) + return t; + } /* Otherwise there's no point in checking linkage on template functions; we can't know their complete types. */ diff --git a/gcc/testsuite/g++.dg/abi/lambda-vis.C b/gcc/testsuite/g++.dg/abi/lambda-vis.C new file mode 100644 index 0000000..c3eb157 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-vis.C @@ -0,0 +1,23 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-fno-inline" } + +template<typename T> int sfoo (T); // { dg-warning "used but never defined" } +template<typename T> int gfoo (T); // { dg-warning "used but never defined" } +template<typename T> int ifoo (T); // OK +template<typename T> struct Wrapper {}; +template<typename T> Wrapper<T> capture (T &&) {return Wrapper<T> ();} + +static int svar = sfoo (capture ([]{})); + +int gvar = gfoo (capture ([]{})); + +inline int ivar = ifoo (capture ([]{})); + +// { dg-final { scan-assembler {_Z7captureINL4svarMUlvE_EE7WrapperIT_EOS2_:} } } +// { dg-final { scan-assembler {_Z7captureIN4gvarMUlvE_EE7WrapperIT_EOS2_:} } } +// { dg-final { scan-assembler {_Z7captureIN4ivarMUlvE_EE7WrapperIT_EOS2_:} } } + +// Calls to the foos are emitted. +// { dg-final { scan-assembler {call[ \t]*_Z4sfooI7WrapperINL4svarMUlvE_EEEiT_} { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler {call[ \t]*_Z4gfooI7WrapperIN4gvarMUlvE_EEEiT_} { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler {call[ \t]*_Z4ifooI7WrapperIN4ivarMUlvE_EEEiT_} { target { i?86-*-* x86_64-*-* } } } } diff --git a/gcc/testsuite/g++.dg/abi/mangle74.C b/gcc/testsuite/g++.dg/abi/mangle74.C new file mode 100644 index 0000000..4e1c632 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle74.C @@ -0,0 +1,30 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-fno-inline -O0" } + +inline auto var = [] () {return 2;}; + +int bob () +{ +return var (); +} + +struct Foo +{ + static inline auto bar = [] () {return 4;}; +}; + +int bill () +{ + return Foo::bar (); +} + +// this one should have internal linkage (from svar) +static auto svar = [] () {return 8;}; +int thorn () +{ + return svar (); +} + +// { dg-final { scan-assembler "_ZNK3varMUlvE_clEv:" } } +// { dg-final { scan-assembler "_ZNK3Foo3barMUlvE_clEv:" { xfail *-*-* } } } +// { dg-final { scan-assembler-not "_ZNK3FooUlvE_clEv:" { xfail *-*-* } } } |