]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 7 Dec 2017 16:32:03 +0000 (16:32 +0000)
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 7 Dec 2017 16:32:03 +0000 (16:32 +0000)
PR c/81566 - invalid attribute aligned accepted on functions

gcc/ada/ChangeLog:

PR c/81544
* gcc-interface/utils.c (gnat_internal_attribute_table): Initialize
new member of struct attribute_spec.

gcc/c/ChangeLog:

PR c/81544
* c-decl.c (c_decl_attributes): Look up existing declaration and
pass it to decl_attributes.

gcc/c-family/ChangeLog:

PR c/81544
PR c/81566
* c-attribs.c (attr_aligned_exclusions): New array.
(attr_alloc_exclusions, attr_cold_hot_exclusions): Same.
(attr_common_exclusions, attr_const_pure_exclusions): Same.
(attr_gnu_inline_exclusions, attr_inline_exclusions): Same.
(attr_noreturn_exclusions, attr_returns_twice_exclusions): Same.
(attr_warn_unused_result_exclusions): Same.
(handle_hot_attribute, handle_cold_attribute): Simplify.
(handle_const_attribute): Warn on function returning void.
(handle_pure_attribute): Same.
(handle_aligned_attribute): Diagnose conflicting attribute
specifications.
* c-warn.c (diagnose_mismatched_attributes): Simplify.

gcc/cp/ChangeLog:

PR c/81544
* cp-tree.h (decls_match): Add default argument.
* decl.c (decls_match): Avoid calling into the target back end
and triggering an error.
* decl2.c (cplus_decl_attributes): Look up existing declaration and
pass it to decl_attributes.
* tree.c (cxx_attribute_table): Initialize new member of struct
attribute_spec.

gcc/fortran/ChangeLog:

PR c/81544
* f95-lang.c (gfc_attribute_table): Initialize new member of struct
attribute_spec.

gcc/lto/ChangeLog:

PR c/81544
* lto-lang.c (lto_attribute_table): Initialize new member of struct
attribute_spec.

gcc/ChangeLog:

PR c/81544
* attribs.c (empty_attribute_table): Initialize new member of
struct attribute_spec.
(decl_attributes): Add argument.  Handle mutually exclusive
combinations of attributes.
(selftests::test_attribute_exclusions): New function.
(selftests::attribute_c_tests): Ditto.
* attribs.h (decl_attributes): Add default argument.
* selftest.h (attribute_c_tests): Declare.
* selftest-run-tests.c (selftest::run_tests): Call attribute_c_tests.
* tree-core.h (attribute_spec::exclusions, exclude): New type and
member.
* doc/extend.texi (Common Function Attributes): Update const and pure.

gcc/testsuite/ChangeLog:

PR c/81544
* c-c++-common/Wattributes-2.c: New test.
* c-c++-common/Wattributes.c: New test.
* c-c++-common/attributes-3.c: Adjust.
* gcc.dg/Wattributes-6.c: New test.
* gcc.dg/Wattributes-7.c: New test.
* gcc.dg/attr-noinline.c
* gcc.dg/pr44964.c: Same.
* gcc.dg/torture/pr42363.c: Same.
* gcc.dg/tree-ssa/ssa-ccp-2.c: Same.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255469 138bc75d-0d04-0410-961f-82ee72b054a4

62 files changed:
gcc/ChangeLog
gcc/ada/ChangeLog
gcc/ada/gcc-interface/utils.c
gcc/attribs.c
gcc/attribs.h
gcc/brig/brig-lang.c
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-warn.c
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/config/alpha/alpha.c
gcc/config/arc/arc.c
gcc/config/arm/arm.c
gcc/config/avr/avr.c
gcc/config/bfin/bfin.c
gcc/config/cr16/cr16.c
gcc/config/epiphany/epiphany.c
gcc/config/h8300/h8300.c
gcc/config/i386/i386.c
gcc/config/ia64/ia64.c
gcc/config/m32c/m32c.c
gcc/config/m32r/m32r.c
gcc/config/m68k/m68k.c
gcc/config/mcore/mcore.c
gcc/config/microblaze/microblaze.c
gcc/config/mips/mips.c
gcc/config/msp430/msp430.c
gcc/config/nds32/nds32.c
gcc/config/nvptx/nvptx.c
gcc/config/powerpcspe/powerpcspe.c
gcc/config/rl78/rl78.c
gcc/config/rs6000/rs6000.c
gcc/config/rx/rx.c
gcc/config/s390/s390.c
gcc/config/sh/sh.c
gcc/config/sparc/sparc.c
gcc/config/spu/spu.c
gcc/config/stormy16/stormy16.c
gcc/config/v850/v850.c
gcc/config/visium/visium.c
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/tree.c
gcc/doc/extend.texi
gcc/fortran/ChangeLog
gcc/fortran/f95-lang.c
gcc/lto/ChangeLog
gcc/lto/lto-lang.c
gcc/selftest-run-tests.c
gcc/selftest.h
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/attributes-3.c
gcc/testsuite/gcc.dg/attr-noinline.c
gcc/testsuite/gcc.dg/pr44964.c
gcc/testsuite/gcc.dg/torture/pr42363.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c
gcc/tree-core.h
libstdc++-v3/ChangeLog
libstdc++-v3/include/ext/mt_allocator.h

index 95a70f4ab721d79a0ad62c1d997ff01441f04235..f81665f650f93b93c864b9a0fcef66d2d1505d86 100644 (file)
@@ -1,3 +1,50 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * attribs.c (empty_attribute_table): Initialize new member of
+       struct attribute_spec.
+       (decl_attributes): Add argument.  Handle mutually exclusive
+       combinations of attributes.
+       (selftests::test_attribute_exclusions): New function.
+       (selftests::attribute_c_tests): Ditto.
+       * attribs.h (decl_attributes): Add default argument.
+       * selftest.h (attribute_c_tests): Declare.
+       * selftest-run-tests.c (selftest::run_tests): Call attribute_c_tests.
+       * tree-core.h (attribute_spec::exclusions, exclude): New type and
+       member.
+       * doc/extend.texi (Common Function Attributes): Update const and pure.
+       * config/alpha/alpha.c (vms_attribute_table): Initialize new member
+       of struct attribute_spec.
+       * config/arc/arc.c (arc_attribute_table): Same.
+       * config/arm/arm.c (arm_attribute_table): Same.
+       * config/avr/avr.c ( avr_attribute_table): Same.
+       * config/bfin/bfin.c (bfin_attribute_table): Same.
+       * config/cr16/cr16.c (cr16_attribute_table): Same.
+       * config/epiphany/epiphany.c (epiphany_attribute_table): Same.
+       * config/h8300/h8300.c (h8300_attribute_table): Same.
+       * config/i386/i386.c (ix86_attribute_table): Same.
+       * config/ia64/ia64.c (ia64_attribute_table): Same.
+       * config/m32c/m32c.c (m32c_attribute_table): Same.
+       * config/m32r/m32r.c (m32r_attribute_table): Same.
+       * config/m68k/m68k.c (m68k_attribute_table): Same.
+       * config/mcore/mcore.c (mcore_attribute_table): Same.
+       * config/microblaze/microblaze.c (microblaze_attribute_table): Same.
+       * config/mips/mips.c (mips_attribute_table): Same.
+       * config/msp430/msp430.c (msp430_attribute_table): Same.
+       * config/nds32/nds32.c (nds32_attribute_table): Same.
+       * config/nvptx/nvptx.c (nvptx_attribute_table): Same.
+       * config/powerpcspe/powerpcspe.c (rs6000_attribute_table): Same.
+       * config/rl78/rl78.c (rl78__attribute_table): Same.
+       * config/rs6000/rs6000.c (rs6000_attribute_table): Same.
+       * onfig/rx/rx.c (rx_attribute_table): Same.
+       * config/s390/s390.c (s390_handle_vectorbool_attribute): Same.
+       * config/sh/sh.c (sh_attribute_table): Same.
+       * config/sparc/sparc.c (sparc_attribute_table): Same.
+       * config/spu/spu.c (spu_attribute_table): Same.
+       * config/stormy16/stormy16.c (xstormy16_attribute_table): Same.
+       * config/v850/v850.c (v850_attribute_table): Same.
+       * config/visium/visium.c (visium_attribute_table): Same.
+
 2017-12-07  Tamar Christina  <tamar.christina@arm.com>
 
        PR target/82641
index 3168ba485016829bdf6d51e319af1effa8774383..b43e50ab9ee382199dcc0d3d895a939505e008ff 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * gcc-interface/utils.c (gnat_internal_attribute_table): Initialize
+       new member of struct attribute_spec.
+
 2017-12-06  Simon Wright  <simon@pushface.org>
 
        PR ada/66205
index 2c80a612b1fb1eb955a33db4de90b095aa3f9bf2..ddeeb0370aed18cb0974defa211b2b931058286e 100644 (file)
@@ -110,45 +110,47 @@ const struct attribute_spec gnat_internal_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "const",        0, 0,  true,  false, false, handle_const_attribute,
-    false },
+    false, NULL },
   { "nothrow",      0, 0,  true,  false, false, handle_nothrow_attribute,
-    false },
+    false, NULL },
   { "pure",         0, 0,  true,  false, false, handle_pure_attribute,
-    false },
+    false, NULL },
   { "no vops",      0, 0,  true,  false, false, handle_novops_attribute,
-    false },
+    false, NULL },
   { "nonnull",      0, -1, false, true,  true,  handle_nonnull_attribute,
-    false },
+    false, NULL },
   { "sentinel",     0, 1,  false, true,  true,  handle_sentinel_attribute,
-    false },
+    false, NULL },
   { "noreturn",     0, 0,  true,  false, false, handle_noreturn_attribute,
-    false },
+    false, NULL },
   { "noinline",     0, 0,  true,  false, false, handle_noinline_attribute,
-    false },
+    false, NULL },
   { "noclone",      0, 0,  true,  false, false, handle_noclone_attribute,
-    false },
+    false, NULL },
   { "leaf",         0, 0,  true,  false, false, handle_leaf_attribute,
-    false },
+    false, NULL },
   { "always_inline",0, 0,  true,  false, false, handle_always_inline_attribute,
-    false },
+    false, NULL },
   { "malloc",       0, 0,  true,  false, false, handle_malloc_attribute,
-    false },
+    false, NULL },
   { "type generic", 0, 0,  false, true, true, handle_type_generic_attribute,
-    false },
+    false, NULL },
 
   { "vector_size",  1, 1,  false, true, false,  handle_vector_size_attribute,
-    false },
+    false, NULL },
   { "vector_type",  0, 0,  false, true, false,  handle_vector_type_attribute,
-    false },
-  { "may_alias",    0, 0, false, true, false, NULL, false },
+    false, NULL },
+  { "may_alias",    0, 0, false, true, false, NULL, false, NULL },
 
   /* ??? format and format_arg are heavy and not supported, which actually
      prevents support for stdio builtins, which we however declare as part
      of the common builtins.def contents.  */
-  { "format",     3, 3,  false, true,  true,  fake_attribute_handler, false },
-  { "format_arg", 1, 1,  false, true,  true,  fake_attribute_handler, false },
+  { "format",     3, 3,  false, true,  true,  fake_attribute_handler, false,
+    NULL },
+  { "format_arg", 1, 1,  false, true,  true,  fake_attribute_handler, false,
+    NULL },
 
-  { NULL,         0, 0, false, false, false, NULL, false }
+  { NULL,         0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Associates a GNAT tree node to a GCC tree node. It is used in
index 809f4c3a8d55b461e8c546281d63675547afd1dc..f65fd15814f818269aaa0437e5eb98725e718bd8 100644 (file)
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "langhooks.h"
 #include "plugin.h"
+#include "selftest.h"
+#include "hash-set.h"
 
 /* Table of the tables of attributes (common, language, format, machine)
    searched.  */
@@ -94,7 +96,7 @@ static bool attributes_initialized = false;
 
 static const struct attribute_spec empty_attribute_table[] =
 {
-  { NULL, 0, 0, false, false, false, NULL, false }
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Return base name of the attribute.  Ie '__attr__' is turned into 'attr'.
@@ -343,6 +345,97 @@ get_attribute_namespace (const_tree attr)
   return get_identifier ("gnu");
 }
 
+/* Check LAST_DECL and NODE of the same symbol for attributes that are
+   recorded in SPEC to be mutually exclusive with ATTRNAME, diagnose
+   them, and return true if any have been found.  NODE can be a DECL
+   or a TYPE.  */
+
+static bool
+diag_attr_exclusions (tree last_decl, tree node, tree attrname,
+                     const attribute_spec *spec)
+{
+  const attribute_spec::exclusions *excl = spec->exclude;
+
+  tree_code code = TREE_CODE (node);
+
+  if ((code == FUNCTION_DECL && !excl->function
+       && (!excl->type || !spec->affects_type_identity))
+      || (code == VAR_DECL && !excl->variable
+         && (!excl->type || !spec->affects_type_identity))
+      || (((code == TYPE_DECL || RECORD_OR_UNION_TYPE_P (node)) && !excl->type)))
+    return false;
+
+  /* True if an attribute that's mutually exclusive with ATTRNAME
+     has been found.  */
+  bool found = false;
+
+  if (last_decl && last_decl != node && TREE_TYPE (last_decl) != node)
+    {
+      /* Check both the last DECL and its type for conflicts with
+        the attribute being added to the current decl or type.  */
+      found |= diag_attr_exclusions (last_decl, last_decl, attrname, spec);
+      tree decl_type = TREE_TYPE (last_decl);
+      found |= diag_attr_exclusions (last_decl, decl_type, attrname, spec);
+    }
+
+  /* NODE is either the current DECL to which the attribute is being
+     applied or its TYPE.  For the former, consider the attributes on
+     both the DECL and its type.  */
+  tree attrs[2];
+
+  if (DECL_P (node))
+    {
+      attrs[0] = DECL_ATTRIBUTES (node);
+      attrs[1] = TYPE_ATTRIBUTES (TREE_TYPE (node));
+    }
+  else
+    {
+      attrs[0] = TYPE_ATTRIBUTES (node);
+      attrs[1] = NULL_TREE;
+    }
+
+  /* Iterate over the mutually exclusive attribute names and verify
+     that the symbol doesn't contain it.  */
+  for (unsigned i = 0; i != sizeof attrs / sizeof *attrs; ++i)
+    {
+      if (!attrs[i])
+       continue;
+
+      for ( ; excl->name; ++excl)
+       {
+         /* Avoid checking the attribute against itself.  */
+         if (is_attribute_p (excl->name, attrname))
+           continue;
+
+         if (!lookup_attribute (excl->name, attrs[i]))
+           continue;
+
+         found = true;
+
+         /* Print a note?  */
+         bool note = last_decl != NULL_TREE;
+
+         if (TREE_CODE (node) == FUNCTION_DECL
+             && DECL_BUILT_IN (node))
+           note &= warning (OPT_Wattributes,
+                            "ignoring attribute %qE in declaration of "
+                            "a built-in function %qD because it conflicts "
+                            "with attribute %qs",
+                            attrname, node, excl->name);
+         else
+           note &= warning (OPT_Wattributes,
+                            "ignoring attribute %qE because "
+                            "it conflicts with attribute %qs",
+                            attrname, excl->name);
+
+         if (note)
+           inform (DECL_SOURCE_LOCATION (last_decl),
+                   "previous declaration here");
+       }
+    }
+
+  return found;
+}
 
 /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
    which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
@@ -354,7 +447,8 @@ get_attribute_namespace (const_tree attr)
    a decl attribute to the declaration rather than to its type).  */
 
 tree
