]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/c-family/c-attribs.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / c-family / c-attribs.c
index 1657df7f9df41f0f2fcbcc3479bd9172256c3ec5..e559d3b55d205f22bb6f0f7599e529a8b46fe049 100644 (file)
@@ -1,5 +1,5 @@
 /* C-family attributes handling.
-   Copyright (C) 1992-2018 Free Software Foundation, Inc.
+   Copyright (C) 1992-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -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 "tree-pretty-print.h"
 
 static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -162,7 +163,7 @@ static const struct attribute_spec::exclusions attr_aligned_exclusions[] =
   ATTR_EXCL (NULL, false, false, false)
 };
 
-static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
 {
   ATTR_EXCL ("cold", true, true, true),
   ATTR_EXCL ("hot", true, true, true),
@@ -495,6 +496,205 @@ attribute_takes_identifier_p (const_tree attr_id)
     return targetm.attribute_takes_identifier_p (attr_id);
 }
 
+/* Verify that argument value POS at position ARGNO to attribute NAME
+   applied to function TYPE refers to a function parameter at position
+   POS and the expected type CODE.  Treat CODE == INTEGER_TYPE as
+   matching all C integral types except bool.  If successful, return
+   POS after default conversions, if any.  Otherwise, issue appropriate
+   warnings and return null.  A non-zero 1-based ARGNO should be passed
+   in by callers only for attributes with more than one argument.  */
+
+tree
+positional_argument (const_tree fntype, const_tree atname, tree pos,
+                    tree_code code, int argno /* = 0 */,
+                    int flags /* = posargflags () */)
+{
+  if (pos && TREE_CODE (pos) != IDENTIFIER_NODE
+      && TREE_CODE (pos) != FUNCTION_DECL)
+    pos = default_conversion (pos);
+
+  tree postype = TREE_TYPE (pos);
+  if (pos == error_mark_node || !postype)
+    {
+      /* Only mention the positional argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument is invalid", atname);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i is invalid", atname, argno);
+
+      return NULL_TREE;
+    }
+
+  if (!INTEGRAL_TYPE_P (postype))
+    {
+      /* Handle this case specially to avoid mentioning the value
+        of pointer constants in diagnostics.  Only mention
+        the positional argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument has type %qT",
+                atname, postype);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i has type %qT",
+                atname, argno, postype);
+
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (pos) != INTEGER_CST)
+    {
+      /* Only mention the argument number when it's non-zero.  */
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE is not an integer "
+                "constant",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE is not an integer "
+                "constant",
+                atname, argno, pos);
+
+      return NULL_TREE;
+    }
+
+  /* Argument positions are 1-based.  */
+  if (integer_zerop (pos))
+    {
+      if (flags & POSARG_ZERO)
+       /* Zero is explicitly allowed.  */
+       return pos;
+
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE does not refer to "
+                "a function parameter",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE does not refer to "
+                "a function parameter",
+                atname, argno, pos);
+
+      return NULL_TREE;
+    }
+
+  if (!prototype_p (fntype))
+    return pos;
+
+  /* Verify that the argument position does not exceed the number
+     of formal arguments to the function.  When POSARG_ELLIPSIS
+     is set, ARGNO may be beyond the last argument of a vararg
+     function.  */
+  unsigned nargs = type_num_arguments (fntype);
+  if (!nargs
+      || !tree_fits_uhwi_p (pos)
+      || ((flags & POSARG_ELLIPSIS) == 0
+         && !IN_RANGE (tree_to_uhwi (pos), 1, nargs)))
+    {
+
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE exceeds the number "
+                "of function parameters %u",
+                atname, pos, nargs);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE exceeds the number "
+                "of function parameters %u",
+                atname, argno, pos, nargs);
+      return NULL_TREE;
+    }
+
+  /* Verify that the type of the referenced formal argument matches
+     the expected type.  */
+  unsigned HOST_WIDE_INT ipos = tree_to_uhwi (pos);
+
+  /* Zero was handled above.  */
+  gcc_assert (ipos != 0);
+
+  if (tree argtype = type_argument_type (fntype, ipos))
+    {
+      if (flags & POSARG_ELLIPSIS)
+       {
+         if (argno < 1)
+           error ("%qE attribute argument value %qE does not refer to "
+                  "a variable argument list",
+                  atname, pos);
+         else
+           error ("%qE attribute argument %i value %qE does not refer to "
+                  "a variable argument list",
+                  atname, argno, pos);
+         return NULL_TREE;
+       }
+
+      /* Where the expected code is STRING_CST accept any pointer
+        expected by attribute format (this includes possibly qualified
+        char pointers and, for targets like Darwin, also pointers to
+        struct CFString).  */
+      bool type_match;
+      if (code == STRING_CST)
+       type_match = valid_format_string_type_p (argtype);
+      else if (code == INTEGER_TYPE)
+       /* For integers, accept enums, wide characters and other types
+          that match INTEGRAL_TYPE_P except for bool.  */
+       type_match = (INTEGRAL_TYPE_P (argtype)
+                     && TREE_CODE (argtype) != BOOLEAN_TYPE);
+      else
+       type_match = TREE_CODE (argtype) == code;
+
+      if (!type_match)
+       {
+         if (code == STRING_CST)
+           {
+             /* Reject invalid format strings with an error.  */
+             if (argno < 1)
+               error ("%qE attribute argument value %qE refers to "
+                      "parameter type %qT",
+                      atname, pos, argtype);
+             else
+               error ("%qE attribute argument %i value %qE refers to "
+                      "parameter type %qT",
+                      atname, argno, pos, argtype);
+
+             return NULL_TREE;
+           }
+
+         if (argno < 1)
+           warning (OPT_Wattributes,
+                    "%qE attribute argument value %qE refers to "
+                    "parameter type %qT",
+                    atname, pos, argtype);
+         else
+           warning (OPT_Wattributes,
+                  "%qE attribute argument %i value %qE refers to "
+                    "parameter type %qT",
+                    atname, argno, pos, argtype);
+         return NULL_TREE;
+       }
+    }
+  else if (!(flags & POSARG_ELLIPSIS))
+    {
+      if (argno < 1)
+       warning (OPT_Wattributes,
+                "%qE attribute argument value %qE refers to "
+                "a variadic function parameter of unknown type",
+                atname, pos);
+      else
+       warning (OPT_Wattributes,
+                "%qE attribute argument %i value %qE refers to "
+                "a variadic function parameter of unknown type",
+                atname, argno, pos);
+      return NULL_TREE;
+    }
+
+  return pos;
+}
+
+
 /* Attribute handlers common to C front ends.  */
 
 /* Handle a "packed" attribute; arguments as in
@@ -872,7 +1072,8 @@ handle_nocf_check_attribute (tree *node, tree name,
   else if (!(flag_cf_protection & CF_BRANCH))
     {
       warning (OPT_Wattributes, "%qE attribute ignored. Use "
-                               "-fcf-protection option to enable it", name);
+                               "%<-fcf-protection%> option to enable it",
+                               name);
       *no_add_attrs = true;
     }
 
@@ -1820,7 +2021,8 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
   bool objfile = (TREE_CODE (*node) == FUNCTION_DECL
                  || (VAR_P (*node) && TREE_STATIC (*node)));
   /* Log2 of specified alignment.  */
