This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/3] improve detection of attribute conflicts (PR 81544)


Part 1 of the patch series is the core of the enhancement without
the (trivial) changes to the back ends and front ends other than
C and C++.

Marek, I tried to follow what we discussed in IRC.  Please let
me know if I missed something.

Joseph, I read your comments on Marek's patch for the same bug:
  https://gcc.gnu.org/ml/gcc-patches/2017-07/msg02077.html
I had to make some changes to meet that expectation, in part
because decl_attributes reorders attributes, but with those
I believe it does what you expect.

Jason, I'd appreciate your review of the C++ bits.  I couldn't
find a better way of finding an existing declaration of a function
given one that's about to be introduced, but it feels like there
ought to be an existing API somewhere that I missed.

Martin

PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted

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
	* 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): Warn on conflicting specifications.
	* c-warn.c (diagnose_mismatched_attributes): Simplify.

gcc/cp/ChangeLog:

	PR c/81544
	* decl2.c (cplus_decl_attributes): Look up existing declaration and
	pass it to decl_attributes.
	* name-lookup.c (find_decl): New function.
	* name-lookup.h (find_decl): Declare it.
	* tree.c (cxx_attribute_table): Initialize new member of struct
	attribute_spec.

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.
	* g++.dg/ext/mv11.s: New test.
	* gcc.dg/attr-noinline.c: Adjust.
	* gcc.dg/pr44964.c: Same.
	* gcc.dg/torture/pr42363.c: Same.
	* gcc.dg/tree-ssa/ssa-ccp-2.c: Same.

libstdc++-v3/ChangeLog:

	PR c/81544
	* include/ext/mt_allocator.h (_M_destroy_thread_key): Remove
	pointless attribute const.

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.
	* attribs.h (decl_attributes): Add default argument.
	* tree-core.h (attribute_spec::exclusions, exclude): New type and
	member.

 /* Associates a GNAT tree node to a GCC tree node. It is used in
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 05fa8ef..df3104b 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -94,7 +94,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 +343,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 EXCL 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]))
+	    {
+	      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 +445,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 +525,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 +535,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 +583,9 @@ 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);
+	      // returned_attrs = tree_cons (name, args, returned_attrs);
 	      continue;
 	    }
 	  else
@@ -535,7 +630,9 @@ 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);
+	      // returned_attrs = tree_cons (name, args, returned_attrs);
 	      continue;
 	    }
 
@@ -557,15 +654,55 @@ 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 sussceefully 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.  */
diff --git a/gcc/attribs.h b/gcc/attribs.h
index d4a790b..a9eba0a 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -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);
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 0d9ab2d..8a157f6 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "opts.h"
 #include "gimplify.h"
+#include "bitmap.h"
 
 static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -146,6 +147,92 @@ 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_gnu_inline_exclusions[] =
+{
+  ATTR_EXCL ("gnu_inline", true, true, true),
+  ATTR_EXCL ("noinline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_inline_exclusions[] =
+{
+  ATTR_EXCL ("always_inline", true, true, true),
+  ATTR_EXCL ("noinline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+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_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 ("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
@@ -157,209 +244,230 @@ 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_inline_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_gnu_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 },
   { "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 },
   { "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 },
+			      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 },
-  { NULL,                     0, 0, false, false, false, NULL, false }
+			      false, NULL },
+  { NULL,                     0, 0, false, false, false, NULL, false, NULL }
 };
 
 /* Give the specifications for the format attributes, used by C and all
@@ -374,10 +482,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
@@ -515,14 +623,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
     {
@@ -543,14 +644,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
     {
@@ -1064,7 +1158,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);
 
@@ -1085,6 +1179,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;
 }
 
@@ -1667,14 +1769,18 @@ check_cxx_fundamental_alignment_constraints (tree node,
    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)
 {
   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 hassn't been
+     yet.  */
+  tree last_decl = node[1] ? node[1] : *node;
 
   if (args)
     {
@@ -1693,10 +1799,21 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       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)
     {
@@ -1717,7 +1834,7 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       else
 	*type = build_variant_type_copy (*type);
 
-      SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+      SET_TYPE_ALIGN (*type, bitalign);
       TYPE_USER_ALIGN (*type) = 1;
     }
   else if (! VAR_OR_FUNCTION_DECL_P (decl)
@@ -1726,8 +1843,34 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       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
@@ -1737,21 +1880,9 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       This formally comes from the c++11 specification but we are
       doing it for the GNU attribute syntax as well.  */
     *no_add_attrs = true;
-  else if (TREE_CODE (decl) == FUNCTION_DECL
-	   && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
-    {
-      if (DECL_USER_ALIGN (decl))
-	error ("alignment for %q+D was previously specified as %d "
-	       "and may not be decreased", decl,
-	       DECL_ALIGN (decl) / BITS_PER_UNIT);
-      else
-	error ("alignment for %q+D must be at least %d", decl,
-	       DECL_ALIGN (decl) / BITS_PER_UNIT);
-      *no_add_attrs = true;
-    }
   else
     {
-      SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+      SET_DECL_ALIGN (decl, bitalign);
       DECL_USER_ALIGN (decl) = 1;
     }
 
@@ -2476,8 +2607,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);
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index e970ab2..8bbfcb5 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2143,36 +2143,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;
 }
 
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index a54e121..5852c0d 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -4589,7 +4589,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);
 }
 
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 115cdaf..f2bac2a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6080,7 +6080,7 @@ extern void finish_scope			(void);
 extern void push_switch				(tree);
 extern void pop_switch				(void);
 extern tree make_lambda_name			(void);