-decl_attributes (tree *node, tree attributes, int flags)
+decl_attributes (tree *node, tree attributes, int flags,
+                tree last_decl /* = NULL_TREE */)
 {
   tree a;
   tree returned_attrs = NULL_TREE;
@@ -433,6 +527,8 @@ decl_attributes (tree *node, tree attributes, int flags)
 
   targetm.insert_attributes (*node, &attributes);
 
+  /* Note that attributes on the same declaration are not necessarily
+     in the same order as in the source.  */
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
       tree ns = get_attribute_namespace (a);
@@ -441,7 +537,6 @@ decl_attributes (tree *node, tree attributes, int flags)
       tree *anode = node;
       const struct attribute_spec *spec =
        lookup_scoped_attribute_spec (ns, name);
-      bool no_add_attrs = 0;
       int fn_ptr_quals = 0;
       tree fn_ptr_tmp = NULL_TREE;
 
@@ -490,7 +585,8 @@ decl_attributes (tree *node, tree attributes, int flags)
                       | (int) ATTR_FLAG_ARRAY_NEXT))
            {
              /* Pass on this attribute to be tried again.  */
-             returned_attrs = tree_cons (name, args, returned_attrs);
+             tree attr = tree_cons (name, args, NULL_TREE);
+             returned_attrs = chainon (returned_attrs, attr);
              continue;
            }
          else
@@ -535,7 +631,8 @@ decl_attributes (tree *node, tree attributes, int flags)
          else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
            {
              /* Pass on this attribute to be tried again.  */
-             returned_attrs = tree_cons (name, args, returned_attrs);
+             tree attr = tree_cons (name, args, NULL_TREE);
+             returned_attrs = chainon (returned_attrs, attr);
              continue;
            }
 
@@ -557,15 +654,56 @@ decl_attributes (tree *node, tree attributes, int flags)
          continue;
        }
 
+      bool no_add_attrs = false;
+
       if (spec->handler != NULL)
        {
          int cxx11_flag =
            cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
 
-         returned_attrs = chainon ((*spec->handler) (anode, name, args,
-                                                     flags|cxx11_flag,
-                                                     &no_add_attrs),
-                                   returned_attrs);
+         /* Pass in an array of the current declaration followed
+            by the last pushed/merged declaration if  one exists.
+            If the handler changes CUR_AND_LAST_DECL[0] replace
+            *ANODE with its value.  */
+         tree cur_and_last_decl[] = { *anode, last_decl };
+         tree ret = (spec->handler) (cur_and_last_decl, name, args,
+                                     flags|cxx11_flag, &no_add_attrs);
+
+         *anode = cur_and_last_decl[0];
+         if (ret == error_mark_node)
+           {
+             warning (OPT_Wattributes, "%qE attribute ignored", name);
+             no_add_attrs = true;
+           }
+         else
+           returned_attrs = chainon (ret, returned_attrs);
+       }
+
+      /* If the attribute was successfully handled on its own and is
+        about to be added check for exclusions with other attributes
+        on the current declation as well as the last declaration of
+        the same symbol already processed (if one exists).  */
+      bool built_in = flags & ATTR_FLAG_BUILT_IN;
+      if (spec->exclude
+         && !no_add_attrs
+         && (flag_checking || !built_in))
+       {
+         /* Always check attributes on user-defined functions.
+            Check them on built-ins only when -fchecking is set.
+            Ignore __builtin_unreachable -- it's both const and
+            noreturn.  */
+
+         if (!built_in
+             || !DECL_P (*anode)
+             || (DECL_FUNCTION_CODE (*anode) != BUILT_IN_UNREACHABLE
+                 && (DECL_FUNCTION_CODE (*anode)
+                     != BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE)))
+           {
+             bool no_add = diag_attr_exclusions (last_decl, *anode, name, spec);
+             if (!no_add && anode != node)
+               no_add = diag_attr_exclusions (last_decl, *node, name, spec);
+             no_add_attrs |= no_add;
+           }
        }
 
       /* Layout the decl in case anything changed.  */
@@ -1647,3 +1785,124 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 
   return list;
 }
+
+#if CHECKING_P
+
+namespace selftest
+{
+
+/* Helper types to verify the consistency attribute exclusions.  */
+
+typedef std::pair<const char *, const char *> excl_pair;
+
+struct excl_hash_traits: typed_noop_remove<excl_pair>
+{
+  typedef excl_pair  value_type;
+  typedef value_type compare_type;
+
+  static hashval_t hash (const value_type &x)
+  {
+    hashval_t h1 = htab_hash_string (x.first);
+    hashval_t h2 = htab_hash_string (x.second);
+    return h1 ^ h2;
+  }
+
+  static bool equal (const value_type &x, const value_type &y)
+  {
+    return !strcmp (x.first, y.first) && !strcmp (x.second, y.second);
+  }
+
+  static void mark_deleted (value_type &x)
+  {
+    x = value_type (NULL, NULL);
+  }
+
+  static void mark_empty (value_type &x)
+  {
+    x = value_type ("", "");
+  }
+
+  static bool is_deleted (const value_type &x)
+  {
+    return !x.first && !x.second;
+  }
+
+  static bool is_empty (const value_type &x)
+  {
+    return !*x.first && !*x.second;
+  }
+};
+
+
+/* Self-test to verify that each attribute exclusion is symmetric,
+   meaning that if attribute A is encoded as incompatible with
+   attribute B then the opposite relationship is also encoded.
+   This test also detects most cases of misspelled attribute names
+   in exclusions.  */
+
+static void
+test_attribute_exclusions ()
+{
+  /* Iterate over the array of attribute tables first (with TI0 as
+     the index) and over the array of attribute_spec in each table
+     (with SI0 as the index).  */
+  const size_t ntables = ARRAY_SIZE (attribute_tables);
+
+  /* Set of pairs of mutually exclusive attributes.  */
+  typedef hash_set<excl_pair, excl_hash_traits> exclusion_set;
+  exclusion_set excl_set;
+
+  for (size_t ti0 = 0; ti0 != ntables; ++ti0)
+    for (size_t s0 = 0; attribute_tables[ti0][s0].name; ++s0)
+      {
+       const attribute_spec::exclusions *excl
+         = attribute_tables[ti0][s0].exclude;
+
+       /* Skip each attribute that doesn't define exclusions.  */
+       if (!excl)
+         continue;
+
+       const char *attr_name = attribute_tables[ti0][s0].name;
+
+       /* Iterate over the set of exclusions for every attribute
+          (with EI0 as the index) adding the exclusions defined
+          for each to the set.  */
+       for (size_t ei0 = 0; excl[ei0].name; ++ei0)
+         {
+           const char *excl_name = excl[ei0].name;
+
+           if (!strcmp (attr_name, excl_name))
+             continue;
+
+           excl_set.add (excl_pair (attr_name, excl_name));
+         }
+      }
+
+  /* Traverse the set of mutually exclusive pairs of attributes
+     and verify that they are symmetric.  */
+  for (exclusion_set::iterator it = excl_set.begin ();
+       it != excl_set.end ();
+       ++it)
+    {
+      if (!excl_set.contains (excl_pair ((*it).second, (*it).first)))
+       {
+         /* An exclusion for an attribute has been found that
+            doesn't have a corresponding exclusion in the opposite
+            direction.  */
+         char desc[120];
+         sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric",
+                  (*it).first, (*it).second);
+         fail (SELFTEST_LOCATION, desc);
+       }
+    }
+}
+
+void
+attribute_c_tests ()
+{
+  test_attribute_exclusions ();
+}
+
+} /* namespace selftest */
+
+#endif /* CHECKING_P */
index f4bfe03e4673008eb2fa3bba3154e09ca31fd374..182c71d27c8f60291fcfb0e03988b47f4b2d869f 100644 (file)
@@ -31,7 +31,7 @@ extern void init_attributes (void);
    from tree.h.  Depending on these flags, some attributes may be
    returned to be applied at a later stage (for example, to apply
    a decl attribute to the declaration rather than to its type).  */
-extern tree decl_attributes (tree *, tree, int);
+extern tree decl_attributes (tree *, tree, int, tree = NULL_TREE);
 
 extern bool cxx11_attribute_p (const_tree);
 extern tree get_attribute_name (const_tree);
index f34d958763272b5ac18dd7a693232049f216337f..2d9e8c06d12f1bd72d86e7fda1f596cefd7f09bb 100644 (file)
@@ -450,16 +450,16 @@ const struct attribute_spec brig_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        do_diagnostic } */
   { "leaf",                  0, 0, true,  false, false,
-                             handle_leaf_attribute, false },
+                             handle_leaf_attribute, false, NULL },
   { "const",                  0, 0, true,  false, false,
-                             handle_const_attribute, false },
+                             handle_const_attribute, false, NULL },
   { "pure",                   0, 0, true,  false, false,
-                             handle_pure_attribute, false },
+                             handle_pure_attribute, false, NULL },
   { "nothrow",                0, 0, true,  false, false,
-                             handle_nothrow_attribute, false },
+                             handle_nothrow_attribute, false, NULL },
   { "returns_twice",          0, 0, true,  false, false,
-                             handle_returns_twice_attribute, false },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+                             handle_returns_twice_attribute, false, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Attribute handlers.  */
index a845fbf896632eaff8b5b6ff997480c0b5d40b7c..4ad83f3628736bb32c18ed1a06659feeea4f785c 100644 (file)
@@ -1,3 +1,20 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       PR c/81566
+       * c-attribs.c (attr_aligned_exclusions): New array.
+       (attr_alloc_exclusions, attr_cold_hot_exclusions): Same.
+       (attr_common_exclusions, attr_const_pure_exclusions): Same.
+       (attr_gnu_inline_exclusions, attr_inline_exclusions): Same.
+       (attr_noreturn_exclusions, attr_returns_twice_exclusions): Same.
+       (attr_warn_unused_result_exclusions): Same.
+       (handle_hot_attribute, handle_cold_attribute): Simplify.
+       (handle_const_attribute): Warn on function returning void.
+       (handle_pure_attribute): Same.
+       (handle_aligned_attribute): Diagnose conflicting attribute
+       specifications.
+       * c-warn.c (diagnose_mismatched_attributes): Simplify.
+
 2017-12-06  David Malcolm  <dmalcolm@redhat.com>
 
        PR c/83236
index cff5b44e26aa1e478332898889bb89b085ee1e6b..186df05eec58e5c6d81d0a8614b67ceb927582da 100644 (file)
@@ -150,6 +150,93 @@ static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
                                                       int, bool *);
 