-  int pow2align = check_user_alignment (align_expr, objfile, true);
+  int pow2align = check_user_alignment (align_expr, objfile,
+                                       /* warn_zero = */ true);
   if (pow2align == -1
       || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags))
     {
@@ -1836,6 +2038,9 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
   unsigned curalign = 0;
   unsigned lastalign = 0;
 
+  /* True when SET_DECL_ALIGN() should be called for the decl when
+     *NO_ADD_ATTRS is false.  */
+  bool set_align = true;
   if (is_type)
     {
       if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
@@ -1884,23 +2089,35 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
        curalign = lastalign;
 
       curalign /= BITS_PER_UNIT;
-      bitalign /= BITS_PER_UNIT;
+      unsigned newalign = bitalign / BITS_PER_UNIT;
 
-      bool diagd = true;
       auto_diagnostic_group d;
-      if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
-       diagd = warning (OPT_Wattributes,
-                         "ignoring attribute %<%E (%u)%> because it conflicts "
-                         "with attribute %<%E (%u)%>",
-                         name, bitalign, name, curalign);
+      if ((DECL_USER_ALIGN (decl)
+          || DECL_USER_ALIGN (last_decl)))
+       {
+         if (warning (OPT_Wattributes,
+                      "ignoring attribute %<%E (%u)%> because it conflicts "
+                      "with attribute %<%E (%u)%>",
+                      name, newalign, name, curalign)
+             && note)
+           inform (DECL_SOURCE_LOCATION (last_decl),
+                   "previous declaration here");
+         /* Only reject attempts to relax/override an alignment
+            explicitly specified previously and accept declarations
+            that appear to relax the implicit function alignment for
+            the target.  Both increasing and increasing the alignment
+            set by -falign-functions setting is permitted.  */
+         *no_add_attrs = true;
+       }
       else if (!warn_if_not_aligned_p)
-       /* Do not error out for attribute warn_if_not_aligned.  */
-       error ("alignment for %q+D must be at least %d", decl, curalign);
-
-      if (diagd && note)
-       inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here");
-
-      *no_add_attrs = true;
+       {
+         /* Do not fail for attribute warn_if_not_aligned.  Otherwise,
+            silently avoid applying the alignment to the declaration
+            because it's implicitly satisfied by the target.  Apply
+            the attribute nevertheless so it can be retrieved by
+            __builtin_has_attribute.  */
+         set_align = false;
+       }
     }
   else if (DECL_USER_ALIGN (decl)
           && DECL_ALIGN (decl) > bitalign)
@@ -1917,33 +2134,29 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
           && TREE_CODE (decl) == FUNCTION_DECL
           && DECL_ALIGN (decl) > bitalign)
     {
-      /* Don't warn function alignment here if warn_if_not_aligned_p is
-        true.  It will be warned later.  */
+      /* Don't warn for function alignment here if warn_if_not_aligned_p
+        is true.  It will be warned about later.  */
       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
-    {
-      if (warn_if_not_aligned_p)
-       {
-         if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl))
-           {
-             SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
-             warn_if_not_aligned_p = false;
-           }
-       }
-      else
        {
-         SET_DECL_ALIGN (decl, bitalign);
-         DECL_USER_ALIGN (decl) = 1;
+         /* Only reject attempts to relax/override an alignment
+            explicitly specified previously and accept declarations
+            that appear to relax the implicit function alignment for
+            the target.  Both increasing and increasing the alignment
+            set by -falign-functions setting is permitted.  */
+         error ("alignment for %q+D was previously specified as %d "
+                "and may not be decreased", decl,
+                DECL_ALIGN (decl) / BITS_PER_UNIT);
+         *no_add_attrs = true;
        }
     }
