+2001-09-21 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ Table-driven attributes.
+ * c-decl.c, config/alpha/alpha.c, config/arc/arc.c,
+ config/arm/arm.c, config/arm/pe.c, config/avr/avr.c,
+ config/avr/avr.h, config/d30v/d30v.h, config/fr30/fr30.h,
+ config/h8300/h8300.c, config/i386/cygwin.h, config/i386/winnt.c,
+ config/m32r/m32r.c, config/mcore/mcore.c, config/sh/sh.c,
+ config/stormy16/stormy16.h, config/v850/v850.c, doc/c-tree.texi,
+ doc/tm.texi, ggc-common.c, integrate.c, print-tree.c, tree.c,
+ tree.h: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
+ * tree.h (struct tree_decl): Change machine_attributes to
+ attributes.
+ * doc/c-tree.texi: Document that all attributes are now attached
+ to decls and types.
+ * c-common.c (add_attribute, attrtab, attrtab_idx,
+ default_valid_lang_attribute, valid_lang_attribute): Remove.
+ (attribute_tables, attributes_initialized,
+ c_common_attribute_table, default_lang_attribute_table): New
+ variables.
+ (handle_packed_attribute, handle_nocommon_attribute,
+ handle_common_attribute, handle_noreturn_attribute,
+ handle_unused_attribute, handle_const_attribute,
+ handle_transparent_union_attribute, handle_constructor_attribute,
+ handle_destructor_attribute, handle_mode_attribute,
+ handle_section_attribute, handle_aligned_attribute,
+ handle_weak_attribute, handle_alias_attribute,
+ handle_no_instrument_function_attribute,
+ handle_no_check_memory_usage_attribute, handle_malloc_attribute,
+ handle_no_limit_stack_attribute, handle_pure_attribute): New
+ functions.
+ (init_attributes, decl_attributes): Rewrite to implement
+ table-driven attributes.
+ * c-common.h (enum attribute_flags): Move to tree.h.
+ * c-format.c (decl_handle_format_attribute,
+ decl_handle_format_arg_attribute): Rename to
+ handle_format_attribute and handle_format_arg_attribute. Update
+ for table-driven attributes.
+ * c-common.h (decl_handle_format_attribute,
+ decl_handle_format_arg_attribute): Remove prototypes.
+ (handle_format_attribute, handle_format_arg_attribute): Add
+ prototypes.
+ * c-decl.c (grokdeclarator): Handle attributes nested inside
+ declarators.
+ * c-parse.in (setattrs, maybe_setattrs): Remove.
+ (maybe_type_quals_setattrs): Rename to maybe_type_quals_attrs.
+ Update to handle nested attributes properly.
+ (maybe_resetattrs, after_type_declarator,
+ parm_declarator_nostarttypename, notype_declarator, absdcl1_noea,
+ absdcl1_ea, direct_absdcl1): Update to handle nested attributes
+ properly.
+ (make_pointer_declarator): Update to handle nested attributes
+ properly.
+ * doc/extend.texi: Update documentation of limits of attributes
+ syntax. Warn about problems with attribute semantics in C++.
+ * target.h (struct target): Remove valid_decl_attribute and
+ valid_type_attribute. Add attribute_table and
+ function_attribute_inlinable_p.
+ * target-def.h (TARGET_VALID_DECL_ATTRIBUTE,
+ TARGET_VALID_TYPE_ATTRIBUTE): Remove.
+ (TARGET_ATTRIBUTE_TABLE, TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P):
+ Add.
+ (TARGET_INITIALIZER): Update.
+ * integrate.c (FUNCTION_ATTRIBUTE_INLINABLE_P): Remove default
+ definition.
+ (function_attribute_inlinable_p): New function. Check for the
+ presence of any machine attributes before using
+ targetm.function_attribute_inlinable_p.
+ (function_cannot_inline_p): Update.
+ * Makefile.in (integrate.o): Update dependencies.
+ * doc/tm.texi: Update documentation of target attributes and
+ example definition of TARGET_VALID_TYPE_ATTRIBUTE.
+ * tree.c (default_valid_attribute_p, valid_machine_attribute):
+ Remove.
+ (default_target_attribute_table,
+ default_function_attribute_inlinable_p): New.
+ (lookup_attribute): Update comment to clarify handling of multiple
+ attributes with the same name.
+ (merge_attributes, attribute_list_contained): Allow multiple
+ attributes with the same name but different arguments to appear in
+ the same attribute list.
+ * tree.h (default_valid_attribute_p): Remove prototype.
+ (struct attribute_spec): New.
+ (default_target_attribute_table): Declare.
+ (enum attribute_flags): Move from c-common.h. Add
+ ATTR_FLAG_TYPE_IN_PLACE.
+ (default_function_attribute_inlinable_p): Declare.
+ * config/alpha/alpha.c (vms_valid_decl_attribute_p): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (vms_attribute_table): New.
+ * config/arc/arc.c (arc_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (arc_attribute_table, arc_handle_interrupt_attribute): New.
+ * config/arm/arm.c (arm_valid_type_attribute_p,
+ arm_valid_decl_attribute_p, arm_pe_valid_decl_attribute_p):
+ Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
+ define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (arm_attribute_table, arm_handle_fndecl_attribute,
+ arm_handle_isr_attribute): New.
+ * config/avr/avr.c (avr_valid_type_attribute,
+ avr_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE, TARGET_VALID_TYPE_ATTRIBUTE): Don't
+ define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (avr_attribute_table, avr_handle_progmem_attribute,
+ avr_handle_fndecl_attribute): New.
+ * config/c4x/c4x.c (c4x_valid_type_attribute_p): Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (c4x_attribute_table, c4x_handle_fntype_attribute): New.
+ * config/h8300/h8300.c (h8300_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (h8300_attribute_table, h8300_handle_fndecl_attribute,
+ h8300_handle_eightbit_data_attribute,
+ h8300_handle_tiny_data_attribute): New.
+ * config/i386/i386-protos.h (ix86_valid_type_attribute_p,
+ i386_pe_valid_decl_attribute_p, i386_pe_valid_type_attribute_p):
+ Remove prototypes.
+ (ix86_handle_dll_attribute, ix86_handle_shared_attribute): New
+ declarations.
+ * config/i386/i386.c (ix86_valid_type_attribute_p: Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE, TARGET_VALID_DECL_ATTRIBUTE): Don't
+ define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (ix86_attribute_table, ix86_handle_cdecl_attribute,
+ ix86_handle_regparm_attribute): New.
+ * config/i386/winnt.c (i386_pe_valid_decl_attribute_p,
+ i386_pe_valid_type_attribute_p): Remove.
+ (ix86_handle_dll_attribute, ix86_handle_shared_attribute): New.
+ * config/ia64/ia64.c (ia64_valid_type_attribute): Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (ia64_attribute_table): New.
+ * config/m32r/m32r.c (m32r_valid_decl_attribute, interrupt_ident1,
+ interrupt_ident2, model_ident1, model_ident2): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (init_idents): Update.
+ (m32r_attribute_table, m32r_handle_model_attribute): New.
+ * config/m68hc11/m68hc11.c (m68hc11_valid_type_attribute_p):
+ Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (m68hc11_attribute_table, m68hc11_handle_fntype_attribute): New.
+ * config/mcore/mcore.c (mcore_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (mcore_attribute_table, mcore_handle_naked_attribute): New.
+ * config/ns32k/ns32k.c (ns32k_valid_type_attribute_p): Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (ns32k_attribute_table, ns32k_handle_fntype_attribute): New.
+ * config/rs6000/rs6000.c (rs6000_valid_type_attribute_p): Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (rs6000_attribute_table, rs6000_handle_longcall_attribute): New.
+ * config/sh/sh.c (sh_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (sh_attribute_table, sh_handle_interrupt_handler_attribute,
+ sh_handle_sp_switch_attribute, sh_handle_trap_exit_attribute):
+ New.
+ * config/stormy16/stormy16.c (stormy16_valid_type_attribute):
+ Remove.
+ (TARGET_VALID_TYPE_ATTRIBUTE): Don't define
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (stormy16_attribute_table, stormy16_handle_interrupt_attribute):
+ New.
+ * config/v850/v850.c (v850_valid_decl_attribute): Remove.
+ (TARGET_VALID_DECL_ATTRIBUTE): Don't define.
+ (TARGET_ATTRIBUTE_TABLE): Define.
+ (v850_attribute_table, v850_handle_interrupt_attribute,
+ v850_handle_data_area_attribute): New.
+ * config/v850/v850-c.c (mark_current_function_as_interrupt):
+ Return void. Call decl_attributes instead of
+ valid_machine_attribute.
+
Fri Sep 21 01:49:41 2001 J"orn Rennecke <amylaar@redhat.com>
* sh-protos.h (sh_pr_n_sets): Declare.
integrate.o : integrate.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
debug.h $(INTEGRATE_H) insn-config.h $(EXPR_H) real.h $(REGS_H) \
intl.h function.h output.h $(RECOG_H) except.h toplev.h $(LOOP_H) \
- $(PARAMS_H) $(TM_P_H)
+ $(PARAMS_H) $(TM_P_H) $(TARGET_H)
jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
insn-config.h $(RECOG_H) $(EXPR_H) real.h except.h function.h \
toplev.h $(INSN_ATTR_H) $(TM_P_H) reload.h $(PREDICT_H)
{NULL, 0, 0},
};
-static void add_attribute PARAMS ((enum attrs, const char *,
- int, int, int));
static void init_attributes PARAMS ((void));
-static int default_valid_lang_attribute PARAMS ((tree, tree, tree, tree));
static int constant_fits_type_p PARAMS ((tree, tree));
/* Keep a stack of if statements. We record the number of compound
return value;
}
\f
-/* To speed up processing of attributes, we maintain an array of
- IDENTIFIER_NODES and the corresponding attribute types. */
-
-/* Array to hold attribute information. */
-
-static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
-
-static int attrtab_idx = 0;
-
-/* Add an entry to the attribute table above. */
-
-static void
-add_attribute (id, string, min_len, max_len, decl_req)
- enum attrs id;
- const char *string;
- int min_len, max_len;
- int decl_req;
+/* Table of the tables of attributes (common, language, machine) searched. */
+static const struct attribute_spec *attribute_tables[3];
+
+static bool attributes_initialized = false;
+
+static tree handle_packed_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_nocommon_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_common_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_unused_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_const_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_mode_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_section_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_aligned_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_weak_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_check_memory_usage_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_malloc_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_pure_attribute PARAMS ((tree *, tree, tree, int, bool *));
+
+/* Table of machine-independent attributes common to all C-like languages. */
+static const struct attribute_spec c_common_attribute_table[] =
{
- char buf[100];
-
- attrtab[attrtab_idx].id = id;
- attrtab[attrtab_idx].name = get_identifier (string);
- attrtab[attrtab_idx].min = min_len;
- attrtab[attrtab_idx].max = max_len;
- attrtab[attrtab_idx++].decl_req = decl_req;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "packed", 0, 0, false, false, false, handle_packed_attribute },
+ { "nocommon", 0, 0, true, false, false, handle_nocommon_attribute },
+ { "common", 0, 0, true, false, false, handle_common_attribute },
+ /* 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 },
+ { "volatile", 0, 0, true, false, false, handle_noreturn_attribute },
+ { "unused", 0, 0, false, false, false, handle_unused_attribute },
+ /* The same comments as for noreturn attributes apply to const ones. */
+ { "const", 0, 0, true, false, false, handle_const_attribute },
+ { "transparent_union", 0, 0, false, false, false, handle_transparent_union_attribute },
+ { "constructor", 0, 0, true, false, false, handle_constructor_attribute },
+ { "destructor", 0, 0, true, false, false, handle_destructor_attribute },
+ { "mode", 1, 1, true, false, false, handle_mode_attribute },
+ { "section", 1, 1, true, false, false, handle_section_attribute },
+ { "aligned", 0, 1, false, false, false, handle_aligned_attribute },
+ { "format", 3, 3, true, false, false, handle_format_attribute },
+ { "format_arg", 1, 1, true, false, false, handle_format_arg_attribute },
+ { "weak", 0, 0, true, false, false, handle_weak_attribute },
+ { "alias", 1, 1, true, false, false, handle_alias_attribute },
+ { "no_instrument_function", 0, 0, true, false, false, handle_no_instrument_function_attribute },
+ { "no_check_memory_usage", 0, 0, true, false, false, handle_no_check_memory_usage_attribute },
+ { "malloc", 0, 0, true, false, false, handle_malloc_attribute },
+ { "no_stack_limit", 0, 0, true, false, false, handle_no_limit_stack_attribute },
+ { "pure", 0, 0, true, false, false, handle_pure_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- sprintf (buf, "__%s__", string);
+/* Default empty table of language attributes. */
+static const struct attribute_spec default_lang_attribute_table[] =
+{
+ { NULL, 0, 0, false, false, false, NULL }
+};
- attrtab[attrtab_idx].id = id;
- attrtab[attrtab_idx].name = get_identifier (buf);
- attrtab[attrtab_idx].min = min_len;
- attrtab[attrtab_idx].max = max_len;
- attrtab[attrtab_idx++].decl_req = decl_req;
-}
+/* Table of machine-independent attributes for a particular language. */
+const struct attribute_spec *lang_attribute_table = default_lang_attribute_table;
-/* Initialize attribute table. */
+/* Initialize attribute tables, and make some sanity checks
+ if --enable-checking. */
static void
init_attributes ()
{
- add_attribute (A_PACKED, "packed", 0, 0, 0);
- add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
- add_attribute (A_COMMON, "common", 0, 0, 1);
- add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
- add_attribute (A_NORETURN, "volatile", 0, 0, 1);
- add_attribute (A_UNUSED, "unused", 0, 0, 0);
- add_attribute (A_CONST, "const", 0, 0, 1);
- add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
- add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
- add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1);
- add_attribute (A_MODE, "mode", 1, 1, 1);
- add_attribute (A_SECTION, "section", 1, 1, 1);
- add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
- add_attribute (A_FORMAT, "format", 3, 3, 1);
- add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
- add_attribute (A_WEAK, "weak", 0, 0, 1);
- add_attribute (A_ALIAS, "alias", 1, 1, 1);
- add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
- add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
- add_attribute (A_MALLOC, "malloc", 0, 0, 1);
- add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
- add_attribute (A_PURE, "pure", 0, 0, 1);
+#ifdef ENABLE_CHECKING
+ int i;
+#endif
+ attribute_tables[0] = c_common_attribute_table;
+ attribute_tables[1] = lang_attribute_table;
+ attribute_tables[2] = targetm.attribute_table;
+#ifdef ENABLE_CHECKING
+ /* Make some sanity checks on the attribute tables. */
+ for (i = 0;
+ i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+ i++)
+ {
+ int j;
+ for (j = 0; attribute_tables[i][j].name != NULL; j++)
+ {
+ /* The name must not begin and end with __. */
+ const char *name = attribute_tables[i][j].name;
+ int len = strlen (name);
+ if (name[0] == '_' && name[1] == '_'
+ && name[len - 1] == '_' && name[len - 2] == '_')
+ abort ();
+ /* The minimum and maximum lengths must be consistent. */
+ if (attribute_tables[i][j].min_length < 0)
+ abort ();
+ if (attribute_tables[i][j].max_length != -1
+ && attribute_tables[i][j].max_length < attribute_tables[i][j].min_length)
+ abort ();
+ /* An attribute cannot require both a DECL and a TYPE. */
+ if (attribute_tables[i][j].decl_required
+ && attribute_tables[i][j].type_required)
+ abort ();
+ /* If an attribute requires a function type, in particular
+ it requires a type. */
+ if (attribute_tables[i][j].function_type_required
+ && !attribute_tables[i][j].type_required)
+ abort ();
+ }
+ }
+ /* Check that each name occurs just once in each table. */
+ for (i = 0;
+ i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+ i++)
+ {
+ int j, k;
+ for (j = 0; attribute_tables[i][j].name != NULL; j++)
+ for (k = j + 1; attribute_tables[i][k].name != NULL; k++)
+ if (!strcmp (attribute_tables[i][j].name,
+ attribute_tables[i][k].name))
+ abort ();
+ }
+ /* Check that no name occurs in more than one table. */
+ for (i = 0;
+ i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+ i++)
+ {
+ int j;
+ for (j = i + 1;
+ j < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+ j++)
+ {
+ int k, l;
+ for (k = 0; attribute_tables[i][k].name != NULL; k++)
+ for (l = 0; attribute_tables[j][l].name != NULL; l++)
+ if (!strcmp (attribute_tables[i][k].name,
+ attribute_tables[j][l].name))
+ abort ();
+ }
+ }
+#endif
+ attributes_initialized = true;
}
\f
-/* Default implementation of valid_lang_attribute, below. By default, there
- are no language-specific attributes. */
-
-static int
-default_valid_lang_attribute (attr_name, attr_args, decl, type)
- tree attr_name ATTRIBUTE_UNUSED;
- tree attr_args ATTRIBUTE_UNUSED;
- tree decl ATTRIBUTE_UNUSED;
- tree type ATTRIBUTE_UNUSED;
-{
- return 0;
-}
-
-/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific
- attribute for either declaration DECL or type TYPE and 0 otherwise. */
-
-int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree))
- = default_valid_lang_attribute;
-
/* 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.
- FLAGS gives further information, in the form of a bitwise OR of flags
- in enum attribute_flags from c-common.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). */
+ 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). */
tree
decl_attributes (node, attributes, flags)
tree *node, attributes;
- int flags ATTRIBUTE_UNUSED;
+ int flags;
{
- tree decl = 0, type = 0;
- int is_type = 0;
tree a;
+ tree returned_attrs = NULL_TREE;
- if (attrtab_idx == 0)
+ if (!attributes_initialized)
init_attributes ();
- if (DECL_P (*node))
- {
- decl = *node;
- type = TREE_TYPE (decl);
- is_type = TREE_CODE (*node) == TYPE_DECL;
- }
- else if (TYPE_P (*node))
- type = *node, is_type = 1;
-
(*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;
int i;
- enum attrs id;
-
- for (i = 0; i < attrtab_idx; i++)
- if (attrtab[i].name == name)
- break;
- if (i == attrtab_idx)
+ for (i = 0;
+ i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
+ i++)
{
- if (! valid_machine_attribute (name, args, decl, type)
- && ! (* valid_lang_attribute) (name, args, decl, type))
- warning ("`%s' attribute directive ignored",
- IDENTIFIER_POINTER (name));
- else if (decl != 0)
- type = TREE_TYPE (decl);
- continue;
+ 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;
}
- else if (attrtab[i].decl_req && decl == 0)
+
+ if (spec == NULL)
{
- warning ("`%s' attribute does not apply to types",
+ warning ("`%s' attribute directive ignored",
IDENTIFIER_POINTER (name));
continue;
}
- else if (list_length (args) < attrtab[i].min
- || list_length (args) > attrtab[i].max)
+ 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 `%s' attribute",
IDENTIFIER_POINTER (name));
continue;
}
- id = attrtab[i].id;
- switch (id)
+ if (spec->decl_required && !DECL_P (*anode))
{
- case A_PACKED:
- if (is_type)
- TYPE_PACKED (type) = 1;
- else if (TREE_CODE (decl) == FIELD_DECL)
- DECL_PACKED (decl) = 1;
- /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
- used for DECL_REGISTER. It wouldn't mean anything anyway. */
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
-
- case A_NOCOMMON:
- if (TREE_CODE (decl) == VAR_DECL)
- DECL_COMMON (decl) = 0;
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
-
- case A_COMMON:
- if (TREE_CODE (decl) == VAR_DECL)
- DECL_COMMON (decl) = 1;
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
-
- case A_NORETURN:
- if (TREE_CODE (decl) == FUNCTION_DECL)
- TREE_THIS_VOLATILE (decl) = 1;
- else if (TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (decl) = type
- = build_pointer_type
- (build_type_variant (TREE_TYPE (type),
- TREE_READONLY (TREE_TYPE (type)), 1));
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
-
- case A_MALLOC:
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_IS_MALLOC (decl) = 1;
- /* ??? TODO: Support types. */
+ 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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ {
+ warning ("`%s' attribute does not apply to types",
+ IDENTIFIER_POINTER (name));
+ continue;
+ }
+ }
- case A_UNUSED:
- if (is_type)
- if (decl)
- TREE_USED (decl) = 1;
- else
- TREE_USED (type) = 1;
- else if (TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == FUNCTION_DECL
- || TREE_CODE (decl) == LABEL_DECL)
- TREE_USED (decl) = 1;
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ if (spec->type_required && DECL_P (*anode))
+ {
+ anode = &TREE_TYPE (*anode);
+ }
- case A_CONST:
- if (TREE_CODE (decl) == FUNCTION_DECL)
- TREE_READONLY (decl) = 1;
- else if (TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (decl) = type
- = build_pointer_type
- (build_type_variant (TREE_TYPE (type), 1,
- TREE_THIS_VOLATILE (TREE_TYPE (type))));
- else
- warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ 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))
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *anode = build_type_copy (*anode);
+ anode = &TREE_TYPE (*anode);
+ }
+ 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;
+ }
- case A_PURE:
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_IS_PURE (decl) = 1;
- /* ??? TODO: Support types. */
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ if (TREE_CODE (*anode) != FUNCTION_TYPE
+ && TREE_CODE (*anode) != METHOD_TYPE)
+ {
+ warning ("`%s' attribute only applies to function types",
+ IDENTIFIER_POINTER (name));
+ continue;
+ }
+ }
+ if (spec->handler != NULL)
+ returned_attrs = chainon ((*spec->handler) (anode, name, args,
+ flags, &no_add_attrs),
+ returned_attrs);
+ if (!no_add_attrs)
+ {
+ tree old_attrs;
+ tree a;
- case A_T_UNION:
- if (is_type
- && TREE_CODE (type) == UNION_TYPE
- && (decl == 0
- || (TYPE_FIELDS (type) != 0
- && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
- TYPE_TRANSPARENT_UNION (type) = 1;
- else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
- && TREE_CODE (type) == UNION_TYPE
- && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
- DECL_TRANSPARENT_UNION (decl) = 1;
+ if (DECL_P (*anode))
+ old_attrs = DECL_ATTRIBUTES (*anode);
else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ old_attrs = TYPE_ATTRIBUTES (*anode);
- case A_CONSTRUCTOR:
- if (TREE_CODE (decl) == FUNCTION_DECL
- && TREE_CODE (type) == FUNCTION_TYPE
- && decl_function_context (decl) == 0)
+ for (a = lookup_attribute (spec->name, old_attrs);
+ a != NULL_TREE;
+ a = lookup_attribute (spec->name, TREE_CHAIN (a)))
{
- DECL_STATIC_CONSTRUCTOR (decl) = 1;
- TREE_USED (decl) = 1;
+ if (simple_cst_equal (TREE_VALUE (a), args) == 1)
+ break;
}
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
- case A_DESTRUCTOR:
- if (TREE_CODE (decl) == FUNCTION_DECL
- && TREE_CODE (type) == FUNCTION_TYPE
- && decl_function_context (decl) == 0)
+ if (a == NULL_TREE)
{
- DECL_STATIC_DESTRUCTOR (decl) = 1;
- TREE_USED (decl) = 1;
+ /* 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);
+ else
+ *anode = build_type_attribute_variant (*anode,
+ tree_cons (name, args,
+ old_attrs));
}
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+ }
+ }
- case A_MODE:
- if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- else
- {
- int j;
- const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
- int len = strlen (p);
- enum machine_mode mode = VOIDmode;
- tree typefm;
-
- if (len > 4 && p[0] == '_' && p[1] == '_'
- && p[len - 1] == '_' && p[len - 2] == '_')
- {
- char *newp = (char *) alloca (len - 1);
+ return returned_attrs;
+}
- strcpy (newp, &p[2]);
- newp[len - 4] = '\0';
- p = newp;
- }
+/* Handle a "packed" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_packed_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree *type = NULL;
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) == TYPE_DECL)
+ type = &TREE_TYPE (*node);
+ }
+ else
+ type = node;
+ if (type)
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *type = build_type_copy (*type);
+ TYPE_PACKED (*type) = 1;
+ }
+ else if (TREE_CODE (*node) == FIELD_DECL)
+ DECL_PACKED (*node) = 1;
+ /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
+ used for DECL_REGISTER. It wouldn't mean anything anyway. */
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- /* Give this decl a type with the specified mode.
- First check for the special modes. */
- if (! strcmp (p, "byte"))
- mode = byte_mode;
- else if (!strcmp (p, "word"))
- mode = word_mode;
- else if (! strcmp (p, "pointer"))
- mode = ptr_mode;
- else
- for (j = 0; j < NUM_MACHINE_MODES; j++)
- if (!strcmp (p, GET_MODE_NAME (j)))
- mode = (enum machine_mode) j;
-
- if (mode == VOIDmode)
- error ("unknown machine mode `%s'", p);
- else if (0 == (typefm = type_for_mode (mode,
- TREE_UNSIGNED (type))))
- error ("no data type for mode `%s'", p);
- else
- {
- if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
- ? TYPE_PRECISION(uintmax_type_node)
- : TYPE_PRECISION(intmax_type_node))
- && pedantic)
- pedwarn ("type with more precision than %s",
- TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
- TREE_TYPE (decl) = type = typefm;
- DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
- if (TREE_CODE (decl) != FIELD_DECL)
- layout_decl (decl, 0);
- }
- }
- break;
+ return NULL_TREE;
+}
- case A_SECTION:
- if (targetm.have_named_sections)
- {
- if ((TREE_CODE (decl) == FUNCTION_DECL
- || TREE_CODE (decl) == VAR_DECL)
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
- {
- if (TREE_CODE (decl) == VAR_DECL
- && current_function_decl != NULL_TREE
- && ! TREE_STATIC (decl))
- error_with_decl (decl,
- "section attribute cannot be specified for local variables");
- /* The decl may have already been given a section attribute
- from a previous declaration. Ensure they match. */
- else if (DECL_SECTION_NAME (decl) != NULL_TREE
- && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
- TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
- error_with_decl (*node,
- "section of `%s' conflicts with previous declaration");
- else
- DECL_SECTION_NAME (decl) = TREE_VALUE (args);
- }
- else
- error_with_decl (*node,
- "section attribute not allowed for `%s'");
- }
- else
- error_with_decl (*node,
- "section attributes are not supported for this target");
- break;
+/* Handle a "nocommon" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == VAR_DECL)
+ DECL_COMMON (*node) = 0;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- case A_ALIGNED:
- {
- tree align_expr
- = (args ? TREE_VALUE (args)
- : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
- int i;
-
- /* Strip any NOPs of any kind. */
- while (TREE_CODE (align_expr) == NOP_EXPR
- || TREE_CODE (align_expr) == CONVERT_EXPR
- || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
- align_expr = TREE_OPERAND (align_expr, 0);
-
- if (TREE_CODE (align_expr) != INTEGER_CST)
- {
- error ("requested alignment is not a constant");
- continue;
- }
+ return NULL_TREE;
+}
- if ((i = tree_log2 (align_expr)) == -1)
- error ("requested alignment is not a power of 2");
- else if (i > HOST_BITS_PER_INT - 2)
- error ("requested alignment is too large");
- else if (is_type)
- {
- /* If we have a TYPE_DECL, then copy the type, so that we
- don't accidentally modify a builtin type. See pushdecl. */
- if (decl && TREE_TYPE (decl) != error_mark_node
- && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
- {
- tree tt = TREE_TYPE (decl);
- DECL_ORIGINAL_TYPE (decl) = tt;
- tt = build_type_copy (tt);
- TYPE_NAME (tt) = decl;
- TREE_USED (tt) = TREE_USED (decl);
- TREE_TYPE (decl) = tt;
- type = tt;
- }
-
- TYPE_ALIGN (type) = (1 << i) * BITS_PER_UNIT;
- TYPE_USER_ALIGN (type) = 1;
- }
- else if (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != FIELD_DECL)
- error_with_decl (decl,
- "alignment may not be specified for `%s'");
- else
- {
- DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
- DECL_USER_ALIGN (decl) = 1;
- }
- }
- break;
+/* Handle a "common" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_common_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == VAR_DECL)
+ DECL_COMMON (*node) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- case A_FORMAT:
- decl_handle_format_attribute (decl, args);
- break;
+ return NULL_TREE;
+}
- case A_FORMAT_ARG:
- decl_handle_format_arg_attribute (decl, args);
- break;
+/* Handle a "noreturn" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = TREE_TYPE (*node);
+
+ /* See FIXME comment in c_common_attribute_table. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_THIS_VOLATILE (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type (build_type_variant (TREE_TYPE (type),
+ TREE_READONLY (TREE_TYPE (type)), 1));
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- case A_WEAK:
- declare_weak (decl);
- break;
+ return NULL_TREE;
+}
- case A_ALIAS:
- if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
- || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
- error_with_decl (decl,
- "`%s' defined both normally and as an alias");
- else if (decl_function_context (decl) == 0)
- {
- tree id;
+/* Handle a "unused" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_unused_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
+ {
+ tree decl = *node;
+
+ if (TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == LABEL_DECL
+ || TREE_CODE (decl) == TYPE_DECL)
+ TREE_USED (decl) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_type_copy (*node);
+ TREE_USED (*node) = 1;
+ }
- id = TREE_VALUE (args);
- if (TREE_CODE (id) != STRING_CST)
- {
- error ("alias arg not a string");
- break;
- }
- id = get_identifier (TREE_STRING_POINTER (id));
- /* This counts as a use of the object pointed to. */
- TREE_USED (id) = 1;
+ return NULL_TREE;
+}
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_INITIAL (decl) = error_mark_node;
- else
- DECL_EXTERNAL (decl) = 0;
- assemble_alias (decl, id);
- }
- else
- warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
- break;
+/* Handle a "const" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_const_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = TREE_TYPE (*node);
+
+ /* See FIXME comment on noreturn in c_common_attribute_table. */
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_READONLY (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type (build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type))));
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- case A_NO_CHECK_MEMORY_USAGE:
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
- }
- else if (DECL_INITIAL (decl))
- {
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
- }
- else
- DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
- break;
+ return NULL_TREE;
+}
- case A_NO_INSTRUMENT_FUNCTION:
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
- }
- else if (DECL_INITIAL (decl))
- {
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
- }
- else
- DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
- break;
+/* Handle a "transparent_union" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree decl = NULL_TREE;
+ tree *type = NULL;
+ int is_type = 0;
+
+ if (DECL_P (*node))
+ {
+ decl = *node;
+ type = &TREE_TYPE (decl);
+ is_type = TREE_CODE (*node) == TYPE_DECL;
+ }
+ else if (TYPE_P (*node))
+ type = node, is_type = 1;
+
+ if (is_type
+ && TREE_CODE (*type) == UNION_TYPE
+ && (decl == 0
+ || (TYPE_FIELDS (*type) != 0
+ && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
+ {
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *type = build_type_copy (*type);
+ TYPE_TRANSPARENT_UNION (*type) = 1;
+ }
+ else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
+ && TREE_CODE (*type) == UNION_TYPE
+ && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))
+ DECL_TRANSPARENT_UNION (decl) = 1;
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "constructor" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_constructor_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && decl_function_context (decl) == 0)
+ {
+ DECL_STATIC_CONSTRUCTOR (decl) = 1;
+ TREE_USED (decl) = 1;
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "destructor" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_destructor_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && TREE_CODE (type) == FUNCTION_TYPE
+ && decl_function_context (decl) == 0)
+ {
+ DECL_STATIC_DESTRUCTOR (decl) = 1;
+ TREE_USED (decl) = 1;
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "mode" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_mode_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+
+ *no_add_attrs = true;
+
+ if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ else
+ {
+ int j;
+ const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+ int len = strlen (p);
+ enum machine_mode mode = VOIDmode;
+ tree typefm;
+
+ if (len > 4 && p[0] == '_' && p[1] == '_'
+ && p[len - 1] == '_' && p[len - 2] == '_')
+ {
+ char *newp = (char *) alloca (len - 1);
+
+ strcpy (newp, &p[2]);
+ newp[len - 4] = '\0';
+ p = newp;
+ }
+
+ /* Give this decl a type with the specified mode.
+ First check for the special modes. */
+ if (! strcmp (p, "byte"))
+ mode = byte_mode;
+ else if (!strcmp (p, "word"))
+ mode = word_mode;
+ else if (! strcmp (p, "pointer"))
+ mode = ptr_mode;
+ else
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ if (!strcmp (p, GET_MODE_NAME (j)))
+ mode = (enum machine_mode) j;
+
+ if (mode == VOIDmode)
+ error ("unknown machine mode `%s'", p);
+ else if (0 == (typefm = type_for_mode (mode,
+ TREE_UNSIGNED (type))))
+ error ("no data type for mode `%s'", p);
+ else
+ {
+ if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
+ ? TYPE_PRECISION(uintmax_type_node)
+ : TYPE_PRECISION(intmax_type_node))
+ && pedantic)
+ pedwarn ("type with more precision than %s",
+ TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
+ TREE_TYPE (decl) = type = typefm;
+ DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
+ if (TREE_CODE (decl) != FIELD_DECL)
+ layout_decl (decl, 0);
+ }
+ }
- case A_NO_LIMIT_STACK:
- if (TREE_CODE (decl) != FUNCTION_DECL)
+ return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_section_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (targetm.have_named_sections)
+ {
+ if ((TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+ {
+ if (TREE_CODE (decl) == VAR_DECL
+ && current_function_decl != NULL_TREE
+ && ! TREE_STATIC (decl))
{
error_with_decl (decl,
- "`%s' attribute applies only to functions",
- IDENTIFIER_POINTER (name));
+ "section attribute cannot be specified for local variables");
+ *no_add_attrs = true;
}
- else if (DECL_INITIAL (decl))
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ else if (DECL_SECTION_NAME (decl) != NULL_TREE
+ && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+ TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
{
- error_with_decl (decl,
- "can't set `%s' attribute after definition",
- IDENTIFIER_POINTER (name));
+ error_with_decl (*node,
+ "section of `%s' conflicts with previous declaration");
+ *no_add_attrs = true;
}
else
- DECL_NO_LIMIT_STACK (decl) = 1;
- break;
+ DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+ }
+ else
+ {
+ error_with_decl (*node,
+ "section attribute not allowed for `%s'");
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ error_with_decl (*node,
+ "section attributes are not supported for this target");
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "aligned" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_aligned_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags;
+ bool *no_add_attrs;
+{
+ tree decl = NULL_TREE;
+ tree *type = NULL;
+ int is_type = 0;
+ tree align_expr = (args ? TREE_VALUE (args)
+ : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+ int i;
+
+ if (DECL_P (*node))
+ {
+ decl = *node;
+ type = &TREE_TYPE (decl);
+ is_type = TREE_CODE (*node) == TYPE_DECL;
+ }
+ else if (TYPE_P (*node))
+ type = node, is_type = 1;
+
+ /* Strip any NOPs of any kind. */
+ while (TREE_CODE (align_expr) == NOP_EXPR
+ || TREE_CODE (align_expr) == CONVERT_EXPR
+ || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
+ align_expr = TREE_OPERAND (align_expr, 0);
+
+ if (TREE_CODE (align_expr) != INTEGER_CST)
+ {
+ error ("requested alignment is not a constant");
+ *no_add_attrs = true;
+ }
+ else if ((i = tree_log2 (align_expr)) == -1)
+ {
+ error ("requested alignment is not a power of 2");
+ *no_add_attrs = true;
+ }
+ else if (i > HOST_BITS_PER_INT - 2)
+ {
+ error ("requested alignment is too large");
+ *no_add_attrs = true;
+ }
+ else if (is_type)
+ {
+ /* If we have a TYPE_DECL, then copy the type, so that we
+ don't accidentally modify a builtin type. See pushdecl. */
+ if (decl && TREE_TYPE (decl) != error_mark_node
+ && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
+ {
+ tree tt = TREE_TYPE (decl);
+ *type = build_type_copy (*type);
+ DECL_ORIGINAL_TYPE (decl) = tt;
+ TYPE_NAME (*type) = decl;
+ TREE_USED (*type) = TREE_USED (decl);
+ TREE_TYPE (decl) = *type;
}
+ else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *type = build_type_copy (*type);
+
+ TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
+ TYPE_USER_ALIGN (*type) = 1;
+ }
+ else if (TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != FIELD_DECL)
+ {
+ error_with_decl (decl,
+ "alignment may not be specified for `%s'");
+ *no_add_attrs = true;
+ }
+ else
+ {
+ DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
+ DECL_USER_ALIGN (decl) = 1;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_weak_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs ATTRIBUTE_UNUSED;
+{
+ declare_weak (*node);
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_alias_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+ || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
+ {
+ error_with_decl (decl,
+ "`%s' defined both normally and as an alias");
+ *no_add_attrs = true;
+ }
+ else if (decl_function_context (decl) == 0)
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("alias arg not a string");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ id = get_identifier (TREE_STRING_POINTER (id));
+ /* This counts as a use of the object pointed to. */
+ TREE_USED (id) = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (decl) = error_mark_node;
+ else
+ DECL_EXTERNAL (decl) = 0;
+ assemble_alias (decl, id);
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_instrument_function" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "`%s' attribute applies only to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (DECL_INITIAL (decl))
+ {
+ error_with_decl (decl,
+ "can't set `%s' attribute after definition",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_check_memory_usage" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_no_check_memory_usage_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "`%s' attribute applies only to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (DECL_INITIAL (decl))
+ {
+ error_with_decl (decl,
+ "can't set `%s' attribute after definition",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
+ else
+ DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_malloc_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_MALLOC (*node) = 1;
+ /* ??? TODO: Support types. */
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "no_limit_stack" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "`%s' attribute applies only to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (DECL_INITIAL (decl))
+ {
+ error_with_decl (decl,
+ "can't set `%s' attribute after definition",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ DECL_NO_LIMIT_STACK (decl) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_pure_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ DECL_IS_PURE (*node) = 1;
+ /* ??? TODO: Support types. */
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
return NULL_TREE;
}
extern tree fname_decl PARAMS ((unsigned, tree));
extern const char *fname_string PARAMS ((unsigned));
-/* Flags that may be passed in the third argument of decl_attributes. */
-enum attribute_flags
-{
- /* The type passed in is the type of a DECL, and any attributes that
- should be passed in again to be applied to the DECL rather than the
- type should be returned. */
- ATTR_FLAG_DECL_NEXT = 1,
- /* The type passed in is a function return type, and any attributes that
- should be passed in again to be applied to the function type rather
- than the return type should be returned. */
- ATTR_FLAG_FUNCTION_NEXT = 2,
- /* The type passed in is an array element type, and any attributes that
- should be passed in again to be applied to the array type rather
- than the element type should be returned. */
- ATTR_FLAG_ARRAY_NEXT = 4
-};
-
extern tree decl_attributes PARAMS ((tree *, tree, int));
extern void init_function_format_info PARAMS ((void));
extern void check_function_format PARAMS ((int *, tree, tree, tree));
extern void set_Wformat PARAMS ((int));
-extern void decl_handle_format_attribute PARAMS ((tree, tree));
-extern void decl_handle_format_arg_attribute PARAMS ((tree, tree));
+extern tree handle_format_attribute PARAMS ((tree *, tree, tree,
+ int, bool *));
+extern tree handle_format_arg_attribute PARAMS ((tree *, tree, tree,
+ int, bool *));
extern void c_apply_type_quals_to_decl PARAMS ((int, tree));
extern tree c_sizeof PARAMS ((tree));
extern tree c_alignof PARAMS ((tree));
int errmsg = 0;
if (DECL_P (olddecl))
- DECL_MACHINE_ATTRIBUTES (newdecl)
+ DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
if (TREE_CODE (newtype) == ERROR_MARK
/* NEWDECL contains the merged attribute lists.
Update OLDDECL to be the same. */
- DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
+ DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
return 1;
}
enum tree_code innermost_code = ERROR_MARK;
int bitfield = 0;
int size_varies = 0;
- tree decl_machine_attr = NULL_TREE;
+ tree decl_attr = NULL_TREE;
tree array_ptr_quals = NULL_TREE;
int array_parm_static = 0;
+ tree returned_attrs = NULL_TREE;
if (decl_context == BITFIELD)
bitfield = 1, decl_context = FIELD;
decl = TREE_OPERAND (decl, 0);
break;
+ case TREE_LIST:
+ decl = TREE_VALUE (decl);
+ break;
+
case IDENTIFIER_NODE:
name = IDENTIFIER_POINTER (decl);
decl = 0;
else if (TREE_CODE (id) == TYPE_DECL)
{
type = TREE_TYPE (id);
- decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
+ decl_attr = DECL_ATTRIBUTES (id);
typedef_decl = id;
}
/* Built-in types come as identifiers. */
/* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]),
an INDIRECT_REF (for *...),
a CALL_EXPR (for ...(...)),
+ a TREE_LIST (for nested attributes),
an identifier (for the name being declared)
or a null pointer (for the place in an absolute declarator
where the name was omitted).
array_parm_static = 0;
}
- if (TREE_CODE (declarator) == ARRAY_REF)
+ if (TREE_CODE (declarator) == TREE_LIST)
+ {
+ /* We encode a declarator with embedded attributes using
+ a TREE_LIST. */
+ tree attrs = TREE_PURPOSE (declarator);
+ tree inner_decl;
+ int attr_flags = 0;
+ declarator = TREE_VALUE (declarator);
+ inner_decl = declarator;
+ while (inner_decl != NULL_TREE
+ && TREE_CODE (inner_decl) == TREE_LIST)
+ inner_decl = TREE_VALUE (inner_decl);
+ if (inner_decl == NULL_TREE
+ || TREE_CODE (inner_decl) == IDENTIFIER_NODE)
+ attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
+ if (TREE_CODE (inner_decl) == CALL_EXPR)
+ attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
+ if (TREE_CODE (inner_decl) == ARRAY_REF)
+ attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
+ returned_attrs = decl_attributes (&type,
+ chainon (returned_attrs, attrs),
+ attr_flags);
+ }
+ else if (TREE_CODE (declarator) == ARRAY_REF)
{
register tree itype = NULL_TREE;
register tree size = TREE_OPERAND (declarator, 1);
if ((specbits & (1 << (int) RID_SIGNED))
|| (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
+ decl_attributes (&decl, returned_attrs, 0);
return decl;
}
pedwarn ("ISO C forbids const or volatile function types");
if (type_quals)
type = c_build_qualified_type (type, type_quals);
+ decl_attributes (&type, returned_attrs, 0);
return type;
}
or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */
{
- register tree decl;
+ tree decl;
if (decl_context == PARM)
{
pedwarn ("invalid storage class for function `%s'", name);
decl = build_decl (FUNCTION_DECL, declarator, type);
- decl = build_decl_attribute_variant (decl, decl_machine_attr);
+ decl = build_decl_attribute_variant (decl, decl_attr);
if (pedantic && type_quals && ! DECL_IN_SYSTEM_HEADER (decl))
pedwarn ("ISO C forbids qualified function types");
if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (decl)))
mark_addressable (decl);
+ decl_attributes (&decl, returned_attrs, 0);
+
return decl;
}
}
TYPE_SIZE (t) = 0;
- decl_attributes (&t, attributes, 0);
+ decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
/* Nameless union parm types are useful as GCC extension. */
if (! (TREE_CODE (t) == UNION_TYPE && TYPE_NAME (t) == 0) && !pedantic)
if (in_parm_level_p ())
warning ("enum defined inside parms");
- decl_attributes (&enumtype, attributes, 0);
+ decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
/* Calculate the maximum value of any enumerator in this type. */
int, int));
static void record_international_format PARAMS ((tree, tree, int));
-/* Handle the format attribute (with arguments ARGS) attached to the decl
- DECL. It is already verified that DECL is a decl and ARGS contains
- exactly three arguments. */
-
-void
-decl_handle_format_attribute (decl, args)
- tree decl, args;
+/* Handle a "format" attribute; arguments as in
+ struct attribute_spec.handler. */
+tree
+handle_format_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
+ tree decl = *node;
tree type = TREE_TYPE (decl);
tree format_type_id = TREE_VALUE (args);
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
{
error_with_decl (decl,
"argument format specified for non-function `%s'");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
error ("unrecognized format specifier");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
else
{
if (format_type == format_type_error)
{
warning ("`%s' is an unrecognized format function type", p);
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
}
|| TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
{
error ("format string has invalid operand number");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
format_num = TREE_INT_CST_LOW (format_num_expr);
if (first_arg_num != 0 && first_arg_num <= format_num)
{
error ("format string arg follows the args to be formatted");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
/* If a parameter list is specified, verify that the format_num
!= char_type_node))
{
error ("format string arg not a string type");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
else if (first_arg_num != 0)
if (arg_num != first_arg_num)
{
error ("args to be formatted is not '...'");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
}
}
if (format_type == strftime_format_type && first_arg_num != 0)
{
error ("strftime formats cannot format arguments");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
format_type, format_num, first_arg_num);
+ return NULL_TREE;
}
-/* Handle the format_arg attribute (with arguments ARGS) attached to
- the decl DECL. It is already verified that DECL is a decl and
- ARGS contains exactly one argument. */
-
-void
-decl_handle_format_arg_attribute (decl, args)
- tree decl, args;
+/* Handle a "format" attribute; arguments as in
+ struct attribute_spec.handler. */
+tree
+handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
+ tree decl = *node;
tree type = TREE_TYPE (decl);
tree format_num_expr = TREE_VALUE (args);
unsigned HOST_WIDE_INT format_num;
{
error_with_decl (decl,
"argument format specified for non-function `%s'");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
/* Strip any conversions from the first arg number and verify it
|| TREE_INT_CST_HIGH (format_num_expr) != 0)
{
error ("format string has invalid operand number");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
format_num = TREE_INT_CST_LOW (format_num_expr);
!= char_type_node))
{
error ("format string arg not a string type");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
}
!= char_type_node))
{
error ("function does not return string type");
- return;
+ *no_add_attrs = true;
+ return NULL_TREE;
}
record_international_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
format_num);
+ return NULL_TREE;
}
typedef struct function_format_info
%type <ttype> declspecs_ts declspecs_nots
%type <ttype> declspecs_ts_nosa declspecs_nots_nosa
%type <ttype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
-%type <ttype> maybe_type_quals_setattrs typespec_nonattr typespec_attr
+%type <ttype> maybe_type_quals_attrs typespec_nonattr typespec_attr
%type <ttype> typespec_reserved_nonattr typespec_reserved_attr
%type <ttype> typespec_nonreserved_nonattr
%type <ttype> init maybeasm
%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
-%type <ttype> maybe_setattrs
%type <ttype> any_word extension
%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
all_prefix_attributes = prefix_attributes; }
;
-/* ??? Yuck. See maybe_setattrs. */
-setattrs: /* empty */
- { all_prefix_attributes = chainon ($<ttype>0, all_prefix_attributes); }
- ;
-
-maybe_setattrs:
- /* ??? Yuck. setattrs is a quick hack. We can't use
- prefix_attributes because $1 only applies to this
- declarator. We assume setspecs has already been done.
- setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
- attributes could be recognized here or in `attributes').
- Properly attributes ought to be able to apply to any level of
- nested declarator, but the necessary compiler support isn't
- present, so the attributes apply to a declaration (which may be
- nested). */
- maybe_attribute setattrs
- ;
-
/* Possibly attributes after a comma, which should reset all_prefix_attributes
to prefix_attributes with these ones chained on the front. */
maybe_resetattrs:
- { all_prefix_attributes = prefix_attributes; }
- maybe_setattrs
+ maybe_attribute
+ { all_prefix_attributes = chainon ($1, prefix_attributes); }
;
decl:
| declspecs_sc_ts_sa_ea
;
-/* A (possibly empty) sequence of type qualifiers and attributes, to be
- followed by the effect of setattrs if any attributes were present. */
-maybe_type_quals_setattrs:
+/* A (possibly empty) sequence of type qualifiers and attributes. */
+maybe_type_quals_attrs:
/* empty */
{ $$ = NULL_TREE; }
| declspecs_nosc_nots
- { tree specs, attrs;
- split_specs_attrs ($1, &specs, &attrs);
- /* ??? Yuck. See maybe_setattrs. */
- if (attrs != NULL_TREE)
- all_prefix_attributes = chainon (attrs, all_prefix_attributes);
- $$ = specs; }
+ { $$ = $1; }
;
/* A type specifier (but not a type qualifier).
/* A declarator that is allowed only after an explicit typespec. */
after_type_declarator:
- '(' maybe_setattrs after_type_declarator ')'
- { $$ = $3; }
+ '(' maybe_attribute after_type_declarator ')'
+ { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
| after_type_declarator '(' parmlist_or_identifiers %prec '.'
{ $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
/* | after_type_declarator '(' error ')' %prec '.'
poplevel (0, 0, 0); } */
| after_type_declarator array_declarator %prec '.'
{ $$ = set_array_declarator_type ($2, $1, 0); }
- | '*' maybe_type_quals_setattrs after_type_declarator %prec UNARY
+ | '*' maybe_type_quals_attrs after_type_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
| TYPENAME
ifobjc
poplevel (0, 0, 0); } */
| parm_declarator_nostarttypename array_declarator %prec '.'
{ $$ = set_array_declarator_type ($2, $1, 0); }
- | '*' maybe_type_quals_setattrs parm_declarator_starttypename %prec UNARY
+ | '*' maybe_type_quals_attrs parm_declarator_starttypename %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
- | '*' maybe_type_quals_setattrs parm_declarator_nostarttypename %prec UNARY
+ | '*' maybe_type_quals_attrs parm_declarator_nostarttypename %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
- | '(' maybe_setattrs parm_declarator_nostarttypename ')'
- { $$ = $3; }
+ | '(' maybe_attribute parm_declarator_nostarttypename ')'
+ { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
;
/* A declarator allowed whether or not there has been
/* | notype_declarator '(' error ')' %prec '.'
{ $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
poplevel (0, 0, 0); } */
- | '(' maybe_setattrs notype_declarator ')'
- { $$ = $3; }
- | '*' maybe_type_quals_setattrs notype_declarator %prec UNARY
+ | '(' maybe_attribute notype_declarator ')'
+ { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
+ | '*' maybe_type_quals_attrs notype_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
| notype_declarator array_declarator %prec '.'
{ $$ = set_array_declarator_type ($2, $1, 0); }
absdcl1_noea:
direct_absdcl1
- | '*' maybe_type_quals_setattrs absdcl1_noea
+ | '*' maybe_type_quals_attrs absdcl1_noea
{ $$ = make_pointer_declarator ($2, $3); }
;
absdcl1_ea:
- '*' maybe_type_quals_setattrs
+ '*' maybe_type_quals_attrs
{ $$ = make_pointer_declarator ($2, NULL_TREE); }
- | '*' maybe_type_quals_setattrs absdcl1_ea
+ | '*' maybe_type_quals_attrs absdcl1_ea
{ $$ = make_pointer_declarator ($2, $3); }
;
direct_absdcl1:
- '(' maybe_setattrs absdcl1 ')'
- { $$ = $3; }
+ '(' maybe_attribute absdcl1 ')'
+ { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
| direct_absdcl1 '(' parmlist
{ $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
| direct_absdcl1 array_declarator
/* Return something to represent absolute declarators containing a *.
TARGET is the absolute declarator that the * contains.
- TYPE_QUALS is a list of modifiers such as const or volatile
- to apply to the pointer type, represented as identifiers.
+ TYPE_QUALS_ATTRS is a list of modifiers such as const or volatile
+ to apply to the pointer type, represented as identifiers, possible mixed
+ with attributes.
- We return an INDIRECT_REF whose "contents" are TARGET
- and whose type is the modifier list. */
+ We return an INDIRECT_REF whose "contents" are TARGET (inside a TREE_LIST,
+ if attributes are present) and whose type is the modifier list. */
tree
-make_pointer_declarator (type_quals, target)
- tree type_quals, target;
+make_pointer_declarator (type_quals_attrs, target)
+ tree type_quals_attrs, target;
{
- return build1 (INDIRECT_REF, type_quals, target);
+ tree quals, attrs;
+ tree itarget = target;
+ split_specs_attrs (type_quals_attrs, &quals, &attrs);
+ if (attrs != NULL_TREE)
+ itarget = tree_cons (attrs, target, NULL_TREE);
+ return build1 (INDIRECT_REF, quals, itarget);
}
\f
/* Initialize the GCC target structure. */
#if TARGET_ABI_OPEN_VMS
-static int vms_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
+const struct attribute_spec vms_attribute_table[];
static unsigned int vms_section_type_flags PARAMS ((tree, const char *, int));
static void vms_asm_named_section PARAMS ((const char *, unsigned int));
static void vms_asm_out_constructor PARAMS ((rtx, int));
static void vms_asm_out_destructor PARAMS ((rtx, int));
-# undef TARGET_VALID_DECL_ATTRIBUTE
-# define TARGET_VALID_DECL_ATTRIBUTE vms_valid_decl_attribute_p
+# undef TARGET_ATTRIBUTE_TABLE
+# define TARGET_ATTRIBUTE_TABLE vms_attribute_table
# undef TARGET_SECTION_TYPE_FLAGS
# define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
#endif
#if TARGET_ABI_OPEN_VMS
-static int
-vms_valid_decl_attribute_p (decl, attributes, identifier, args)
- tree decl ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+const struct attribute_spec vms_attribute_table[] =
{
- if (is_attribute_p ("overlaid", identifier))
- return (args == NULL_TREE);
- return 0;
-}
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "overlaid", 0, 0, true, false, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL }
+};
#endif
{
unsigned int flags = default_section_type_flags (decl, name, reloc);
- if (decl && DECL_MACHINE_ATTRIBUTES (decl)
- && lookup_attribute ("overlaid", DECL_MACHINE_ATTRIBUTES (decl)))
+ if (decl && DECL_ATTRIBUTES (decl)
+ && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl)))
flags |= SECTION_VMS_OVERLAY;
return flags;
static void record_cc_ref PARAMS ((rtx));
static void arc_init_reg_tables PARAMS ((void));
static int get_arc_condition_code PARAMS ((rtx));
-static int arc_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+const struct attribute_spec arc_attribute_table[];
+static tree arc_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
\f
#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE arc_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE arc_attribute_table
struct gcc_target targetm = TARGET_INITIALIZER;
\f
interrupt - for interrupt functions
*/
-/* Return nonzero if IDENTIFIER is a valid decl attribute. */
+const struct attribute_spec arc_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
-static int
-arc_valid_decl_attribute (type, attributes, identifier, args)
- tree type ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
+/* Handle an "interrupt" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+arc_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+ tree *node ATTRIBUTE_UNUSED;
+ tree name;
tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
- if (identifier == get_identifier ("__interrupt__")
- && list_length (args) == 1
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
- {
- tree value = TREE_VALUE (args);
+ tree value = TREE_VALUE (args);
- if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
- || !strcmp (TREE_STRING_POINTER (value), "ilink2"))
- return 1;
+ if (TREE_CODE (value) != STRING_CST)
+ {
+ warning ("argument of `%s' attribute is not a string constant",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 0;
+ else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
+ && strcmp (TREE_STRING_POINTER (value), "ilink2"))
+ {
+ warning ("argument of `%s' attribute is not \"ilink1\" or \"ilink2\"",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
}
\f
fn_type = ARC_FUNCTION_NORMAL;
/* Now see if this is an interrupt handler. */
- for (a = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+ for (a = DECL_ATTRIBUTES (current_function_decl);
a;
a = TREE_CHAIN (a))
{
static Ulong arm_compute_save_reg_mask PARAMS ((void));
static Ulong arm_isr_value PARAMS ((tree));
static Ulong arm_compute_func_type PARAMS ((void));
-static int arm_valid_type_attribute_p PARAMS ((tree, tree,
- tree, tree));
-static int arm_valid_decl_attribute_p PARAMS ((tree, tree,
- tree, tree));
+static tree arm_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree arm_handle_isr_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec arm_attribute_table[];
static void arm_output_function_epilogue PARAMS ((FILE *,
HOST_WIDE_INT));
static void arm_output_function_prologue PARAMS ((FILE *,
#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
#endif
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE arm_valid_type_attribute_p
-
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#ifdef ARM_PE
- static int arm_pe_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
-# define TARGET_VALID_DECL_ATTRIBUTE arm_pe_valid_decl_attribute_p
-#else
-# define TARGET_VALID_DECL_ATTRIBUTE arm_valid_decl_attribute_p
-#endif
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
if (current_function_needs_context)
type |= ARM_FT_NESTED;
- attr = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+ attr = DECL_ATTRIBUTES (current_function_decl);
a = lookup_attribute ("naked", attr);
if (a != NULL_TREE)
}
\f
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
- specific attribute for TYPE. The attributes in ATTRIBUTES have
- previously been assigned to TYPE. */
-static int
-arm_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+/* Table of machine attributes. */
+const struct attribute_spec arm_attribute_table[] =
{
- if ( TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != METHOD_TYPE
- && TREE_CODE (type) != FIELD_DECL
- && TREE_CODE (type) != TYPE_DECL)
- return 0;
-
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
/* Function calls made to this symbol must be done indirectly, because
it may lie outside of the 26 bit addressing range of a normal function
call. */
- if (is_attribute_p ("long_call", identifier))
- return (args == NULL_TREE);
-
+ { "long_call", 0, 0, false, true, true, NULL },
/* Whereas these functions are always known to reside within the 26 bit
addressing range. */
- if (is_attribute_p ("short_call", identifier))
- return (args == NULL_TREE);
-
+ { "short_call", 0, 0, false, true, true, NULL },
/* Interrupt Service Routines have special prologue and epilogue requirements. */
- if (is_attribute_p ("isr", identifier)
- || is_attribute_p ("interrupt", identifier))
- return arm_isr_value (args);
+ { "isr", 0, 1, false, false, false, arm_handle_isr_attribute },
+ { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute },
+ { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute },
+#ifdef ARM_PE
+ /* ARM/PE has three new attributes:
+ interfacearm - ?
+ dllexport - for exporting a function/variable that will live in a dll
+ dllimport - for importing a function/variable from a dll
+
+ Microsoft allows multiple declspecs in one __declspec, separating
+ them with spaces. We do NOT support this. Instead, use __declspec
+ multiple times.
+ */
+ { "dllimport", 0, 0, true, false, false, NULL },
+ { "dllexport", 0, 0, true, false, false, NULL },
+ { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute },
+#endif
+ { NULL, 0, 0, false, false, false, NULL }
+};
- return 0;
+/* Handle an attribute requiring a FUNCTION_DECL;
+ arguments as in struct attribute_spec.handler. */
+static tree
+arm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "interrupt" or "isr" attribute;
+ arguments as in struct attribute_spec.handler. */
+static tree
+arm_handle_isr_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ /* FIXME: the argument if any is checked for type attributes;
+ should it be checked for decl ones? */
+ }
+ else
+ {
+ if (TREE_CODE (*node) == FUNCTION_TYPE
+ || TREE_CODE (*node) == METHOD_TYPE)
+ {
+ if (arm_isr_value (args) == ARM_FT_UNKNOWN)
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ }
+ else if (TREE_CODE (*node) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
+ && arm_isr_value (args) != ARM_FT_UNKNOWN)
+ {
+ *node = build_type_copy (*node);
+ TREE_TYPE (*node) = build_type_attribute_variant (TREE_TYPE (*node),
+ tree_cons (name,
+ args,
+ TYPE_ATTRIBUTES (TREE_TYPE (*node))));
+ *no_add_attrs = true;
+ }
+ else
+ {
+ /* Possibly pass this attribute on from the type to a decl. */
+ if (flags & ((int) ATTR_FLAG_DECL_NEXT
+ | (int) ATTR_FLAG_FUNCTION_NEXT
+ | (int) ATTR_FLAG_ARRAY_NEXT))
+ {
+ *no_add_attrs = true;
+ return tree_cons (name, args, NULL_TREE);
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ }
+ }
+ }
+
+ return NULL_TREE;
}
/* Return 0 if the attributes for two types are incompatible, 1 if they
return 1;
}
\f
-/* Routines for use with attributes. */
-
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ATTRIBUTES are any existing attributes and ARGS are
- the arguments supplied with ATTR.
-
- Supported attributes:
-
- naked:
- don't output any prologue or epilogue code, the user is assumed
- to do the right thing.
-
- isr or interrupt:
- Interrupt Service Routine.
-
- interfacearm:
- Always assume that this function will be entered in ARM mode,
- not Thumb mode, and that the caller wishes to be returned to in
- ARM mode. */
-static int
-arm_valid_decl_attribute_p (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args;
-{
- /* The interrupt attribute can take args, so check for it before
- rejecting other attributes on the grounds that they did have args. */
- if (is_attribute_p ("isr", attr)
- || is_attribute_p ("interrupt", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
-
- if (args != NULL_TREE)
- return 0;
-
- if (is_attribute_p ("naked", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
-
-#ifdef ARM_PE
- if (is_attribute_p ("interfacearm", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
-#endif /* ARM_PE */
-
- return 0;
-}
-
-#ifdef ARM_PE
-
-/* ARM/PE has three new attributes:
- naked - for interrupt functions
- dllexport - for exporting a function/variable that will live in a dll
- dllimport - for importing a function/variable from a dll
-
- Microsoft allows multiple declspecs in one __declspec, separating
- them with spaces. We do NOT support this. Instead, use __declspec
- multiple times.
-*/
-
-static int
-arm_pe_valid_decl_attribute_p (decl, attributes, attr, args)
- tree decl;
- tree attributes;
- tree attr;
- tree args;
-{
- if (args != NULL_TREE)
- return 0;
-
- if (is_attribute_p ("dllexport", attr))
- return 1;
-
- if (is_attribute_p ("dllimport", attr))
- return 1;
-
- return arm_valid_decl_attribute_p (decl, attributes, attr, args);
-}
-
-#endif /* ARM_PE */
-\f
/* Routines for use in generating RTL. */
rtx
arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
return TRUE;
#ifdef ARM_PE
- return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE;
+ return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
#else
return FALSE;
#endif
/* Routines for GCC for ARM/pe.
- Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000, 2001 Free Software Foundation, Inc.
Contributed by Doug Evans (dje@cygnus.com).
This file is part of GNU CC.
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
+ exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
if (exp)
return 1;
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
+ imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
if (imp)
return 1;
static int reg_was_0 PARAMS ((rtx insn, rtx op));
static int io_address_p PARAMS ((rtx x, int size));
void debug_hard_reg_set PARAMS ((HARD_REG_SET set));
-static int avr_valid_type_attribute PARAMS ((tree, tree, tree, tree));
-static int avr_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+static tree avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec avr_attribute_table[];
static void avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE avr_valid_decl_attribute
-
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE avr_valid_type_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
struct gcc_target targetm = TARGET_INITIALIZER;
\f
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
- a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
return (c != ALL_REGS && c != ADDW_REGS);
}
-/* Only `progmem' attribute valid for type. */
-
-static int
-avr_valid_type_attribute (type, attributes, identifier, args)
- tree type ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args ATTRIBUTE_UNUSED;
-{
- return is_attribute_p ("progmem", identifier);
-}
-
-/* If IDENTIFIER with arguments ARGS is a valid machine specific
- attribute for DECL return 1.
- Valid attributes:
+/* Valid attributes:
progmem - put data to program memory;
signal - make a function to be hardware interrupt. After function
prologue interrupts are disabled;
interrupt - make a function to be hardware interrupt. After function
prologue interrupts are enabled;
- naked - don't generate function prologue/epilogue and `ret' command. */
+ naked - don't generate function prologue/epilogue and `ret' command.
-static int
-avr_valid_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args ATTRIBUTE_UNUSED;
+ Only `progmem' attribute valid for type. */
+
+const struct attribute_spec avr_attribute_table[] =
{
- if (is_attribute_p ("interrupt", attr)
- || is_attribute_p ("signal", attr)
- || is_attribute_p ("naked", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute },
+ { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { "naked", 0, 0, true, false, false, avr_handle_fndecl_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("progmem", attr)
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+/* Handle a "progmem" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_progmem_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node))
{
- if (DECL_INITIAL (decl) == NULL_TREE && !DECL_EXTERNAL (decl))
+ if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
{
- warning ("Only initialized variables can be placed into "
- "program memory area.");
- return 0;
+ if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
+ {
+ warning ("Only initialized variables can be placed into "
+ "program memory area.");
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 1;
}
- return 0;
+
+ return NULL_TREE;
}
+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
+ struct attribute_spec.handler. */
+static tree
+avr_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
/* Look for attribute `progmem' in DECL
if found return 1, otherwise 0. */
return 0;
if (NULL_TREE
- != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
+ != lookup_attribute ("progmem", DECL_ATTRIBUTES (decl)))
return 1;
a=decl;
FUNDECL is a C variable whose value is a tree node that describes
the function in question. Normally it is a node of type
`FUNCTION_DECL' that describes the declaration of the function.
- From this you can obtain the DECL_MACHINE_ATTRIBUTES of the
+ From this you can obtain the DECL_ATTRIBUTES of the
function.
FUNTYPE is a C variable whose value is a tree node that describes
static int c4x_r11_set_p PARAMS ((rtx));
static int c4x_rptb_valid_p PARAMS ((rtx, rtx));
static int c4x_label_ref_used_p PARAMS ((rtx, rtx));
-static int c4x_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
+static tree c4x_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec c4x_attribute_table[];
static void c4x_insert_attributes PARAMS ((tree, tree *));
static void c4x_asm_named_section PARAMS ((const char *, unsigned int));
static int c4x_adjust_cost PARAMS ((rtx, rtx, rtx, int));
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE c4x_valid_type_attribute_p
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE c4x_attribute_table
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES c4x_insert_attributes
}
}
+/* Table of valid machine attributes. */
+const struct attribute_spec c4x_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 0, 0, false, true, true, c4x_handle_fntype_attribute },
+ /* FIXME: code elsewhere in this file treats "naked" as a synonym of
+ "interrupt"; should it be accepted here? */
+ { "assembler", 0, 0, false, true, true, c4x_handle_fntype_attribute },
+ { "leaf_pretend", 0, 0, false, true, true, c4x_handle_fntype_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
- specific attribute for TYPE. The attributes in ATTRIBUTES have
- previously been assigned to TYPE. */
-
-static int
-c4x_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
+/* Handle an attribute requiring a FUNCTION_TYPE;
+ arguments as in struct attribute_spec.handler. */
+static tree
+c4x_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
- if (TREE_CODE (type) != FUNCTION_TYPE)
- return 0;
-
- if (is_attribute_p ("interrupt", identifier))
- return 1;
-
- if (is_attribute_p ("assembler", identifier))
- return 1;
-
- if (is_attribute_p ("leaf_pretend", identifier))
- return 1;
-
- return 0;
+ if (TREE_CODE (*node) != FUNCTION_TYPE)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
}
FUNDECL is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_DECL' that
describes the declaration of the function. From this it is possible to
- obtain the DECL_MACHINE_ATTRIBUTES of the function.
+ obtain the DECL_ATTRIBUTES of the function.
FUNTYPE is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_TYPE' that
/*{{{ Comment. */
/* Definitions of FR30 target.
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of GNU CC.
FUNDECL is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_DECL' that
describes the declaration of the function. From this it is possible to
- obtain the DECL_MACHINE_ATTRIBUTES of the function.
+ obtain the DECL_ATTRIBUTES of the function.
FUNTYPE is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_TYPE' that
static void push PARAMS ((FILE *, int));
static void pop PARAMS ((FILE *, int));
static const char *cond_string PARAMS ((enum rtx_code));
-static int h8300_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+const struct attribute_spec h8300_attribute_table[];
+static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree h8300_handle_tiny_data_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void h8300_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void h8300_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void h8300_asm_named_section PARAMS ((const char *, unsigned int));
const char *h8_push_op, *h8_pop_op, *h8_mov_op;
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE h8300_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE h8300_attribute_table
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("OS_Task", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("OS_Task", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("monitor", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("monitor", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("function_vector", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("function_vector", DECL_ATTRIBUTES (func));
return a != NULL_TREE;
}
if (TREE_CODE (decl) != VAR_DECL)
return 0;
- a = lookup_attribute ("eightbit_data", DECL_MACHINE_ATTRIBUTES (decl));
+ a = lookup_attribute ("eightbit_data", DECL_ATTRIBUTES (decl));
return a != NULL_TREE;
}
if (TREE_CODE (decl) != VAR_DECL)
return 0;
- a = lookup_attribute ("tiny_data", DECL_MACHINE_ATTRIBUTES (decl));
+ a = lookup_attribute ("tiny_data", DECL_ATTRIBUTES (decl));
return a != NULL_TREE;
}
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ATTRIBUTES are any existing attributes and ARGS are the arguments
- supplied with ATTR.
-
- Supported attributes:
+/* Supported attributes:
interrupt_handler: output a prologue and epilogue suitable for an
interrupt handler.
tiny_data: This variable lives in the tiny data area and can be
referenced with 16-bit absolute memory references. */
-static int
-h8300_valid_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args;
+const struct attribute_spec h8300_attribute_table[] =
{
- if (args != NULL_TREE)
- return 0;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt_handler", 0, 0, true, false, false, h8300_handle_fndecl_attribute },
+ { "OS_Task", 0, 0, true, false, false, h8300_handle_fndecl_attribute },
+ { "monitor", 0, 0, true, false, false, h8300_handle_fndecl_attribute },
+ { "function_vector", 0, 0, true, false, false, h8300_handle_fndecl_attribute },
+ { "eightbit_data", 0, 0, true, false, false, h8300_handle_eightbit_data_attribute },
+ { "tiny_data", 0, 0, true, false, false, h8300_handle_tiny_data_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("interrupt_handler", attr)
- || is_attribute_p ("OS_Task", attr)
- || is_attribute_p ("monitor", attr)
- || is_attribute_p ("function_vector", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
- if (is_attribute_p ("eightbit_data", attr)
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
+ struct attribute_spec.handler. */
+static tree
+h8300_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "eightbit_data" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+h8300_handle_eightbit_data_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
{
if (DECL_INITIAL (decl) == NULL_TREE)
{
warning ("Only initialized variables can be placed into the 8-bit area.");
- return 0;
+ *no_add_attrs = true;
}
- DECL_SECTION_NAME (decl) = build_string (7, ".eight");
- return 1;
+ else
+ DECL_SECTION_NAME (decl) = build_string (7, ".eight");
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- if (is_attribute_p ("tiny_data", attr)
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ return NULL_TREE;
+}
+
+/* Handle an "tiny_data" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+h8300_handle_tiny_data_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree decl = *node;
+
+ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
{
if (DECL_INITIAL (decl) == NULL_TREE)
{
warning ("Only initialized variables can be placed into the 8-bit area.");
- return 0;
+ *no_add_attrs = true;
}
- DECL_SECTION_NAME (decl) = build_string (6, ".tiny");
- return 1;
+ else
+ DECL_SECTION_NAME (decl) = build_string (6, ".tiny");
+ }
+ else
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 0;
+ return NULL_TREE;
}
void
It's also used to handle dllimport override semantics. */
#if 0
#define REDO_SECTION_INFO_P(DECL) \
- ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \
+ ((DECL_ATTRIBUTES (DECL) != NULL_TREE) \
|| (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL)))
#else
#define REDO_SECTION_INFO_P(DECL) 1
extern int ix86_data_alignment PARAMS ((tree, int));
extern int ix86_local_alignment PARAMS ((tree, int));
extern int ix86_constant_alignment PARAMS ((tree, int));
-extern int ix86_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
-extern int i386_pe_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
-extern int i386_pe_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
+extern tree ix86_handle_dll_attribute PARAMS ((tree *, tree, tree, int, bool *));
+extern tree ix86_handle_shared_attribute PARAMS ((tree *, tree, tree, int, bool *));
+
extern unsigned int i386_pe_section_type_flags PARAMS ((tree, const char *,
int));
extern void i386_pe_asm_named_section PARAMS ((const char *, unsigned int));
static int ix86_save_reg PARAMS ((int, int));
static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *));
static int ix86_comp_type_attributes PARAMS ((tree, tree));
+const struct attribute_spec ix86_attribute_table[];
+static tree ix86_handle_cdecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree ix86_handle_regparm_attribute PARAMS ((tree *, tree, tree, int, bool *));
#ifdef DO_GLOBAL_CTORS_BODY
static void ix86_svr3_asm_out_constructor PARAMS ((rtx, int));
#endif
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
-# define TARGET_VALID_TYPE_ATTRIBUTE i386_pe_valid_type_attribute_p
-# undef TARGET_VALID_DECL_ATTRIBUTE
-# define TARGET_VALID_DECL_ATTRIBUTE i386_pe_valid_decl_attribute_p
# undef TARGET_MERGE_DECL_ATTRIBUTES
# define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
-#else
-# define TARGET_VALID_TYPE_ATTRIBUTE ix86_valid_type_attribute_p
#endif
#undef TARGET_COMP_TYPE_ATTRIBUTES
#endif
}
\f
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
- attribute for TYPE. The attributes in ATTRIBUTES have previously been
- assigned to TYPE. */
-
-int
-ix86_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+/* Table of valid machine attributes. */
+const struct attribute_spec ix86_attribute_table[] =
{
- if (TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != METHOD_TYPE
- && TREE_CODE (type) != FIELD_DECL
- && TREE_CODE (type) != TYPE_DECL)
- return 0;
-
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
/* Stdcall attribute says callee is responsible for popping arguments
if they are not variable. */
- if (is_attribute_p ("stdcall", identifier)
- && !TARGET_64BIT)
- return (args == NULL_TREE);
-
- /* Cdecl attribute says the callee is a normal C declaration. */
- if (is_attribute_p ("cdecl", identifier)
- && !TARGET_64BIT)
- return (args == NULL_TREE);
-
+ { "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute },
+ /* Cdecl attribute says the callee is a normal C declaration */
+ { "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute },
/* Regparm attribute specifies how many integer arguments are to be
passed in registers. */
- if (is_attribute_p ("regparm", identifier))
+ { "regparm", 1, 1, false, true, true, ix86_handle_regparm_attribute },
+#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ { "dllimport", 1, 1, false, false, false, ix86_handle_dll_attribute },
+ { "dllexport", 1, 1, false, false, false, ix86_handle_dll_attribute },
+ { "shared", 1, 1, true, false, false, ix86_handle_shared_attribute },
+#endif
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Handle a "cdecl" or "stdcall" attribute;
+ arguments as in struct attribute_spec.handler. */
+static tree
+ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != METHOD_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
{
- tree cst;
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- if (! args || TREE_CODE (args) != TREE_LIST
- || TREE_CHAIN (args) != NULL_TREE
- || TREE_VALUE (args) == NULL_TREE)
- return 0;
+ if (TARGET_64BIT)
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- cst = TREE_VALUE (args);
- if (TREE_CODE (cst) != INTEGER_CST)
- return 0;
+ return NULL_TREE;
+}
- if (compare_tree_int (cst, REGPARM_MAX) > 0)
- return 0;
+/* Handle a "regparm" attribute;
+ arguments as in struct attribute_spec.handler. */
+static tree
+ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != METHOD_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
+ tree cst;
- return 1;
+ cst = TREE_VALUE (args);
+ if (TREE_CODE (cst) != INTEGER_CST)
+ {
+ warning ("`%s' attribute requires an integer constant argument",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (compare_tree_int (cst, REGPARM_MAX) > 0)
+ {
+ warning ("argument to `%s' attribute larger than %d",
+ IDENTIFIER_POINTER (name), REGPARM_MAX);
+ *no_add_attrs = true;
+ }
}
- return 0;
+ return NULL_TREE;
}
#if defined (OSF_OS) || defined (TARGET_OSF1ELF)
/* Subroutines for insn-output.c for Windows NT.
Contributed by Douglas Rupp (drupp@cs.washington.edu)
- Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
void i386_pe_mark_dllexport PARAMS ((tree));
void i386_pe_mark_dllimport PARAMS ((tree));
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ATTRIBUTES are any existing attributes and ARGS are the arguments
- supplied with ATTR. */
-
-int
-i386_pe_valid_decl_attribute_p (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
+/* Handle a "dllimport" or "dllexport" attribute;
+ arguments as in struct attribute_spec.handler. */
+tree
+ix86_handle_dll_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
tree args;
+ int flags;
+ bool *no_add_attrs;
{
- if (args == NULL_TREE)
+ /* These attributes may apply to structure and union types being created,
+ but otherwise should pass to the declaration involved. */
+ if (!DECL_P (*node))
{
- if (is_attribute_p ("dllexport", attr))
- return 1;
- if (is_attribute_p ("dllimport", attr))
- return 1;
- if (is_attribute_p ("shared", attr))
- return TREE_CODE (decl) == VAR_DECL;
+ if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
+ | (int) ATTR_FLAG_ARRAY_NEXT))
+ {
+ *no_add_attrs = true;
+ return tree_cons (name, args, NULL_TREE);
+ }
+ if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
}
- return 0;
+ return NULL_TREE;
}
-/* Return nonzero if ATTR is a valid attribute for TYPE.
- ATTRIBUTES are any existing attributes and ARGS are the arguments
- supplied with ATTR. */
-
-int
-i386_pe_valid_type_attribute_p (type, attributes, attr, args)
- tree type;
- tree attributes;
- tree attr;
- tree args;
+/* Handle a "shared" attribute;
+ arguments as in struct attribute_spec.handler. */
+tree
+ix86_handle_shared_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
- if (args == NULL_TREE
- && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
+ if (TREE_CODE (*node) != VAR_DECL)
{
- if (is_attribute_p ("dllexport", attr))
- return 1;
- if (is_attribute_p ("dllimport", attr))
- return 1;
+ warning ("`%s' attribute only applies to variables",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return ix86_valid_type_attribute_p (type, attributes, attr, args);
+ return NULL_TREE;
}
\f
/* Return the type that we should use to determine if DECL is
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
+ exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
if (exp)
return 1;
if (TREE_CODE (decl) != VAR_DECL
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
+ imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
if (imp)
return 1;
flags = SECTION_WRITE;
if (decl && TREE_CODE (decl) == VAR_DECL
- && lookup_attribute ("shared", DECL_MACHINE_ATTRIBUTES (decl)))
+ && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
flags |= SECTION_PE_SHARED;
}
static rtx ia64_expand_lock_test_and_set PARAMS ((enum machine_mode,
tree, rtx));
static rtx ia64_expand_lock_release PARAMS ((enum machine_mode, tree, rtx));
-static int ia64_valid_type_attribute PARAMS((tree, tree, tree, tree));
+const struct attribute_spec ia64_attribute_table[];
static void ia64_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void ia64_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void ia64_output_function_end_prologue PARAMS ((FILE *));
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE ia64_valid_type_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE ia64_attribute_table
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS ia64_init_builtins
}
}
-/* Return true if IDENTIFIER is a valid attribute for TYPE. */
-
-static int
-ia64_valid_type_attribute (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+/* Table of valid machine attributes. */
+const struct attribute_spec ia64_attribute_table[] =
{
- /* We only support an attribute for function calls. */
-
- if (TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != METHOD_TYPE)
- return 0;
-
- /* The "syscall_linkage" attribute says the callee is a system call entry
- point. This affects ia64_epilogue_uses. */
-
- if (is_attribute_p ("syscall_linkage", identifier))
- return args == NULL_TREE;
-
- return 0;
-}
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "syscall_linkage", 0, 0, false, true, true, NULL },
+ { NULL, 0, 0, false, false, false, NULL }
+};
\f
/* For ia64, SYMBOL_REF_FLAG set means that it is a function.
static void init_reg_tables PARAMS ((void));
static void block_move_call PARAMS ((rtx, rtx, rtx));
static int m32r_is_insn PARAMS ((rtx));
-static int m32r_valid_decl_attribute PARAMS ((tree, tree,
- tree, tree));
+const struct attribute_spec m32r_attribute_table[];
+static tree m32r_handle_model_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void m32r_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void m32r_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE m32r_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE m32r_attribute_table
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue
Grep for MODEL in m32r.h for more info.
*/
-static tree interrupt_ident1;
-static tree interrupt_ident2;
-static tree model_ident1;
-static tree model_ident2;
static tree small_ident1;
static tree small_ident2;
static tree medium_ident1;
static void
init_idents PARAMS ((void))
{
- if (interrupt_ident1 == 0)
+ if (small_ident1 == 0)
{
- interrupt_ident1 = get_identifier ("interrupt");
- interrupt_ident2 = get_identifier ("__interrupt__");
- model_ident1 = get_identifier ("model");
- model_ident2 = get_identifier ("__model__");
small_ident1 = get_identifier ("small");
small_ident2 = get_identifier ("__small__");
medium_ident1 = get_identifier ("medium");
}
}
-/* Return nonzero if IDENTIFIER is a valid decl attribute. */
+const struct attribute_spec m32r_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 0, 0, true, false, false, NULL },
+ { "model", 1, 1, true, false, false, m32r_handle_model_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
-static int
-m32r_valid_decl_attribute (type, attributes, identifier, args)
- tree type ATTRIBUTE_UNUSED;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
+
+/* Handle an "model" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+m32r_handle_model_attribute (node, name, args, flags, no_add_attrs)
+ tree *node ATTRIBUTE_UNUSED;
+ tree name;
tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
- init_idents ();
-
- if ((identifier == interrupt_ident1
- || identifier == interrupt_ident2)
- && list_length (args) == 0)
- return 1;
+ tree arg;
- if ((identifier == model_ident1
- || identifier == model_ident2)
- && list_length (args) == 1
- && (TREE_VALUE (args) == small_ident1
- || TREE_VALUE (args) == small_ident2
- || TREE_VALUE (args) == medium_ident1
- || TREE_VALUE (args) == medium_ident2
- || TREE_VALUE (args) == large_ident1
- || TREE_VALUE (args) == large_ident2))
- return 1;
+ init_idents ();
+ arg = TREE_VALUE (args);
+
+ if (arg != small_ident1
+ && arg != small_ident2
+ && arg != medium_ident1
+ && arg != medium_ident2
+ && arg != large_ident1
+ && arg != large_ident2)
+ {
+ warning ("invalid argument of `%s' attribute",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- return 0;
+ return NULL_TREE;
}
\f
/* A C statement or statements to switch to the appropriate
{
case VAR_DECL :
case FUNCTION_DECL :
- model = lookup_attribute ("model", DECL_MACHINE_ATTRIBUTES (decl));
+ model = lookup_attribute ("model", DECL_ATTRIBUTES (decl));
break;
case STRING_CST :
case CONSTRUCTOR :
return fn_type;
/* Compute function type. */
- fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE
+ fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE
? M32R_FUNCTION_INTERRUPT
: M32R_FUNCTION_NORMAL);
static int must_parenthesize PARAMS ((rtx));
static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
static int m68hc11_auto_inc_p PARAMS ((rtx));
-static int m68hc11_valid_type_attribute_p PARAMS((tree, tree,
- tree, tree));
+static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec m68hc11_attribute_table[];
void create_regs_rtx PARAMS ((void));
static void m68hc11_add_gc_roots PARAMS ((void));
static int nb_soft_regs;
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE m68hc11_valid_type_attribute_p
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
\f
/* Declaration of types. */
-/* If defined, a C expression whose value is nonzero if IDENTIFIER
- with arguments ARGS is a valid machine specific attribute for TYPE.
- The attributes in ATTRIBUTES have previously been assigned to TYPE. */
-
-static int
-m68hc11_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+const struct attribute_spec m68hc11_attribute_table[] =
{
- if (TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
- return 0;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
+ { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (TREE_CODE (type) == FUNCTION_TYPE)
+/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
+ arguments as in struct attribute_spec.handler. */
+static tree
+m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
{
- if (is_attribute_p ("interrupt", identifier))
- return (args == NULL_TREE);
- if (is_attribute_p ("trap", identifier))
- return (args == NULL_TREE);
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 0;
+ return NULL_TREE;
}
/* Define this macro if references to a symbol must be treated
static void mcore_mark_dllimport PARAMS ((tree));
static int mcore_dllexport_p PARAMS ((tree));
static int mcore_dllimport_p PARAMS ((tree));
-static int mcore_valid_decl_attribute PARAMS ((tree, tree,
- tree, tree));
+const struct attribute_spec mcore_attribute_table[];
+static tree mcore_handle_naked_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void mcore_asm_named_section PARAMS ((const char *,
unsigned int));
\f
#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
#endif
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE mcore_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE mcore_attribute_table
struct gcc_target targetm = TARGET_INITIALIZER;
\f
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- return lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)) != 0;
+ return lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)) != 0;
}
static int
&& TREE_CODE (decl) != FUNCTION_DECL)
return 0;
- return lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)) != 0;
+ return lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)) != 0;
}
/* Cover function to implement ENCODE_SECTION_INFO. */
dllexport - for exporting a function/variable that will live in a dll
dllimport - for importing a function/variable from a dll
naked - do not create a function prologue/epilogue. */
-static int
-mcore_valid_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args;
-{
- if (args != NULL_TREE)
- return 0;
- if (is_attribute_p ("dllexport", attr))
- return 1;
+const struct attribute_spec mcore_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "dllexport", 0, 0, true, false, false, NULL },
+ { "dllimport", 0, 0, true, false, false, NULL },
+ { "naked", 0, 0, true, false, false, mcore_handle_naked_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("dllimport", attr))
- return 1;
-
- if (is_attribute_p ("naked", attr) &&
- TREE_CODE (decl) == FUNCTION_DECL)
+/* Handle a "naked" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+mcore_handle_naked_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL)
{
/* PR14310 - don't complain about lack of return statement
in naked functions. The solution here is a gross hack
}
else if (saved_warn_return_type_count)
saved_warn_return_type_count = 2;
-
- return 1;
+ }
+ else
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 0;
+ return NULL_TREE;
}
/* Cover function for UNIQUE_SECTION. */
int
mcore_naked_function_p ()
{
- return lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE;
+ return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
}
static void
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
+#include "toplev.h"
#ifdef OSF_OS
int ns32k_num_files = 0;
static rtx gen_indexed_expr PARAMS ((rtx, rtx, rtx));
static const char *singlemove_string PARAMS ((rtx *));
static void move_tail PARAMS ((rtx[], int, int));
-static int ns32k_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
+static tree ns32k_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec ns32k_attribute_table[];
static void ns32k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void ns32k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE ns32k_valid_type_attribute_p
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE ns32k_attribute_table
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE ns32k_output_function_prologue
return 0;
}
\f
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
- attribute for TYPE. The attributes in ATTRIBUTES have previously been
- assigned to TYPE. */
-
-static int
-ns32k_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
-{
- if (TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != FIELD_DECL
- && TREE_CODE (type) != TYPE_DECL)
- return 0;
+/* Table of machine-specific attributes. */
+const struct attribute_spec ns32k_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
/* Stdcall attribute says callee is responsible for popping arguments
if they are not variable. */
- if (is_attribute_p ("stdcall", identifier))
- return (args == NULL_TREE);
-
+ { "stdcall", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
/* Cdecl attribute says the callee is a normal C declaration */
- if (is_attribute_p ("cdecl", identifier))
- return (args == NULL_TREE);
+ { "cdecl", 0, 0, false, true, true, ns32k_handle_fntype_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- return 0;
+/* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
+ arguments as in struct attribute_spec.handler. */
+static tree
+ns32k_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
}
\f
static void rs6000_free_machine_status PARAMS ((struct function *));
static void rs6000_init_machine_status PARAMS ((struct function *));
static int rs6000_ra_ever_killed PARAMS ((void));
-static int rs6000_valid_type_attribute_p PARAMS ((tree, tree, tree, tree));
+static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
+const struct attribute_spec rs6000_attribute_table[];
static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static rtx rs6000_emit_set_long_const PARAMS ((rtx,
#endif
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE rs6000_valid_type_attribute_p
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
}
\f
-/* If defined, a C expression whose value is nonzero if IDENTIFIER
- with arguments ARGS is a valid machine specific attribute for TYPE.
- The attributes in ATTRIBUTES have previously been assigned to TYPE. */
-
-static int
-rs6000_valid_type_attribute_p (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
- tree args;
+/* Table of valid machine attributes. */
+const struct attribute_spec rs6000_attribute_table[] =
{
- if (TREE_CODE (type) != FUNCTION_TYPE
- && TREE_CODE (type) != FIELD_DECL
- && TREE_CODE (type) != TYPE_DECL)
- return 0;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- /* Longcall attribute says that the function is not within 2**26 bytes
- of the current function, and to do an indirect call. */
- if (is_attribute_p ("longcall", identifier))
- return (args == NULL_TREE);
+/* Handle a "longcall" attribute;
+ arguments as in struct attribute_spec.handler. */
+static tree
+rs6000_handle_longcall_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != FIELD_DECL
+ && TREE_CODE (*node) != TYPE_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- return 0;
+ return NULL_TREE;
}
/* Return a reference suitable for calling a function with the
static void mark_use PARAMS ((rtx, rtx *));
static HOST_WIDE_INT rounded_frame_size PARAMS ((int));
static rtx mark_constant_pool_use PARAMS ((rtx));
-static int sh_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+const struct attribute_spec sh_attribute_table[];
+static tree sh_handle_interrupt_handler_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree sh_handle_sp_switch_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree sh_handle_trap_exit_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void sh_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void sh_insert_attributes PARAMS ((tree, tree *));
static void sh_asm_named_section PARAMS ((const char *, unsigned int));
static int sh_adjust_cost PARAMS ((rtx, rtx, rtx, int));
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE sh_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sh_attribute_table
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue
if ((lookup_attribute
("interrupt_handler",
- DECL_MACHINE_ATTRIBUTES (current_function_decl)))
+ DECL_ATTRIBUTES (current_function_decl)))
!= NULL_TREE)
interrupt_handler = 1;
else
if ((lookup_attribute
("interrupt_handler",
- DECL_MACHINE_ATTRIBUTES (current_function_decl)))
+ DECL_ATTRIBUTES (current_function_decl)))
!= NULL_TREE)
interrupt_handler = 1;
else
current_function_interrupt
= lookup_attribute ("interrupt_handler",
- DECL_MACHINE_ATTRIBUTES (current_function_decl))
+ DECL_ATTRIBUTES (current_function_decl))
!= NULL_TREE;
/* We have pretend args if we had an object sent partially in registers
return;
}
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ATTRIBUTES are any existing attributes and ARGS are the arguments
- supplied with ATTR.
-
- Supported attributes:
+/* Supported attributes:
interrupt_handler -- specifies this function is an interrupt handler.
trap_exit -- use a trapa to exit an interrupt function instead of
an rte instruction. */
-static int
-sh_valid_decl_attribute (decl, attributes, attr, args)
- tree decl;
- tree attributes ATTRIBUTE_UNUSED;
- tree attr;
- tree args;
+const struct attribute_spec sh_attribute_table[] =
{
- if (TREE_CODE (decl) != FUNCTION_DECL)
- return 0;
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute },
+ { "sp_switch", 1, 1, true, false, false, sh_handle_sp_switch_attribute },
+ { "trap_exit", 1, 1, true, false, false, sh_handle_trap_exit_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
- if (is_attribute_p ("interrupt_handler", attr))
+/* Handle an "interrupt_handler" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+sh_handle_interrupt_handler_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
{
- return 1;
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- if (is_attribute_p ("sp_switch", attr))
+ return NULL_TREE;
+}
+
+/* Handle an "sp_switch" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+sh_handle_sp_switch_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (!pragma_interrupt)
{
/* The sp_switch attribute only has meaning for interrupt functions. */
- if (!pragma_interrupt)
- return 0;
-
- /* sp_switch must have an argument. */
- if (!args || TREE_CODE (args) != TREE_LIST)
- return 0;
-
+ warning ("`%s' attribute only applies to interrupt functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
/* The argument must be a constant string. */
- if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
- return 0;
-
+ warning ("`%s' attribute argument not a string constant",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
sp_switch = gen_rtx_SYMBOL_REF (VOIDmode,
TREE_STRING_POINTER (TREE_VALUE (args)));
- return 1;
}
- if (is_attribute_p ("trap_exit", attr))
+ return NULL_TREE;
+}
+
+/* Handle an "trap_exit" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+sh_handle_trap_exit_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (!pragma_interrupt)
{
/* The trap_exit attribute only has meaning for interrupt functions. */
- if (!pragma_interrupt)
- return 0;
-
- /* trap_exit must have an argument. */
- if (!args || TREE_CODE (args) != TREE_LIST)
- return 0;
-
+ warning ("`%s' attribute only applies to interrupt functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+ {
/* The argument must be a constant integer. */
- if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
- return 0;
-
+ warning ("`%s' attribute argument not an integer constant",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ {
trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args));
- return 1;
}
- return 0;
+ return NULL_TREE;
}
\f
return lookup_attribute ("interrupt", attributes) != NULL_TREE;
}
-/* If defined, a C function which returns nonzero if IDENTIFIER
- with arguments ARGS is a valid machine specific attribute for TYPE.
- The attributes in ATTRIBUTES have previously been assigned to TYPE. */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE stormy16_valid_type_attribute
-static int stormy16_valid_type_attribute PARAMS ((tree TYPE,
- tree ATTRIBUTES,
- tree IDENTIFIER,
- tree ARGS));
-
-static int
-stormy16_valid_type_attribute (type, attributes, identifier, args)
- tree type;
- tree attributes ATTRIBUTE_UNUSED;
- tree identifier;
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE stormy16_attribute_table
+static tree stormy16_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static const struct attribute_spec stormy16_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 0, 0, false, true, true, stormy16_handle_interrupt_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Handle an "interrupt" attribute;
+ arguments as in struct attribute_spec.handler. */
+static tree
+stormy16_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
- if (TREE_CODE (type) != FUNCTION_TYPE)
- return 0;
-
- if (is_attribute_p ("interrupt", identifier))
- return 1;
+ if (TREE_CODE (*node) != FUNCTION_TYPE)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
- return 0;
+ return NULL_TREE;
}
\f
struct gcc_target targetm = TARGET_INITIALIZER;
FUNDECL is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_DECL' that
describes the declaration of the function. From this it is possible to
- obtain the DECL_MACHINE_ATTRIBUTES of the function.
+ obtain the DECL_ATTRIBUTES of the function.
FUNTYPE is a C variable whose value is a tree node that describes the
function in question. Normally it is a node of type `FUNCTION_TYPE' that
\f
static int pop_data_area PARAMS ((v850_data_area));
static int push_data_area PARAMS ((v850_data_area));
-static int mark_current_function_as_interrupt PARAMS ((void));
+static void mark_current_function_as_interrupt PARAMS ((void));
\f
/* Push a data area onto the stack. */
/* Set the machine specific 'interrupt' attribute on the current function. */
-static int
+static void
mark_current_function_as_interrupt ()
{
tree name;
return 0;
}
- return valid_machine_attribute
- (name, NULL_TREE, current_function_decl, NULL_TREE);
+ decl_attributes (¤t_function_decl,
+ tree_cons (name, NULL_TREE, NULL_TREE), 0);
}
\f
static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
static int ep_memory_offset PARAMS ((enum machine_mode, int));
static void v850_set_data_area PARAMS ((tree, v850_data_area));
-static int v850_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+const struct attribute_spec v850_attribute_table[];
+static tree v850_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree v850_handle_data_area_attribute PARAMS ((tree *, tree, tree, int, bool *));
static void v850_insert_attributes PARAMS ((tree, tree *));
/* True if the current function has anonymous arguments. */
static int v850_interrupt_p = FALSE;
\f
/* Initialize the GCC target structure. */
-#undef TARGET_VALID_DECL_ATTRIBUTE
-#define TARGET_VALID_DECL_ATTRIBUTE v850_valid_decl_attribute
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
v850_get_data_area (decl)
tree decl;
{
- if (lookup_attribute ("sda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_SDA;
- if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_TDA;
- if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_ZDA;
return DATA_AREA_NORMAL;
return;
}
- DECL_MACHINE_ATTRIBUTES (decl) = tree_cons
- (name, NULL, DECL_MACHINE_ATTRIBUTES (decl));
+ DECL_ATTRIBUTES (decl) = tree_cons
+ (name, NULL, DECL_ATTRIBUTES (decl));
}
\f
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ARGS are the arguments supplied with ATTR. */
+const struct attribute_spec v850_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt_handler", 0, 0, true, false, false, v850_handle_interrupt_attribute },
+ { "interrupt", 0, 0, true, false, false, v850_handle_interrupt_attribute },
+ { "sda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { "tda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { "zda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
-static int
-v850_valid_decl_attribute (decl, unused, attr, args)
- tree decl;
- tree unused ATTRIBUTE_UNUSED;
- tree attr;
- tree args;
+/* Handle an "interrupt" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "sda", "tda" or "zda" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_data_area_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
v850_data_area data_area;
v850_data_area area;
-
- if (args != NULL_TREE)
- return 0;
-
- if (is_attribute_p ("interrupt_handler", attr)
- || is_attribute_p ("interrupt", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ tree decl = *node;
/* Implement data area attribute. */
- if (is_attribute_p ("sda", attr))
+ if (is_attribute_p ("sda", name))
data_area = DATA_AREA_SDA;
- else if (is_attribute_p ("tda", attr))
+ else if (is_attribute_p ("tda", name))
data_area = DATA_AREA_TDA;
- else if (is_attribute_p ("zda", attr))
+ else if (is_attribute_p ("zda", name))
data_area = DATA_AREA_ZDA;
else
- return 0;
+ abort ();
switch (TREE_CODE (decl))
{
case VAR_DECL:
if (current_function_decl != NULL_TREE)
- error_with_decl (decl, "\
+ {
+ error_with_decl (decl, "\
a data area attribute cannot be specified for local variables");
-
+ *no_add_attrs = true;
+ }
+
/* Drop through. */
case FUNCTION_DECL:
area = v850_get_data_area (decl);
if (area != DATA_AREA_NORMAL && data_area != area)
- error_with_decl (decl, "\
+ {
+ error_with_decl (decl, "\
data area of '%s' conflicts with previous declaration");
-
- return 1;
+ *no_add_attrs = true;
+ }
+ break;
default:
break;
}
-
- return 0;
+
+ return NULL_TREE;
}
\f
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
if (a != NULL_TREE)
ret = 1;
else
{
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
ret = a != NULL_TREE;
}
+2001-09-21 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ Table-driven attributes.
+ * decl.c: Rename DECL_MACHINE_ATTRIBUTES to DECL_ATTRIBUTES.
+ * decl2.c (cplus_decl_attributes): Only take one attributes
+ parameter.
+ * cp-tree.c (cplus_decl_attributes): Update prototype.
+ * class.c (finish_struct), decl.c (start_decl, start_function),
+ decl2.c (grokfield), friend.c (do_friend), parse.y
+ (parse_bitfield): Update calls to cplus_decl_attributes.
+ * decl.c (grokdeclarator): Take a pointer to a single ordinary
+ attribute list.
+ * decl.h (grokdeclarator): Update prototype.
+ * decl2.c (grokfield): Take a single ordinary attribute list.
+ * friend.c (do_friend): Likewise.
+ * decl.c (shadow_tag, groktypename, start_decl,
+ start_handler_parms, grokdeclarator, grokparms, start_function,
+ start_method), decl2.c (grokfield, grokbitfield, grokoptypename),
+ parse.y (parse_field, parse_bitfield, component_decl_1), pt.c
+ (process_template_parm, do_decl_instantiation): Pass single
+ ordinary attribute lists around.
+ * decl.c (grokdeclarator): Correct handling of nested attributes.
+ Revert the patch
+ 1998-10-18 Jason Merrill <jason@yorick.cygnus.com>
+ * decl.c (grokdeclarator): Embedded attrs bind to the right,
+ not the left.
+ .
+ * cp-tree.h (cp_valid_lang_attribute): Remove declaration
+ (cp_attribute_table): Declare.
+ * decl.c (valid_lang_attribute): Don't define.
+ (lang_attribute_table): Define.
+ (init_decl_processing): Initialize lang_attribute_table instead of
+ valid_lang_attribute.
+ * tree.c (cp_valid_lang_attribute): Remove.
+ (handle_java_interface_attribute, handle_com_interface_attribute,
+ handle_init_priority_attribute): New functions.
+ (cp_attribute_table): New array.
+ * decl2.c (import_export_class): Don't use
+ targetm.valid_type_attribute.
+
2001-09-15 Gabriel Dos Reis <gdr@merlin.codesourcery.com>
* Make-lang.in (cp/error.o): Depend on real.h
as necessary. */
unreverse_member_declarations (t);
- cplus_decl_attributes (&t, attributes, NULL_TREE, 0);
+ cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
/* Nadger the current location so that diagnostics point to the start of
the struct, not the end. */
extern tree groktypefield PARAMS ((tree, tree));
extern tree grokoptypename PARAMS ((tree, tree));
extern int copy_assignment_arg_p PARAMS ((tree, int));
-extern void cplus_decl_attributes PARAMS ((tree *, tree, tree, int));
+extern void cplus_decl_attributes PARAMS ((tree *, tree, int));
extern tree constructor_name_full PARAMS ((tree));
extern tree constructor_name PARAMS ((tree));
extern void defer_fn PARAMS ((tree));
walk_tree_fn,
void *));
extern tree copy_tree_r PARAMS ((tree *, int *, void *));
-extern int cp_valid_lang_attribute PARAMS ((tree, tree, tree, tree));
+extern const struct attribute_spec cp_attribute_table[];
extern tree make_ptrmem_cst PARAMS ((tree, tree));
extern tree cp_build_qualified_type_real PARAMS ((tree, int, int));
extern void remap_save_expr PARAMS ((tree *, splay_tree, tree, int *));
#include "tm_p.h"
#include "target.h"
-extern int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree));
+extern const struct attribute_spec *lang_attribute_table;
#ifndef BOOL_TYPE_SIZE
/* `bool' has size and alignment `1', on all platforms. */
/* Copy all the DECL_... slots specified in the new decl
except for any that we copy here from the old type. */
- DECL_MACHINE_ATTRIBUTES (newdecl)
+ DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
/* NEWDECL contains the merged attribute lists.
Update OLDDECL to be the same. */
- DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
+ DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
return 1;
}
/* Show we use EH for cleanups. */
using_eh_for_cleanups ();
- valid_lang_attribute = cp_valid_lang_attribute;
+ lang_attribute_table = cp_attribute_table;
/* Maintain consistency. Perhaps we should just complain if they
say -fwritable-strings? */
if (TYPE_FIELDS (t))
{
tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
- NULL_TREE);
+ NULL);
finish_anon_union (decl);
}
}
return typename;
return grokdeclarator (TREE_VALUE (typename),
TREE_PURPOSE (typename),
- TYPENAME, 0, NULL_TREE);
+ TYPENAME, 0, NULL);
}
/* Decode a declarator in an ordinary declaration or data definition.
tree context;
extern int have_extern_spec;
extern int used_extern_spec;
- tree attrlist;
#if 0
/* See code below that used this. */
used_extern_spec = 1;
}
- if (attributes || prefix_attributes)
- attrlist = build_tree_list (attributes, prefix_attributes);
- else
- attrlist = NULL_TREE;
+ attributes = chainon (attributes, prefix_attributes);
decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
- attrlist);
+ &attributes);
if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE)
return NULL_TREE;
}
/* Set attributes here so if duplicate decl, will have proper attributes. */
- cplus_decl_attributes (&decl, attributes, prefix_attributes, 0);
+ cplus_decl_attributes (&decl, attributes, 0);
if (context && COMPLETE_TYPE_P (complete_type (context)))
{
if (declspecs)
{
decl = grokdeclarator (declarator, declspecs, CATCHPARM,
- 1, NULL_TREE);
+ 1, NULL);
if (decl == NULL_TREE)
error ("invalid catch parameter");
}
BITFIELD for a field with specified width.
INITIALIZED is 1 if the decl has an initializer.
- ATTRLIST is a TREE_LIST node with prefix attributes in TREE_VALUE and
- normal attributes in TREE_PURPOSE, or NULL_TREE.
+ ATTRLIST is a pointer to the list of attributes, which may be NULL
+ if there are none; *ATTRLIST may be modified if attributes from inside
+ the declarator should be applied to the declaration.
In the TYPENAME case, DECLARATOR is really an abstract declarator.
It may also be so in the PARM case, for a prototype where the
tree declarator;
enum decl_context decl_context;
int initialized;
- tree attrlist;
+ tree *attrlist;
{
RID_BIT_TYPE specbits;
int nclasses = 0;
int bitfield = 0;
#if 0
/* See the code below that used this. */
- tree decl_machine_attr = NULL_TREE;
+ tree decl_attr = NULL_TREE;
#endif
/* Set this to error_mark_node for FIELD_DECLs we could not handle properly.
All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */
tree raises = NULL_TREE;
int template_count = 0;
tree in_namespace = NULL_TREE;
- tree inner_attrs;
- int ignore_attrs;
+ tree returned_attrs = NULL_TREE;
RIDBIT_RESET_ALL (specbits);
if (decl_context == FUNCDEF)
cp_finish_decl so we can get the variable
initialized... */
- tree attributes, prefix_attributes;
+ tree attributes;
*next = TREE_OPERAND (decl, 0);
init = CALL_DECLARATOR_PARMS (decl);
if (attrlist)
{
- attributes = TREE_PURPOSE (attrlist);
- prefix_attributes = TREE_VALUE (attrlist);
+ attributes = *attrlist;
}
else
{
attributes = NULL_TREE;
- prefix_attributes = NULL_TREE;
}
decl = start_decl (declarator, declspecs, 1,
- attributes, prefix_attributes);
+ attributes, NULL_TREE);
decl_type_access_control (decl);
if (decl)
{
type = TREE_TYPE (t);
#if 0
/* See the code below that used this. */
- decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
+ decl_attr = DECL_ATTRIBUTES (id);
#endif
typedef_decl = t;
}
Descend through it, creating more complex types, until we reach
the declared identifier (or NULL_TREE, in an absolute declarator). */
- inner_attrs = NULL_TREE;
- ignore_attrs = 0;
-
while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
&& TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
{
}
}
- /* See the comment for the TREE_LIST case, below. */
- if (ignore_attrs)
- ignore_attrs = 0;
- else if (inner_attrs)
- {
- decl_attributes (&type, inner_attrs, 0);
- inner_attrs = NULL_TREE;
- }
-
switch (TREE_CODE (declarator))
{
case TREE_LIST:
{
/* We encode a declarator with embedded attributes using
- a TREE_LIST. The attributes apply to the declarator
- directly inside them, so we have to skip an iteration
- before applying them to the type. If the declarator just
- inside is the declarator-id, we apply the attrs to the
- decl itself. */
- inner_attrs = TREE_PURPOSE (declarator);
- ignore_attrs = 1;
+ a TREE_LIST. */
+ tree attrs = TREE_PURPOSE (declarator);
+ tree inner_decl;
declarator = TREE_VALUE (declarator);
+ inner_decl = declarator;
+ while (inner_decl != NULL_TREE
+ && TREE_CODE (inner_decl) == TREE_LIST)
+ inner_decl = TREE_VALUE (inner_decl);
+ int attr_flags = 0;
+ if (inner_decl == NULL_TREE
+ || TREE_CODE (inner_decl) == IDENTIFIER_NODE)
+ attr_flags |= (int) ATTR_FLAG_DECL_NEXT;
+ if (TREE_CODE (inner_decl) == CALL_EXPR)
+ attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT;
+ if (TREE_CODE (inner_decl) == ARRAY_REF)
+ attr_flags |= (int) ATTR_FLAG_ARRAY_NEXT;
+ returned_attrs = decl_attributes (&type,
+ chainon (returned_attrs, attrs),
+ attr_flags);
}
break;
}
}
- /* See the comment for the TREE_LIST case, above. */
- if (inner_attrs)
+ if (returned_attrs)
{
- if (! ignore_attrs)
- decl_attributes (&type, inner_attrs, 0);
- else if (attrlist)
- TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist));
+ if (attrlist)
+ *attrlist = chainon (returned_attrs, *attrlist);
else
- attrlist = build_tree_list (NULL_TREE, inner_attrs);
+ attrlist = &returned_attrs;
}
/* Now TYPE has the actual type. */
return decl;
#if 0
/* This clobbers the attrs stored in `decl' from `attrlist'. */
- /* The decl and setting of decl_machine_attr is also turned off. */
- decl = build_decl_attribute_variant (decl, decl_machine_attr);
+ /* The decl and setting of decl_attr is also turned off. */
+ decl = build_decl_attribute_variant (decl, decl_attr);
#endif
/* [class.conv.ctor]
}
t = do_friend (ctype, declarator, decl,
- last_function_parms, attrlist, flags, quals,
+ last_function_parms, *attrlist, flags, quals,
funcdef_flag);
}
if (t && funcdef_flag)
break;
decl = grokdeclarator (TREE_VALUE (decl), TREE_PURPOSE (decl),
- PARM, init != NULL_TREE, NULL_TREE);
+ PARM, init != NULL_TREE, NULL);
if (! decl || TREE_TYPE (decl) == error_mark_node)
continue;
}
else
{
- decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE);
+ decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0;
pushlevel (0);
current_binding_level->parm_flag = 1;
- cplus_decl_attributes (&decl1, NULL_TREE, attrs, 0);
+ cplus_decl_attributes (&decl1, attrs, 0);
/* Promote the value to int before returning it. */
if (c_promoting_integer_type_p (restype))
tree declarator, declspecs, attrlist;
{
tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
- attrlist);
+ &attrlist);
/* Something too ugly to handle. */
if (fndecl == NULL_TREE)
};
/* We need this in here to get the decl_context definition. */
-extern tree grokdeclarator PARAMS ((tree, tree, enum decl_context, int, tree));
+extern tree grokdeclarator PARAMS ((tree, tree, enum decl_context, int, tree *));
/* Parsing a function declarator leaves a list of parameter names
or a chain or parameter decls here. */
&& TREE_CHAIN (init) == NULL_TREE)
init = NULL_TREE;
- value = grokdeclarator (declarator, declspecs, FIELD, init != 0, attrlist);
+ value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);
if (! value || value == error_mark_node)
/* friend or constructor went bad. */
return value;
value = push_template_decl (value);
if (attrlist)
- cplus_decl_attributes (&value, TREE_PURPOSE (attrlist),
- TREE_VALUE (attrlist), 0);
+ cplus_decl_attributes (&value, attrlist, 0);
if (TREE_CODE (value) == VAR_DECL)
{
tree declarator, declspecs, width;
{
register tree value = grokdeclarator (declarator, declspecs, BITFIELD,
- 0, NULL_TREE);
+ 0, NULL);
if (! value) return NULL_TREE; /* friends went bad. */
grokoptypename (declspecs, declarator)
tree declspecs, declarator;
{
- tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE);
+ tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL);
return mangle_conv_op_name_for_type (t);
}
}
\f
void
-cplus_decl_attributes (decl, attributes, prefix_attributes, flags)
- tree *decl, attributes, prefix_attributes;
+cplus_decl_attributes (decl, attributes, flags)
+ tree *decl, attributes;
int flags;
{
if (*decl == NULL_TREE || *decl == void_type_node)
if (TREE_CODE (*decl) == TEMPLATE_DECL)
decl = &DECL_TEMPLATE_RESULT (*decl);
- decl_attributes (decl, chainon (attributes, prefix_attributes), flags);
+ decl_attributes (decl, attributes, flags);
if (TREE_CODE (*decl) == TYPE_DECL)
SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
if (CLASSTYPE_INTERFACE_ONLY (ctype))
return;
- if ((*targetm.valid_type_attribute) (ctype,
- TYPE_ATTRIBUTES (ctype),
- get_identifier ("dllimport"),
- NULL_TREE)
- && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
+ if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
import_export = -1;
- else if ((*targetm.valid_type_attribute) (ctype,
- TYPE_ATTRIBUTES (ctype),
- get_identifier ("dllexport"),
- NULL_TREE)
- && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
+ else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
import_export = 1;
/* If we got -fno-implicit-templates, we import template classes that
int funcdef_flag;
{
int is_friend_template = 0;
- tree prefix_attributes, attributes;
/* Every decl that gets here is a friend of something. */
DECL_FRIEND_P (decl) = 1;
handle them in start_decl_1, but since this is a friend decl start_decl_1
never gets to see it. */
- if (attrlist)
- {
- attributes = TREE_PURPOSE (attrlist);
- prefix_attributes = TREE_VALUE (attrlist);
- }
- else
- {
- attributes = NULL_TREE;
- prefix_attributes = NULL_TREE;
- }
-
/* Set attributes here so if duplicate decl, will have proper attributes. */
- cplus_decl_attributes (&decl, attributes, prefix_attributes, 0);
+ cplus_decl_attributes (&decl, attrlist, 0);
return decl;
}
tree declarator, attributes, asmspec, init;
{
tree d = grokfield (declarator, current_declspecs, init, asmspec,
- build_tree_list (attributes, prefix_attributes));
+ chainon (attributes, prefix_attributes));
decl_type_access_control (d);
return d;
}
tree declarator, attributes, width;
{
tree d = grokbitfield (declarator, current_declspecs, width);
- cplus_decl_attributes (&d, attributes, prefix_attributes, 0);
+ cplus_decl_attributes (&d, chainon (attributes, prefix_attributes), 0);
decl_type_access_control (d);
return d;
}
$$ = NULL_TREE;
}
| notype_declarator maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, NULL_TREE, $4, $2,
- build_tree_list ($3, NULL_TREE)); }
+ { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
| constructor_declarator maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, NULL_TREE, $4, $2,
- build_tree_list ($3, NULL_TREE)); }
+ { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
| ':' expr_no_commas
{ $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
| error
{ tree specs, attrs;
split_specs_attrs ($1.t, &specs, &attrs);
$$ = grokfield ($2, specs, $5, $3,
- build_tree_list ($4, attrs)); }
+ chainon ($4, attrs)); }
| component_constructor_declarator maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, NULL_TREE, $4, $2,
- build_tree_list ($3, NULL_TREE)); }
+ { $$ = grokfield ($$, NULL_TREE, $4, $2, $3); }
| using_decl
{ $$ = do_class_using_decl ($1); }
my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260);
/* is a const-param */
parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm),
- PARM, 0, NULL_TREE);
+ PARM, 0, NULL);
/* [temp.param]
do_decl_instantiation (declspecs, declarator, storage)
tree declspecs, declarator, storage;
{
- tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL_TREE);
+ tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL);
tree result = NULL_TREE;
int extern_p = 0;
static tree find_tree_r PARAMS ((tree *, int *, void *));
extern int cp_statement_code_p PARAMS ((enum tree_code));
+static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_init_priority_attribute PARAMS ((tree *, tree, tree, int, bool *));
+
/* If REF is an lvalue, returns the kind of lvalue that REF is.
Otherwise, returns clk_none. If TREAT_CLASS_RVALUES_AS_LVALUES is
non-zero, rvalues of class type are considered lvalues. */
return 1;
}
-/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific
- attribute for either declaration DECL or type TYPE and 0 otherwise.
- Plugged into valid_lang_attribute. */
-
-int
-cp_valid_lang_attribute (attr_name, attr_args, decl, type)
- tree attr_name;
- tree attr_args ATTRIBUTE_UNUSED;
- tree decl ATTRIBUTE_UNUSED;
- tree type ATTRIBUTE_UNUSED;
+/* Table of valid C++ attributes. */
+const struct attribute_spec cp_attribute_table[] =
{
- if (is_attribute_p ("java_interface", attr_name))
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "java_interface", 0, 0, false, false, false, handle_java_interface_attribute },
+ { "com_interface", 0, 0, false, false, false, handle_com_interface_attribute },
+ { "init_priority", 1, 1, true, false, false, handle_init_priority_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Handle a "java_interface" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_java_interface_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags;
+ bool *no_add_attrs;
+{
+ if (DECL_P (*node)
+ || !CLASS_TYPE_P (*node)
+ || !TYPE_FOR_JAVA (*node))
{
- if (attr_args != NULL_TREE
- || decl != NULL_TREE
- || ! CLASS_TYPE_P (type)
- || ! TYPE_FOR_JAVA (type))
- {
- error ("`java_interface' attribute can only be applied to Java class definitions");
- return 0;
- }
- TYPE_JAVA_INTERFACE (type) = 1;
- return 1;
+ error ("`%s' attribute can only be applied to Java class definitions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
}
- if (is_attribute_p ("com_interface", attr_name))
- {
- static int warned;
- if (attr_args != NULL_TREE
- || decl != NULL_TREE
- || ! CLASS_TYPE_P (type)
- || type != TYPE_MAIN_VARIANT (type))
- {
- warning ("`com_interface' attribute can only be applied to class definitions");
- return 0;
- }
+ if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+ *node = build_type_copy (*node);
+ TYPE_JAVA_INTERFACE (*node) = 1;
- if (! warned++)
- warning ("\
-`com_interface' is obsolete; g++ vtables are now COM-compatible by default");
- return 1;
- }
- else if (is_attribute_p ("init_priority", attr_name))
+ return NULL_TREE;
+}
+
+/* Handle a "com_interface" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_com_interface_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ static int warned;
+
+ *no_add_attrs = true;
+
+ if (DECL_P (*node)
+ || !CLASS_TYPE_P (*node)
+ || *node != TYPE_MAIN_VARIANT (*node))
{
- tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
- int pri;
+ warning ("`%s' attribute can only be applied to class definitions",
+ IDENTIFIER_POINTER (name));
+ return NULL_TREE;
+ }
- if (initp_expr)
- STRIP_NOPS (initp_expr);
+ if (!warned++)
+ warning ("`%s' is obsolete; g++ vtables are now COM-compatible by default",
+ IDENTIFIER_POINTER (name));
+
+ return NULL_TREE;
+}
+
+/* Handle an "init_priority" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_init_priority_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree initp_expr = TREE_VALUE (args);
+ tree decl = *node;
+ tree type = TREE_TYPE (decl);
+ int pri;
+
+ STRIP_NOPS (initp_expr);
- if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
- {
- error ("requested init_priority is not an integer constant");
- return 0;
- }
+ if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
+ {
+ error ("requested init_priority is not an integer constant");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
- pri = TREE_INT_CST_LOW (initp_expr);
+ pri = TREE_INT_CST_LOW (initp_expr);
- type = strip_array_types (type);
-
- if (decl == NULL_TREE
- || TREE_CODE (decl) != VAR_DECL
- || ! TREE_STATIC (decl)
- || DECL_EXTERNAL (decl)
- || (TREE_CODE (type) != RECORD_TYPE
- && TREE_CODE (type) != UNION_TYPE)
- /* Static objects in functions are initialized the
- first time control passes through that
- function. This is not precise enough to pin down an
- init_priority value, so don't allow it. */
- || current_function_decl)
- {
- error ("can only use init_priority attribute on file-scope definitions of objects of class type");
- return 0;
- }
-
- if (pri > MAX_INIT_PRIORITY || pri <= 0)
- {
- error ("requested init_priority is out of range");
- return 0;
- }
+ type = strip_array_types (type);
+
+ if (decl == NULL_TREE
+ || TREE_CODE (decl) != VAR_DECL
+ || !TREE_STATIC (decl)
+ || DECL_EXTERNAL (decl)
+ || (TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != UNION_TYPE)
+ /* Static objects in functions are initialized the
+ first time control passes through that
+ function. This is not precise enough to pin down an
+ init_priority value, so don't allow it. */
+ || current_function_decl)
+ {
+ error ("can only use `%s' attribute on file-scope definitions of objects of class type",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
- /* Check for init_priorities that are reserved for
- language and runtime support implementations.*/
- if (pri <= MAX_RESERVED_INIT_PRIORITY)
- {
- warning
- ("requested init_priority is reserved for internal use");
- }
+ if (pri > MAX_INIT_PRIORITY || pri <= 0)
+ {
+ error ("requested init_priority is out of range");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
- if (SUPPORTS_INIT_PRIORITY)
- {
- DECL_INIT_PRIORITY (decl) = pri;
- return 1;
- }
- else
- {
- error ("init_priority attribute is not supported on this platform");
- return 0;
- }
+ /* Check for init_priorities that are reserved for
+ language and runtime support implementations.*/
+ if (pri <= MAX_RESERVED_INIT_PRIORITY)
+ {
+ warning
+ ("requested init_priority is reserved for internal use");
}
- return 0;
+ if (SUPPORTS_INIT_PRIORITY)
+ {
+ DECL_INIT_PRIORITY (decl) = pri;
+ return NULL_TREE;
+ }
+ else
+ {
+ error ("`%s' attribute is not supported on this platform",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
}
/* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the
further attributes in the list.
Attributes may be attached to declarations and to types; these
-attributes may be accessed with the following macros. At present only
-machine-dependent attributes are stored in this way (other attributes
-cause changes to the declaration or type or to other internal compiler
-data structures, but are not themselves stored along with the
-declaration or type), but in future all attributes may be stored like
-this.
-
-@deftypefn {Tree Macro} tree DECL_MACHINE_ATTRIBUTES (tree @var{decl})
+attributes may be accessed with the following macros. All attributes
+are stored in this way, and many also cause other changes to the
+declaration or type or to other internal compiler data structures.
+
+@deftypefn {Tree Macro} tree DECL_ATTRIBUTES (tree @var{decl})
This macro returns the attributes on the declaration @var{decl}.
@end deftypefn
infelicities in the grammar for attributes, some forms described here
may not be successfully parsed in all cases.
+There are some problems with the semantics of attributes in C++. For
+example, there are no manglings for attributes, although they may affect
+code generation, so problems may arise when attributed types are used in
+conjunction with templates or overloading. Similarly, @code{typeid}
+does not distinguish between types with different attributes. Support
+for attributes in C++ may be restricted in future to attributes on
+declarations only, but not on nested declarators.
+
@xref{Function Attributes}, for details of the semantics of attributes
applying to functions. @xref{Variable Attributes}, for details of the
semantics of attributes applying to variables. @xref{Type Attributes},
Otherwise, an attribute specifier appears as part of a declaration,
counting declarations of unnamed parameters and type names, and relates
to that declaration (which may be nested in another declaration, for
-example in the case of a parameter declaration). In future, attribute
-specifiers in some places may however apply to a particular declarator
-within a declaration instead; these cases are noted below. Where an
+example in the case of a parameter declaration), or to a particular declarator
+within a declaration. Where an
attribute specifier is applied to a parameter declared as a function or
an array, it should apply to the function or array rather than the
pointer to which the parameter is implicitly converted, but this is not
An attribute specifier list may appear at the start of a nested
declarator. At present, there are some limitations in this usage: the
-attributes apply to the identifier declared, rather than to a specific
-declarator. When attribute specifiers follow the @code{*} of a pointer
+attributes correctly apply to the declarator, but for most individual
+attributes the semantics this implies are not implemented.
+When attribute specifiers follow the @code{*} of a pointer
declarator, they may be mixed with any type qualifiers present.
-The following describes intended future
-semantics which make this syntax more useful only. It will make the
+The following describes the formal semantics of this syntax. It will make the
most sense if you are familiar with the formal specification of
declarators in the ISO C standard.
@noindent
specifies the type ``pointer to 8-byte-aligned pointer to @code{char}''.
-Note again that this describes intended future semantics, not current
-implementation.
+Note again that this does not work with most attributes; for example,
+the usage of @samp{aligned} and @samp{noreturn} attributes given above
+is not yet supported.
+
+For compatibility with existing code written for compiler versions that
+did not implement attributes on nested declarators, some laxity is
+allowed in the placing of attributes. If an attribute that only applies
+to types is applied to a declaration, it will be treated as applying to
+the type of that declaration. If an attribute that only applies to
+declarations is applied to the type of a declaration, it will be treated
+as applying to that declaration; and, for compatibility with code
+placing the attributes immediately before the identifier declared, such
+an attribute applied to a function return type will be treated as
+applying to the function type, and such an attribute applied to an array
+element type will be treated as applying to the array type. If an
+attribute that only applies to function types is applied to a
+pointer-to-function type, it will be treated as applying to the pointer
+target type; if such an attribute is applied to a function return type
+that is not a pointer-to-function type, it will be treated as applying
+to the function type.
@node Function Prototypes
@section Prototypes and Old-Style Function Definitions
* Debugging Info:: Defining the format of debugging output.
* Cross-compilation:: Handling floating point for cross-compilers.
* Mode Switching:: Insertion of mode-switching instructions.
+* Target Attributes:: Defining target-specific uses of @code{__attribute__}.
* Misc:: Everything else.
@end menu
/* @r{Initialize the GCC target structure.} */
-#undef TARGET_VALID_TYPE_ATTRIBUTE
-#define TARGET_VALID_TYPE_ATTRIBUTE @var{machine}_valid_type_attribute_p
+#undef TARGET_COMP_TYPE_ATTRIBUTES
+#define TARGET_COMP_TYPE_ATTRIBUTES @var{machine}_comp_type_attributes
struct gcc_target targetm = TARGET_INITIALIZER;
@end smallexample
* Caller Saves::
* Function Entry::
* Profiling::
-* Inlining and Tail Calls::
+* Tail Calls::
@end menu
@node Frame Layout
@var{fundecl} is a C variable whose value is a tree node that describes
the function in question. Normally it is a node of type
@code{FUNCTION_DECL} that describes the declaration of the function.
-From this you can obtain the @code{DECL_MACHINE_ATTRIBUTES} of the function.
+From this you can obtain the @code{DECL_ATTRIBUTES} of the function.
@var{funtype} is a C variable whose value is a tree node that
describes the function in question. Normally it is a node of type
@end table
-@node Inlining and Tail Calls
-@subsection Permitting inlining and tail calls
-@cindex inlining
+@node Tail Calls
+@subsection Permitting tail calls
+@cindex tail calls
@table @code
-@findex FUNCTION_ATTRIBUTE_INLINABLE_P
-@item FUNCTION_ATTRIBUTE_INLINABLE_P (@var{decl})
-A C expression that evaluates to true if it is ok to inline @var{decl}
-into the current function, despite its having target-specific
-attributes. By default, if a function has a target specific attribute
-attached to it, it will not be inlined.
-
@findex FUNCTION_OK_FOR_SIBCALL
@item FUNCTION_OK_FOR_SIBCALL (@var{decl})
A C expression that evaluates to true if it is ok to perform a sibling
the insn(s) are to be inserted.
@end table
+@node Target Attributes
+@section Defining target-specific uses of @code{__attribute__}
+@cindex target attributes
+@cindex machine attributes
+@cindex attributes, target-specific
+
+Target-specific attributes may be defined for functions, data and types.
+These are described using the following target hooks; they also need to
+be documented in @file{extend.texi}.
+
+@deftypevr {Target Hook} {const struct attribute_spec *} TARGET_ATTRIBUTE_TABLE
+If defined, this target hook points to an array of @samp{struct
+attribute_spec} (defined in @file{tree.h}) specifying the machine
+specific attributes for this target and some of the restrictions on the
+entities to which these attributes are applied and the arguments they
+take.
+@end deftypevr
+
+@deftypefn {Target Hook} int TARGET_COMP_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2})
+If defined, this target hook is a function which returns zero if the attributes on
+@var{type1} and @var{type2} are incompatible, one if they are compatible,
+and two if they are nearly compatible (which causes a warning to be
+generated). If this is not defined, machine-specific attributes are
+supposed always to be compatible.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_SET_DEFAULT_TYPE_ATTRIBUTES (tree @var{type})
+If defined, this target hook is a function which assigns default attributes to
+newly defined @var{type}.
+@end deftypefn
+
+@deftypefn {Target Hook} tree TARGET_MERGE_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2})
+Define this target hook if the merging of type attributes needs special
+handling. If defined, the result is a list of the combined
+@code{TYPE_ATTRIBUTES} of @var{type1} and @var{type2}. It is assumed
+that @code{comptypes} has already been called and returned 1. This
+function may call @code{merge_attributes} to handle machine-independent
+merging.
+@end deftypefn
+
+@deftypefn {Target Hook} tree TARGET_MERGE_DECL_ATTRIBUTES (tree @var{olddecl}, tree @var{newdecl})
+Define this target hook if the merging of decl attributes needs special
+handling. If defined, the result is a list of the combined
+@code{DECL_ATTRIBUTES} of @var{olddecl} and @var{newdecl}.
+@var{newdecl} is a duplicate declaration of @var{olddecl}. Examples of
+when this is needed are when one attribute overrides another, or when an
+attribute is nullified by a subsequent definition. This function may
+call @code{merge_attributes} to handle machine-independent merging.
+
+@findex TARGET_DLLIMPORT_DECL_ATTRIBUTES
+If the only target-specific handling you require is @samp{dllimport} for
+Windows targets, you should define the macro
+@code{TARGET_DLLIMPORT_DECL_ATTRIBUTES}. This links in a function
+called @code{merge_dllimport_decl_attributes} which can then be defined
+as the expansion of @code{TARGET_MERGE_DECL_ATTRIBUTES}. This is done
+in @file{i386/cygwin.h} and @file{i386/i386.c}, for example.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_INSERT_ATTRIBUTES (tree @var{node}, tree *@var{attr_ptr})
+Define this target hook if you want to be able to add attributes to a decl
+when it is being created. This is normally useful for back ends which
+wish to implement a pragma by using the attributes which correspond to
+the pragma's effect. The @var{node} argument is the decl which is being
+created. The @var{attr_ptr} argument is a pointer to the attribute list
+for this decl. The list itself should not be modified, since it may be
+shared with other decls, but attributes may be chained on the head of
+the list and @code{*@var{attr_ptr}} modified to point to the new
+attributes, or a copy of the list may be made if further changes are
+needed.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (tree @var{fndecl})
+@cindex inlining
+This target hook returns @code{true} if it is ok to inline @var{fndecl}
+into the current function, despite its having target-specific
+attributes, @code{false} otherwise. By default, if a function has a
+target specific attribute attached to it, it will not be inlined.
+@end deftypefn
+
@node Misc
@section Miscellaneous Parameters
@cindex parameters, miscellaneous
definition of target-specific pragmas for GCC@.
If the pragma can be implemented by attributes then you should consider
-defining @samp{INSERT_ATTRIBUTES} as well.
+defining the target hook @samp{TARGET_INSERT_ATTRIBUTES} as well.
Preprocessor macros that appear on pragma lines are not expanded. All
@samp{#pragma} directives that do not match any registered pragma are
invocations of this pragma cause the previous values to be stacked, so
that invocations of @samp{#pragma pack(pop)} will return to the previous
value.
-@end table
-
-@deftypefn {Target Hook} int TARGET_VALID_DECL_ATTRIBUTE (tree @var{decl}, tree @var{attributes}, tree @var{identifier}, tree @var{args})
-If defined, this target hook is a function which returns nonzero if @var{identifier} with
-arguments @var{args} is a valid machine specific attribute for @var{decl}.
-The attributes in @var{attributes} have previously been assigned to @var{decl}.
-@end deftypefn
-
-@deftypefn {Target Hook} int TARGET_VALID_TYPE_ATTRIBUTE (tree @var{type}, tree @var{attributes}, tree @var{identifier}, tree @var{args})
-If defined, this target hook is a function which returns nonzero if @var{identifier} with
-arguments @var{args} is a valid machine specific attribute for @var{type}.
-The attributes in @var{attributes} have previously been assigned to @var{type}.
-@end deftypefn
-
-@deftypefn {Target Hook} int TARGET_COMP_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2})
-If defined, this target hook is a function which returns zero if the attributes on
-@var{type1} and @var{type2} are incompatible, one if they are compatible,
-and two if they are nearly compatible (which causes a warning to be
-generated). If this is not defined, machine-specific attributes are
-supposed always to be compatible.
-@end deftypefn
-
-@deftypefn {Target Hook} void TARGET_SET_DEFAULT_TYPE_ATTRIBUTES (tree @var{type})
-If defined, this target hook is a function which assigns default attributes to
-newly defined @var{type}.
-@end deftypefn
-@deftypefn {Target Hook} tree TARGET_MERGE_TYPE_ATTRIBUTES (tree @var{type1}, tree @var{type2})
-Define this target hook if the merging of type attributes needs special
-handling. If defined, the result is a list of the combined
-@code{TYPE_ATTRIBUTES} of @var{type1} and @var{type2}. It is assumed
-that @code{comptypes} has already been called and returned 1. This
-function may call @code{merge_attributes} to handle machine-independent
-merging.
-@end deftypefn
-
-@deftypefn {Target Hook} tree TARGET_MERGE_DECL_ATTRIBUTES (tree @var{olddecl}, tree @var{newdecl})
-Define this target hook if the merging of decl attributes needs special
-handling. If defined, the result is a list of the combined
-@code{DECL_MACHINE_ATTRIBUTES} of @var{olddecl} and @var{newdecl}.
-@var{newdecl} is a duplicate declaration of @var{olddecl}. Examples of
-when this is needed are when one attribute overrides another, or when an
-attribute is nullified by a subsequent definition. This function may
-call @code{merge_attributes} to handle machine-independent merging.
-
-@findex TARGET_DLLIMPORT_DECL_ATTRIBUTES
-If the only target-specific handling you require is @samp{dllimport} for
-Windows targets, you should define the macro
-@code{TARGET_DLLIMPORT_DECL_ATTRIBUTES}. This links in a function
-called @code{merge_dllimport_decl_attributes} which can then be defined
-as the expansion of @code{TARGET_MERGE_DECL_ATTRIBUTES}. This is done
-in @file{i386/cygwin.h} and @file{i386/i386.c}, for example.
-@end deftypefn
-
-@deftypefn {Target Hook} void TARGET_INSERT_ATTRIBUTES (tree @var{node}, tree *@var{attr_ptr})
-Define this target hook if you want to be able to add attributes to a decl
-when it is being created. This is normally useful for back ends which
-wish to implement a pragma by using the attributes which correspond to
-the pragma's effect. The @var{node} argument is the decl which is being
-created. The @var{attr_ptr} argument is a pointer to the attribute list
-for this decl. The list itself should not be modified, since it may be
-shared with other decls, but attributes may be chained on the head of
-the list and @code{*@var{attr_ptr}} modified to point to the new
-attributes, or a copy of the list may be made if further changes are
-needed.
-@end deftypefn
-
-@table @code
@findex DOLLARS_IN_IDENTIFIERS
@item DOLLARS_IN_IDENTIFIERS
Define this macro to control use of the character @samp{$} in identifier
ggc_mark_tree (DECL_INITIAL (t));
ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t));
ggc_mark_tree (DECL_SECTION_NAME (t));
- ggc_mark_tree (DECL_MACHINE_ATTRIBUTES (t));
+ ggc_mark_tree (DECL_ATTRIBUTES (t));
if (DECL_RTL_SET_P (t))
ggc_mark_rtx (DECL_RTL (t));
ggc_mark_rtx (DECL_LIVE_RANGE_RTL (t));
#include "loop.h"
#include "params.h"
#include "ggc.h"
+#include "target.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \
: (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
#endif
-
-/* Decide whether a function with a target specific attribute
- attached can be inlined. By default we disallow this. */
-#ifndef FUNCTION_ATTRIBUTE_INLINABLE_P
-#define FUNCTION_ATTRIBUTE_INLINABLE_P(FNDECL) 0
-#endif
\f
/* Private type used by {get/has}_func_hard_reg_initial_val. */
initial_value_pair *entries;
} initial_value_struct;
+static bool function_attribute_inlinable_p PARAMS ((tree));
+
static void setup_initial_hard_reg_value_integration PARAMS ((struct function *, struct inline_remap *));
static rtvec initialize_for_inline PARAMS ((tree));
return x;
}
+/* Return false if the function FNDECL cannot be inlined on account of its
+ attributes, true otherwise. */
+static bool
+function_attribute_inlinable_p (fndecl)
+ tree fndecl;
+{
+ bool has_machine_attr = false;
+ tree a;
+
+ for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a))
+ {
+ tree name = TREE_PURPOSE (a);
+ int i;
+
+ for (i = 0; targetm.attribute_table[i].name != NULL; i++)
+ {
+ if (is_attribute_p (targetm.attribute_table[i].name, name))
+ {
+ has_machine_attr = true;
+ break;
+ }
+ }
+ if (has_machine_attr)
+ break;
+ }
+
+ if (has_machine_attr)
+ return (*targetm.function_attribute_inlinable_p) (fndecl);
+ else
+ return true;
+}
+
/* Zero if the current function (whose FUNCTION_DECL is FNDECL)
is safe and reasonable to integrate into other functions.
Nonzero means value is a warning msgid with a single %s
/* If the function has a target specific attribute attached to it,
then we assume that we should not inline it. This can be overriden
- by the target if it defines FUNCTION_ATTRIBUTE_INLINABLE_P. */
- if (DECL_MACHINE_ATTRIBUTES (fndecl)
- && ! FUNCTION_ATTRIBUTE_INLINABLE_P (fndecl))
+ by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. */
+ if (!function_attribute_inlinable_p (fndecl))
return N_("function with target specific attribute(s) cannot be inlined");
return NULL;
/* Prints out tree in human readable form - GNU C-compiler
- Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GCC.
}
print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4);
- print_node_brief (file, "machine_attributes",
- DECL_MACHINE_ATTRIBUTES (node), indent + 4);
+ print_node_brief (file, "attributes",
+ DECL_ATTRIBUTES (node), indent + 4);
print_node_brief (file, "abstract_origin",
DECL_ABSTRACT_ORIGIN (node), indent + 4);
/* All in tree.c. */
#define TARGET_MERGE_DECL_ATTRIBUTES merge_decl_attributes
#define TARGET_MERGE_TYPE_ATTRIBUTES merge_type_attributes
-#define TARGET_VALID_DECL_ATTRIBUTE default_valid_attribute_p
-#define TARGET_VALID_TYPE_ATTRIBUTE default_valid_attribute_p
+#define TARGET_ATTRIBUTE_TABLE default_target_attribute_table
#define TARGET_COMP_TYPE_ATTRIBUTES default_comp_type_attributes
#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES default_set_default_type_attributes
#define TARGET_INSERT_ATTRIBUTES default_insert_attributes
+#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P default_function_attribute_inlinable_p
/* In builtins.c. */
#define TARGET_INIT_BUILTINS default_init_builtins
TARGET_SCHED, \
TARGET_MERGE_DECL_ATTRIBUTES, \
TARGET_MERGE_TYPE_ATTRIBUTES, \
- TARGET_VALID_DECL_ATTRIBUTE, \
- TARGET_VALID_TYPE_ATTRIBUTE, \
+ TARGET_ATTRIBUTE_TABLE, \
TARGET_COMP_TYPE_ATTRIBUTES, \
TARGET_SET_DEFAULT_TYPE_ATTRIBUTES, \
TARGET_INSERT_ATTRIBUTES, \
+ TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \
TARGET_INIT_BUILTINS, \
TARGET_EXPAND_BUILTIN, \
TARGET_SECTION_TYPE_FLAGS, \
/* Given two types, merge their attributes and return the result. */
tree (* merge_type_attributes) PARAMS ((tree, tree));
- /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
- specific attribute for DECL. The attributes in ATTRIBUTES have
- previously been assigned to DECL. */
- int (* valid_decl_attribute) PARAMS ((tree decl, tree attributes,
- tree identifier, tree args));
-
- /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
- specific attribute for TYPE. The attributes in ATTRIBUTES have
- previously been assigned to TYPE. */
- int (* valid_type_attribute) PARAMS ((tree type, tree attributes,
- tree identifier, tree args));
+ /* Table of machine attributes and functions to handle them. */
+ const struct attribute_spec *attribute_table;
/* Return zero if the attributes on TYPE1 and TYPE2 are incompatible,
one if they are compatible and two if they are nearly compatible
/* Insert attributes on the newly created DECL. */
void (* insert_attributes) PARAMS ((tree decl, tree *attributes));
+ /* Return true if FNDECL (which has at least one machine attribute)
+ can be inlined despite its machine attributes, false otherwise. */
+ bool (* function_attribute_inlinable_p) PARAMS ((tree fndecl));
+
/* Set up target-specific built-in functions. */
void (* init_builtins) PARAMS ((void));
+2001-09-21 Joseph S. Myers <jsm28@cam.ac.uk>
+
+ Table-driven attributes.
+ * g++.dg/ext/attrib1.C: New test.
+
2001-09-20 DJ Delorie <dj@redhat.com>
* gcc.dg/20000926-1.c: Update expected warning messages.
--- /dev/null
+// Test for interpretation of attribute immediately before function name.
+// Origin: Joseph Myers <jsm28@cam.ac.uk>
+// { dg-do compile }
+
+// An attribute immediately before the function name should in this
+// case properly apply to the return type, but compatibility with
+// existing code using this form requires it to apply to the function
+// type instead in the case of attributes applying to function types,
+// and to the declaration in the case of attributes applying to declarations.
+int ****__attribute__((format(printf, 1, 2))) foo(const char *, ...);
return wfl;
}
\f
-/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
+/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
is ATTRIBUTE. */
tree
build_decl_attribute_variant (ddecl, attribute)
tree ddecl, attribute;
{
- DECL_MACHINE_ATTRIBUTES (ddecl) = attribute;
+ DECL_ATTRIBUTES (ddecl) = attribute;
return ddecl;
}
return ttype;
}
-/* Default value of targetm.valid_decl_attribute_p and
- targetm.valid_type_attribute_p that always returns false. */
-
-int
-default_valid_attribute_p (attr_name, attr_args, decl, type)
- tree attr_name ATTRIBUTE_UNUSED;
- tree attr_args ATTRIBUTE_UNUSED;
- tree decl ATTRIBUTE_UNUSED;
- tree type ATTRIBUTE_UNUSED;
-{
- return 0;
-}
-
/* Default value of targetm.comp_type_attributes that always returns 1. */
int
{
}
-/* Return 1 if ATTR_NAME and ATTR_ARGS is valid for either declaration
- DECL or type TYPE and 0 otherwise. Validity is determined the
- target functions valid_decl_attribute and valid_machine_attribute. */
-
-int
-valid_machine_attribute (attr_name, attr_args, decl, type)
- tree attr_name;
- tree attr_args;
- tree decl;
- tree type;
+/* Default value of targetm.attribute_table that is empty. */
+const struct attribute_spec default_target_attribute_table[] =
{
- tree type_attrs;
-
- if (TREE_CODE (attr_name) != IDENTIFIER_NODE)
- abort ();
-
- if (decl)
- {
- tree decl_attrs = DECL_MACHINE_ATTRIBUTES (decl);
-
- if ((*targetm.valid_decl_attribute) (decl, decl_attrs, attr_name,
- attr_args))
- {
- tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
- decl_attrs);
-
- if (attr != NULL_TREE)
- {
- /* Override existing arguments. Declarations are unique
- so we can modify this in place. */
- TREE_VALUE (attr) = attr_args;
- }
- else
- {
- decl_attrs = tree_cons (attr_name, attr_args, decl_attrs);
- decl = build_decl_attribute_variant (decl, decl_attrs);
- }
-
- /* Don't apply the attribute to both the decl and the type. */
- return 1;
- }
- }
-
- type_attrs = TYPE_ATTRIBUTES (type);
- if ((*targetm.valid_type_attribute) (type, type_attrs, attr_name,
- attr_args))
- {
- tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
- type_attrs);
-
- if (attr != NULL_TREE)
- {
- /* Override existing arguments. ??? This currently
- works since attribute arguments are not included in
- `attribute_hash_list'. Something more complicated
- may be needed in the future. */
- TREE_VALUE (attr) = attr_args;
- }
- else
- {
- /* If this is part of a declaration, create a type variant,
- otherwise, this is part of a type definition, so add it
- to the base type. */
- type_attrs = tree_cons (attr_name, attr_args, type_attrs);
- if (decl != 0)
- type = build_type_attribute_variant (type, type_attrs);
- else
- TYPE_ATTRIBUTES (type) = type_attrs;
- }
-
- if (decl)
- TREE_TYPE (decl) = type;
-
- return 1;
- }
- /* Handle putting a type attribute on pointer-to-function-type
- by putting the attribute on the function type. */
- else if (POINTER_TYPE_P (type)
- && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- && (*targetm.valid_type_attribute) (TREE_TYPE (type), type_attrs,
- attr_name, attr_args))
- {
- tree inner_type = TREE_TYPE (type);
- tree inner_attrs = TYPE_ATTRIBUTES (inner_type);
- tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
- type_attrs);
-
- if (attr != NULL_TREE)
- TREE_VALUE (attr) = attr_args;
- else
- {
- inner_attrs = tree_cons (attr_name, attr_args, inner_attrs);
- inner_type = build_type_attribute_variant (inner_type,
- inner_attrs);
- }
-
- if (decl)
- TREE_TYPE (decl) = build_pointer_type (inner_type);
- else
- {
- /* Clear TYPE_POINTER_TO for the old inner type, since
- `type' won't be pointing to it anymore. */
- TYPE_POINTER_TO (TREE_TYPE (type)) = NULL_TREE;
- TREE_TYPE (type) = inner_type;
- }
-
- return 1;
- }
+ { NULL, 0, 0, false, false, false, NULL }
+};
- return 0;
+/* Default value of targetm.function_attribute_inlinable_p that always
+ returns false. */
+bool
+default_function_attribute_inlinable_p (fndecl)
+ tree fndecl ATTRIBUTE_UNUSED;
+{
+ /* By default, functions with machine attributes cannot be inlined. */
+ return false;
}
/* Return non-zero if IDENT is a valid name for attribute ATTR,
/* Given an attribute name and a list of attributes, return a pointer to the
attribute's list element if the attribute is part of the list, or NULL_TREE
- if not found. */
+ if not found. If the attribute appears more than once, this only
+ returns the first occurance; the TREE_CHAIN of the return value should
+ be passed back in if further occurances are wanted. */
tree
lookup_attribute (attr_name, list)
else
{
/* Pick the longest list, and hang on the other list. */
- /* ??? For the moment we punt on the issue of attrs with args. */
if (list_length (a1) < list_length (a2))
attributes = a2, a2 = a1;
for (; a2 != 0; a2 = TREE_CHAIN (a2))
- if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes) == NULL_TREE)
- {
- a1 = copy_node (a2);
- TREE_CHAIN (a1) = attributes;
- attributes = a1;
- }
+ {
+ tree a;
+ for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ attributes);
+ a != NULL_TREE;
+ a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ TREE_CHAIN (a)))
+ {
+ if (simple_cst_equal (TREE_VALUE (a), TREE_VALUE (a2)) == 1)
+ break;
+ }
+ if (a == NULL_TREE)
+ {
+ a1 = copy_node (a2);
+ TREE_CHAIN (a1) = attributes;
+ attributes = a1;
+ }
+ }
}
}
return attributes;
merge_decl_attributes (olddecl, newdecl)
tree olddecl, newdecl;
{
- return merge_attributes (DECL_MACHINE_ATTRIBUTES (olddecl),
- DECL_MACHINE_ATTRIBUTES (newdecl));
+ return merge_attributes (DECL_ATTRIBUTES (olddecl),
+ DECL_ATTRIBUTES (newdecl));
}
#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
tree a;
int delete_dllimport_p;
- old = DECL_MACHINE_ATTRIBUTES (old);
- new = DECL_MACHINE_ATTRIBUTES (new);
+ old = DECL_ATTRIBUTES (old);
+ new = DECL_ATTRIBUTES (new);
/* What we need to do here is remove from `old' dllimport if it doesn't
appear in `new'. dllimport behaves like extern: if a declaration is
for (; t2 != 0; t2 = TREE_CHAIN (t2))
{
- tree attr
- = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
+ tree attr;
+ for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
+ attr != NULL_TREE;
+ attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+ TREE_CHAIN (attr)))
+ {
+ if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) == 1)
+ break;
+ }
if (attr == 0)
return 0;
/* Front-end tree definitions for GNU compiler.
- Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GCC.
type, or NULL_TREE if the given decl has "file scope". */
#define DECL_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context)
#define DECL_FIELD_CONTEXT(NODE) (FIELD_DECL_CHECK (NODE)->decl.context)
-/* In a DECL this is the field where configuration dependent machine
- attributes are store */
-#define DECL_MACHINE_ATTRIBUTES(NODE) (DECL_CHECK (NODE)->decl.machine_attributes)
+/* In a DECL this is the field where attributes are stored. */
+#define DECL_ATTRIBUTES(NODE) (DECL_CHECK (NODE)->decl.attributes)
/* In a FIELD_DECL, this is the field position, counting in bytes, of the
byte containing the bit closest to the beginning of the structure. */
#define DECL_FIELD_OFFSET(NODE) (FIELD_DECL_CHECK (NODE)->decl.arguments)
tree abstract_origin;
tree assembler_name;
tree section_name;
- tree machine_attributes;
+ tree attributes;
rtx rtl; /* RTL representation for object. */
rtx live_range_rtl;
extern tree build_type_attribute_variant PARAMS ((tree, tree));
extern tree build_decl_attribute_variant PARAMS ((tree, tree));
+/* Structure describing an attribute and a function to handle it. */
+struct attribute_spec
+{
+ /* The name of the attribute (without any leading or trailing __),
+ or NULL to mark the end of a table of attributes. */
+ const char *name;
+ /* The minimum length of the list of arguments of the attribute. */
+ int min_length;
+ /* The maximum length of the list of arguments of the attribute
+ (-1 for no maximum). */
+ int max_length;
+ /* Whether this attribute requires a DECL. If it does, it will be passed
+ from types of DECLs, function return types and array element types to
+ the DECLs, function types and array types respectively; but when
+ applied to a type in any other circumstances, it will be ignored with
+ a warning. (If greater control is desired for a given attribute,
+ this should be false, and the flags argument to the handler may be
+ used to gain greater control in that case.) */
+ bool decl_required;
+ /* Whether this attribute requires a type. If it does, it will be passed
+ from a DECL to the type of that DECL. */
+ bool type_required;
+ /* Whether this attribute requires a function (or method) type. If it does,
+ it will be passed from a function pointer type to the target type,
+ and from a function return type (which is not itself a function
+ pointer type) to the function type. */
+ bool function_type_required;
+ /* Function to handle this attribute. NODE points to the node to which
+ the attribute is to be applied. If a DECL, it should be modified in
+ place; if a TYPE, a copy should be created. NAME is the name of the
+ attribute (possibly with leading or trailing __). ARGS is the TREE_LIST
+ of the arguments (which may be NULL). FLAGS gives further information
+ about the context of the attribute. Afterwards, the attributes will
+ be added to the DECL_ATTRIBUTES or TYPE_ATTRIBUTES, as appropriate,
+ unless *NO_ADD_ATTRS is set to true (which should be done on error,
+ as well as in any other cases when the attributes should not be added
+ to the DECL or TYPE). Depending on FLAGS, any attributes to be
+ applied to another type or DECL later may be returned;
+ otherwise the return value should be NULL_TREE. This pointer may be
+ NULL if no special handling is required beyond the checks implied
+ by the rest of this structure. */
+ tree (*handler) PARAMS ((tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs));
+};
+
+extern const struct attribute_spec default_target_attribute_table[];
+
+/* Flags that may be passed in the third argument of decl_attributes, and
+ to handler functions for attributes. */
+enum attribute_flags
+{
+ /* The type passed in is the type of a DECL, and any attributes that
+ should be passed in again to be applied to the DECL rather than the
+ type should be returned. */
+ ATTR_FLAG_DECL_NEXT = 1,
+ /* The type passed in is a function return type, and any attributes that
+ should be passed in again to be applied to the function type rather
+ than the return type should be returned. */
+ ATTR_FLAG_FUNCTION_NEXT = 2,
+ /* The type passed in is an array element type, and any attributes that
+ should be passed in again to be applied to the array type rather
+ than the element type should be returned. */
+ ATTR_FLAG_ARRAY_NEXT = 4,
+ /* The type passed in is a structure, union or enumeration type being
+ created, and should be modified in place. */
+ ATTR_FLAG_TYPE_IN_PLACE = 8
+};
+
/* Default versions of target-overridable functions. */
extern tree merge_decl_attributes PARAMS ((tree, tree));
extern tree merge_type_attributes PARAMS ((tree, tree));
-extern int default_valid_attribute_p PARAMS ((tree, tree, tree, tree));
extern int default_comp_type_attributes PARAMS ((tree, tree));
extern void default_set_default_type_attributes PARAMS ((tree));
extern void default_insert_attributes PARAMS ((tree, tree *));
+extern bool default_function_attribute_inlinable_p PARAMS ((tree));
/* Split a list of declspecs and attributes into two. */