+/* Helper to define attribute exclusions.  */
+#define ATTR_EXCL(name, function, type, variable)      \
+  { name, function, type, variable }
+
+/* Define attributes that are mutually exclusive with one another.  */
+static const struct attribute_spec::exclusions attr_aligned_exclusions[] =
+{
+  /* Attribute name     exclusion applies to:
+                       function, type, variable */
+  ATTR_EXCL ("aligned", true, false, false),
+  ATTR_EXCL ("packed", true, false, false),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
+static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+  ATTR_EXCL ("cold", true, true, true),
+  ATTR_EXCL ("hot", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
+static const struct attribute_spec::exclusions attr_common_exclusions[] =
+{
+  ATTR_EXCL ("common", true, true, true),
+  ATTR_EXCL ("nocommon", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_inline_exclusions[] =
+{
+  ATTR_EXCL ("noinline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
+{
+  ATTR_EXCL ("always_inline", true, true, true),
+  ATTR_EXCL ("gnu_inline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+{
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL ("returns_twice", true, true, true),
+  ATTR_EXCL ("warn_unused_result", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions
+attr_warn_unused_result_exclusions[] =
+{
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("warn_unused_result", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
+{
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc.  */
+static const struct attribute_spec::exclusions attr_alloc_exclusions[] =
+{
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
+{
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
 /* Table of machine-independent attributes common to all C-like languages.
 
    All attributes referencing arguments should be additionally processed
@@ -161,214 +248,233 @@ const struct attribute_spec c_common_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "packed",                 0, 0, false, false, false,
-                             handle_packed_attribute , false},
+                             handle_packed_attribute, false,
+                             attr_aligned_exclusions },
   { "nocommon",               0, 0, true,  false, false,
-                             handle_nocommon_attribute, false},
+                             handle_nocommon_attribute, false,
+                             attr_common_exclusions },
   { "common",                 0, 0, true,  false, false,
-                             handle_common_attribute, false },
+                             handle_common_attribute, false,
+                             attr_common_exclusions },
   /* FIXME: logically, noreturn attributes should be listed as
      "false, true, true" and apply to function types.  But implementing this
      would require all the places in the compiler that use TREE_THIS_VOLATILE
      on a decl to identify non-returning functions to be located and fixed
      to check the function type instead.  */
   { "noreturn",               0, 0, true,  false, false,
-                             handle_noreturn_attribute, false },
+                             handle_noreturn_attribute, false,
+                             attr_noreturn_exclusions },
   { "volatile",               0, 0, true,  false, false,
-                             handle_noreturn_attribute, false },
+                             handle_noreturn_attribute, false, NULL },
   { "stack_protect",          0, 0, true,  false, false,
-                             handle_stack_protect_attribute, false },
+                             handle_stack_protect_attribute, false, NULL },
   { "noinline",               0, 0, true,  false, false,
-                             handle_noinline_attribute, false },
+                             handle_noinline_attribute, false,
+                             attr_noinline_exclusions },
   { "noclone",                0, 0, true,  false, false,
-                             handle_noclone_attribute, false },
+                             handle_noclone_attribute, false, NULL },
   { "no_icf",                 0, 0, true,  false, false,
-                             handle_noicf_attribute, false },
+                             handle_noicf_attribute, false, NULL },
   { "noipa",                 0, 0, true,  false, false,
-                             handle_noipa_attribute, false },
+                             handle_noipa_attribute, false, NULL },
   { "leaf",                   0, 0, true,  false, false,
-                             handle_leaf_attribute, false },
+                             handle_leaf_attribute, false, NULL },
   { "always_inline",          0, 0, true,  false, false,
-                             handle_always_inline_attribute, false },
+                             handle_always_inline_attribute, false,
+                             attr_inline_exclusions },
   { "gnu_inline",             0, 0, true,  false, false,
-                             handle_gnu_inline_attribute, false },
+                             handle_gnu_inline_attribute, false,
+                             attr_inline_exclusions },
   { "artificial",             0, 0, true,  false, false,
-                             handle_artificial_attribute, false },
+                             handle_artificial_attribute, false, NULL },
   { "flatten",                0, 0, true,  false, false,
-                             handle_flatten_attribute, false },
+                             handle_flatten_attribute, false, NULL },
   { "used",                   0, 0, true,  false, false,
-                             handle_used_attribute, false },
+                             handle_used_attribute, false, NULL },
   { "unused",                 0, 0, false, false, false,
-                             handle_unused_attribute, false },
+                             handle_unused_attribute, false, NULL },
   { "externally_visible",     0, 0, true,  false, false,
-                             handle_externally_visible_attribute, false },
+                             handle_externally_visible_attribute, false, NULL },
   { "no_reorder",            0, 0, true, false, false,
-                              handle_no_reorder_attribute, false },
+                             handle_no_reorder_attribute, false, NULL },
   /* The same comments as for noreturn attributes apply to const ones.  */
   { "const",                  0, 0, true,  false, false,
-                             handle_const_attribute, false },
+                             handle_const_attribute, false,
+                             attr_const_pure_exclusions },
   { "scalar_storage_order",   1, 1, false, false, false,
-                             handle_scalar_storage_order_attribute, false },
+                             handle_scalar_storage_order_attribute, false, NULL },
   { "transparent_union",      0, 0, false, false, false,
-                             handle_transparent_union_attribute, false },
+                             handle_transparent_union_attribute, false, NULL },
   { "constructor",            0, 1, true,  false, false,
-                             handle_constructor_attribute, false },
+                             handle_constructor_attribute, false, NULL },
   { "destructor",             0, 1, true,  false, false,
-                             handle_destructor_attribute, false },
+                             handle_destructor_attribute, false, NULL },
   { "mode",                   1, 1, false,  true, false,
-                             handle_mode_attribute, false },
+                             handle_mode_attribute, false, NULL },
   { "section",                1, 1, true,  false, false,
-                             handle_section_attribute, false },
+                             handle_section_attribute, false, NULL },
   { "aligned",                0, 1, false, false, false,
-                             handle_aligned_attribute, false },
+                             handle_aligned_attribute, false,
+                             attr_aligned_exclusions },
   { "warn_if_not_aligned",    0, 1, false, false, false,
                              handle_warn_if_not_aligned_attribute,
-                             false },
+                             false, NULL },
   { "weak",                   0, 0, true,  false, false,
-                             handle_weak_attribute, false },
+                             handle_weak_attribute, false, NULL },
   { "noplt",                   0, 0, true,  false, false,
-                             handle_noplt_attribute, false },
+                             handle_noplt_attribute, false, NULL },
   { "ifunc",                  1, 1, true,  false, false,
-                             handle_ifunc_attribute, false },
+                             handle_ifunc_attribute, false, NULL },
   { "alias",                  1, 1, true,  false, false,
-                             handle_alias_attribute, false },
+                             handle_alias_attribute, false, NULL },
   { "weakref",                0, 1, true,  false, false,
-                             handle_weakref_attribute, false },
+                             handle_weakref_attribute, false, NULL },
   { "no_instrument_function", 0, 0, true,  false, false,
                              handle_no_instrument_function_attribute,
-                             false },
+                             false, NULL },
   { "no_profile_instrument_function",  0, 0, true, false, false,
                              handle_no_profile_instrument_function_attribute,
-                             false },
+                             false, NULL },
   { "malloc",                 0, 0, true,  false, false,
-                             handle_malloc_attribute, false },
+                             handle_malloc_attribute, false,
+                             attr_alloc_exclusions },
   { "returns_twice",          0, 0, true,  false, false,
-                             handle_returns_twice_attribute, false },
+                             handle_returns_twice_attribute, false,
+                             attr_returns_twice_exclusions },
   { "no_stack_limit",         0, 0, true,  false, false,
-                             handle_no_limit_stack_attribute, false },
+                             handle_no_limit_stack_attribute, false, NULL },
   { "pure",                   0, 0, true,  false, false,
-                             handle_pure_attribute, false },
+                             handle_pure_attribute, false,
+                             attr_const_pure_exclusions },
   { "transaction_callable",   0, 0, false, true,  false,
-                             handle_tm_attribute, false },
+                             handle_tm_attribute, false, NULL },
   { "transaction_unsafe",     0, 0, false, true,  false,
-                             handle_tm_attribute, true },
+                             handle_tm_attribute, true, NULL },
   { "transaction_safe",       0, 0, false, true,  false,
-                             handle_tm_attribute, true },
+                             handle_tm_attribute, true, NULL },
   { "transaction_safe_dynamic", 0, 0, true, false,  false,
-                             handle_tm_attribute, false },
+                             handle_tm_attribute, false, NULL },
   { "transaction_may_cancel_outer", 0, 0, false, true, false,
-                             handle_tm_attribute, false },
+                             handle_tm_attribute, false, NULL },
   /* ??? These two attributes didn't make the transition from the
      Intel language document to the multi-vendor language document.  */
   { "transaction_pure",       0, 0, false, true,  false,
-                             handle_tm_attribute, false },
+                             handle_tm_attribute, false, NULL },
   { "transaction_wrap",       1, 1, true,  false,  false,
-                            handle_tm_wrap_attribute, false },
+                            handle_tm_wrap_attribute, false, NULL },
   /* For internal use (marking of builtins) only.  The name contains space
      to prevent its usage in source code.  */
   { "no vops",                0, 0, true,  false, false,
-                             handle_novops_attribute, false },
+                             handle_novops_attribute, false, NULL },
   { "deprecated",             0, 1, false, false, false,
-                             handle_deprecated_attribute, false },
+                             handle_deprecated_attribute, false, NULL },
   { "vector_size",           1, 1, false, true, false,
-                             handle_vector_size_attribute, true },
+                             handle_vector_size_attribute, true, NULL },
   { "visibility",            1, 1, false, false, false,
-                             handle_visibility_attribute, false },
+                             handle_visibility_attribute, false, NULL },
   { "tls_model",             1, 1, true,  false, false,
-                             handle_tls_model_attribute, false },
+                             handle_tls_model_attribute, false, NULL },
   { "nonnull",                0, -1, false, true, true,
-                             handle_nonnull_attribute, false },
+                             handle_nonnull_attribute, false, NULL },
   { "nonstring",              0, 0, true, false, false,
-                             handle_nonstring_attribute, false },
+                             handle_nonstring_attribute, false, NULL },
   { "nothrow",                0, 0, true,  false, false,
-                             handle_nothrow_attribute, false },
-  { "may_alias",             0, 0, false, true, false, NULL, false },
+                             handle_nothrow_attribute, false, NULL },
+  { "may_alias",             0, 0, false, true, false, NULL, false, NULL },
   { "cleanup",               1, 1, true, false, false,
-                             handle_cleanup_attribute, false },
+                             handle_cleanup_attribute, false, NULL },
   { "warn_unused_result",     0, 0, false, true, true,
-                             handle_warn_unused_result_attribute, false },
+                             handle_warn_unused_result_attribute, false,
+                             attr_warn_unused_result_exclusions },
   { "sentinel",               0, 1, false, true, true,
-                             handle_sentinel_attribute, false },
+                             handle_sentinel_attribute, false, NULL },
   /* For internal use (marking of builtins) only.  The name contains space
      to prevent its usage in source code.  */
   { "type generic",           0, 0, false, true, true,
-                             handle_type_generic_attribute, false },
+                             handle_type_generic_attribute, false, NULL },
   { "alloc_size",            1, 2, false, true, true,
-                             handle_alloc_size_attribute, false },
+                             handle_alloc_size_attribute, false,
+                             attr_alloc_exclusions },
   { "cold",                   0, 0, true,  false, false,
-                             handle_cold_attribute, false },
+                             handle_cold_attribute, false,
+                             attr_cold_hot_exclusions },
   { "hot",                    0, 0, true,  false, false,
-                             handle_hot_attribute, false },
+                             handle_hot_attribute, false,
+                             attr_cold_hot_exclusions },
   { "no_address_safety_analysis",
                              0, 0, true, false, false,
                              handle_no_address_safety_analysis_attribute,
-                             false },
+                             false, NULL },
   { "no_sanitize",           1, 1, true, false, false,
                              handle_no_sanitize_attribute,
-                             false },
+                             false, NULL },
   { "no_sanitize_address",    0, 0, true, false, false,
                              handle_no_sanitize_address_attribute,
-                             false },
+                             false, NULL },
   { "no_sanitize_thread",     0, 0, true, false, false,
                              handle_no_sanitize_thread_attribute,
-                             false },
+                             false, NULL },
   { "no_sanitize_undefined",  0, 0, true, false, false,
                              handle_no_sanitize_undefined_attribute,
-                             false },
+                             false, NULL },
   { "asan odr indicator",     0, 0, true, false, false,
                              handle_asan_odr_indicator_attribute,
-                             false },
+                             false, NULL },
   { "warning",               1, 1, true,  false, false,
-                             handle_error_attribute, false },
+                             handle_error_attribute, false, NULL },
   { "error",                 1, 1, true,  false, false,
-                             handle_error_attribute, false },
+                             handle_error_attribute, false, NULL },
   { "target",                 1, -1, true, false, false,
-                             handle_target_attribute, false },
+                             handle_target_attribute, false, NULL },
   { "target_clones",          1, -1, true, false, false,
-                             handle_target_clones_attribute, false },
+                             handle_target_clones_attribute, false, NULL },
   { "optimize",               1, -1, true, false, false,
-                             handle_optimize_attribute, false },
+                             handle_optimize_attribute, false, NULL },
   /* For internal use only.  The leading '*' both prevents its usage in
      source code and signals that it may be overridden by machine tables.  */
   { "*tm regparm",            0, 0, false, true, true,
-                             ignore_attribute, false },
+                             ignore_attribute, false, NULL },
   { "no_split_stack",        0, 0, true,  false, false,
-                             handle_no_split_stack_attribute, false },
+                             handle_no_split_stack_attribute, false, NULL },
   /* For internal use (marking of builtins and runtime functions) only.
      The name contains space to prevent its usage in source code.  */
   { "fn spec",               1, 1, false, true, true,
-                             handle_fnspec_attribute, false },
+                             handle_fnspec_attribute, false, NULL },
   { "warn_unused",            0, 0, false, false, false,
-                             handle_warn_unused_attribute, false },
+                             handle_warn_unused_attribute, false, NULL },
   { "returns_nonnull",        0, 0, false, true, true,
-                             handle_returns_nonnull_attribute, false },
+                             handle_returns_nonnull_attribute, false, NULL },
   { "omp declare simd",       0, -1, true,  false, false,
-                             handle_omp_declare_simd_attribute, false },
+                             handle_omp_declare_simd_attribute, false, NULL },
+  { "cilk simd function",     0, -1, true,  false, false,
+                             handle_omp_declare_simd_attribute, false, NULL },
   { "simd",                  0, 1, true,  false, false,
-                             handle_simd_attribute, false },
+                             handle_simd_attribute, false, NULL },
   { "omp declare target",     0, 0, true, false, false,
-                             handle_omp_declare_target_attribute, false },
+                             handle_omp_declare_target_attribute, false, NULL },
   { "omp declare target link", 0, 0, true, false, false,
-                             handle_omp_declare_target_attribute, false },
+                             handle_omp_declare_target_attribute, false, NULL },
   { "alloc_align",           1, 1, false, true, true,
-                             handle_alloc_align_attribute, false },
+                             handle_alloc_align_attribute, false,
+                             attr_alloc_exclusions },
   { "assume_aligned",        1, 2, false, true, true,
-                             handle_assume_aligned_attribute, false },
+                             handle_assume_aligned_attribute, false, NULL },
   { "designated_init",        0, 0, false, true, false,
-                             handle_designated_init_attribute, false },
+                             handle_designated_init_attribute, false, NULL },
   { "bnd_variable_size",      0, 0, true,  false, false,
-                             handle_bnd_variable_size_attribute, false },
+                             handle_bnd_variable_size_attribute, false, NULL },
   { "bnd_legacy",             0, 0, true, false, false,
-                             handle_bnd_legacy, false },
+                             handle_bnd_legacy, false, NULL },
   { "bnd_instrument",         0, 0, true, false, false,
-                             handle_bnd_instrument, false },
+                             handle_bnd_instrument, false, NULL },
   { "fallthrough",           0, 0, false, false, false,
-                             handle_fallthrough_attribute, false },
+                             handle_fallthrough_attribute, false, NULL },
   { "patchable_function_entry",        1, 2, true, false, false,
                              handle_patchable_function_entry_attribute,
-                             false },
-  { "nocf_check",                    0, 0, false, true, true,
-                             handle_nocf_check_attribute, true },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+                             false, NULL },
+  { "nocf_check",            0, 0, false, true, true,
+                             handle_nocf_check_attribute, true, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Give the specifications for the format attributes, used by C and all
@@ -383,10 +489,10 @@ const struct attribute_spec c_common_format_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "format",                 3, 3, false, true,  true,
-                             handle_format_attribute, false },
+                             handle_format_attribute, false, NULL },
   { "format_arg",             1, 1, false, true,  true,
-                             handle_format_arg_attribute, false },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+                             handle_format_arg_attribute, false, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain
@@ -524,14 +630,7 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   if (TREE_CODE (*node) == FUNCTION_DECL
       || TREE_CODE (*node) == LABEL_DECL)
     {
-      if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL)
-       {
-         warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
-                  "with attribute %qs", name, "cold");
-         *no_add_attrs = true;
-       }
-      /* Most of the rest of the hot processing is done later with
-        lookup_attribute.  */
+      /* Attribute hot processing is done later with lookup_attribute.  */
     }
   else
     {
@@ -552,14 +651,7 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   if (TREE_CODE (*node) == FUNCTION_DECL
       || TREE_CODE (*node) == LABEL_DECL)
     {
-      if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL)
-       {
-         warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
-                  "with attribute %qs", name, "hot");
-         *no_add_attrs = true;
-       }
-      /* Most of the rest of the cold processing is done later with
-        lookup_attribute.  */
+      /* Attribute cold processing is done later with lookup_attribute.  */
     }
   else
     {
@@ -1086,7 +1178,7 @@ handle_no_reorder_attribute (tree *pnode,
 
 static tree
 handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-                       int ARG_UNUSED (flags), bool *no_add_attrs)
+                       int flags, bool *no_add_attrs)
 {
   tree type = TREE_TYPE (*node);
 
@@ -1107,6 +1199,14 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
       *no_add_attrs = true;
     }
 
