The C++ FE was missing diagnostics e.g. when an "always_inline" on DECL was
followed by DECL with the "noinline" attribute.  The C FE already has code
dealing with this, so I factored it out to a common function.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-05-11  Marek Polacek  <pola...@redhat.com>

        PR c++/71024
        * c-common.c (diagnose_mismatched_attributes): New function.
        * c-common.h (diagnose_mismatched_attributes): Declare.

        * c-decl.c (diagnose_mismatched_decls): Factor out code to
        diagnose_mismatched_attributes and call it.

        * decl.c (duplicate_decls): Call diagnose_mismatched_decls.

        * c-c++-common/attributes-3.c: New test.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index 63a18c8..665448c 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -12824,4 +12824,58 @@ get_source_date_epoch ()
   return (time_t) epoch;
 }
 
+/* Check and possibly warn if two declarations have contradictory
+   attributes, such as always_inline vs. noinline.  */
+
+bool
+diagnose_mismatched_attributes (tree olddecl, tree newdecl)
+{
+  bool warned = false;
+
+  tree a1 = lookup_attribute ("optimize", DECL_ATTRIBUTES (olddecl));
+  tree a2 = lookup_attribute ("optimize", DECL_ATTRIBUTES (newdecl));
+  /* An optimization attribute applied on a declaration after the
+     definition is likely not what the user wanted.  */
+  if (a2 != NULL_TREE
+      && DECL_SAVED_TREE (olddecl) != NULL_TREE
+      && (a1 == NULL_TREE || !attribute_list_equal (a1, a2)))
+    warned |= warning (OPT_Wattributes,
+                      "optimization attribute on %qD follows "
+                      "definition but the attribute doesn%'t match",
+                      newdecl);
+
+  /* Diagnose inline __attribute__ ((noinline)) which is silly.  */
+  if (DECL_DECLARED_INLINE_P (newdecl)
+      && DECL_UNINLINABLE (olddecl)
+      && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+    warned |= warning (OPT_Wattributes, "inline declaration of %qD follows "
+                      "declaration with attribute noinline", newdecl);
+  else if (DECL_DECLARED_INLINE_P (olddecl)
+          && DECL_UNINLINABLE (newdecl)
+          && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
+    warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+                      "noinline follows inline declaration ", newdecl);
+  else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))
+          && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl)))
+    warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+                      "%qs follows declaration with attribute %qs",
+                      newdecl, "noinline", "always_inline");
+  else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl))
+          && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+    warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+                      "%qs follows declaration with attribute %qs",
+                      newdecl, "always_inline", "noinline");
+  else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl))
+          && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl)))
+    warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+                      "%qs follows declaration with attribute %qs",
+                      newdecl, "cold", "hot");
+  else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl))
+          && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl)))
+    warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+                      "%qs follows declaration with attribute %qs",
+                      newdecl, "hot", "cold");
+  return warned;
+}
+
 #include "gt-c-family-c-common.h"
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index 4454d08..0ee9f56 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -850,6 +850,7 @@ extern bool keyword_is_type_qualifier (enum rid);
 extern bool keyword_is_decl_specifier (enum rid);
 extern bool cxx_fundamental_alignment_p (unsigned);
 extern bool pointer_to_zero_sized_aggr_p (tree);
+extern bool diagnose_mismatched_attributes (tree, tree);
 
 #define c_sizeof(LOC, T)  c_sizeof_or_alignof_type (LOC, T, true, false, 1)
 #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index 9c09536..6ba0e0e 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -2227,55 +2227,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