-extern int decls_match				(tree, tree);
+extern int decls_match				(tree, tree, bool = true);
 extern tree duplicate_decls			(tree, tree, bool);
 extern tree declare_local_label			(tree);
 extern tree define_label			(location_t, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index aab2019..c9c8cd1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -993,7 +993,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;
 
@@ -1088,6 +1088,7 @@ decls_match (tree newdecl, tree olddecl)
       if (types_match
 	  && !DECL_EXTERN_C_P (newdecl)
 	  && !DECL_EXTERN_C_P (olddecl)
+	  && record_versions
 	  && targetm.target_option.function_versions (newdecl, olddecl))
 	{
 	  /* Mark functions as versions if necessary.  Modify the mangled decl
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 2a52f8c..585822e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1404,7 +1404,10 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
 		       attributes, flags);
     }
   else
-    decl_attributes (decl, attributes, flags);
+    {
+      tree last_decl = find_decl (*decl);
+      decl_attributes (decl, attributes, flags, last_decl);
+    }
 
   if (TREE_CODE (*decl) == TYPE_DECL)
     SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 4dc19da..e18e3fa 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -2291,6 +2291,71 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
     }
 }
 
+/* Given a new DECL that hasn't been pushed yet, try to find the last
+   DECL for the same symbol and return it, oterwise return null.  */
+
+tree
+find_decl (tree decl)
+{
+  if (!DECL_P (decl))
+    return NULL_TREE;
+
+  /* if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl) */
+  /*   set_decl_context_in_fn (current_function_decl, decl); */
+
+  /* The binding level we will be pushing into.  During local class
+     pushing, we want to push to the containing scope.  */
+  cp_binding_level *level = current_binding_level;
+  while (level->kind == sk_class)
+    level = level->level_chain;
+
+  tree name = DECL_NAME (decl);
+  if (!name)
+    return NULL_TREE;
+
+  cxx_binding *binding = NULL; /* Local scope binding.  */
+  tree ns = NULL_TREE; /* Searched namespace.  */
+  tree *slot = NULL; /* Binding slot in namespace.  */
+  tree old = NULL_TREE;
+
+  if (level->kind == sk_namespace)
+    {
+      /* We look in the decl's namespace for an existing
+	 declaration, even though we push into the current
+	 namespace.  */
+      ns = (DECL_NAMESPACE_SCOPE_P (decl)
+	    ? CP_DECL_CONTEXT (decl) : current_namespace);
+      /* Create the binding, if this is current namespace, because
+	 that's where we'll be pushing anyway.  */
+      slot = find_namespace_slot (ns, name, ns == current_namespace);
+      if (slot)
+	old = MAYBE_STAT_DECL (*slot);
+    }
+  else
+    {
+      binding = find_local_binding (level, name);
+      if (binding)
+	old = binding->value;
+    }
+
+  /* if (current_function_decl && VAR_OR_FUNCTION_DECL_P (decl) */
+  /*     && DECL_EXTERNAL (decl)) */
+  /*   set_local_extern_decl_linkage (decl, old != NULL_TREE); */
+
+  if (old == error_mark_node)
+    old = NULL_TREE;
+
+  for (ovl_iterator iter (old); iter; ++iter)
+    {
+      if (iter.using_p ())
+	; /* Ignore using decls here.  */
+      else if (decls_match (decl, *iter, /*record_decls=*/false))
+	return *iter;
+    }
+
+  return NULL_TREE;
+}
+
 /* Record DECL as belonging to the current lexical scope.  Check for
    errors (such as an incompatible declaration for the same name
    already seen in the same scope).  IS_FRIEND is true if DECL is
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 2e2075c..ce0826e 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -339,4 +339,6 @@ extern void pop_nested_namespace (tree);
 extern void push_to_top_level (void);
 extern void pop_from_top_level (void);
 
+extern tree find_decl (tree);
+
 #endif /* GCC_CP_NAME_LOOKUP_H */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 8f18665..6cbf4b2 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4314,10 +4314,10 @@ const struct attribute_spec cxx_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "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.  */
@@ -4326,10 +4326,10 @@ const struct attribute_spec std_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
        affects_type_identity } */
   { "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
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 278d0c9..943b349 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1933,6 +1933,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
diff --git a/libstdc++-v3/include/ext/mt_allocator.h b/libstdc++-v3/include/ext/mt_allocator.h
index effb13b..f349ff8 100644
--- a/libstdc++-v3/include/ext/mt_allocator.h
+++ b/libstdc++-v3/include/ext/mt_allocator.h
@@ -355,7 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       // XXX GLIBCXX_ABI Deprecated
-      _GLIBCXX_CONST void 
+      void 
       _M_destroy_thread_key(void*) throw ();
 
       size_t 
diff --git a/gcc/testsuite/c-c++-common/Wattributes-2.c b/gcc/testsuite/c-c++-common/Wattributes-2.c
new file mode 100644
index 0000000..0904742
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wattributes-2.c
@@ -0,0 +1,74 @@
+/* PR c/81566 - invalid attribute aligned accepted on functions
+   { dg-do compile }
+   { dg-options "-Wall -Wattributes -ftrack-macro-expansion=0" } */
+
+#define ATTR(list) __attribute__ (list)
+#define ALIGN(n)   ATTR ((aligned (n)))
+
+/* It's okay to increase the alignment of a function.  */
+
+void ALIGN (16) ALIGN (32)
+falign32_1 (void);
+
+void ALIGN (16) falign32_2 (void);
+void ALIGN (32) falign32_2 (void);
+
+void falign32_2 (void) { }
+
+void ALIGN (32) falign32_2 (void);
+
+/* It's not okay to decrease it.  */
+
+void ALIGN (32) ALIGN (16)
+falign64_3 (void);            /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */
+
+void ALIGN (32)
+falign64_3 (void);
+
+void falign64_3 (void);
+
+void falign64_3 (void) { }
+
+
+void ALIGN (32)
+falign64_4 (void);            /* { dg-message "previous declaration here" } */
+
+void ALIGN (16)
+falign64_4 (void);            /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */
+
+void ALIGN (32)
+falign64_4 (void);            /* { dg-message "previous declaration here" } */
+
+void ALIGN (16)
+falign64_4 (void);            /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */
+
+void ALIGN (64)
+falign64_4 (void);
+
+void ALIGN (32)
+falign64_4 (void);            /* { dg-warning "ignoring attribute .aligned \\(32\\). because it conflicts with attribute .aligned \\(64\\)." } */
+
+void falign64_4 (void);
+
+void ALIGN (64)
+falign64_4 (void) { }
+
+void falign64_4 (void);
+
+void ALIGN (64)
+falign64_4 (void);
+
+
+void ATTR ((aligned (16), aligned (32)))
+falign64_5 (void);
+
+void ATTR ((aligned (32), aligned (64)))
+falign64_5 (void);
+
+void ATTR ((aligned (16), aligned (32), aligned (64)))
+falign64_5 (void);            /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(64\\)." } */
+                              /* { dg-warning "ignoring attribute .aligned \\(32\\). because it conflicts with attribute .aligned \\(64\\)." "" { target *-*-* } .-1 } */
+
+
+void ATTR ((aligned (16), aligned (32), aligned (16)))
+falign64_6 (void);            /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */
diff --git a/gcc/testsuite/c-c++-common/Wattributes.c b/gcc/testsuite/c-c++-common/Wattributes.c
new file mode 100644
index 0000000..d0c4d06
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wattributes.c
@@ -0,0 +1,437 @@
+/* { dg-do compile }
+   { dg-options "-Wall -Wattributes -ftrack-macro-expansion=0" } */
+
+#define ATTR(attrlist) __attribute__ (attrlist)
+
+/* Exercise the handling of the mutually exclusive attributes
+   aligned and packed.  */
+
+/* Pointless but benign.  */
+struct ATTR ((aligned, aligned))
+AlignedAligned { int i; };
+
+struct ATTR ((aligned, packed))
+AlignedPacked { int i; };     /* { dg-warning "ignoring attribute .packed. because it conflicts with attribute .aligned." } */
+
+struct ATTR ((packed, aligned))
+PackedAligned { int i; };     /* { dg-warning "ignoring attribute .aligned. because it conflicts with attribute .packed." } */
+
+/* Silly but benign.  */
+struct ATTR ((packed, packed))
+PackedPacked { int i; };
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   always_inline and noinline.  */
+
+inline void ATTR ((always_inline))
+falways_inline1 (void);
+
+inline void ATTR ((__always_inline__))
+falways_inline1 (void);
+
+inline void ATTR ((always_inline, __always_inline__))
+falways_inline1 (void);
+
+/* Verify that repeating attribute always_inline doesn't trigger a warning.  */
+inline void ATTR ((always_inline))
+falways_inline1 (void);       /* { dg-message "previous declaration here" } */
+
+void ATTR ((noinline))
+falways_inline1 (void) { }    /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */
+
+/* And again.  */
+void ATTR ((always_inline))
+falways_inline (void);
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and warn_unused_result.  */
+
+int ATTR ((__noreturn__))
+fnoret1 (void);
+
+int ATTR ((noreturn))
+fnoret1 (void);               /* { dg-message "previous declaration here" } */
+
+int ATTR ((warn_unused_result))
+fnoret1 (void);               /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+
+/* Verify that repeating attribute noreturn doesn't trigger a warning.  */
+int ATTR ((noreturn)) fnoret1 (void);
+
+int call_noret1 (void)
+{
+  /* Verify that attribute warn_unused_result was, in fact, ignored
+     on the second declaration of fnoret1.  */
+  fnoret1 ();
+}
+
+int ATTR ((noreturn, warn_unused_result))
+fnoret2 (void);               /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+
+/* Verify that repeating attribute noreturn doesn't trigger a warning.  */
+int ATTR ((noreturn)) fnoret2 (void);
+
+int call_noret2 (void)
+{
+  /* Verify that attribute warn_unused_result was, in fact, ignored
+     on the second declaration of fnoret2.  */
+  fnoret2 ();
+}
+
+/* Verify again but this time in different scopes.  */
+
+int ATTR ((noreturn))
+fnoret3 (void);               /* { dg-message "previous declaration here" } */
+
+void declare_noret3 (void)
+{
+  int ATTR ((warn_unused_result))
+  fnoret3 (void);             /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+}
+
+void declare_noret4 (void)
+{
+  int ATTR ((warn_unused_result))
+  fnoret4 (void);             /* { dg-message "previous declaration here" } */
+}
+
+int ATTR ((noreturn))
+fnoret4 (void);               /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .warn_unused_result." } */
+
+
+/* And again, but with both declared in a different local scope.  */
+
+void declare_noret5_1 (void)
+{
+  int ATTR ((noreturn))
+  fnoret5 (void);             /* { dg-message "previous declaration here" } */
+}
+
+int declare_noret5_2 (void)
+{
+  int ATTR ((warn_unused_result))
+  fnoret5 (void);             /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+
+  /* Verify that no warning is issued below (because the warn_unused_result
+     attribute above was dropped).  */
+  fnoret5 ();
+}
+
+/* Verify that attribute noreturn isn't diagnosed on a declaration
+   that was previously declared warn_unused_result and that attribute
+   was dropped (because the function returs void).  */
+
+void ATTR ((warn_unused_result))
+fnorety6 (void);             /* { dg-warning ".warn_unused_result. attribute ignored" } */
+
+void ATTR ((noreturn))
+fnoret6 (void);
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and alloc_align.  */
+
+void* ATTR ((noreturn))
+fnoret_alloc_align1 (int);    /* { dg-message "previous declaration here" } */
+
+void* ATTR ((alloc_align (1)))
+fnoret_alloc_align1 (int);    /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */
+
+void* ATTR ((noreturn, alloc_align (1)))
+fnoret_alloc_align2 (int);    /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((noreturn)) ATTR ((alloc_align (1)))
+fnoret_alloc_align3 (int);    /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((alloc_align (1)))
+falloc_align_noret1 (int);    /* { dg-message "previous declaration here" } */
+
+void* ATTR ((noreturn))
+falloc_align_noret1 (int);    /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_align." } */
+
+
+void* ATTR ((alloc_align (1), noreturn))
+falloc_align_noret2 (int);    /* { dg-warning "ignoring attribute .(noreturn|alloc_align). because it conflicts with attribute .(alloc_align|noreturn)." } */
+
+void* ATTR ((alloc_align (1))) ATTR ((noreturn))
+falloc_align_noret3 (int);    /* { dg-warning "ignoring attribute .(noreturn|alloc_align). because it conflicts with attribute .(noreturn|alloc_align)." } */
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and alloc_size.  */
+
+void* ATTR ((noreturn))
+fnoret_alloc_size1 (int);     /* { dg-message "previous declaration here" } */
+
+void* ATTR ((alloc_size (1)))
+fnoret_alloc_size1 (int);     /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */
+
+void* ATTR ((noreturn, alloc_size (1)))
+fnoret_alloc_size2 (int);     /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((noreturn)) ATTR ((alloc_size (1)))
+fnoret_alloc_size3 (int);     /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((alloc_size (1)))
+falloc_size_noret1 (int);     /* { dg-message "previous declaration here" } */
+
+void* ATTR ((noreturn))
+falloc_size_noret1 (int);     /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */
+
+
+void* ATTR ((alloc_size (1), noreturn))
+falloc_size_noret2 (int);     /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */
+
+void* ATTR ((alloc_size (1))) ATTR ((noreturn))
+falloc_size_noret3 (int);     /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and const.  */
+
+int ATTR ((noreturn))
+fnoret_const1 (int);          /* { dg-message "previous declaration here" } */
+
+int ATTR ((const))
+fnoret_const1 (int);          /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */
+
+/* Unfortunately, attributes on a single declarations may not be processed
+   in the same order as specified... */
+int ATTR ((noreturn, const))
+fnoret_const2 (int);          /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((noreturn)) ATTR ((const))
+fnoret_const3 (int);          /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((const))
+fconst_noret1 (int);          /* { dg-message "previous declaration here" } */
+
+int ATTR ((noreturn))
+fconst_noret1 (int);          /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */
+
+
+int ATTR ((const, noreturn))
+fconst_noret2 (int);          /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */
+
+int ATTR ((const)) ATTR ((noreturn))
+fconst_noret3 (int);          /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and malloc.  */
+
+void* ATTR ((noreturn))
+fnoret_malloc1 (int);         /* { dg-message "previous declaration here" } */
+
+void* ATTR ((malloc))
+fnoret_malloc1 (int);         /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */
+
+/* Unfortunately, attributes on a single declarations may not be processed
+   in the same order as specified... */
+void* ATTR ((noreturn, malloc))
+fnoret_malloc2 (int);         /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((noreturn)) ATTR ((malloc))
+fnoret_malloc3 (int);         /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */
+
+
+void* ATTR ((__malloc__))
+fmalloc_noret1 (int);
+
+void* ATTR ((malloc))
+fmalloc_noret1 (int);         /* { dg-message "previous declaration here" } */
+
+void* ATTR ((noreturn))
+fmalloc_noret1 (int);         /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */
+
+
+void* ATTR ((malloc, noreturn))
+fmalloc_noret2 (int);         /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */
+
+void* ATTR ((malloc)) ATTR ((noreturn))
+fmalloc_noret3 (int);         /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and pure.  */
+
+int ATTR ((noreturn))
+fnoret_pure1 (int);           /* { dg-message "previous declaration here" } */
+
+int ATTR ((pure))
+fnoret_pure1 (int);           /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */
+
+/* Unfortunately, attributes on a single declarations may not be processed
+   in the same order as specified... */
+int ATTR ((noreturn, pure))
+fnoret_pure2 (int);           /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((noreturn)) ATTR ((pure))
+fnoret_pure3 (int);           /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((__pure__))
+fpure_noret1 (int);
+
+int ATTR ((pure))
+fpure_noret1 (int);           /* { dg-message "previous declaration here" } */
+
+int ATTR ((noreturn))
+fpure_noret1 (int);           /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pure." } */
+
+
+int ATTR ((pure, noreturn))
+fpure_noret2 (int);           /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pur." } */
+
+int ATTR ((pure)) ATTR ((noreturn))
+fpure_noret3 (int);            /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pure." } */
+
+
+/* Exercise the handling of the mutually exclusive attributes
+   noreturn and returns_twice.  */
+
+int ATTR ((noreturn))
+fnoret_returns_twice1 (int);  /* { dg-message "previous declaration here" } */
+
+int ATTR ((returns_twice))
+fnoret_returns_twice1 (int);  /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */
+
+/* Unfortunately, attributes on a single declarations may not be processed
+   in the same order as specified... */
+int ATTR ((noreturn, returns_twice))
+fnoret_returns_twice2 (int);  /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((noreturn)) ATTR ((returns_twice))
+fnoret_returns_twice3 (int);  /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */
+
+
+int ATTR ((returns_twice))
+freturns_twice_noret1 (int);  /* { dg-message "previous declaration here" } */
+
+int ATTR ((noreturn))
+freturns_twice_noret1 (int);  /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */
+
+
+int ATTR ((returns_twice, noreturn))
+freturns_twice_noret2 (int);  /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */
+
+int ATTR ((returns_twice)) ATTR ((noreturn))
+freturns_twice_noret3 (int);  /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */
+
+
+/* Exercise the interaction of multiple combinations of mutually
+   exclusive attributes specified on distinct declarations.  */
+
+inline int ATTR ((always_inline))
+finline_cold_noreturn (int);
+
+inline int ATTR ((cold))
+finline_cold_noreturn (int);
+
+inline int ATTR ((noreturn))
+finline_cold_noreturn (int);
+
+inline int ATTR ((noinline))
+finline_cold_noreturn (int);    /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */
+
+inline int ATTR ((hot))
+finline_cold_noreturn (int);    /* { dg-warning "ignoring attribute .hot. because it conflicts with attribute .cold." } */
+
+inline int ATTR ((warn_unused_result))
+finline_cold_noreturn (int);    /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+
+inline int ATTR ((always_inline))
+finline_cold_noreturn (int);
+
+/* Expect no warning for the missing return statement below because
+   the function is noreturn.  */
+inline int ATTR ((noreturn))
+finline_cold_noreturn (int i) { (void)&i; __builtin_abort (); }
+
+
+/* Exercise the interaction of multiple combinations of mutually
+   exclusive attributes with some specified on the same declaration
+   and some on distinct declarations.  */
+
+inline int ATTR ((always_inline, hot))
+finline_hot_noret_align (int);
+
+inline int ATTR ((noreturn, noinline))
+finline_hot_noret_align (int);  /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */
+
+inline int ATTR ((cold, aligned (8)))
+finline_hot_noret_align (int);  /* { dg-warning "ignoring attribute .cold. because it conflicts with attribute .hot." } */
+
+inline int ATTR ((warn_unused_result))
+finline_hot_noret_align (int);  /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */
+
+inline int ATTR ((aligned (4)))
+finline_hot_noret_align (int);  /* { dg-warning "ignoring attribute .aligned \\(4\\). because it conflicts with attribute .aligned \\(8\\)." } */
+
+inline int ATTR ((aligned (8)))
+finline_hot_noret_align (int);
+
+inline int ATTR ((const))
+finline_hot_noret_align (int);  /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */
+
+/* Expect no warning for the missing return statement below because
+   the function is noreturn.  */
+inline int ATTR ((noreturn))
+finline_hot_noret_align (int i) { (void)&i; __builtin_abort (); }
+
+
+/* Exercise variable attributes.  */
+
+extern int ATTR ((common))
+decl_common1;                 /* { dg-message "previous declaration here" } */
+
+extern int ATTR ((nocommon))
+decl_common1;                 /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */
+
+
+extern int ATTR ((nocommon))
+decl_common2;                 /* { dg-message "previous declaration here" } */
+
+extern int ATTR ((common))
+decl_common2;                 /* { dg-warning "ignoring attribute .common. because it conflicts with attribute .nocommon." } */
+
+
+extern int ATTR ((common, nocommon))
+decl_common3;                 /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */
+
+
+extern int ATTR ((common, nocommon))
+decl_common4;                 /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */
+
+
+void declare_common5_in_local_scope (void)
+{
+  extern int ATTR ((common))
+  decl_common5;               /* { dg-message "previous declaration here" } */
+  (void)&decl_common5;
+}
+
+extern int ATTR ((nocommon))
+decl_common5;                 /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */
+
+
+extern int ATTR ((nocommon))
+decl_common6;                 /* { dg-message "previous declaration here" } */
+
+void declare_common6_in_local_scope (void)
+{
+  extern int ATTR ((common))
+  decl_common6;               /* { dg-warning "ignoring attribute .common. because it conflicts with attribute .nocommon." } */
+  (void)&decl_common6;
+}
diff --git a/gcc/testsuite/c-c++-common/attributes-3.c b/gcc/testsuite/c-c++-common/attributes-3.c
index 821278c..9d3a61c 100644
--- a/gcc/testsuite/c-c++-common/attributes-3.c
+++ b/gcc/testsuite/c-c++-common/attributes-3.c
@@ -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 "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */
 
 extern __attribute__((noinline)) int fn4 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "attribute .always_inline. follows declaration with attribute .noinline." } */
+extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." } */
 
 extern __attribute__((hot)) int fn5 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((cold)) int fn5 (void); /* { dg-warning "attribute .cold. follows declaration with attribute .hot." } */
+extern __attribute__((cold)) int fn5 (void); /* { dg-warning "ignoring attribute .cold. because it conflicts with attribute .hot." } */
 
 extern __attribute__((cold)) int fn6 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot. follows declaration with attribute .cold." } */
+extern __attribute__((hot)) int fn6 (void); /* { dg-warning "ignoring attribute .hot. because it conflicts with attribute .cold." } */
diff --git a/gcc/testsuite/g++.dg/ext/mv11.s b/gcc/testsuite/g++.dg/ext/mv11.s
new file mode 100644
index 0000000..32e8940
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/mv11.s
@@ -0,0 +1 @@
+	.file	"mv11.C"
diff --git a/gcc/testsuite/gcc.dg/attr-noinline.c b/gcc/testsuite/gcc.dg/attr-noinline.c
index c2a5b1d..13cc660 100644
--- a/gcc/testsuite/gcc.dg/attr-noinline.c
+++ b/gcc/testsuite/gcc.dg/attr-noinline.c
@@ -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();}
 
diff --git a/gcc/testsuite/gcc.dg/pr44964.c b/gcc/testsuite/gcc.dg/pr44964.c
index 1df1bde..6c252ee 100644
--- a/gcc/testsuite/gcc.dg/pr44964.c
+++ b/gcc/testsuite/gcc.dg/pr44964.c
@@ -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))
diff --git a/gcc/testsuite/gcc.dg/torture/pr42363.c b/gcc/testsuite/gcc.dg/torture/pr42363.c
index 9c9da13..ad0eac8 100644
--- a/gcc/testsuite/gcc.dg/torture/pr42363.c
+++ b/gcc/testsuite/gcc.dg/torture/pr42363.c
@@ -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 ();
 }
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c
index 146b76c..58a4742 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c
@@ -113,7 +113,7 @@ int test9 (int *intarr)
 
 int test99 (int *intarr)
 {
-  extern int foo9 (int) __attribute__ ((pure));
+  extern int foo9 (int) __attribute__ ((const));
   int h, v;
   g9 = 9;
   h = foo9 (g9);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]