+  /* void __builtin_unreachable(void) is const.  Accept other such
+     built-ins but warn on user-defined functions that return void.  */
+  if (!(flags & ATTR_FLAG_BUILT_IN)
+      && TREE_CODE (*node) == FUNCTION_DECL
+      && VOID_TYPE_P (TREE_TYPE (type)))
+    warning (OPT_Wattributes, "%qE attribute on function "
+            "returning %<void%>", name);
+
   return NULL_TREE;
 }
 
@@ -1689,15 +1789,19 @@ check_cxx_fundamental_alignment_constraints (tree node,
    handle_aligned_attribute.  */
 
 static tree
-common_handle_aligned_attribute (tree *node, tree args, int flags,
+common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
                                 bool *no_add_attrs,
                                 bool warn_if_not_aligned_p)
 {
   tree decl = NULL_TREE;
   tree *type = NULL;
-  int is_type = 0;
+  bool is_type = false;
   tree align_expr;
-  int i;
+
+  /* The last (already pushed) declaration with all validated attributes
+     merged in or the current about-to-be-pushed one if one hasn't been
+     yet.  */
+  tree last_decl = node[1] ? node[1] : *node;
 
   if (args)
     {
@@ -1716,10 +1820,21 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
       is_type = TREE_CODE (*node) == TYPE_DECL;
     }
   else if (TYPE_P (*node))
-    type = node, is_type = 1;
+    type = node, is_type = true;
+
+  /* Log2 of specified alignment.  */
+  int pow2align = check_user_alignment (align_expr, true);
+
+  /* The alignment in bits corresponding to the specified alignment.  */
+  unsigned bitalign = (1U << pow2align) * BITS_PER_UNIT;
+
+  /* The alignment of the current declaration and that of the last
+     pushed declaration, determined on demand below.  */
+  unsigned curalign = 0;
+  unsigned lastalign = 0;
 
-  if ((i = check_user_alignment (align_expr, true)) == -1
-      || !check_cxx_fundamental_alignment_constraints (*node, i, flags))
+  if (pow2align == -1
+      || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags))
     *no_add_attrs = true;
   else if (is_type)
     {
@@ -1742,12 +1857,12 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
 
       if (warn_if_not_aligned_p)
        {
-         SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+         SET_TYPE_WARN_IF_NOT_ALIGN (*type, bitalign);
          warn_if_not_aligned_p = false;
        }
       else
        {
-         SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+         SET_TYPE_ALIGN (*type, bitalign);
          TYPE_USER_ALIGN (*type) = 1;
        }
     }
@@ -1757,8 +1872,34 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
       error ("alignment may not be specified for %q+D", decl);
       *no_add_attrs = true;
     }
+  else if (TREE_CODE (decl) == FUNCTION_DECL
+          && ((curalign = DECL_ALIGN (decl)) > bitalign
+              || ((lastalign = DECL_ALIGN (last_decl)) > bitalign)))
+    {
+      /* Either a prior attribute on the same declaration or one
+        on a prior declaration of the same function specifies
+        stricter alignment than this attribute.  */
+      bool note = lastalign != 0;
+      if (lastalign)
+       curalign = lastalign;
+
+      curalign /= BITS_PER_UNIT;
+      bitalign /= BITS_PER_UNIT;
+
+      if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
+       warning (OPT_Wattributes,
+                "ignoring attribute %<%E (%u)%> because it conflicts with "
+                "attribute %<%E (%u)%>", name, bitalign, name, curalign);
+      else
+       error ("alignment for %q+D must be at least %d", decl, curalign);
+
+      if (note)
+       inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here");
+
+      *no_add_attrs = true;
+    }
   else if (DECL_USER_ALIGN (decl)
-          && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
+          && DECL_ALIGN (decl) > bitalign)
     /* C++-11 [dcl.align/4]:
 
           When multiple alignment-specifiers are specified for an
@@ -1770,7 +1911,7 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
     *no_add_attrs = true;
   else if (!warn_if_not_aligned_p
           && TREE_CODE (decl) == FUNCTION_DECL
-          && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
+          && DECL_ALIGN (decl) > bitalign)
     {
       /* Don't warn function alignment here if warn_if_not_aligned_p is
         true.  It will be warned later.  */
@@ -1789,13 +1930,13 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
        {
          if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl))
            {
-             SET_DECL_WARN_IF_NOT_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+             SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
              warn_if_not_aligned_p = false;
            }
        }
       else
        {
-         SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+         SET_DECL_ALIGN (decl, bitalign);
          DECL_USER_ALIGN (decl) = 1;
        }
     }
@@ -1814,10 +1955,10 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
    struct attribute_spec.handler.  */
 
 static tree
-handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+handle_aligned_attribute (tree *node, tree name, tree args,
                          int flags, bool *no_add_attrs)
 {
-  return common_handle_aligned_attribute (node, args, flags,
+  return common_handle_aligned_attribute (node, name, args, flags,
                                         no_add_attrs, false);
 }
 
@@ -1825,11 +1966,11 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
    struct attribute_spec.handler.  */
 
 static tree
-handle_warn_if_not_aligned_attribute (tree *node, tree ARG_UNUSED (name),
+handle_warn_if_not_aligned_attribute (tree *node, tree name,
                                      tree args, int flags,
                                      bool *no_add_attrs)
 {
-  return common_handle_aligned_attribute (node, args, flags,
+  return common_handle_aligned_attribute (node, name, args, flags,
                                          no_add_attrs, true);
 }
 
@@ -2538,8 +2679,15 @@ handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
                       int ARG_UNUSED (flags), bool *no_add_attrs)
 {
   if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_PURE_P (*node) = 1;
-  /* ??? TODO: Support types.  */
+    {
+      tree type = TREE_TYPE (*node);
+      if (VOID_TYPE_P (TREE_TYPE (type)))
+       warning (OPT_Wattributes, "%qE attribute on function "
+                "returning %<void%>", name);
+
+      DECL_PURE_P (*node) = 1;
+      /* ??? TODO: Support types.  */
+    }
   else
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
index 6cfded97e2454a89f404c6c41038310dbb70141c..6045d6e17a97f508b3b9b1d769a39949852cc0b0 100644 (file)
@@ -2230,36 +2230,19 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl)
                       newdecl);
 
   /* Diagnose inline __attribute__ ((noinline)) which is silly.  */
+  const char *noinline = "noinline";
+
   if (DECL_DECLARED_INLINE_P (newdecl)
       && DECL_UNINLINABLE (olddecl)
-      && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+      && lookup_attribute (noinline, DECL_ATTRIBUTES (olddecl)))
     warned |= warning (OPT_Wattributes, "inline declaration of %qD follows "
-                      "declaration with attribute noinline", newdecl);
+                      "declaration with attribute %qs", newdecl, noinline);
   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");
+                      "%qs follows inline declaration ", newdecl, noinline);
+
   return warned;
 }
 
index 91267c023c8c1e3de35b4c7a373ff14b80b9f764..6e11827f39ccd154d91aaffa01dc1737ad81c9a1 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * c-decl.c (c_decl_attributes): Look up existing declaration and
+       pass it to decl_attributes.
+
 2017-12-06  David Malcolm  <dmalcolm@redhat.com>
 
        PR c/83236
index 607c705ff843b8e0d4efc38d0068032cda03c4d6..aaa967874727613e3fc955627ab18829340a53c6 100644 (file)
@@ -4632,7 +4632,16 @@ c_decl_attributes (tree *node, tree attributes, int flags)
        attributes = tree_cons (get_identifier ("omp declare target"),
                                NULL_TREE, attributes);
     }
-  return decl_attributes (node, attributes, flags);
+
+  /* Look up the current declaration with all the attributes merged
+     so far so that attributes on the current declaration that's
+     about to be pushed that conflict with the former can be detected,
+     diagnosed, and rejected as appropriate.  */
+  tree last_decl = lookup_name (DECL_NAME (*node));
+  if (!last_decl)
+    last_decl = lookup_name_in_scope (DECL_NAME (*node), external_scope);
+
+  return decl_attributes (node, attributes, flags, last_decl);
 }
 
 
index ece8879cb227e961cccbd27473bd6338ad21a056..edf9cb4af5932e1edbe251ffc996c1d3b0db3358 100644 (file)
@@ -7506,9 +7506,10 @@ common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED,
 static const struct attribute_spec vms_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { COMMON_OBJECT,   0, 1, true,  false, false, common_object_handler, false },
-  { NULL,            0, 0, false, false, false, NULL, false }
+       affects_type_identity, exclusions } */
+  { COMMON_OBJECT,   0, 1, true,  false, false, common_object_handler, false,
+    NULL },
+  { NULL,            0, 0, false, false, false, NULL, false, NULL }
 };
 
 void
index 6b6bf8224e6831f363dbd03b93effe03f795da48..aaefc300a9f2296646c0db12d8d6928c780203fc 100644 (file)
@@ -219,21 +219,23 @@ const struct attribute_spec arc_attribute_table[] =
 {
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
       affects_type_identity } */
-  { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute, true },
+  { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute,
+      true, NULL },
   /* Function calls made to this symbol must be done indirectly, because
      it may lie outside of the 21/25 bit addressing range of a normal function
      call.  */
-  { "long_call",    0, 0, false, true,  true,  NULL, false },
+  { "long_call",    0, 0, false, true,  true,  NULL, false, NULL },
   /* Whereas these functions are always known to reside within the 25 bit
      addressing range of unconditionalized bl.  */
-  { "medium_call",   0, 0, false, true,  true,  NULL, false },
+  { "medium_call",   0, 0, false, true,  true,  NULL, false, NULL },
   /* And these functions are always known to reside within the 21 bit
      addressing range of blcc.  */
-  { "short_call",   0, 0, false, true,  true,  NULL, false },
+  { "short_call",   0, 0, false, true,  true,  NULL, false, NULL },
   /* Function which are not having the prologue and epilogue generated
      by the compiler.  */
-  { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false },
-  { NULL, 0, 0, false, false, false, NULL, false }
+  { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false,
+    NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 static int arc_comp_type_attributes (const_tree, const_tree);
 static void arc_file_start (void);
index b98637714ab703d42dd40ac189e4271e3cc6bbe2..f34b6e0d93315e99372cc61d22c971f2641d7943 100644 (file)
@@ -323,24 +323,24 @@ static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT);
 static const struct attribute_spec arm_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   /* Function calls made to this symbol must be done indirectly, because
      it may lie outside of the 26 bit addressing range of a normal function
      call.  */
