[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" }

Reply via email to