aboutsummaryrefslogtreecommitdiff
path: root/gcc/attribs.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/attribs.c')
-rw-r--r--gcc/attribs.c456
1 files changed, 280 insertions, 176 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c
index affb21d8578..04db498507f 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, NULL, false }
};
/* Return base name of the attribute. Ie '__attr__' is turned into 'attr'.
@@ -343,15 +343,268 @@ get_attribute_namespace (const_tree attr)
return get_identifier ("gnu");
}
+/* Lookup the spec for attribute A using FLAGS, and issue any warnings or
+ errors as appropriate. Return NULL or a valid spec. */
+
+static const struct attribute_spec *
+process_attribute_spec (tree a, int flags)
+{
+ tree name = get_attribute_name (a);
+ tree ns = get_attribute_namespace (a);
+ tree args = TREE_VALUE (a);
+ const struct attribute_spec *spec = lookup_scoped_attribute_spec (ns, name);
+
+ 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);
+ }
+ return NULL;
+ }
+ 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);
+ return NULL;
+ }
+ gcc_assert (is_attribute_p (spec->name, name));
+ return spec;
+}
+
+/* Perform the type specific processing of type_attribute. This is factored
+ out to allow decl_attributes() to process underlying types when necessary.
+ In those cases, DECL_NODE is passed in so the decl can have re-layout
+ called. SPEC is the already verified attribute spec structure. Otherwise
+ the parameters match those of type_attribute. */
+
+static tree
+finalize_type_attribute (tree *node, const struct attribute_spec *spec,
+ tree a, tree returned_attrs, int flags,
+ tree *decl_node = NULL)
+{
+ bool no_add_attrs = 0;
+ int fn_ptr_quals = 0;
+ tree fn_ptr_tmp = NULL_TREE;
+ tree name = get_attribute_name (a);
+ tree args = TREE_VALUE (a);
+ tree *anode = node;
+
+ gcc_checking_assert (TYPE_P (*node));
+
+ 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);
+ return returned_attrs;
+ }
+
+ if (TREE_CODE (*anode) != FUNCTION_TYPE
+ && TREE_CODE (*anode) != METHOD_TYPE)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute only applies to function types",
+ name);
+ return returned_attrs;
+ }
+ }
+
+ if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+ && TYPE_SIZE (*anode) != NULL_TREE)
+ {
+ warning (OPT_Wattributes, "type attributes ignored after type is already defined");
+ return returned_attrs;
+ }
+
+ if (spec->type_handler != NULL)
+ {
+ int cxx11_flag =
+ cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
+
+ returned_attrs = chainon ((*spec->type_handler) (anode, name, args,
+ flags|cxx11_flag,
+ &no_add_attrs),
+ returned_attrs);
+ }
+
+ /* If there was a decl change the layout in case anything changed. */
+ if (decl_node && spec->type_required
+ && (TREE_CODE (*decl_node) == VAR_DECL
+ || TREE_CODE (*decl_node) == PARM_DECL
+ || TREE_CODE (*decl_node) == RESULT_DECL))
+ relayout_decl (*decl_node);
+
+ if (!no_add_attrs)
+ {
+ tree old_attrs;
+ tree a;
+
+ 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)
+ {
+ 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_node)
+ TREE_TYPE (*decl_node) = fn_ptr_tmp;
+ else
+ {
+ gcc_assert (TREE_CODE (*node) == POINTER_TYPE);
+ *node = fn_ptr_tmp;
+ }
+ }
+ return returned_attrs;
+
+}
/* 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,
- it should be modified in place; if a TYPE, a copy should be created
- unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
- information, in the form of a bitwise OR of flags in enum attribute_flags
- 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). */
+ which is a TYPE. A copy should be created unless ATTR_FLAG_TYPE_IN_PLACE
+ is set in FLAGS. FLAGS gives further information, in the form of a
+ bitwise OR of flags in enum attribute_flags 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). */
+
+tree
+type_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;
+
+ gcc_checking_assert (TYPE_P (*node));
+
+ if (!attributes_initialized)
+ init_attributes ();
+
+ targetm.insert_attributes (*node, &attributes);
+
+ for (a = attributes; a; a = TREE_CHAIN (a))
+ {
+ tree name = get_attribute_name (a);
+ tree args = TREE_VALUE (a);
+ const struct attribute_spec *spec = process_attribute_spec (a, flags);
+
+ if (!spec)
+ continue;
+
+ if (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)
+ {
+ 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;
+ }
+ }
+
+ returned_attrs = finalize_type_attribute (node, spec, a, returned_attrs,
+ flags);
+ }
+
+ return returned_attrs;
+}
+
+
+
+
+/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
+ which is a DECL (including a TYPE_DECL) it should be modified in place;
+ FLAGS gives further information, in the form of a bitwise OR of flags in
+ enum attribute_flags from tree.h. Depending on these flags, some
+ attributes may be returned to be applied at a later stage. */
tree
decl_attributes (tree *node, tree attributes, int flags)
@@ -359,9 +612,12 @@ 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;
+ gcc_checking_assert (DECL_P (*node));
+
if (!attributes_initialized)
init_attributes ();
@@ -418,155 +674,47 @@ decl_attributes (tree *node, tree attributes, int flags)
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);
+ const struct attribute_spec *spec = process_attribute_spec (a, flags);
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));
+ gcc_assert (DECL_P (*node));
- 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. */
- if (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 (!spec)
+ 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))
+ if (spec->type_required)
{
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");
+ returned_attrs = finalize_type_attribute (anode, spec, a,
+ returned_attrs, flags,
+ node);
continue;
}
- if (spec->handler != NULL)
+ if (spec->decl_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 = chainon ((*spec->decl_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);
+ old_attrs = DECL_ATTRIBUTES (*anode);
for (a = lookup_attribute (spec->name, old_attrs);
a != NULL_TREE;
@@ -577,55 +725,11 @@ decl_attributes (tree *node, tree attributes, int flags)
}
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));
- }
+ /* This attribute isn't already in the list. */
+ DECL_ATTRIBUTES (*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;
}
@@ -670,7 +774,7 @@ get_attribute_name (const_tree attr)
void
apply_tm_attr (tree fndecl, tree attr)
{
- decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
+ type_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
}
/* Makes a function attribute of the form NAME(ARG_NAME) and chains