-  { "long_call",    0, 0, false, true,  true,  NULL, false },
+  { "long_call",    0, 0, false, true,  true,  NULL, false, NULL },
   /* Whereas these functions are always known to reside within the 26 bit
      addressing range.  */
-  { "short_call",   0, 0, false, true,  true,  NULL, false },
+  { "short_call",   0, 0, false, true,  true,  NULL, false, NULL },
   /* Specify the procedure call conventions for a function.  */
   { "pcs",          1, 1, false, true,  true,  arm_handle_pcs_attribute,
-    false },
+    false, NULL },
   /* Interrupt Service Routines have special prologue and epilogue requirements.  */
   { "isr",          0, 1, false, false, false, arm_handle_isr_attribute,
-    false },
+    false, NULL },
   { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute,
-    false },
+    false, NULL },
   { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute,
-    false },
+    false, NULL },
 #ifdef ARM_PE
   /* ARM/PE has three new attributes:
      interfacearm - ?
@@ -351,22 +351,24 @@ static const struct attribute_spec arm_attribute_table[] =
      them with spaces.  We do NOT support this.  Instead, use __declspec
      multiple times.
   */
-  { "dllimport",    0, 0, true,  false, false, NULL, false },
-  { "dllexport",    0, 0, true,  false, false, NULL, false },
+  { "dllimport",    0, 0, true,  false, false, NULL, false, NULL },
+  { "dllexport",    0, 0, true,  false, false, NULL, false, NULL },
   { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute,
-    false },
+    false, NULL },
 #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
-  { "dllimport",    0, 0, false, false, false, handle_dll_attribute, false },
-  { "dllexport",    0, 0, false, false, false, handle_dll_attribute, false },
+  { "dllimport",    0, 0, false, false, false, handle_dll_attribute, false,
+    NULL },
+  { "dllexport",    0, 0, false, false, false, handle_dll_attribute, false,
+    NULL },
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
-    false },
+    false, NULL },
 #endif
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
-    arm_handle_cmse_nonsecure_entry, false },
+    arm_handle_cmse_nonsecure_entry, false, NULL },
   { "cmse_nonsecure_call", 0, 0, true, false, false,
-    arm_handle_cmse_nonsecure_call, true },
-  { NULL,           0, 0, false, false, false, NULL, false }
+    arm_handle_cmse_nonsecure_call, true, NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
index b1d8a84d154d757ec9348f3156093d6f9260b02f..7b654a620867b450159f61cec4325d08b05aadd1 100644 (file)
@@ -9877,28 +9877,28 @@ avr_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute,
-    false },
+    false, NULL },
   { "signal",    0, 0, true,  false, false,  avr_handle_fndecl_attribute,
-    false },
+    false, NULL },
   { "interrupt", 0, 0, true,  false, false,  avr_handle_fndecl_attribute,
-    false },
+    false, NULL },
   { "no_gccisr", 0, 0, true,  false, false,  avr_handle_fndecl_attribute,
-    false },
+    false, NULL },
   { "naked",     0, 0, false, true,  true,   avr_handle_fntype_attribute,
-    false },
+    false, NULL },
   { "OS_task",   0, 0, false, true,  true,   avr_handle_fntype_attribute,
-    false },
+    false, NULL },
   { "OS_main",   0, 0, false, true,  true,   avr_handle_fntype_attribute,
-    false },
+    false, NULL },
   { "io",        0, 1, true, false, false,  avr_handle_addr_attribute,
-    false },
+    false, NULL },
   { "io_low",    0, 1, true, false, false,  avr_handle_addr_attribute,
-    false },
+    false, NULL },
   { "address",   1, 1, true, false, false,  avr_handle_addr_attribute,
-    false },
+    false, NULL },
   { "absdata",   0, 0, true, false, false,  avr_handle_absdata_attribute,
-    false },
-  { NULL,        0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 
 
index c95f82dc3aebb62652748ea295f8f8a8c98bebc3..a5947435f3e99e1200060b8185d6b7ce4bdfaac9 100644 (file)
@@ -4906,29 +4906,30 @@ bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name),
 static const struct attribute_spec bfin_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "interrupt_handler", 0, 0, false, true,  true, handle_int_attribute,
-    false },
+    false, NULL },
   { "exception_handler", 0, 0, false, true,  true, handle_int_attribute,
-    false },
-  { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute, false },
-  { "nesting", 0, 0, false, true,  true, NULL, false },
-  { "kspisusp", 0, 0, false, true,  true, NULL, false },
-  { "saveall", 0, 0, false, true,  true, NULL, false },
+    false, NULL },
+  { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute, false,
+    NULL },
+  { "nesting", 0, 0, false, true,  true, NULL, false, NULL },
+  { "kspisusp", 0, 0, false, true,  true, NULL, false, NULL },
+  { "saveall", 0, 0, false, true,  true, NULL, false, NULL },
   { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "l1_text", 0, 0, true, false, false,  bfin_handle_l1_text_attribute,
-    false },
+    false, NULL },
   { "l1_data", 0, 0, true, false, false,  bfin_handle_l1_data_attribute,
-    false },
+    false, NULL },
   { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
-    false },
+    false, NULL },
   { "l1_data_B", 0, 0, true, false, false,  bfin_handle_l1_data_attribute,
-    false },
-  { "l2", 0, 0, true, false, false,  bfin_handle_l2_attribute, false },
-  { NULL, 0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { "l2", 0, 0, true, false, false,  bfin_handle_l2_attribute, false, NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
index 55e0965ad2f2a1e3aeb2ec7165f5eb03b933648a..bd4e028f328ecdff2e57aca05cbcd5717e116e4d 100644 (file)
@@ -207,9 +207,9 @@ static void cr16_print_operand_address (FILE *, machine_mode, rtx);
 static const struct attribute_spec cr16_attribute_table[] = {
   /* ISRs have special prologue and epilogue requirements.  */
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity }.  */
-  {"interrupt", 0, 0, false, true, true, NULL, false},
-  {NULL, 0, 0, false, false, false, NULL, false}
+       affects_type_identity, exclusions }.  */
+  {"interrupt", 0, 0, false, true, true, NULL, false, NULL},
+  {NULL, 0, 0, false, false, false, NULL, false, NULL}
 };
 
 /* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive
index 26b0f3cca74441dac2472d886e08340e742a5149..dece119cdb80c50abd8305d9e60fc308b503e10a 100644 (file)
@@ -460,13 +460,14 @@ epiphany_init_reg_tables (void)
 
 static const struct attribute_spec epiphany_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "interrupt",  0, 9, true,  false, false, epiphany_handle_interrupt_attribute, true },
-  { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
-  { "long_call",  0, 0, false, true, true, NULL, false },
-  { "short_call", 0, 0, false, true, true, NULL, false },
-  { "disinterrupt", 0, 0, false, true, true, NULL, true },
-  { NULL,         0, 0, false, false, false, NULL, false }
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity, exclusions } */
+  { "interrupt",  0, 9, true,  false, false, epiphany_handle_interrupt_attribute, true, NULL },
+  { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false, NULL },
+  { "long_call",  0, 0, false, true, true, NULL, false, NULL },
+  { "short_call", 0, 0, false, true, true, NULL, false, NULL },
+  { "disinterrupt", 0, 0, false, true, true, NULL, true, NULL },
+  { NULL,         0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Handle an "interrupt" attribute; arguments as in
index bf1160130e4622eece30eb08dfcbfa5bd09d8c81..d4e8c461c800c678ca1e0ae0b3e3b125a7868b86 100644 (file)
@@ -5425,22 +5425,22 @@ h8300_insert_attributes (tree node, tree *attributes)
 static const struct attribute_spec h8300_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "interrupt_handler", 0, 0, true,  false, false,
-    h8300_handle_fndecl_attribute, false },
+    h8300_handle_fndecl_attribute, false, NULL },
   { "saveall",           0, 0, true,  false, false,
-    h8300_handle_fndecl_attribute, false },
+    h8300_handle_fndecl_attribute, false, NULL },
   { "OS_Task",           0, 0, true,  false, false,
-    h8300_handle_fndecl_attribute, false },
+    h8300_handle_fndecl_attribute, false, NULL },
   { "monitor",           0, 0, true,  false, false,
-    h8300_handle_fndecl_attribute, false },
+    h8300_handle_fndecl_attribute, false, NULL },
   { "function_vector",   0, 0, true,  false, false,
-    h8300_handle_fndecl_attribute, false },
+    h8300_handle_fndecl_attribute, false, NULL },
   { "eightbit_data",     0, 0, true,  false, false,
-    h8300_handle_eightbit_data_attribute, false },
+    h8300_handle_eightbit_data_attribute, false, NULL },
   { "tiny_data",         0, 0, true,  false, false,
-    h8300_handle_tiny_data_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+    h8300_handle_tiny_data_attribute, false, NULL },
+  { NULL,                0, 0, false, false, false, NULL, false, NULL }
 };
 
 
index 850ad4011a3f5e1dfd31e333017e98d9473cb94a..5d77f28dfa3d96cef8f32304f65d9e0d0c564109 100644 (file)
@@ -44693,69 +44693,71 @@ ix86_expand_round_sse4 (rtx op0, rtx op1)
 static const struct attribute_spec ix86_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   /* Stdcall attribute says callee is responsible for popping arguments
      if they are not variable.  */
   { "stdcall",   0, 0, false, true,  true,  ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* Fastcall attribute says callee is responsible for popping arguments
      if they are not variable.  */
   { "fastcall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* Thiscall attribute says callee is responsible for popping arguments
      if they are not variable.  */
   { "thiscall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* Cdecl attribute says the callee is a normal C declaration */
   { "cdecl",     0, 0, false, true,  true,  ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* Regparm attribute specifies how many integer arguments are to be
      passed in registers.  */
   { "regparm",   1, 1, false, true,  true,  ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* Sseregparm attribute says we are using x86_64 calling conventions
      for FP arguments.  */
   { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute,
-    true },
+    true, NULL },
   /* The transactional memory builtins are implicitly regparm or fastcall
      depending on the ABI.  Override the generic do-nothing attribute that
      these builtins were declared with.  */
   { "*tm regparm", 0, 0, false, true, true, ix86_handle_tm_regparm_attribute,
-    true },
+    true, NULL },
   /* force_align_arg_pointer says this function realigns the stack at entry.  */
   { (const char *)&ix86_force_align_arg_pointer_string, 0, 0,
-    false, true,  true, ix86_handle_force_align_arg_pointer_attribute, false },
+    false, true,  true, ix86_handle_force_align_arg_pointer_attribute, false,
+    NULL },
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
-  { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false },
-  { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false },
+  { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false, NULL },
+  { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false, NULL },
   { "shared",    0, 0, true,  false, false, ix86_handle_shared_attribute,
-    false },
+    false, NULL },
 #endif
   { "ms_struct", 0, 0, false, false,  false, ix86_handle_struct_attribute,
-    false },
+    false, NULL },
   { "gcc_struct", 0, 0, false, false,  false, ix86_handle_struct_attribute,
-    false },
+    false, NULL },
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
   /* ms_abi and sysv_abi calling convention function attributes.  */
-  { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true },
-  { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true },
-  { "ms_abi va_list", 0, 0, false, false, false, NULL, false },
-  { "sysv_abi va_list", 0, 0, false, false, false, NULL, false },
+  { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true, NULL },
+  { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true,
+    NULL },
+  { "ms_abi va_list", 0, 0, false, false, false, NULL, false, NULL },
+  { "sysv_abi va_list", 0, 0, false, false, false, NULL, false, NULL },
   { "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute,
-    false },
+    false, NULL },
   { "callee_pop_aggregate_return", 1, 1, false, true, true,
-    ix86_handle_callee_pop_aggregate_return, true },
+    ix86_handle_callee_pop_aggregate_return, true, NULL },
   { "interrupt", 0, 0, false, true, true,
-    ix86_handle_interrupt_attribute, false },
+    ix86_handle_interrupt_attribute, false, NULL },
   { "no_caller_saved_registers", 0, 0, false, true, true,
-    ix86_handle_no_caller_saved_registers_attribute, false },
+    ix86_handle_no_caller_saved_registers_attribute, false, NULL },
   { "naked", 0, 0, true, false, false,
-    ix86_handle_fndecl_attribute, false },
+    ix86_handle_fndecl_attribute, false, NULL },
 
   /* End element.  */
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Implement targetm.vectorize.builtin_vectorization_cost.  */
index 84a5b5678a749eb43e43d9c3154bccf7fd15b5c7..ad4bb17d1adeb70a86f4eb410c4a8754649d0121 100644 (file)
@@ -360,17 +360,17 @@ static bool ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d);
 static const struct attribute_spec ia64_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { "syscall_linkage", 0, 0, false, true,  true,  NULL, false },