+  else if (warn_if_not_aligned_p
+          && TREE_CODE (decl) == FIELD_DECL
+          && !DECL_C_BIT_FIELD (decl))
+    {
+      SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
+      warn_if_not_aligned_p = false;
+      set_align = false;
+    }
 
   if (warn_if_not_aligned_p)
     {
@@ -1951,6 +2164,11 @@ common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
             decl);
       *no_add_attrs = true;
     }
+  else if (!is_type && !*no_add_attrs && set_align)
+    {
+      SET_DECL_ALIGN (decl, bitalign);
+      DECL_USER_ALIGN (decl) = 1;
+    }
 
   return NULL_TREE;
 }
@@ -2255,6 +2473,12 @@ handle_copy_attribute (tree *node, tree name, tree args,
              || is_attribute_p ("weakref", atname))
            continue;
 
+         /* Attribute leaf only applies to extern functions.
+            Avoid copying it to static ones.  */
+         if (!TREE_PUBLIC (decl)
+             && is_attribute_p ("leaf", atname))
+           continue;
+
          tree atargs = TREE_VALUE (at);
          /* Create a copy of just the one attribute ar AT, including
             its argumentsm and add it to DECL.  */
@@ -2272,13 +2496,28 @@ handle_copy_attribute (tree *node, tree name, tree args,
       return NULL_TREE;
     }
 
+  /* A function declared with attribute nothrow has the attribute
+     attached to it, but a C++ throw() function does not.  */
+  if (TREE_NOTHROW (ref))
+    TREE_NOTHROW (decl) = true;
+
+  /* Similarly, a function declared with attribute noreturn has it
+     attached on to it, but a C11 _Noreturn function does not.  */
   tree reftype = ref;
+  if (DECL_P (ref)
+      && TREE_THIS_VOLATILE (ref)
+      && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype)))
+    TREE_THIS_VOLATILE (decl) = true;
+
   if (DECL_P (ref) || EXPR_P (ref))
     reftype = TREE_TYPE (ref);
 
   if (POINTER_TYPE_P (reftype))
     reftype = TREE_TYPE (reftype);
 
+  if (!TYPE_P (reftype))
+    return NULL_TREE;
+
   tree attrs = TYPE_ATTRIBUTES (reftype);
 
   /* Copy type attributes from REF to DECL.  */
