Another ICE with delayed noexcept parsing, but a bit gnarlier. A function definition marked with __attribute__((used)) ought to be emitted even when it is not referenced in a TU. For a member function template marked with __attribute__((used)) this means that it will be instantiated: in instantiate_class_template_1 we have
11971 /* Instantiate members marked with attribute used. */ 11972 if (r != error_mark_node && DECL_PRESERVE_P (r)) 11973 mark_used (r); It is not so surprising that this doesn't work well with delayed noexcept parsing: when we're processing the function template we delay the parsing, so the member "foo" is found, but then when we're instantiating it, "foo" hasn't yet been seen, which creates a discrepancy and a crash ensues. "foo" hasn't yet been seen because instantiate_class_template_1 just loops over the class members and instantiates right away. It stands to reason to disable delayed noexcept parsing when the function is marked with used (clang++ also rejects). Unfortunately we can't just use lookup_attribute when parsing and check if "used" is there and if so, clear CP_PARSER_FLAGS_DELAY_NOEXCEPT, because we accept attributes following the noexcept-specifier, like this: void g() noexcept(...) __attribute__((used)); Oh well. This patch should handle various forms of attributes in one place. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10? gcc/cp/ChangeLog: PR c++/97966 * parser.c (cp_parser_save_default_args): Don't delay parsing of the noexcept-specifier of a function marked with attribute used. gcc/testsuite/ChangeLog: PR c++/97966 * g++.dg/cpp0x/noexcept63.C: New test. --- gcc/cp/parser.c | 20 +++++++++- gcc/testsuite/g++.dg/cpp0x/noexcept63.C | 49 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept63.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c713852fe93..07ab966e099 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30880,7 +30880,25 @@ cp_parser_save_default_args (cp_parser* parser, tree decl) /* Remember if there is a noexcept-specifier to post process. */ tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); if (UNPARSED_NOEXCEPT_SPEC_P (spec)) - vec_safe_push (unparsed_noexcepts, decl); + { + /* Don't actually delay parsing of the noexcept-specifier of + a member function marked with attribute used. */ + if (__builtin_expect (DECL_PRESERVE_P (decl), 0)) + { + auto cleanup = make_temp_override + (parser->local_variables_forbidden_p); + if (DECL_THIS_STATIC (decl)) + parser->local_variables_forbidden_p |= THIS_FORBIDDEN; + inject_this_parameter (current_class_type, TYPE_UNQUALIFIED); + spec = cp_parser_late_noexcept_specifier (parser, + TREE_PURPOSE (spec)); + if (spec == error_mark_node) + spec = NULL_TREE; + fixup_deferred_exception_variants (TREE_TYPE (decl), spec); + } + else + vec_safe_push (unparsed_noexcepts, decl); + } } /* DEFAULT_ARG contains the saved tokens for the initializer of DECL, diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept63.C b/gcc/testsuite/g++.dg/cpp0x/noexcept63.C new file mode 100644 index 00000000000..8efeac93a30 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept63.C @@ -0,0 +1,49 @@ +// PR c++/97966 +// { dg-do compile { target c++11 } } + +template <int> +struct S1 { + __attribute__((used)) S1() noexcept(noexcept(this->foo())); // { dg-error "has no member" } + void foo(); +}; + +template <int> +struct S2 { + __attribute__((used)) void bar() noexcept(noexcept(this->foo())); // { dg-error "has no member" } + void foo(); +}; + +template <int> +struct S3 { + void __attribute__((used)) bar() noexcept(noexcept(this->foo())); // { dg-error "has no member" } + void foo(); +}; + +template <int> +struct S4 { + [[gnu::used]] void bar() noexcept(noexcept(this->foo())); // { dg-error "has no member" } + void foo(); +}; + +template <int> +struct S5 { + void bar() noexcept(noexcept(this->foo())) __attribute__((used)); // { dg-error "has no member" } + void foo(); +}; + +template <int> +struct S6 { + static void bar() noexcept(noexcept(this->foo())) __attribute__((used)); // { dg-error ".this. may not be used in this context" } + void foo(); +}; + +void +g () +{ + S1<1> s1; + S2<1> s2; + S3<1> s3; + S4<1> s4; + S5<1> s5; + S6<1> s6; +} base-commit: cfaaa6a1ca744c1a93fa08a3e7ab2a821383cac1 -- 2.29.2