+       affects_type_identity, exclusions } */
+  { "syscall_linkage", 0, 0, false, true,  true,  NULL, false, NULL },
   { "model",          1, 1, true, false, false, ia64_handle_model_attribute,
-    false },
+    false, NULL },
 #if TARGET_ABI_OPEN_VMS
   { "common_object",   1, 1, true, false, false,
-    ia64_vms_common_object_attribute, false },
+    ia64_vms_common_object_attribute, false, NULL },
 #endif
   { "version_id",      1, 1, true, false, false,
-    ia64_handle_version_id_attribute, false },
-  { NULL,             0, 0, false, false, false, NULL, false }
+    ia64_handle_version_id_attribute, false, NULL },
+  { NULL,             0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Initialize the GCC target structure.  */
index 5987513e97d144d196acd114971ce02c52522e59..281b54ca31c07e6f8109f387567def324e984aa2 100644 (file)
@@ -3000,12 +3000,14 @@ current_function_special_page_vector (rtx x)
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table
 static const struct attribute_spec m32c_attribute_table[] = {
-  {"interrupt", 0, 0, false, false, false, interrupt_handler, false},
-  {"bank_switch", 0, 0, false, false, false, interrupt_handler, false},
-  {"fast_interrupt", 0, 0, false, false, false, interrupt_handler, false},
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity, exclusions } */
+  {"interrupt", 0, 0, false, false, false, interrupt_handler, false, NULL},
+  {"bank_switch", 0, 0, false, false, false, interrupt_handler, false, NULL},
+  {"fast_interrupt", 0, 0, false, false, false, interrupt_handler, false, NULL},
   {"function_vector", 1, 1, true,  false, false, function_vector_handler,
-   false},
-  {0, 0, 0, 0, 0, 0, 0, false}
+   false, NULL},
+  {0, 0, 0, 0, 0, 0, 0, false, NULL}
 };
 
 #undef TARGET_COMP_TYPE_ATTRIBUTES
index f1044575550b19aa7c815fb5f153f73a4e5062d2..bcca103aa2a9677355d087d9bbe6e98bded062e7 100644 (file)
@@ -111,11 +111,11 @@ static HOST_WIDE_INT m32r_starting_frame_offset (void);
 static const struct attribute_spec m32r_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { "interrupt", 0, 0, true,  false, false, NULL, false },
+       affects_type_identity, exclusions } */
+  { "interrupt", 0, 0, true,  false, false, NULL, false, NULL },
   { "model",     1, 1, true,  false, false, m32r_handle_model_attribute,
-    false },
-  { NULL,        0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
index cd2e15e2f6c8cc5cf05ae00ca4d88ee5c2e1cdef..c5b034a615d687e4cb37f540e5ed2e16ee92f0f6 100644 (file)
@@ -348,14 +348,14 @@ static bool m68k_modes_tieable_p (machine_mode, machine_mode);
 static const struct attribute_spec m68k_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "interrupt", 0, 0, true,  false, false, m68k_handle_fndecl_attribute,
     false },
   { "interrupt_handler", 0, 0, true,  false, false,
-    m68k_handle_fndecl_attribute, false },
+    m68k_handle_fndecl_attribute, false, NULL },
   { "interrupt_thread", 0, 0, true,  false, false,
-    m68k_handle_fndecl_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+    m68k_handle_fndecl_attribute, false, NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 
 struct gcc_target targetm = TARGET_INITIALIZER;
index 04dfb9d085a9e6ffef2db420f8f8143ee1aa1b91..af36ebeb36fa0a486d55f6ec11a0b44483f63f55 100644 (file)
@@ -152,12 +152,12 @@ static bool         mcore_modes_tieable_p         (machine_mode, machine_mode);
 static const struct attribute_spec mcore_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { "dllexport", 0, 0, true,  false, false, NULL, false },
-  { "dllimport", 0, 0, true,  false, false, NULL, false },
+       affects_type_identity, exclusions } */
+  { "dllexport", 0, 0, true,  false, false, NULL, false, NULL },
+  { "dllimport", 0, 0, true,  false, false, NULL, false, NULL },
   { "naked",     0, 0, true,  false, false, mcore_handle_naked_attribute,
-    false },
-  { NULL,        0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
index 74875238774f0d806e400b4996ebcecb58ff75e7..acdff6c655d05fcdc93079f1d8758812c46981f8 100644 (file)
@@ -216,17 +216,17 @@ int save_volatiles;
 
 const struct attribute_spec microblaze_attribute_table[] = {
   /* name         min_len, max_len, decl_req, type_req, fn_type, req_handler,
-     affects_type_identity */
+     affects_type_identity, exclusions */
   {"interrupt_handler", 0,       0,     true,    false,   false,        NULL,
-    false },
+    false, NULL },
   {"break_handler",     0,       0,     true,    false,   false,        NULL,
-    false },
+    false, NULL },
   {"fast_interrupt",    0,       0,     true,    false,   false,        NULL,
-    false },
+    false, NULL },
   {"save_volatiles"   , 0,       0,     true,    false,   false,        NULL,
-    false },
+    false, NULL },
   { NULL,              0,       0,    false,    false,   false,        NULL,
-    false }
+    false, NULL }
 };
 
 static int microblaze_interrupt_function_p (tree);
index 7dde705bae7e31ea3ae644d28bce9709784a55d1..4e70a9b2572c4a72cbe231b370cda6df0e108ec5 100644 (file)
@@ -597,27 +597,27 @@ static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int,
 static const struct attribute_spec mips_attribute_table[] = {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        om_diagnostic } */
-  { "long_call",   0, 0, false, true,  true,  NULL, false },
-  { "short_call",  0, 0, false, true,  true,  NULL, false },
-  { "far",                0, 0, false, true,  true,  NULL, false },
-  { "near",        0, 0, false, true,  true,  NULL, false },
+  { "long_call",   0, 0, false, true,  true,  NULL, false, NULL },
+  { "short_call",  0, 0, false, true,  true,  NULL, false, NULL },
+  { "far",                0, 0, false, true,  true,  NULL, false, NULL },
+  { "near",        0, 0, false, true,  true,  NULL, false, NULL },
   /* We would really like to treat "mips16" and "nomips16" as type
      attributes, but GCC doesn't provide the hooks we need to support
      the right conversion rules.  As declaration attributes, they affect
      code generation but don't carry other semantics.  */
-  { "mips16",     0, 0, true,  false, false, NULL, false },
-  { "nomips16",    0, 0, true,  false, false, NULL, false },
-  { "micromips",   0, 0, true,  false, false, NULL, false },
-  { "nomicromips", 0, 0, true,  false, false, NULL, false },
-  { "nocompression", 0, 0, true,  false, false, NULL, false },
+  { "mips16",     0, 0, true,  false, false, NULL, false, NULL },
+  { "nomips16",    0, 0, true,  false, false, NULL, false, NULL },
+  { "micromips",   0, 0, true,  false, false, NULL, false, NULL },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false, NULL },
+  { "nocompression", 0, 0, true,  false, false, NULL, false, NULL },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 1, false, true,  true, mips_handle_interrupt_attr,
-    false },
+    false, NULL },
   { "use_shadow_register_set", 0, 1, false, true,  true,
-    mips_handle_use_shadow_register_set_attr, false },
-  { "keep_interrupts_masked",  0, 0, false, true,  true, NULL, false },
-  { "use_debug_exception_return", 0, 0, false, true,  true, NULL, false },
-  { NULL,         0, 0, false, false, false, NULL, false }
+    mips_handle_use_shadow_register_set_attr, false, NULL },
+  { "keep_interrupts_masked",  0, 0, false, true,  true, NULL, false, NULL },
+  { "use_debug_exception_return", 0, 0, false, true,  true, NULL, false, NULL },
+  { NULL,         0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* A table describing all the processors GCC knows about; see
index 0ee0b6c2dbc42d4e9d4cda100c03577ee63df6c7..3d33f7caba84b9eced2f77a5d918ad916b576d1f 100644 (file)
@@ -2052,20 +2052,25 @@ const struct attribute_spec msp430_attribute_table[] =
   /* Name        min_num_args     type_req,             affects_type_identity
                       max_num_args,     fn_type_req
                           decl_req               handler.  */
-  { ATTR_INTR,        0, 1, true,  false, false, msp430_attr, false },
-  { ATTR_NAKED,       0, 0, true,  false, false, msp430_attr, false },
-  { ATTR_REENT,       0, 0, true,  false, false, msp430_attr, false },
-  { ATTR_CRIT,        0, 0, true,  false, false, msp430_attr, false },
-  { ATTR_WAKEUP,      0, 0, true,  false, false, msp430_attr, false },
-
-  { ATTR_LOWER,       0, 0, true,  false, false, msp430_section_attr, false },
-  { ATTR_UPPER,       0, 0, true,  false, false, msp430_section_attr, false },
-  { ATTR_EITHER,      0, 0, true,  false, false, msp430_section_attr, false },
-
-  { ATTR_NOINIT,      0, 0, true,  false, false, msp430_data_attr, false },
-  { ATTR_PERSIST,     0, 0, true,  false, false, msp430_data_attr, false },
-
-  { NULL,             0, 0, false, false, false, NULL, false }
+  { ATTR_INTR,        0, 1, true,  false, false, msp430_attr, false, NULL },
+  { ATTR_NAKED,       0, 0, true,  false, false, msp430_attr, false, NULL },
+  { ATTR_REENT,       0, 0, true,  false, false, msp430_attr, false, NULL },
+  { ATTR_CRIT,        0, 0, true,  false, false, msp430_attr, false, NULL },
+  { ATTR_WAKEUP,      0, 0, true,  false, false, msp430_attr, false, NULL },
+
+  { ATTR_LOWER,       0, 0, true,  false, false, msp430_section_attr, false,
+    NULL },
+  { ATTR_UPPER,       0, 0, true,  false, false, msp430_section_attr, false,
+    NULL },
+  { ATTR_EITHER,      0, 0, true,  false, false, msp430_section_attr, false,
+    NULL },
+
+  { ATTR_NOINIT,      0, 0, true,  false, false, msp430_data_attr, false,
+    NULL },
+  { ATTR_PERSIST,     0, 0, true,  false, false, msp430_data_attr, false,
+    NULL },
+
+  { NULL,             0, 0, false, false, false, NULL, false, NULL }
 };
 
 #undef  TARGET_ASM_FUNCTION_PROLOGUE
index 5f2e66730002f4b9b4a3200f3dea675a9ae18373..8c3702c148befa818ba077835fbf02ef3c55e991 100644 (file)
@@ -86,30 +86,30 @@ static const struct attribute_spec nds32_attribute_table[] =
               function_type_required, handler, affects_type_identity } */
 
   /* The interrupt vid: [0-63]+ (actual vector number starts from 9 to 72).  */
-  { "interrupt",    1, 64, false, false, false, NULL, false },
+  { "interrupt",    1, 64, false, false, false, NULL, false, NULL },
   /* The exception vid: [1-8]+  (actual vector number starts from 1 to 8).  */
-  { "exception",    1,  8, false, false, false, NULL, false },
+  { "exception",    1,  8, false, false, false, NULL, false, NULL },
   /* Argument is user's interrupt numbers.  The vector number is always 0.  */
-  { "reset",        1,  1, false, false, false, NULL, false },
+  { "reset",        1,  1, false, false, false, NULL, false, NULL },
 
   /* The attributes describing isr nested type.  */
-  { "nested",       0,  0, false, false, false, NULL, false },
-  { "not_nested",   0,  0, false, false, false, NULL, false },
-  { "nested_ready", 0,  0, false, false, false, NULL, false },
+  { "nested",       0,  0, false, false, false, NULL, false, NULL },
+  { "not_nested",   0,  0, false, false, false, NULL, false, NULL },
+  { "nested_ready", 0,  0, false, false, false, NULL, false, NULL },
 
   /* The attributes describing isr register save scheme.  */
-  { "save_all",     0,  0, false, false, false, NULL, false },
-  { "partial_save", 0,  0, false, false, false, NULL, false },
+  { "save_all",     0,  0, false, false, false, NULL, false, NULL },
+  { "partial_save", 0,  0, false, false, false, NULL, false, NULL },
 
   /* The attributes used by reset attribute.  */
-  { "nmi",          1,  1, false, false, false, NULL, false },
-  { "warm",         1,  1, false, false, false, NULL, false },
+  { "nmi",          1,  1, false, false, false, NULL, false, NULL },
+  { "warm",         1,  1, false, false, false, NULL, false, NULL },
 
   /* The attribute telling no prologue/epilogue.  */
-  { "naked",        0,  0, false, false, false, NULL, false },
+  { "naked",        0,  0, false, false, false, NULL, false, NULL },
 
   /* The last attribute spec is set to be NULL.  */
-  { NULL,           0,  0, false, false, false, NULL, false }
+  { NULL,           0,  0, false, false, false, NULL, false, NULL }
 };
 
 
index 634f66038fa8e0542f8aa1421b33caaef65ed2be..16ff370bb32eee2507afa020082d17a712dc2eee 100644 (file)
@@ -4458,10 +4458,12 @@ nvptx_handle_shared_attribute (tree *node, tree name, tree ARG_UNUSED (args),
 static const struct attribute_spec nvptx_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  { "kernel", 0, 0, true, false,  false, nvptx_handle_kernel_attribute, false },
-  { "shared", 0, 0, true, false,  false, nvptx_handle_shared_attribute, false },
-  { NULL, 0, 0, false, false, false, NULL, false }
+       affects_type_identity, exclusions } */
+  { "kernel", 0, 0, true, false,  false, nvptx_handle_kernel_attribute, false,
+    NULL },
+  { "shared", 0, 0, true, false,  false, nvptx_handle_shared_attribute, false,
+    NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Limit vector alignments to BIGGEST_ALIGNMENT.  */
index b5fc656a8f1d9bd279b6faade023e784c70bdb29..44165802be4074710e9156b496c2c2dd12969cec 100644 (file)
@@ -1534,21 +1534,21 @@ static const char alt_reg_names[][8] =
 static const struct attribute_spec rs6000_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute,
-    false },
+    false, NULL },
   { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
-    false },
+    false, NULL },
   { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
-    false },
+    false, NULL },
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 #ifndef TARGET_PROFILE_KERNEL
index 7b381b1f78a16162193cbcc23da0d3b0b6e8871a..58c8fe8ed1ca32a4fc0947246a640ee5d6b62be2 100644 (file)
@@ -860,14 +860,14 @@ const struct attribute_spec rl78_attribute_table[] =
   /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
      affects_type_identity.  */
   { "interrupt",      0, 0, true, false, false, rl78_handle_func_attribute,
-    false },
+    false, NULL },
   { "brk_interrupt",  0, 0, true, false, false, rl78_handle_func_attribute,
-    false },
+    false, NULL },
   { "naked",          0, 0, true, false, false, rl78_handle_naked_attribute,
-    false },
+    false, NULL },
   { "saddr",          0, 0, true, false, false, rl78_handle_saddr_attribute,
-    false },
-  { NULL,             0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,             0, 0, false, false, false, NULL, false, NULL }
 };
 
 