-    {
-      tree a1 = lookup_attribute ("optimize", DECL_ATTRIBUTES (olddecl));
-      tree a2 = lookup_attribute ("optimize", DECL_ATTRIBUTES (newdecl));
-      /* An optimization attribute applied on a declaration after the
-        definition is likely not what the user wanted.  */
-      if (a2 != NULL_TREE
-         && DECL_SAVED_TREE (olddecl) != NULL_TREE
-         && (a1 == NULL_TREE || !attribute_list_equal (a1, a2)))
-       warned |= warning (OPT_Wattributes,
-                          "optimization attribute on %qD follows "
-                          "definition but the attribute doesn%'t match",
-                          newdecl);
-
-      /* Diagnose inline __attribute__ ((noinline)) which is silly.  */
-      if (DECL_DECLARED_INLINE_P (newdecl)
-         && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-       warned |= warning (OPT_Wattributes,
-                          "inline declaration of %qD follows "
-                          "declaration with attribute noinline", newdecl);
-      else if (DECL_DECLARED_INLINE_P (olddecl)
-              && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
-       warned |= warning (OPT_Wattributes,
-                          "declaration of %q+D with attribute "
-                          "noinline follows inline declaration ", newdecl);
-      else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))
-              && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl)))
-       warned |= warning (OPT_Wattributes,
-                          "declaration of %q+D with attribute "
-                          "%qs follows declaration with attribute %qs",
-                          newdecl, "noinline", "always_inline");
-      else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl))
-              && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-       warned |= warning (OPT_Wattributes,
-                          "declaration of %q+D with attribute "
-                          "%qs follows declaration with attribute %qs",
-                          newdecl, "always_inline", "noinline");
-      else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl))
-              && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl)))
-       warned |= warning (OPT_Wattributes,
-                          "declaration of %q+D with attribute %qs follows "
-                          "declaration with attribute %qs", newdecl, "cold",
-                          "hot");
-      else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl))
-              && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl)))
-       warned |= warning (OPT_Wattributes,
-                          "declaration of %q+D with attribute %qs follows "
-                          "declaration with attribute %qs", newdecl, "hot",
-                          "cold");
-    }
+    warned |= diagnose_mismatched_attributes (olddecl, newdecl);
   else /* PARM_DECL, VAR_DECL */
     {
       /* Redeclaration of a parameter is a constraint violation (this is
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 8dbc730..126d870 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -1389,38 +1389,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
newdecl_is_friend)
   if (DECL_P (olddecl)
       && TREE_CODE (newdecl) == FUNCTION_DECL
       && TREE_CODE (olddecl) == FUNCTION_DECL
-      && (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl)))
-    {
-      if (DECL_DECLARED_INLINE_P (newdecl)
-         && DECL_UNINLINABLE (newdecl)
-         && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
-       /* Already warned elsewhere.  */;
-      else if (DECL_DECLARED_INLINE_P (olddecl)
-              && DECL_UNINLINABLE (olddecl)
-              && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-       /* Already warned.  */;
-      else if (DECL_DECLARED_INLINE_P (newdecl)
-              && DECL_UNINLINABLE (olddecl)
-              && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
-       {
-         if (warning_at (DECL_SOURCE_LOCATION (newdecl),
-                         OPT_Wattributes, "function %qD redeclared as inline",
-                         newdecl))
-           inform (DECL_SOURCE_LOCATION (olddecl),
-                   "previous declaration of %qD with attribute noinline",
-                   olddecl);
-       }
-      else if (DECL_DECLARED_INLINE_P (olddecl)
-              && DECL_UNINLINABLE (newdecl)
-              && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
-       {
-         if (warning_at (DECL_SOURCE_LOCATION (newdecl),
-                         OPT_Wattributes, "function %qD redeclared with "
-                         "attribute noinline", newdecl))
-           inform (DECL_SOURCE_LOCATION (olddecl),
-                   "previous declaration of %qD was inline",
-                   olddecl);
-       }
+      && diagnose_mismatched_attributes (olddecl, newdecl))
+    {
+      if (DECL_INITIAL (olddecl))
+       inform (DECL_SOURCE_LOCATION (olddecl),
+               "previous definition of %q+D was here", olddecl);
+      else
+       inform (DECL_SOURCE_LOCATION (olddecl),
+               "previous declaration of %qD was here", olddecl);
     }
 
   /* Check for redeclaration and other discrepancies.  */
diff --git gcc/testsuite/c-c++-common/attributes-3.c 
gcc/testsuite/c-c++-common/attributes-3.c
index e69de29..821278c 100644
--- gcc/testsuite/c-c++-common/attributes-3.c
+++ gcc/testsuite/c-c++-common/attributes-3.c
@@ -0,0 +1,27 @@
+/* PR c++/71024 */
+/* { dg-do compile } */
+/* { dg-prune-output "declared but never defined" } */
+
+void
+fn0 (void) /* { dg-message "previous definition" } */
+{
+}
+extern void __attribute__((optimize ("O2"))) fn0 (void); /* { dg-warning 
"optimization attribute" } */
+
+extern __attribute__((noinline)) int fn1 (void); /* { dg-message "previous 
declaration" } */
+extern inline int fn1 (void); /* { dg-warning "inline declaration of" } */
+
+extern inline int fn2 (void); /* { dg-message "previous declaration" } */
+extern __attribute__((noinline)) int fn2 (void); /* { dg-warning "attribute 
noinline follows inline declaration" } */
+
+extern __attribute__((always_inline)) int fn3 (void); /* { dg-message 
"previous declaration" } */
+extern __attribute__((noinline)) int fn3 (void); /* { dg-warning "attribute 
.noinline. follows declaration with attribute .always_inline." } */
+
+extern __attribute__((noinline)) int fn4 (void); /* { dg-message "previous 
declaration" } */
+extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning 
"attribute .always_inline. follows declaration with attribute .noinline." } */
+
+extern __attribute__((hot)) int fn5 (void); /* { dg-message "previous 
declaration" } */
+extern __attribute__((cold)) int fn5 (void); /* { dg-warning "attribute .cold. 
follows declaration with attribute .hot." } */
+
+extern __attribute__((cold)) int fn6 (void); /* { dg-message "previous 
declaration" } */
+extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot. 
follows declaration with attribute .cold." } */

        Marek

Reply via email to