[dcl.attr.noreturn] says "The first declaration of a function shall specify the noreturn attribute if any declaration of that function specifies the noreturn attribute" meaning that we should diagnose
void func (); void func [[noreturn]] (); but we do not. I'd been meaning to issue a hard error for [[noreturn]] and only a warning for __attribute__((noreturn)) but then I found out that we treat [[noreturn]] exactly as the GNU attribute, and so cxx11_attribute_p returns false for it, so I decided to make it a pedwarn for all the cases. A pedwarn counts as a diagnostic, so we'd be conforming still. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-06-15 Marek Polacek <pola...@redhat.com> PR c++/60364 - noreturn after first decl not diagnosed. * decl.c (duplicate_decls): Warn when the first declaration doesn't have noreturn but a subsequent has. * g++.dg/warn/noreturn-8.C: New test. diff --git gcc/cp/decl.c gcc/cp/decl.c index 0a3ef452536..e50873d111c 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -1922,10 +1922,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TREE_CODE (newdecl) == FUNCTION_DECL) { - if (merge_attr && diagnose_mismatched_attributes (olddecl, newdecl)) - inform (olddecl_loc, DECL_INITIAL (olddecl) - ? G_("previous definition of %qD here") - : G_("previous declaration of %qD here"), olddecl); + if (merge_attr) + { + if (diagnose_mismatched_attributes (olddecl, newdecl)) + inform (olddecl_loc, DECL_INITIAL (olddecl) + ? G_("previous definition of %qD here") + : G_("previous declaration of %qD here"), olddecl); + + /* [dcl.attr.noreturn]: The first declaration of a function shall + specify the noreturn attribute if any declaration of that function + specifies the noreturn attribute. */ + if (TREE_THIS_VOLATILE (newdecl) + && !TREE_THIS_VOLATILE (olddecl) + && pedwarn (newdecl_loc, OPT_Wpedantic, "function %qD declared " + "%<noreturn%> but its first declaration was not", + newdecl)) + inform (olddecl_loc, "previous declaration of %qD", olddecl); + } /* Now that functions must hold information normally held by field decls, there is extra work to do so that diff --git gcc/testsuite/g++.dg/warn/noreturn-8.C gcc/testsuite/g++.dg/warn/noreturn-8.C new file mode 100644 index 00000000000..d876cf9d156 --- /dev/null +++ gcc/testsuite/g++.dg/warn/noreturn-8.C @@ -0,0 +1,21 @@ +// PR c++/60364 - noreturn after first decl not diagnosed. +// { dg-do compile { target c++11 } } +// { dg-options "-Wpedantic" } + +void f (); // { dg-message "previous declaration" } +void f [[noreturn]] (); // { dg-warning "declared 'noreturn' but its first declaration was not" } + +void f2 (); // { dg-message "previous declaration" } +void f2 [[gnu::noreturn]] (); // { dg-warning "declared 'noreturn' but its first declaration was not" } + +void f3 (); // { dg-message "previous declaration" } +__attribute__((noreturn)) void f3 (); // { dg-warning "declared 'noreturn' but its first declaration was not" } + +void f4 () { __builtin_abort (); } // { dg-message "previous declaration" } +void f4 [[noreturn]] (); // { dg-warning "declared 'noreturn' but its first declaration was not" } + +void f5 () { __builtin_abort (); } // { dg-message "previous declaration" } +void f5 [[gnu::noreturn]] (); // { dg-warning "declared 'noreturn' but its first declaration was not" } + +void f6 () { __builtin_abort (); } // { dg-message "previous declaration" } +__attribute__((noreturn)) void f6 (); // { dg-warning "declared 'noreturn' but its first declaration was not" }