index 83aa428c32c8645a04a0bea104517798b45bedbd..155ea6e9d991048899173049a126904ea98f4c8f 100644 (file)
@@ -1518,21 +1518,21 @@ static const char alt_reg_names[][8] =
 static const struct attribute_spec rs6000_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute,
-    false },
+    false, NULL },
   { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
-    false },
+    false, NULL },
   { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
-    false },
+    false, NULL },
   { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
-    false },
+    false, NULL },
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 #ifndef TARGET_PROFILE_KERNEL
index 021cf5c8aa7abd76c269c9538917c6bafa5242fa..84032b70d388dc7b040516b63ea5a0bfce0c56c6 100644 (file)
@@ -2732,16 +2732,16 @@ rx_handle_vector_attribute (tree * node,
 const struct attribute_spec rx_attribute_table[] =
 {
   /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-     affects_type_identity.  */
+     affects_type_identity, exclusions.  */
   { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
-    false },
+    false, NULL },
   { "interrupt",      0, -1, true, false, false, rx_handle_func_attribute,
-    false },
+    false, NULL },
   { "naked",          0, 0, true, false, false, rx_handle_func_attribute,
-    false },
+    false, NULL },
   { "vector",         1, -1, true, false, false, rx_handle_vector_attribute,
-    false },
-  { NULL,             0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,             0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE.  */
index 4e089557e102328e5640e04ddd95f19dfa2f3e35..c87f44db29a289426884ee320fc0d2608e6adce7 100644 (file)
@@ -1178,10 +1178,12 @@ s390_handle_vectorbool_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
 }
 
 static const struct attribute_spec s390_attribute_table[] = {
-  { "hotpatch", 2, 2, true, false, false, s390_handle_hotpatch_attribute, false },
-  { "s390_vector_bool", 0, 0, false, true, false, s390_handle_vectorbool_attribute, true },
+  { "hotpatch", 2, 2, true, false, false,
+    s390_handle_hotpatch_attribute, false, NULL },
+  { "s390_vector_bool", 0, 0, false, true, false,
+    s390_handle_vectorbool_attribute, true, NULL },
   /* End element.  */
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Return the alignment for LABEL.  We default to the -falign-labels
index 3c6d525eb0ccb23ef4524f6611659afeb0bbeb81..0d7d7bc53ca21fdec925feddd67247b548e51d62 100644 (file)
@@ -330,24 +330,24 @@ static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t);
 static const struct attribute_spec sh_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "interrupt_handler", 0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
+    sh_handle_interrupt_handler_attribute, false, NULL },
   { "sp_switch",         1, 1, true,  false, false,
-     sh_handle_sp_switch_attribute, false },
+     sh_handle_sp_switch_attribute, false, NULL },
   { "trap_exit",         1, 1, true,  false, false,
-    sh_handle_trap_exit_attribute, false },
+    sh_handle_trap_exit_attribute, false, NULL },
   { "renesas",           0, 0, false, true, false,
-    sh_handle_renesas_attribute, false },
+    sh_handle_renesas_attribute, false, NULL },
   { "trapa_handler",     0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
+    sh_handle_interrupt_handler_attribute, false, NULL },
   { "nosave_low_regs",   0, 0, true,  false, false,
-    sh_handle_interrupt_handler_attribute, false },
+    sh_handle_interrupt_handler_attribute, false, NULL },
   { "resbank",           0, 0, true,  false, false,
-    sh_handle_resbank_handler_attribute, false },
+    sh_handle_resbank_handler_attribute, false, NULL },
   { "function_vector",   1, 1, true,  false, false,
-    sh2a_handle_function_vector_handler_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+    sh2a_handle_function_vector_handler_attribute, false, NULL },
+  { NULL,                0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 /* Initialize the GCC target structure.  */
index 9124ce9cf718c773736d655fa39f6c56c7edeb85..54e7a0e161a2e7bc38dd7a6e8bcd2ee79d8ae20e 100644 (file)
@@ -691,9 +691,9 @@ static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT);
 static const struct attribute_spec sparc_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       do_diagnostic } */
+       do_diagnostic, exclusions } */
   SUBTARGET_ATTRIBUTE_TABLE,
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 #endif
 \f
index 78252101ef57397976a674bc066285eb959a6452..dc9e13356baf6a591ae22a1890ce85c75b9b5a48 100644 (file)
@@ -7215,12 +7215,12 @@ spu_constant_alignment (const_tree, HOST_WIDE_INT align)
 static const struct attribute_spec spu_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "naked",          0, 0, true,  false, false, spu_handle_fndecl_attribute,
-    false },
+    false, NULL },
   { "spu_vector",     0, 0, false, true,  false, spu_handle_vector_attribute,
-    false },
-  { NULL,             0, 0, false, false, false, NULL, false }
+    false, NULL },
+  { NULL,             0, 0, false, false, false, NULL, false, NULL }
 };
 
 /*  TARGET overrides.  */
index d0bd4335073ae5637af2aee2181208750cda6a2e..3a21260fda7c40e692c1480baa0497516248b7d2 100644 (file)
@@ -2190,14 +2190,14 @@ static tree xstormy16_handle_below100_attribute
 static const struct attribute_spec xstormy16_attribute_table[] =
 {
   /* name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-     affects_type_identity.  */
+     affects_type_identity, exclusions.  */
   { "interrupt", 0, 0, false, true,  true,
-    xstormy16_handle_interrupt_attribute , false },
+    xstormy16_handle_interrupt_attribute , false, NULL },
   { "BELOW100",  0, 0, false, false, false,
-    xstormy16_handle_below100_attribute, false },
+    xstormy16_handle_below100_attribute, false, NULL },
   { "below100",  0, 0, false, false, false,
-    xstormy16_handle_below100_attribute, false },
-  { NULL,        0, 0, false, false, false, NULL, false }
+    xstormy16_handle_below100_attribute, false, NULL },
+  { NULL,        0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Handle an "interrupt" attribute;
index 32c6a036eb37f410cafb2ebe68d60daa14b99692..3d0bbf55e2481ef8b1439bf65e24c57f8ecf246e 100644 (file)
@@ -3188,18 +3188,18 @@ v850_adjust_insn_length (rtx_insn *insn, int length)
 static const struct attribute_spec v850_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "interrupt_handler", 0, 0, true,  false, false,
-    v850_handle_interrupt_attribute, false },
+    v850_handle_interrupt_attribute, false, NULL },
   { "interrupt",         0, 0, true,  false, false,
-    v850_handle_interrupt_attribute, false },
+    v850_handle_interrupt_attribute, false, NULL },
   { "sda",               0, 0, true,  false, false,
-    v850_handle_data_area_attribute, false },
+    v850_handle_data_area_attribute, false, NULL },
   { "tda",               0, 0, true,  false, false,
-    v850_handle_data_area_attribute, false },
+    v850_handle_data_area_attribute, false, NULL },
   { "zda",               0, 0, true,  false, false,
-    v850_handle_data_area_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+    v850_handle_data_area_attribute, false, NULL },
+  { NULL,                0, 0, false, false, false, NULL, false, NULL }
 };
 \f
 static void
index 3311dd2a349d39fd730cb6000c67d6ab17ad0145..a8b90019aa9b1e015c1bdc02656abf2f1bfc0f55 100644 (file)
@@ -146,9 +146,10 @@ static inline bool current_function_has_lr_slot (void);
 static const struct attribute_spec visium_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
-  {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
-  {NULL, 0, 0, false, false, false, NULL, false}
+       affects_type_identity, exclusions } */
+  {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false,
+   NULL},
+  {NULL, 0, 0, false, false, false, NULL, false, NULL},
 };
 
 static struct machine_function *visium_init_machine_status (void);
index 9bfc72c361dcec2a7c4f723fc369e3875812ce5f..e492f0a9867588d959cae9ce4789c32ceaec3d6c 100644 (file)
@@ -1,3 +1,14 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * cp-tree.h (decls_match): Add default argument.
+       * decl.c (decls_match): Avoid calling into the target back end
+       and triggering an error.
+       * decl2.c (cplus_decl_attributes): Look up existing declaration and
+       pass it to decl_attributes.
+       * tree.c (cxx_attribute_table): Initialize new member of struct
+       attribute_spec.
+
 2017-12-06  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/80259
index 575255d64e70c7a5f002369b2aad02749d05b020..708d172bf6176394c32e0368b236a64c059ab377 100644 (file)
@@ -6116,7 +6116,7 @@ extern void note_break_stmt                       (void);
 extern bool note_iteration_stmt_body_start     (void);
 extern void note_iteration_stmt_body_end       (bool);
 extern tree make_lambda_name                   (void);
-extern int decls_match                         (tree, tree);
+extern int decls_match                         (tree, tree, bool = true);
 extern bool maybe_version_functions            (tree, tree);
 extern tree duplicate_decls                    (tree, tree, bool);
 extern tree declare_local_label                        (tree);
