Exemplo n.º 1
0
/*
 *	Return a type like TYPE except that its TREE_READONLY
 *	is CONSTP and its TREE_VOLATILE is VOLATILEP.
 *
 *	Such variant types already made are recorded so that
 *	duplicates are not made.
 *
 *	A variant types should never be used as the type of
 *	an expression. Always copy the variant information into
 *	the TREE_READONLY and TREE_VOLATILE of the expression,
 *	and then give the expression as its type the
 *	"main variant", the variant whose TREE_READONLY
 *	and TREE_VOLATILE are zero.  Use TYPE_MAIN_VARIANT
 *	to find the main variant.
 */
tree
build_type_variant (tree type, int constp, int volatilep)
{
	register tree	t, m = TYPE_MAIN_VARIANT (type);
	register OBSTACK *ambient_obstack = current_obstack;

	/*
 	 *	Treat any nonzero argument as 1.
	 */
	constp = !!constp;
	volatilep = !!volatilep;

	/*
	 *	First search the chain variants for one
	 *	that is what we want.
	 */
	for (t = m; t; t = TYPE_NEXT_VARIANT (t))
	{
		if (constp == TREE_READONLY (t) && volatilep == TREE_VOLATILE (t))
			return t;
	}

	/*
	 *	We need a new one.
	 */
	current_obstack = TREE_PERMANENT (type) ?
				&permanent_obstack : saveable_obstack;

	t = copy_node (type);
	TREE_READONLY (t) = constp;
	TREE_VOLATILE (t) = volatilep;
	TYPE_POINTER_TO (t) = NULL_TREE;
	TYPE_REFERENCE_TO (t) = NULL_TREE;

	/*
	 *	Add this type to the chain of variants of TYPE.
	 */
	TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
	TYPE_NEXT_VARIANT (m) = t;

	current_obstack = ambient_obstack;

	return (t);

}	/* end build_type_variant */
Exemplo n.º 2
0
tree
decl_attributes (tree *node, tree attributes, int flags)
{
  tree a;
  tree returned_attrs = NULL_TREE;

  if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node)
    return NULL_TREE;

  if (!attributes_initialized)
    init_attributes ();

  /* If this is a function and the user used #pragma GCC optimize, add the
     options to the attribute((optimize(...))) list.  */
  if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma)
    {
      tree cur_attr = lookup_attribute ("optimize", attributes);
      tree opts = copy_list (current_optimize_pragma);

      if (! cur_attr)
	attributes
	  = tree_cons (get_identifier ("optimize"), opts, attributes);
      else
	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
    }

  if (TREE_CODE (*node) == FUNCTION_DECL
      && optimization_current_node != optimization_default_node
      && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node))
    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node;

  /* If this is a function and the user used #pragma GCC target, add the
     options to the attribute((target(...))) list.  */
  if (TREE_CODE (*node) == FUNCTION_DECL
      && current_target_pragma
      && targetm.target_option.valid_attribute_p (*node, NULL_TREE,
						  current_target_pragma, 0))
    {
      tree cur_attr = lookup_attribute ("target", attributes);
      tree opts = copy_list (current_target_pragma);

      if (! cur_attr)
	attributes = tree_cons (get_identifier ("target"), opts, attributes);
      else
	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
    }

  /* A "naked" function attribute implies "noinline" and "noclone" for
     those targets that support it.  */
  if (TREE_CODE (*node) == FUNCTION_DECL
      && attributes
      && lookup_attribute_spec (get_identifier ("naked"))
      && lookup_attribute ("naked", attributes) != NULL)
    {
      if (lookup_attribute ("noinline", attributes) == NULL)
	attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);

      if (lookup_attribute ("noclone", attributes) == NULL)
	attributes = tree_cons (get_identifier ("noclone"),  NULL, attributes);
    }

  targetm.insert_attributes (*node, &attributes);

  for (a = attributes; a; a = TREE_CHAIN (a))
    {
      tree ns = get_attribute_namespace (a);
      tree name = get_attribute_name (a);
      tree args = TREE_VALUE (a);
      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;

      if (spec == NULL)
	{
	  if (!(flags & (int) ATTR_FLAG_BUILT_IN))
	    {
	      if (ns == NULL_TREE || !cxx11_attribute_p (a))
		warning (OPT_Wattributes, "%qE attribute directive ignored",
			 name);
	      else
		warning (OPT_Wattributes,
			 "%<%E::%E%> scoped attribute directive ignored",
			 ns, name);
	    }
	  continue;
	}
      else if (list_length (args) < spec->min_length
	       || (spec->max_length >= 0
		   && list_length (args) > spec->max_length))
	{
	  error ("wrong number of arguments specified for %qE attribute",
		 name);
	  continue;
	}
      gcc_assert (is_attribute_p (spec->name, name));

      if (TYPE_P (*node)
	  && cxx11_attribute_p (a)
	  && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
	{
	  /* This is a c++11 attribute that appertains to a
	     type-specifier, outside of the definition of, a class
	     type.  Ignore it.  */
	  warning (OPT_Wattributes, "attribute ignored");
	  inform (input_location,
		  "an attribute that appertains to a type-specifier "
		  "is ignored");
	  continue;
	}

      if (spec->decl_required && !DECL_P (*anode))
	{
	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
		       | (int) ATTR_FLAG_FUNCTION_NEXT
		       | (int) ATTR_FLAG_ARRAY_NEXT))
	    {
	      /* Pass on this attribute to be tried again.  */
	      returned_attrs = tree_cons (name, args, returned_attrs);
	      continue;
	    }
	  else
	    {
	      warning (OPT_Wattributes, "%qE attribute does not apply to types",
		       name);
	      continue;
	    }
	}

      /* If we require a type, but were passed a decl, set up to make a
	 new type and update the one in the decl.  ATTR_FLAG_TYPE_IN_PLACE
	 would have applied if we'd been passed a type, but we cannot modify
	 the decl's type in place here.  */
      if (spec->type_required && DECL_P (*anode))
	{
	  anode = &TREE_TYPE (*anode);
	  flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
	}

      if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
	  && TREE_CODE (*anode) != METHOD_TYPE)
	{
	  if (TREE_CODE (*anode) == POINTER_TYPE
	      && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
		  || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
	    {
	      /* OK, this is a bit convoluted.  We can't just make a copy
		 of the pointer type and modify its TREE_TYPE, because if
		 we change the attributes of the target type the pointer
		 type needs to have a different TYPE_MAIN_VARIANT.  So we
		 pull out the target type now, frob it as appropriate, and
		 rebuild the pointer type later.

		 This would all be simpler if attributes were part of the
		 declarator, grumble grumble.  */
	      fn_ptr_tmp = TREE_TYPE (*anode);
	      fn_ptr_quals = TYPE_QUALS (*anode);
	      anode = &fn_ptr_tmp;
	      flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
	    }
	  else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
	    {
	      /* Pass on this attribute to be tried again.  */
	      returned_attrs = tree_cons (name, args, returned_attrs);
	      continue;
	    }

	  if (TREE_CODE (*anode) != FUNCTION_TYPE
	      && TREE_CODE (*anode) != METHOD_TYPE)
	    {
	      warning (OPT_Wattributes,
		       "%qE attribute only applies to function types",
		       name);
	      continue;
	    }
	}

      if (TYPE_P (*anode)
	  && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
	  && TYPE_SIZE (*anode) != NULL_TREE)
	{
	  warning (OPT_Wattributes, "type attributes ignored after type is already defined");
	  continue;
	}

      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);
	}

      /* Layout the decl in case anything changed.  */
      if (spec->type_required && DECL_P (*node)
	  && (TREE_CODE (*node) == VAR_DECL
	      || TREE_CODE (*node) == PARM_DECL
	      || TREE_CODE (*node) == RESULT_DECL))
	relayout_decl (*node);

      if (!no_add_attrs)
	{
	  tree old_attrs;
	  tree a;

	  if (DECL_P (*anode))
	    old_attrs = DECL_ATTRIBUTES (*anode);
	  else
	    old_attrs = TYPE_ATTRIBUTES (*anode);

	  for (a = lookup_attribute (spec->name, old_attrs);
	       a != NULL_TREE;
	       a = lookup_attribute (spec->name, TREE_CHAIN (a)))
	    {
	      if (simple_cst_equal (TREE_VALUE (a), args) == 1)
		break;
	    }

	  if (a == NULL_TREE)
	    {
	      /* This attribute isn't already in the list.  */
	      if (DECL_P (*anode))
		DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
	      else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
		{
		  TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
		  /* If this is the main variant, also push the attributes
		     out to the other variants.  */
		  if (*anode == TYPE_MAIN_VARIANT (*anode))
		    {
		      tree variant;
		      for (variant = *anode; variant;
			   variant = TYPE_NEXT_VARIANT (variant))
			{
			  if (TYPE_ATTRIBUTES (variant) == old_attrs)
			    TYPE_ATTRIBUTES (variant)
			      = TYPE_ATTRIBUTES (*anode);
			  else if (!lookup_attribute
				   (spec->name, TYPE_ATTRIBUTES (variant)))
			    TYPE_ATTRIBUTES (variant) = tree_cons
			      (name, args, TYPE_ATTRIBUTES (variant));
			}
		    }
		}
	      else
		*anode = build_type_attribute_variant (*anode,
						       tree_cons (name, args,
								  old_attrs));
	    }
	}

      if (fn_ptr_tmp)
	{
	  /* Rebuild the function pointer type and put it in the
	     appropriate place.  */
	  fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
	  if (fn_ptr_quals)
	    fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals);
	  if (DECL_P (*node))
	    TREE_TYPE (*node) = fn_ptr_tmp;
	  else
	    {
	      gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
	      *node = fn_ptr_tmp;
	    }
	}
    }

  return returned_attrs;
}
Exemplo n.º 3
0
tree
decl_attributes (tree *node, tree attributes, int flags)
{
  tree a;
  tree returned_attrs = NULL_TREE;

  if (!attributes_initialized)
    init_attributes ();

  targetm.insert_attributes (*node, &attributes);

  for (a = attributes; a; a = TREE_CHAIN (a))
    {
      tree name = TREE_PURPOSE (a);
      tree args = TREE_VALUE (a);
      tree *anode = node;
      const struct attribute_spec *spec = NULL;
      bool no_add_attrs = 0;
      tree fn_ptr_tmp = NULL_TREE;
      size_t i;

      for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
        {
          int j;

          for (j = 0; attribute_tables[i][j].name != NULL; j++)
            {
              if (is_attribute_p (attribute_tables[i][j].name, name))
                {
                  spec = &attribute_tables[i][j];
                  break;
                }
            }
          if (spec != NULL)
            break;
        }

      if (spec == NULL)
        {
          warning (OPT_Wattributes, "%qs attribute directive ignored",
                   IDENTIFIER_POINTER (name));
          continue;
        }
      else if (list_length (args) < spec->min_length
               || (spec->max_length >= 0
                   && list_length (args) > spec->max_length))
        {
          error ("wrong number of arguments specified for %qs attribute",
                 IDENTIFIER_POINTER (name));
          continue;
        }

      if (spec->decl_required && !DECL_P (*anode))
        {
          if (flags & ((int) ATTR_FLAG_DECL_NEXT
                       | (int) ATTR_FLAG_FUNCTION_NEXT
                       | (int) ATTR_FLAG_ARRAY_NEXT))
            {
              /* Pass on this attribute to be tried again.  */
              returned_attrs = tree_cons (name, args, returned_attrs);
              continue;
            }
          else
            {
              warning (OPT_Wattributes, "%qs attribute does not apply to types",
                       IDENTIFIER_POINTER (name));
              continue;
            }
        }

      /* If we require a type, but were passed a decl, set up to make a
         new type and update the one in the decl.  ATTR_FLAG_TYPE_IN_PLACE
         would have applied if we'd been passed a type, but we cannot modify
         the decl's type in place here.  */
      if (spec->type_required && DECL_P (*anode))
        {
          anode = &TREE_TYPE (*anode);
          flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
        }

      if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
          && TREE_CODE (*anode) != METHOD_TYPE)
        {
          if (TREE_CODE (*anode) == POINTER_TYPE
              && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
                  || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
            {
              /* OK, this is a bit convoluted.  We can't just make a copy
                 of the pointer type and modify its TREE_TYPE, because if
                 we change the attributes of the target type the pointer
                 type needs to have a different TYPE_MAIN_VARIANT.  So we
                 pull out the target type now, frob it as appropriate, and
                 rebuild the pointer type later.

                 This would all be simpler if attributes were part of the
                 declarator, grumble grumble.  */
              fn_ptr_tmp = TREE_TYPE (*anode);
              anode = &fn_ptr_tmp;
              flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
            }
          else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
            {
              /* Pass on this attribute to be tried again.  */
              returned_attrs = tree_cons (name, args, returned_attrs);
              continue;
            }

          if (TREE_CODE (*anode) != FUNCTION_TYPE
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
              warning (OPT_Wattributes,
                       "%qs attribute only applies to function types",
                       IDENTIFIER_POINTER (name));
              continue;
            }
        }

      if (TYPE_P (*anode)
          && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
          && TYPE_SIZE (*anode) != NULL_TREE)
        {
          warning (OPT_Wattributes, "type attributes ignored after type is already defined");
          continue;
        }

      if (spec->handler != NULL)
        returned_attrs = chainon ((*spec->handler) (anode, name, args,
                                                    flags, &no_add_attrs),
                                  returned_attrs);

      /* Layout the decl in case anything changed.  */
      if (spec->type_required && DECL_P (*node)
          && (TREE_CODE (*node) == VAR_DECL
              || TREE_CODE (*node) == PARM_DECL
              || TREE_CODE (*node) == RESULT_DECL))
        relayout_decl (*node);

      if (!no_add_attrs)
        {
          tree old_attrs;
          tree a;

          if (DECL_P (*anode))
            old_attrs = DECL_ATTRIBUTES (*anode);
          else
            old_attrs = TYPE_ATTRIBUTES (*anode);

          for (a = lookup_attribute (spec->name, old_attrs);
               a != NULL_TREE;
               a = lookup_attribute (spec->name, TREE_CHAIN (a)))
            {
              if (simple_cst_equal (TREE_VALUE (a), args) == 1)
                break;
            }

          if (a == NULL_TREE)
            {
              /* This attribute isn't already in the list.  */
              if (DECL_P (*anode))
                DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
              else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
                {
                  TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
                  /* If this is the main variant, also push the attributes
                     out to the other variants.  */
                  if (*anode == TYPE_MAIN_VARIANT (*anode))
                    {
                      tree variant;
                      for (variant = *anode; variant;
                           variant = TYPE_NEXT_VARIANT (variant))
                        {
                          if (TYPE_ATTRIBUTES (variant) == old_attrs)
                            TYPE_ATTRIBUTES (variant)
                              = TYPE_ATTRIBUTES (*anode);
                          else if (!lookup_attribute
                                   (spec->name, TYPE_ATTRIBUTES (variant)))
                            TYPE_ATTRIBUTES (variant) = tree_cons
                              (name, args, TYPE_ATTRIBUTES (variant));
                        }
                    }
                }
              else
                *anode = build_type_attribute_variant (*anode,
                                                       tree_cons (name, args,
                                                                  old_attrs));
            }
        }

      if (fn_ptr_tmp)
        {
          /* Rebuild the function pointer type and put it in the
             appropriate place.  */
          fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
          if (DECL_P (*node))
            TREE_TYPE (*node) = fn_ptr_tmp;
          else
            {
              gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
              *node = fn_ptr_tmp;
            }
        }
    }

  return returned_attrs;
}
Exemplo n.º 4
0
tree
decl_attributes (tree *node, tree attributes, int flags)
{
  tree a;
  tree returned_attrs = NULL_TREE;

  if (TREE_TYPE (*node) == error_mark_node)
    return NULL_TREE;

  if (!attributes_initialized)
    init_attributes ();

  /* If this is a function and the user used #pragma GCC optimize, add the
     options to the attribute((optimize(...))) list.  */
  if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma)
    {
      tree cur_attr = lookup_attribute ("optimize", attributes);
      tree opts = copy_list (current_optimize_pragma);

      if (! cur_attr)
	attributes
	  = tree_cons (get_identifier ("optimize"), opts, attributes);
      else
	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
    }

  if (TREE_CODE (*node) == FUNCTION_DECL
      && optimization_current_node != optimization_default_node
      && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node))
    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node;

  /* If this is a function and the user used #pragma GCC target, add the
     options to the attribute((target(...))) list.  */
  if (TREE_CODE (*node) == FUNCTION_DECL
      && current_target_pragma
      && targetm.target_option.valid_attribute_p (*node, NULL_TREE,
						  current_target_pragma, 0))
    {
      tree cur_attr = lookup_attribute ("target", attributes);
      tree opts = copy_list (current_target_pragma);

      if (! cur_attr)
	attributes = tree_cons (get_identifier ("target"), opts, attributes);
      else
	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
    }

  targetm.insert_attributes (*node, &attributes);

  for (a = attributes; a; a = TREE_CHAIN (a))
    {
      tree name = TREE_PURPOSE (a);
      tree args = TREE_VALUE (a);
      tree *anode = node;
      const struct attribute_spec *spec = lookup_attribute_spec (name);
      bool no_add_attrs = 0;
      tree fn_ptr_tmp = NULL_TREE;

      if (spec == NULL)
	{
	  warning (OPT_Wattributes, "%qs attribute directive ignored",
		   IDENTIFIER_POINTER (name));
	  continue;
	}
      else if (list_length (args) < spec->min_length
	       || (spec->max_length >= 0
		   && list_length (args) > spec->max_length))
	{
	  error ("wrong number of arguments specified for %qs attribute",
		 IDENTIFIER_POINTER (name));
	  continue;
	}
      gcc_assert (is_attribute_p (spec->name, name));

      /* If this is a lock attribute and the purpose field of the args is
         an error_mark_node, the attribute arguments have not been parsed yet
         (as we delay the parsing of the attribute arguments until after the
         whole class has been parsed). So don't handle this attribute now
         but simply replace the error_mark_node with the current decl node
         (which we will need when we call this routine again later).  */
      if (args
          && TREE_PURPOSE (args) == error_mark_node
          && is_lock_attribute_with_args (name))
        {
          TREE_PURPOSE (args) = *node;
          continue;
        }

      if (spec->decl_required && !DECL_P (*anode))
	{
	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
		       | (int) ATTR_FLAG_FUNCTION_NEXT
		       | (int) ATTR_FLAG_ARRAY_NEXT))
	    {
	      /* Pass on this attribute to be tried again.  */
	      returned_attrs = tree_cons (name, args, returned_attrs);
	      continue;
	    }
	  else
	    {
	      warning (OPT_Wattributes, "%qs attribute does not apply to types",
		       IDENTIFIER_POINTER (name));
	      continue;
	    }
	}

      /* If we require a type, but were passed a decl, set up to make a
	 new type and update the one in the decl.  ATTR_FLAG_TYPE_IN_PLACE
	 would have applied if we'd been passed a type, but we cannot modify
	 the decl's type in place here.  */
      if (spec->type_required && DECL_P (*anode))
	{
	  anode = &TREE_TYPE (*anode);
	  /* Allow ATTR_FLAG_TYPE_IN_PLACE for the type's naming decl.  */
	  if (!(TREE_CODE (*anode) == TYPE_DECL
		&& *anode == TYPE_NAME (TYPE_MAIN_VARIANT
					(TREE_TYPE (*anode)))))
	    flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
	}

      if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
	  && TREE_CODE (*anode) != METHOD_TYPE)
	{
	  if (TREE_CODE (*anode) == POINTER_TYPE
	      && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
		  || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
	    {
	      /* OK, this is a bit convoluted.  We can't just make a copy
		 of the pointer type and modify its TREE_TYPE, because if
		 we change the attributes of the target type the pointer
		 type needs to have a different TYPE_MAIN_VARIANT.  So we
		 pull out the target type now, frob it as appropriate, and
		 rebuild the pointer type later.

		 This would all be simpler if attributes were part of the
		 declarator, grumble grumble.  */
	      fn_ptr_tmp = TREE_TYPE (*anode);
	      anode = &fn_ptr_tmp;
	      flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
	    }
	  else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
	    {
	      /* Pass on this attribute to be tried again.  */
	      returned_attrs = tree_cons (name, args, returned_attrs);
	      continue;
	    }

	  if (TREE_CODE (*anode) != FUNCTION_TYPE
	      && TREE_CODE (*anode) != METHOD_TYPE)
	    {
	      warning (OPT_Wattributes,
		       "%qs attribute only applies to function types",
		       IDENTIFIER_POINTER (name));
	      continue;
	    }
	}

      if (TYPE_P (*anode)
	  && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
	  && TYPE_SIZE (*anode) != NULL_TREE)
	{
	  warning (OPT_Wattributes, "type attributes ignored after type is already defined");
	  continue;
	}

      if (spec->handler != NULL)
        {
          tree ret_attr = (*spec->handler) (anode, name, args,
                                            flags, &no_add_attrs);
          if (ret_attr)
            {
              /* For the lock attributes whose arguments (i.e. locks) are not
                 supported or the names are not in scope, we would demote the
                 attributes. For example, if 'foo' is not in scope in the
                 attribute "guarded_by(foo->lock), the attribute would be
                 downgraded to a "guarded" attribute. And in this case, the
                 handler would return the new, demoted attribute which is
                 appended to the current one so that it is handled in the next
                 iteration.  */
              if (is_lock_attribute_with_args (name))
                {
                  gcc_assert (no_add_attrs);
                  TREE_CHAIN (ret_attr) = TREE_CHAIN (a);
                  TREE_CHAIN (a) = ret_attr;
                  continue;
                }
              else
                returned_attrs = chainon (ret_attr, returned_attrs);
            }
        }

      /* Layout the decl in case anything changed.  */
      if (spec->type_required && DECL_P (*node)
	  && (TREE_CODE (*node) == VAR_DECL
	      || TREE_CODE (*node) == PARM_DECL
	      || TREE_CODE (*node) == RESULT_DECL))
	relayout_decl (*node);

      if (!no_add_attrs)
	{
	  tree old_attrs;
	  tree a;

	  if (DECL_P (*anode))
	    old_attrs = DECL_ATTRIBUTES (*anode);
	  else
	    old_attrs = TYPE_ATTRIBUTES (*anode);

	  for (a = lookup_attribute (spec->name, old_attrs);
	       a != NULL_TREE;
	       a = lookup_attribute (spec->name, TREE_CHAIN (a)))
	    {
	      if (simple_cst_equal (TREE_VALUE (a), args) == 1)
		break;
              /* If a lock attribute of the same kind is already on the decl,
                 don't add this one again. Instead, merge the arguments.  */
              if (is_lock_attribute_with_args (name))
                {
                  merge_lock_attr_args (a, args);
                  break;
                }
	    }

	  if (a == NULL_TREE)
	    {
	      /* This attribute isn't already in the list.  */
	      if (DECL_P (*anode))
		DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
	      else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
		{
		  TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
		  /* If this is the main variant, also push the attributes
		     out to the other variants.  */
		  if (*anode == TYPE_MAIN_VARIANT (*anode))
		    {
		      tree variant;
		      for (variant = *anode; variant;
			   variant = TYPE_NEXT_VARIANT (variant))
			{
			  if (TYPE_ATTRIBUTES (variant) == old_attrs)
			    TYPE_ATTRIBUTES (variant)
			      = TYPE_ATTRIBUTES (*anode);
			  else if (!lookup_attribute
				   (spec->name, TYPE_ATTRIBUTES (variant)))
			    TYPE_ATTRIBUTES (variant) = tree_cons
			      (name, args, TYPE_ATTRIBUTES (variant));
			}
		    }
		}
	      else
		*anode = build_type_attribute_variant (*anode,
						       tree_cons (name, args,
								  old_attrs));
	    }
	}

      if (fn_ptr_tmp)
	{
	  /* Rebuild the function pointer type and put it in the
	     appropriate place.  */
	  fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
	  if (DECL_P (*node))
	    TREE_TYPE (*node) = fn_ptr_tmp;
	  else
	    {
	      gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
	      *node = fn_ptr_tmp;
	    }
	}
    }

  return returned_attrs;
}