@@ -2563,27 +2802,40 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
    struct attribute_spec.handler.  */
 
 static tree
-handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+handle_alloc_size_attribute (tree *node, tree name, tree args,
                             int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  unsigned arg_count = type_num_arguments (*node);
-  for (; args; args = TREE_CHAIN (args))
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (!POINTER_TYPE_P (rettype))
     {
-      tree position = TREE_VALUE (args);
-      if (position && TREE_CODE (position) != IDENTIFIER_NODE
-         && TREE_CODE (position) != FUNCTION_DECL)
-       position = default_conversion (position);
+      warning (OPT_Wattributes,
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      if (!tree_fits_uhwi_p (position)
-         || !arg_count
-         || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+  for (int i = 1; args; ++i)
+    {
+      tree pos = TREE_VALUE (args);
+      /* NEXT is null when the attribute includes just one argument.
+        That's used to tell positional_argument to avoid mentioning
+        the argument number in diagnostics (since there's just one
+        mentioning it is unnecessary and coule be confusing).  */
+      tree next = TREE_CHAIN (args);
+      if (tree val = positional_argument (decl, name, pos, INTEGER_TYPE,
+                                         next || i > 1 ? i : 0))
+       TREE_VALUE (args) = val;
+      else
        {
-         warning (OPT_Wattributes,
-                  "alloc_size parameter outside range");
          *no_add_attrs = true;
-         return NULL_TREE;
+         break;
        }
+
+      args = next;
     }
+
   return NULL_TREE;
 }
 
@@ -2591,24 +2843,23 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
    struct attribute_spec.handler.  */
 
 static tree
-handle_alloc_align_attribute (tree *node, tree, tree args, int,
+handle_alloc_align_attribute (tree *node, tree name, tree args, int,
                              bool *no_add_attrs)
 {
-  unsigned arg_count = type_num_arguments (*node);
-  tree position = TREE_VALUE (args);
-  if (position && TREE_CODE (position) != IDENTIFIER_NODE
-      && TREE_CODE (position) != FUNCTION_DECL)
-    position = default_conversion (position);
-
-  if (!tree_fits_uhwi_p (position)
-      || !arg_count
-      || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (!POINTER_TYPE_P (rettype))
     {
       warning (OPT_Wattributes,
-              "alloc_align parameter outside range");
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
       *no_add_attrs = true;
       return NULL_TREE;
     }
+
+  if (!positional_argument (*node, name, TREE_VALUE (args), INTEGER_TYPE))
+    *no_add_attrs = true;
+
   return NULL_TREE;
 }
 
@@ -2616,20 +2867,60 @@ handle_alloc_align_attribute (tree *node, tree, tree args, int,
    struct attribute_spec.handler.  */
 
 static tree
-handle_assume_aligned_attribute (tree *, tree, tree args, int,
+handle_assume_aligned_attribute (tree *node, tree name, tree args, int,
                                 bool *no_add_attrs)
 {
+  tree decl = *node;
+  tree rettype = TREE_TYPE (decl);
+  if (TREE_CODE (rettype) != POINTER_TYPE)
+    {
+      warning (OPT_Wattributes,
+              "%qE attribute ignored on a function returning %qT",
+              name, rettype);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* The alignment specified by the first argument.  */
+  tree align = NULL_TREE;
+
   for (; args; args = TREE_CHAIN (args))
     {
-      tree position = TREE_VALUE (args);
-      if (position && TREE_CODE (position) != IDENTIFIER_NODE
-         && TREE_CODE (position) != FUNCTION_DECL)
-       position = default_conversion (position);
+      tree val = TREE_VALUE (args);
+      if (val && TREE_CODE (val) != IDENTIFIER_NODE
+         && TREE_CODE (val) != FUNCTION_DECL)
+       val = default_conversion (val);
 
-      if (TREE_CODE (position) != INTEGER_CST)
+      if (!tree_fits_shwi_p (val))
        {
          warning (OPT_Wattributes,
-                  "assume_aligned parameter not integer constant");
+                  "%qE attribute %E is not an integer constant",
+                  name, val);
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+
+      if (!align)
+       {
+         /* Validate and save the alignment.  */
+         if (!integer_pow2p (val))
+           {
+             warning (OPT_Wattributes,
+                      "%qE attribute argument %E is not a power of 2",
+                      name, val);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+
+         align = val;
+       }
+      else if (tree_int_cst_sgn (val) < 0 || tree_int_cst_le (align, val))
+       {
+         /* The misalignment specified by the second argument
+            must be non-negative and less than the alignment.  */
+         warning (OPT_Wattributes,
+                  "%qE attribute argument %E is not in the range [0, %E)",
+                  name, val, align);
          *no_add_attrs = true;
          return NULL_TREE;
        }
@@ -3262,12 +3553,11 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
 /* Handle the "nonnull" attribute.  */
 
 static tree
-handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+handle_nonnull_attribute (tree *node, tree name,
                          tree args, int ARG_UNUSED (flags),
                          bool *no_add_attrs)
 {
   tree type = *node;
-  unsigned HOST_WIDE_INT attr_arg_num;
 
   /* If no arguments are specified, all pointer arguments should be
      non-null.  Verify a full prototype is given so that the arguments
@@ -3286,57 +3576,23 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
       return NULL_TREE;
     }
 
-  /* Argument list specified.  Verify that each argument number references
-     a pointer argument.  */
-  for (attr_arg_num = 1; args; attr_arg_num++, args = TREE_CHAIN (args))
+  for (int i = 1; args; ++i)
     {
-      unsigned HOST_WIDE_INT arg_num = 0, ck_num;
-
-      tree arg = TREE_VALUE (args);
-      if (arg && TREE_CODE (arg) != IDENTIFIER_NODE
-         && TREE_CODE (arg) != FUNCTION_DECL)
-       TREE_VALUE (args) = arg = default_conversion (arg);
-
-      if (!get_nonnull_operand (arg, &arg_num))
+      tree pos = TREE_VALUE (args);
+      /* NEXT is null when the attribute includes just one argument.
+        That's used to tell positional_argument to avoid mentioning
+        the argument number in diagnostics (since there's just one
+        mentioning it is unnecessary and coule be confusing).  */
+      tree next = TREE_CHAIN (args);
+      if (tree val = positional_argument (type, name, pos, POINTER_TYPE,
+                                         next || i > 1 ? i : 0))
+       TREE_VALUE (args) = val;
+      else
        {
-         error ("nonnull argument has invalid operand number (argument %lu)",
-                (unsigned long) attr_arg_num);
          *no_add_attrs = true;
-         return NULL_TREE;
-       }
-
-      if (prototype_p (type))
-       {
-         function_args_iterator iter;
-         tree argument;
-
-         function_args_iter_init (&iter, type);
-         for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
-           {
-             argument = function_args_iter_cond (&iter);
-             if (argument == NULL_TREE || ck_num == arg_num)
-               break;
-           }
-
-         if (!argument
-             || TREE_CODE (argument) == VOID_TYPE)
-           {
-             error ("nonnull argument with out-of-range operand number "
-                    "(argument %lu, operand %lu)",
-                    (unsigned long) attr_arg_num, (unsigned long) arg_num);
-             *no_add_attrs = true;
-             return NULL_TREE;
-           }
-
-         if (TREE_CODE (argument) != POINTER_TYPE)
-           {
-             error ("nonnull argument references non-pointer operand "
-                    "(argument %lu, operand %lu)",
-                    (unsigned long) attr_arg_num, (unsigned long) arg_num);
-             *no_add_attrs = true;
-             return NULL_TREE;
-           }
+         break;
        }
+      args = next;
     }
 
   return NULL_TREE;
@@ -3886,11 +4142,6 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
         with the sought attributes) has been found on the attribute chain.  */
       bool found_attr = false;
 
-      /* For attribute aligned ignore the attribute list and consider
-        the tree node itself instead.  */
-      if (type && !strcmp ("aligned", namestr))
-       atlist = NULL_TREE;
-
       /* When clear, the first mismatched attribute argument results
         in failure.  Otherwise, the first matched attribute argument
         results in success.  */
@@ -3976,7 +4227,16 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
              if (expr && DECL_P (expr))
                found_match = TREE_READONLY (expr);
            }
-         else if (!strcmp ("const", namestr))
+         else if (!strcmp ("noreturn", namestr))
+           {
+             /* C11 _Noreturn sets the volatile bit without attaching
+                an attribute to the decl.  */
+             if (expr
+                 && DECL_P (expr)
+                 && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr)))
+               found_match = TREE_THIS_VOLATILE (expr);
+           }
+         else if (!strcmp ("pure", namestr))
            {
              if (expr && DECL_P (expr))
                found_match = DECL_PURE_P (expr);