index 7085d5a3976a36ff5e6161f53e347fea3f2f901a..99b22dc878c4a1525c48483f1fbf2f4bf5c89eef 100644 (file)
@@ -992,7 +992,7 @@ push_local_name (tree decl)
    `const int&'.  */
 
 int
-decls_match (tree newdecl, tree olddecl)
+decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
 {
   int types_match;
 
@@ -1087,6 +1087,7 @@ decls_match (tree newdecl, tree olddecl)
       if (types_match
          && !DECL_EXTERN_C_P (newdecl)
          && !DECL_EXTERN_C_P (olddecl)
+         && record_versions
          && maybe_version_functions (newdecl, olddecl))
        return 0;
     }
index 2de36fa99bc5b10b265c4c331e6394a7266598ae..5d30369e80fec6fa4f14b7d984496c2875ea7ad5 100644 (file)
@@ -1482,7 +1482,31 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
                       attributes, flags);
     }
   else
-    decl_attributes (decl, attributes, flags);
+    {
+      tree last_decl = (DECL_P (*decl) && DECL_NAME (*decl)
+                       ? lookup_name (DECL_NAME (*decl)) : NULL_TREE);
+
+      if (last_decl && TREE_CODE (last_decl) == OVERLOAD)
+       for (ovl_iterator iter (last_decl, true); ; ++iter)
+         {
+           if (!iter)
+             {
+               last_decl = NULL_TREE;
+               break;
+             }
+
+           if (TREE_CODE (*iter) == OVERLOAD)
+             continue;
+
+           if (decls_match (*decl, *iter, /*record_decls=*/false))
+             {
+               last_decl = *iter;
+               break;
+             }
+         }
+
+      decl_attributes (decl, attributes, flags, last_decl);
+    }
 
   if (TREE_CODE (*decl) == TYPE_DECL)
     SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
index 43bbf438eaef62c9c02dd1359789e2d0e3fc2e72..0ae2eff4e1e42fabac05531d3ae43dcce794eb24 100644 (file)
@@ -4330,24 +4330,24 @@ handle_nodiscard_attribute (tree *node, tree name, tree /*args*/,
 const struct attribute_spec cxx_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "init_priority",  1, 1, true,  false, false,
-    handle_init_priority_attribute, false },
+    handle_init_priority_attribute, false, NULL },
   { "abi_tag", 1, -1, false, false, false,
-    handle_abi_tag_attribute, true },
-  { NULL,            0, 0, false, false, false, NULL, false }
+    handle_abi_tag_attribute, true, NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Table of C++ standard attributes.  */
 const struct attribute_spec std_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "maybe_unused", 0, 0, false, false, false,
-    handle_unused_attribute, false },
+    handle_unused_attribute, false, NULL },
   { "nodiscard", 0, 0, false, false, false,
-    handle_nodiscard_attribute, false },
-  { NULL,            0, 0, false, false, false, NULL, false }
+    handle_nodiscard_attribute, false, NULL },
+  { NULL, 0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Handle an "init_priority" attribute; arguments as in
index 3d5e15c9744132a1feb3ae9270e14645480d1408..ad4d9d313999ad0f87535e6c624970c545b4e6e0 100644 (file)
@@ -2493,9 +2493,14 @@ are automatically detected and this attribute is ignored.
 @cindex @code{const} function attribute
 @cindex functions that have no side effects
 Many functions do not examine any values except their arguments, and
-have no effects except the return value.  Basically this is just slightly
-more strict class than the @code{pure} attribute below, since function is not
-allowed to read global memory.
+have no effects except to return a value.  Calls to such functions lend
+themselves to optimization such as common subexpression elimination.
+The @code{const} attribute imposes greater restrictions on a function's
+definition than the similar @code{pure} attribute below because it prohibits
+the function from reading global variables.  Consequently, the presence of
+the attribute on a function declarations allows GCC to emit more efficient
+code for some calls to the function.  Decorating the same function with
+both the @code{const} and the @code{pure} attribute is diagnnosed.
 
 @cindex pointer arguments
 Note that a function that has pointer arguments and examines the data
@@ -3190,7 +3195,7 @@ to prevent recursion.
 @cindex functions that have no side effects
 Many functions have no effects except the return value and their
 return value depends only on the parameters and/or global variables.
-Such a function can be subject
+Calls to such functions can be subject
 to common subexpression elimination and loop optimization just as an
 arithmetic operator would be.  These functions should be declared
 with the attribute @code{pure}.  For example,
@@ -3208,6 +3213,11 @@ Interesting non-pure functions are functions with infinite loops or those
 depending on volatile memory or other system resource, that may change between
 two consecutive calls (such as @code{feof} in a multithreading environment).
 
+The @code{pure} attribute imposes similar but looser restrictions on
+a function's defintion than the @code{const} attribute: it allows the
+function to read global variables.  Decorating the same function with
+both the @code{pure} and the @code{const} attribute is diagnosed.
+
 @item returns_nonnull
 @cindex @code{returns_nonnull} function attribute
 The @code{returns_nonnull} attribute specifies that the function
index e0dd79514e8bb5f20f7446143a14af9abe35c025..b48bac45e16960c57c9918d8604afd51c0a2514a 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * f95-lang.c (gfc_attribute_table): Initialize new member of struct
+       attribute_spec.
+
 2017-12-03  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR fortran/36313
index 44bd8dcc2ad028a8e1ec1cd477d9e8dc1790fb57..0ecb2074dcc8482598a3770c03acfb60493157a9 100644 (file)
@@ -92,12 +92,12 @@ static const struct attribute_spec gfc_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "omp declare target", 0, 0, true,  false, false,
-    gfc_handle_omp_declare_target_attribute, false },
+    gfc_handle_omp_declare_target_attribute, false, NULL },
   { "omp declare target link", 0, 0, true,  false, false,
-    gfc_handle_omp_declare_target_attribute, false },
+    gfc_handle_omp_declare_target_attribute, false, NULL },
   { "oacc function", 0, -1, true,  false, false,
-    gfc_handle_omp_declare_target_attribute, false },
-  { NULL,                0, 0, false, false, false, NULL, false }
+    gfc_handle_omp_declare_target_attribute, false, NULL },
+  { NULL,                0, 0, false, false, false, NULL, false, NULL }
 };
 
 #undef LANG_HOOKS_NAME
index 7d997e4f9ff539f07a403c48760901236cbc7385..b8260a0690d9b9f151f48310945cb0f4e2450916 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * lto-lang.c (lto_attribute_table): Initialize new member of struct
+       attribute_spec.
+
 2017-11-30  Jakub Jelinek  <jakub@redhat.com>
 
        * lto.c (create_subid_section_table): Use ; instead of ;;.
index c2ba3dc50c4235be56307ee46c974398325c3cb9..89702a4e652a5ad7b4ee32fb51ca0dd5f383db49 100644 (file)
@@ -57,46 +57,82 @@ static tree handle_format_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
 
+/* Helper to define attribute exclusions.  */
+#define ATTR_EXCL(name, function, type, variable)      \
+  { name, function, type, variable }
+
+/* Define attributes that are mutually exclusive with one another.  */
+static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+{
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL ("returns_twice", true, true, true),
+  ATTR_EXCL ("warn_unused_result", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
+{
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
+{
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
 /* Table of machine-independent attributes supported in GIMPLE.  */
 const struct attribute_spec lto_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       do_diagnostic } */
+       do_diagnostic, exclusions } */
   { "noreturn",               0, 0, true,  false, false,
-                             handle_noreturn_attribute, false },
+                             handle_noreturn_attribute, false,
+                             attr_noreturn_exclusions },
   { "leaf",                  0, 0, true,  false, false,
-                             handle_leaf_attribute, false },
+                             handle_leaf_attribute, false, NULL },
   /* The same comments as for noreturn attributes apply to const ones.  */
   { "const",                  0, 0, true,  false, false,
-                             handle_const_attribute, false },
+                             handle_const_attribute, false,
+                             attr_const_pure_exclusions },
   { "malloc",                 0, 0, true,  false, false,
-                             handle_malloc_attribute, false },
+                             handle_malloc_attribute, false, NULL },
   { "pure",                   0, 0, true,  false, false,
-                             handle_pure_attribute, false },
+                             handle_pure_attribute, false,
+                             attr_const_pure_exclusions },
   { "no vops",                0, 0, true,  false, false,
-                             handle_novops_attribute, false },
+                             handle_novops_attribute, false, NULL },
   { "nonnull",                0, -1, false, true, true,
-                             handle_nonnull_attribute, false },
+                             handle_nonnull_attribute, false, NULL },
   { "nothrow",                0, 0, true,  false, false,
-                             handle_nothrow_attribute, false },
+                             handle_nothrow_attribute, false, NULL },
   { "patchable_function_entry", 1, 2, true, false, false,
                              handle_patchable_function_entry_attribute,
-                             false },
+                             false, NULL },
   { "returns_twice",          0, 0, true,  false, false,
-                             handle_returns_twice_attribute, false },
+                             handle_returns_twice_attribute, false,
+                             attr_returns_twice_exclusions },
   { "sentinel",               0, 1, false, true, true,
-                             handle_sentinel_attribute, false },
+                             handle_sentinel_attribute, false, NULL },
   { "type generic",           0, 0, false, true, true,
-                             handle_type_generic_attribute, false },
+                             handle_type_generic_attribute, false, NULL },
   { "fn spec",               1, 1, false, true, true,
-                             handle_fnspec_attribute, false },
+                             handle_fnspec_attribute, false, NULL },
   { "transaction_pure",              0, 0, false, true, true,
-                             handle_transaction_pure_attribute, false },
+                             handle_transaction_pure_attribute, false, NULL },
   /* For internal use only.  The leading '*' both prevents its usage in
      source code and signals that it may be overridden by machine tables.  */
   { "*tm regparm",            0, 0, false, true, true,
-                             ignore_attribute, false },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+                             ignore_attribute, false, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Give the specifications for the format attributes, used by C and all
@@ -105,12 +141,12 @@ const struct attribute_spec lto_attribute_table[] =
 const struct attribute_spec lto_format_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
-       affects_type_identity } */
+       affects_type_identity, exclusions } */
   { "format",                 3, 3, false, true,  true,
-                             handle_format_attribute, false },
+                             handle_format_attribute, false, NULL },
   { "format_arg",             1, 1, false, true,  true,
-                             handle_format_arg_attribute, false },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+                             handle_format_arg_attribute, false, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 enum built_in_attribute
@@ -264,6 +300,10 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name),
                        tree ARG_UNUSED (args), int ARG_UNUSED (flags),
                        bool * ARG_UNUSED (no_add_attrs))
 {
+  if (TREE_CODE (*node) != FUNCTION_DECL
+      || !DECL_BUILT_IN (*node))
+    inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name);
+
   tree type = TREE_TYPE (*node);
 
   /* See FIXME comment on noreturn in c_common_attribute_table.  */
index 6030d3b22e7d1fda2603c5cb0a63fff2562c7e8e..d57ba992e5c295e3598cff166b2f3270510c5c65 100644 (file)
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "langhooks.h"
 #include "options.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This function needed to be split out from selftest.c as it references
    tests from the whole source tree, and so is within
@@ -85,6 +87,7 @@ selftest::run_tests ()
   spellcheck_c_tests ();
   spellcheck_tree_c_tests ();
   tree_cfg_c_tests ();
+  attribute_c_tests ();
 
   /* This one relies on most of the above.  */
   function_tests_c_tests ();
index cdad939ce68c9c30c09ebe90d84e2063bdf1fbcf..d0aa3b217c013e469d74e7dd3ebbe41143a66036 100644 (file)
@@ -170,6 +170,7 @@ extern const char *path_to_selftest_files;
 
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
+extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void sbitmap_c_tests ();
 extern void diagnostic_c_tests ();
index 6d7ec09240b022a0af1c7537cd2da68cae1df880..4a4406a340594cd1719b9d87fb019ac8e94a7d4e 100644 (file)
@@ -1,3 +1,16 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * c-c++-common/Wattributes-2.c: New test.
+       * c-c++-common/Wattributes.c: New test.
+       * c-c++-common/attributes-3.c: Adjust.
+       * gcc.dg/Wattributes-6.c: New test.
+       * gcc.dg/Wattributes-7.c: New test.
+       * gcc.dg/attr-noinline.c
+       * gcc.dg/pr44964.c: Same.
+       * gcc.dg/torture/pr42363.c: Same.
+       * gcc.dg/tree-ssa/ssa-ccp-2.c: Same.
+
 2017-12-07  Tamar Christina  <tamar.christina@arm.com>
 
        PR target/82641
index 821278c680fb8c30d31e3e92ee73623c9c2c8976..c2be4bbfbeacdfcb2a01c6da82d2a92ccfaa6e24 100644 (file)
@@ -12,16 +12,16 @@ extern __attribute__((noinline)) int fn1 (void); /* { dg-message "previous decla
 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__((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 fn3 (void); /* { dg-warning "attribute .noinline." } */
 
 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__((always_inline)) int fn4 (void); /* { dg-warning "attribute .always_inline." } */
 
 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 fn5 (void); /* { dg-warning "attribute .cold." } */
 
 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." } */
+extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot." } */
index c2a5b1ddacf5939149c45a79f67f61101aca7e4b..13cc6600c28d36debc6a1aeee2ff096a7ecf5db4 100644 (file)
@@ -17,7 +17,7 @@ static void function_declaration_both_after(void) {t();}
 
 static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */
 
-static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute noinline" } */
+static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute .noinline." } */
 
 static inline void function_declaration_noinline_after(void) {t();} /* { dg-message "note: previous definition" } */
 
@@ -41,7 +41,7 @@ static void function_declaration_inline_noinline_after(void) __attribute__((__no
 
 static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */
 
-static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute noinline" } */
+static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute .noinline." } */
 
 static void function_declaration_noinline_inline_before(void) {t();}
 
index 1df1bde0703dd5e273b4eb084360259e916b38ce..6c252ee2616b83a3b0ec6d88f3cf0344822bd707 100644 (file)
@@ -2,8 +2,9 @@
 /* { dg-options "-fkeep-inline-functions -O" } */
 
 static inline __attribute__ ((const))
-void baz (int i)
+int baz (int i)
 {
+  return i;
 }
 
 static __attribute__ ((always_inline))
index 9c9da1373dd49498705fcef8f87739fce228fc77..ad0eac8ceed51efd6a35057415f2b33c7f7ef8c7 100644 (file)
@@ -46,16 +46,18 @@ int bizr (void)
   return i + 1;
 }
 
-/* This might be regarded as pure and folded, rather than inlined.
-   It's pure evil.  */
+/* This might be regarded as pure and folded, rather than inlined,
+   but because it's pure evil it's diagnosed and the noreturn attribute
+   is dropped.  The const attribute is dropped as well because it's
+   mutually exclusive with pure.  */
 static int __attribute__ ((pure, const, noreturn))
-barf (void)
-{
+barf (void) {
+  /* { dg-warning "ignoring attribute .const." "const" { target *-*-* } .-1 } */
+  /* { dg-warning "ignoring attribute .noreturn." "noreturn" { target *-*-* } .-2 } */
 } /* { dg-warning "does return" } */
 
 static int __attribute__ ((pure, const))
-bark (void)
-{
+bark (void) {   /* { dg-warning "ignoring attribute .const." } */
   barf ();
 }
 
index 146b76c49f6c36d0cab6e0d1925930fc2bf07b37..b8c5654ffc2255c8da48a9cadeccd23bf8143dec 100644 (file)
@@ -113,17 +113,18 @@ int test9 (int *intarr)
 
 int test99 (int *intarr)
 {
-  extern int foo9 (int) __attribute__ ((pure));
+  extern int foo99 (int) __attribute__ ((pure));
   int h, v;
   g9 = 9;
-  h = foo9 (g9);
+  h = foo99 (g9);
   v = g9;
   if (v != 9)
     link_error ();
   return g9;
 }
 
-extern int foo99 (int);
+/* foo9 is const because of its declaration in test9.  */
+extern int foo9 (int);
 
 int test999 (int *arr)
 {
@@ -134,10 +135,12 @@ int test999 (int *arr)
   v1 = g9;
   if (v1 != 9)
     link_error ();
-  l = foo99 (l);
+  l = foo9 (l);
   return v1 + l;
 }
 
+/* foo99 is pure because of its declaration in test99.  */
+extern int foo9 (int);
 
 int test9999 (void)
 {
index 5f900b8fe5907c8f146695258463ae8b3e447c49..7672541f1b406fe84a430164a726bdb8293b0291 100644 (file)
@@ -1938,6 +1938,20 @@ struct attribute_spec {
                   int flags, bool *no_add_attrs);
   /* Specifies if attribute affects type's identity.  */
   bool affects_type_identity;
+
+  /* Specifies the name of an attribute that's mutually exclusive with
+     this one, and whether the relationship applies to the function,
+     variable, or type form of the attribute.  */
+  struct exclusions {
+    const char *name;
+    bool function;
+    bool variable;
+    bool type;
+  };
+
+  /* An array of attribute exclusions describing names of other attributes
+     that this attribute is mutually exclusive with.  */
+  const exclusions *exclude;
 };
 
 /* These functions allow a front-end to perform a manual layout of a
index 34ec0b5ff340b6268c83a8825317e4721c07b1ea..f4a04fac43fedcb851069d3963e0a0fcc3b37eba 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-07  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81544
+       * include/ext/mt_allocator.h (_M_destroy_thread_key): Remove
+       attribute const.
+
 2017-12-05  Jason Merrill  <jason@redhat.com>
            Jonathan Wakely  <jwakely@redhat.com>
 
index effb13b7dbcb618aa55464158ddb46116f4051b2..99c20423f94b83d9dad65e8dac04ba1a08ba9c1d 100644 (file)
@@ -355,7 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       // XXX GLIBCXX_ABI Deprecated
-      _GLIBCXX_CONST void 
+      void
       _M_destroy_thread_key(void*) throw ();
 
       size_t