aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Kenner <kenner@vlsi1.ultra.nyu.edu>2001-09-22 13:14:40 +0000
committerRichard Kenner <kenner@gcc.gnu.org>2001-09-22 09:14:40 -0400
commitbb9f8221b43c3a500198fa3a504fa11f5f807988 (patch)
tree00bc4e0b093a48235bf0c46b6102755bcd06cba0
parentab6e6969342d2aa3a7e59eb092767e80bd7852a4 (diff)
downloadgcc-bb9f8221b43c3a500198fa3a504fa11f5f807988.zip
gcc-bb9f8221b43c3a500198fa3a504fa11f5f807988.tar.gz
gcc-bb9f8221b43c3a500198fa3a504fa11f5f807988.tar.bz2
attribs.c: New file, from c-common.c.
* attribs.c: New file, from c-common.c. (attribute_tables): Now four elements. (format_attribute_table, lang_attribute_common): New variables. (init_attributes): Reflect above changes. (handle_mode_attribute): Delete check for wider than uintmax. * c-common.c: Delete parts moved to attribs.c. (enum attrs): Deleted; unused. (c_format_attribute_table): New variable. (c_common_lang_init): Initialize format_attribute_table with it. * c-common.h (decl_attributes): Remove decl. * tree.h (decl_attribute): Move it to here. * Makefile.in (C_AND_OBJS_OBJS): Add attribs.o. (attribs.o): New rule. * ch/Make-lang.in (cc1chill): Add attribs.o. * cp/Make-lang.in (CXX_C_OBJS): Add attribs.o. From-SVN: r45749
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/attribs.c1201
-rw-r--r--gcc/c-common.c1160
-rw-r--r--gcc/c-common.h1
-rw-r--r--gcc/ch/ChangeLog4
-rw-r--r--gcc/ch/Make-lang.in2
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/Make-lang.in3
-rw-r--r--gcc/tree.h3
9 files changed, 1246 insertions, 1148 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9fc2e86..f32e149 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+Sat Sep 22 09:09:32 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * attribs.c: New file, from c-common.c.
+ (attribute_tables): Now four elements.
+ (format_attribute_table, lang_attribute_common): New variables.
+ (init_attributes): Reflect above changes.
+ (handle_mode_attribute): Delete check for wider than uintmax.
+ * c-common.c: Delete parts moved to attribs.c.
+ (enum attrs): Deleted; unused.
+ (c_format_attribute_table): New variable.
+ (c_common_lang_init): Initialize format_attribute_table with it.
+ * c-common.h (decl_attributes): Remove decl.
+ * tree.h (decl_attribute): Move it to here.
+ * Makefile.in (C_AND_OBJS_OBJS): Add attribs.o.
+ (attribs.o): New rule.
+
2001-09-22 Andreas Jaeger <aj@suse.de>
* builtins.c (c_getstr): Remove unused variable.
diff --git a/gcc/attribs.c b/gcc/attribs.c
new file mode 100644
index 0000000..1413dc2
--- /dev/null
+++ b/gcc/attribs.c
@@ -0,0 +1,1201 @@
+/* Functions dealing with attribute handling, used by most front ends.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "flags.h"
+#include "toplev.h"
+#include "output.h"
+#include "rtl.h"
+#include "ggc.h"
+#include "expr.h"
+#include "tm_p.h"
+#include "obstack.h"
+#include "cpplib.h"
+#include "target.h"
+
+static void init_attributes PARAMS ((void));
+
+/* Table of the tables of attributes (common, format, language, machine)
+ searched. */
+static const struct attribute_spec *attribute_tables[4];
+
+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[] =
+{
+ /* { 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 },
+ { "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 }
+};
+
+/* Default empty table of attributes. */
+static const struct attribute_spec empty_attribute_table[] =
+{
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Table of machine-independent attributes for checking formats, if used. */
+const struct attribute_spec *format_attribute_table = empty_attribute_table;
+
+/* Table of machine-independent attributes for a particular language. */
+const struct attribute_spec *lang_attribute_table = empty_attribute_table;
+
+/* Flag saying whether common language attributes are to be supported. */
+int lang_attribute_common = 1;
+
+/* Initialize attribute tables, and make some sanity checks
+ if --enable-checking. */
+
+static void
+init_attributes ()
+{
+#ifdef ENABLE_CHECKING
+ int i;
+#endif
+
+ attribute_tables[0]
+ = lang_attribute_common ? c_common_attribute_table : empty_attribute_table;
+ attribute_tables[1] = lang_attribute_table;
+ attribute_tables[2] = format_attribute_table;
+ attribute_tables[3] = 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, k, l;
+
+ for (j = i + 1;
+ j < ((int) (sizeof (attribute_tables)
+ / sizeof (attribute_tables[0])));
+ j++)
+ 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;
+}
+
+/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
+ which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
+ it should be modified in place; if a TYPE, a copy should be created
+ unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
+ information, in the form of a bitwise OR of flags in enum attribute_flags
+ from tree.h. Depending on these flags, some attributes may be
+ returned to be applied at a later stage (for example, to apply
+ a decl attribute to the declaration rather than to its type). */
+
+tree
+decl_attributes (node, attributes, flags)
+ tree *node, attributes;
+ int flags;
+{
+ tree a;
+ tree returned_attrs = NULL_TREE;
+
+ if (!attributes_initialized)
+ init_attributes ();
+
+ (*targetm.insert_attributes) (*node, &attributes);
+
+ for (a = attributes; a; a = TREE_CHAIN (a))
+ {
+ tree name = TREE_PURPOSE (a);
+ tree args = TREE_VALUE (a);
+ tree *anode = node;
+ const struct attribute_spec *spec = NULL;
+ bool no_add_attrs = 0;
+ int i;
+
+ 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++)
+ {
+ if (is_attribute_p (attribute_tables[i][j].name, name))
+ {
+ spec = &attribute_tables[i][j];
+ break;
+ }
+ }
+ if (spec != NULL)
+ break;
+ }
+
+ if (spec == NULL)
+ {
+ warning ("`%s' attribute directive ignored",
+ IDENTIFIER_POINTER (name));
+ continue;
+ }
+ else if (list_length (args) < spec->min_length
+ || (spec->max_length >= 0
+ && list_length (args) > spec->max_length))
+ {
+ error ("wrong number of arguments specified for `%s' attribute",
+ IDENTIFIER_POINTER (name));
+ continue;
+ }
+
+ if (spec->decl_required && !DECL_P (*anode))
+ {
+ if (flags & ((int) ATTR_FLAG_DECL_NEXT
+ | (int) ATTR_FLAG_FUNCTION_NEXT
+ | (int) ATTR_FLAG_ARRAY_NEXT))
+ {
+ /* Pass on this attribute to be tried again. */
+ returned_attrs = tree_cons (name, args, returned_attrs);
+ continue;
+ }
+ else
+ {
+ warning ("`%s' attribute does not apply to types",
+ IDENTIFIER_POINTER (name));
+ continue;
+ }
+ }
+
+ if (spec->type_required && DECL_P (*anode))
+ anode = &TREE_TYPE (*anode);
+
+ 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;
+ }
+
+ 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;
+
+ if (DECL_P (*anode))
+ old_attrs = DECL_ATTRIBUTES (*anode);
+ else
+ old_attrs = TYPE_ATTRIBUTES (*anode);
+
+ for (a = lookup_attribute (spec->name, old_attrs);
+ a != NULL_TREE;
+ a = lookup_attribute (spec->name, TREE_CHAIN (a)))
+ {
+ if (simple_cst_equal (TREE_VALUE (a), args) == 1)
+ break;
+ }
+
+ if (a == NULL_TREE)
+ {
+ /* This attribute isn't already in the list. */
+ if (DECL_P (*anode))
+ DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+ else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+ TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
+ else
+ *anode = build_type_attribute_variant (*anode,
+ tree_cons (name, args,
+ old_attrs));
+ }
+ }
+ }
+
+ return returned_attrs;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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;
+ }
+
+ return NULL_TREE;
+}
+
+/* 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
+ {
+ TREE_TYPE (decl) = type = typefm;
+ DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
+ if (TREE_CODE (decl) != FIELD_DECL)
+ layout_decl (decl, 0);
+ }
+ }
+
+ 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,
+ "section attribute cannot be specified for local variables");
+ *no_add_attrs = true;
+ }
+
+ /* 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");
+ *no_add_attrs = true;
+ }
+ else
+ 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;
+}
+
+/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
+ lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
+
+ The head of the declspec list is stored in DECLSPECS.
+ The head of the attribute list is stored in PREFIX_ATTRIBUTES.
+
+ Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
+ the list elements. We drop the containing TREE_LIST nodes and link the
+ resulting attributes together the way decl_attributes expects them. */
+
+void
+split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
+ tree specs_attrs;
+ tree *declspecs, *prefix_attributes;
+{
+ tree t, s, a, next, specs, attrs;
+
+ /* This can happen after an __extension__ in pedantic mode. */
+ if (specs_attrs != NULL_TREE
+ && TREE_CODE (specs_attrs) == INTEGER_CST)
+ {
+ *declspecs = NULL_TREE;
+ *prefix_attributes = NULL_TREE;
+ return;
+ }
+
+ /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
+ if (specs_attrs != NULL_TREE
+ && TREE_CODE (specs_attrs) != TREE_LIST)
+ {
+ *declspecs = specs_attrs;
+ *prefix_attributes = NULL_TREE;
+ return;
+ }
+
+ /* Remember to keep the lists in the same order, element-wise. */
+
+ specs = s = NULL_TREE;
+ attrs = a = NULL_TREE;
+ for (t = specs_attrs; t; t = next)
+ {
+ next = TREE_CHAIN (t);
+ /* Declspecs have a non-NULL TREE_VALUE. */
+ if (TREE_VALUE (t) != NULL_TREE)
+ {
+ if (specs == NULL_TREE)
+ specs = s = t;
+ else
+ {
+ TREE_CHAIN (s) = t;
+ s = t;
+ }
+ }
+ /* The TREE_PURPOSE may also be empty in the case of
+ __attribute__(()). */
+ else if (TREE_PURPOSE (t) != NULL_TREE)
+ {
+ if (attrs == NULL_TREE)
+ attrs = a = TREE_PURPOSE (t);
+ else
+ {
+ TREE_CHAIN (a) = TREE_PURPOSE (t);
+ a = TREE_PURPOSE (t);
+ }
+ /* More attrs can be linked here, move A to the end. */
+ while (TREE_CHAIN (a) != NULL_TREE)
+ a = TREE_CHAIN (a);
+ }
+ }
+
+ /* Terminate the lists. */
+ if (s != NULL_TREE)
+ TREE_CHAIN (s) = NULL_TREE;
+ if (a != NULL_TREE)
+ TREE_CHAIN (a) = NULL_TREE;
+
+ /* All done. */
+ *declspecs = specs;
+ *prefix_attributes = attrs;
+}
+
+/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
+ This function is used by the parser when a rule will accept attributes
+ in a particular position, but we don't want to support that just yet.
+
+ A warning is issued for every ignored attribute. */
+
+tree
+strip_attrs (specs_attrs)
+ tree specs_attrs;
+{
+ tree specs, attrs;
+
+ split_specs_attrs (specs_attrs, &specs, &attrs);
+
+ while (attrs)
+ {
+ warning ("`%s' attribute ignored",
+ IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+ attrs = TREE_CHAIN (attrs);
+ }
+
+ return specs;
+}
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 3aa402f..fd1aef1 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -216,12 +216,6 @@ void (*back_end_hook) PARAMS ((tree));
This is a count, since unevaluated expressions can nest. */
int skip_evaluation;
-enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
- A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
- A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
- A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
- A_NO_LIMIT_STACK, A_PURE};
-
/* Information about how a function name is generated. */
struct fname_var_t
{
@@ -243,7 +237,6 @@ const struct fname_var_t fname_vars[] =
{NULL, 0, 0},
};
-static void init_attributes PARAMS ((void));
static int constant_fits_type_p PARAMS ((tree, tree));
/* Keep a stack of if statements. We record the number of compound
@@ -637,1144 +630,6 @@ combine_strings (strings)
return value;
}
-/* 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[] =
-{
- /* { 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 }
-};
-
-/* Default empty table of language attributes. */
-static const struct attribute_spec default_lang_attribute_table[] =
-{
- { NULL, 0, 0, false, false, false, NULL }
-};
-
-/* Table of machine-independent attributes for a particular language. */
-const struct attribute_spec *lang_attribute_table
- = default_lang_attribute_table;
-
-/* Initialize attribute tables, and make some sanity checks
- if --enable-checking. */
-
-static void
-init_attributes ()
-{
-#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;
-}
-
-/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
- which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
- it should be modified in place; if a TYPE, a copy should be created
- unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
- information, in the form of a bitwise OR of flags in enum attribute_flags
- from tree.h. Depending on these flags, some attributes may be
- returned to be applied at a later stage (for example, to apply
- a decl attribute to the declaration rather than to its type). */
-
-tree
-decl_attributes (node, attributes, flags)
- tree *node, attributes;
- int flags;
-{
- tree a;
- tree returned_attrs = NULL_TREE;
-
- if (!attributes_initialized)
- init_attributes ();
-
- (*targetm.insert_attributes) (*node, &attributes);
-
- for (a = attributes; a; a = TREE_CHAIN (a))
- {
- tree name = TREE_PURPOSE (a);
- tree args = TREE_VALUE (a);
- tree *anode = node;
- const struct attribute_spec *spec = NULL;
- bool no_add_attrs = 0;
- int i;
-
- 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++)
- {
- if (is_attribute_p (attribute_tables[i][j].name, name))
- {
- spec = &attribute_tables[i][j];
- break;
- }
- }
- if (spec != NULL)
- break;
- }
-
- if (spec == NULL)
- {
- warning ("`%s' attribute directive ignored",
- IDENTIFIER_POINTER (name));
- continue;
- }
- else if (list_length (args) < spec->min_length
- || (spec->max_length >= 0
- && list_length (args) > spec->max_length))
- {
- error ("wrong number of arguments specified for `%s' attribute",
- IDENTIFIER_POINTER (name));
- continue;
- }
-
- if (spec->decl_required && !DECL_P (*anode))
- {
- if (flags & ((int) ATTR_FLAG_DECL_NEXT
- | (int) ATTR_FLAG_FUNCTION_NEXT
- | (int) ATTR_FLAG_ARRAY_NEXT))
- {
- /* Pass on this attribute to be tried again. */
- returned_attrs = tree_cons (name, args, returned_attrs);
- continue;
- }
- else
- {
- warning ("`%s' attribute does not apply to types",
- IDENTIFIER_POINTER (name));
- continue;
- }
- }
-
- if (spec->type_required && DECL_P (*anode))
- {
- anode = &TREE_TYPE (*anode);
- }
-
- 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;
- }
-
- 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;
-
- if (DECL_P (*anode))
- old_attrs = DECL_ATTRIBUTES (*anode);
- else
- old_attrs = TYPE_ATTRIBUTES (*anode);
-
- for (a = lookup_attribute (spec->name, old_attrs);
- a != NULL_TREE;
- a = lookup_attribute (spec->name, TREE_CHAIN (a)))
- {
- if (simple_cst_equal (TREE_VALUE (a), args) == 1)
- break;
- }
-
- if (a == NULL_TREE)
- {
- /* This attribute isn't already in the list. */
- if (DECL_P (*anode))
- DECL_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
- else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
- TYPE_ATTRIBUTES (*anode) = tree_cons (name, args, old_attrs);
- else
- *anode = build_type_attribute_variant (*anode,
- tree_cons (name, args,
- old_attrs));
- }
- }
- }
-
- return returned_attrs;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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;
- }
-
- return NULL_TREE;
-}
-
-/* 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);
- }
- }
-
- 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,
- "section attribute cannot be specified for local variables");
- *no_add_attrs = true;
- }
- /* 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");
- *no_add_attrs = true;
- }
- else
- 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;
-}
-
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
- lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
- The head of the declspec list is stored in DECLSPECS.
- The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
- Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
- the list elements. We drop the containing TREE_LIST nodes and link the
- resulting attributes together the way decl_attributes expects them. */
-
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
- tree specs_attrs;
- tree *declspecs, *prefix_attributes;
-{
- tree t, s, a, next, specs, attrs;
-
- /* This can happen after an __extension__ in pedantic mode. */
- if (specs_attrs != NULL_TREE
- && TREE_CODE (specs_attrs) == INTEGER_CST)
- {
- *declspecs = NULL_TREE;
- *prefix_attributes = NULL_TREE;
- return;
- }
-
- /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
- if (specs_attrs != NULL_TREE
- && TREE_CODE (specs_attrs) != TREE_LIST)
- {
- *declspecs = specs_attrs;
- *prefix_attributes = NULL_TREE;
- return;
- }
-
- /* Remember to keep the lists in the same order, element-wise. */
-
- specs = s = NULL_TREE;
- attrs = a = NULL_TREE;
- for (t = specs_attrs; t; t = next)
- {
- next = TREE_CHAIN (t);
- /* Declspecs have a non-NULL TREE_VALUE. */
- if (TREE_VALUE (t) != NULL_TREE)
- {
- if (specs == NULL_TREE)
- specs = s = t;
- else
- {
- TREE_CHAIN (s) = t;
- s = t;
- }
- }
- /* The TREE_PURPOSE may also be empty in the case of
- __attribute__(()). */
- else if (TREE_PURPOSE (t) != NULL_TREE)
- {
- if (attrs == NULL_TREE)
- attrs = a = TREE_PURPOSE (t);
- else
- {
- TREE_CHAIN (a) = TREE_PURPOSE (t);
- a = TREE_PURPOSE (t);
- }
- /* More attrs can be linked here, move A to the end. */
- while (TREE_CHAIN (a) != NULL_TREE)
- a = TREE_CHAIN (a);
- }
- }
-
- /* Terminate the lists. */
- if (s != NULL_TREE)
- TREE_CHAIN (s) = NULL_TREE;
- if (a != NULL_TREE)
- TREE_CHAIN (a) = NULL_TREE;
-
- /* All done. */
- *declspecs = specs;
- *prefix_attributes = attrs;
-}
-
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
- This function is used by the parser when a rule will accept attributes
- in a particular position, but we don't want to support that just yet.
-
- A warning is issued for every ignored attribute. */
-
-tree
-strip_attrs (specs_attrs)
- tree specs_attrs;
-{
- tree specs, attrs;
-
- split_specs_attrs (specs_attrs, &specs, &attrs);
-
- while (attrs)
- {
- warning ("`%s' attribute ignored",
- IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
- attrs = TREE_CHAIN (attrs);
- }
-
- return specs;
-}
-
static int is_valid_printf_arglist PARAMS ((tree));
static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
@@ -4917,11 +3772,26 @@ boolean_increment (code, arg)
return val;
}
+/* Give the specifications for the format attributes, used by C and all
+ descendents. */
+
+static const struct attribute_spec c_format_attribute_table[] =
+{
+ { "format", 3, 3, true, false, false,
+ handle_format_attribute },
+ { "format_arg", 1, 1, true, false, false,
+ handle_format_arg_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+extern const struct attribute_spec *format_attribute_table;
/* Do the parts of lang_init common to C and C++. */
void
c_common_lang_init ()
{
+ format_attribute_table = c_format_attribute_table;
+
/* If still "unspecified", make it match -fbounded-pointers. */
if (flag_bounds_check < 0)
flag_bounds_check = flag_bounded_pointers;
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 6ab2c06..3681ed2 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -503,7 +503,6 @@ extern const char *fname_as_string PARAMS ((int));
extern tree fname_decl PARAMS ((unsigned, tree));
extern const char *fname_string PARAMS ((unsigned));
-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));
diff --git a/gcc/ch/ChangeLog b/gcc/ch/ChangeLog
index e9f1939..d28d868 100644
--- a/gcc/ch/ChangeLog
+++ b/gcc/ch/ChangeLog
@@ -1,3 +1,7 @@
+Sat Sep 22 09:15:08 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * Make-lang.in (cc1chill): Add attribs.o.
+
2001-08-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* tree.c (TYPE_HASH): Moved to ../tree.h.
diff --git a/gcc/ch/Make-lang.in b/gcc/ch/Make-lang.in
index 27b36b82..87965ab 100644
--- a/gcc/ch/Make-lang.in
+++ b/gcc/ch/Make-lang.in
@@ -95,7 +95,7 @@ chill-cross: $(srcdir)/ch/chill.in
cc1chill$(exeext): $(P) $(CHILL_SRCS) $(LIBDEPS) $(BACKEND) \
insn-config.h insn-flags.h insn-attr.h insn-codes.h \
- c-typeck.o c-aux-info.o c-common.o \
+ attribs.o c-typeck.o c-aux-info.o c-common.o \
ggc-callbacks.o
cd ch; $(MAKE) $(LANG_FLAGS_TO_PASS) $(CHILL_FLAGS_TO_PASS) ../cc1chill$(exeext)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 25efd97..2fed13f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,7 @@
+Sat Sep 22 09:15:31 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * Make-lang.in (CXX_C_OBJS): Add attribs.o.
+
2001-09-21 Richard Henderson <rth@redhat.com>
* class.c (set_vindex): Mind TARGET_VTABLE_USES_DESCRIPTORS.
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 38b3a8b..21acc01 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -93,7 +93,8 @@ $(DEMANGLER_PROG): cxxmain.o underscore.o $(LIBDEPS)
# The compiler itself.
# Shared with C front end:
-CXX_C_OBJS = c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o c-dump.o $(CXX_TARGET_OBJS)
+CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \
+ c-dump.o $(CXX_TARGET_OBJS)
# Language-specific object files.
CXX_OBJS = cp/call.o cp/decl.o cp/errfn.o cp/expr.o cp/pt.o cp/typeck2.o \
diff --git a/gcc/tree.h b/gcc/tree.h
index fe94fa6..8bec94f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2906,6 +2906,9 @@ extern rtx emit_line_note PARAMS ((const char *, int));
extern int setjmp_call_p PARAMS ((tree));
+/* In attribs.c. */
+extern tree decl_attributes PARAMS ((tree *, tree, int));
+
/* In front end. */
extern int mark_addressable PARAMS ((tree));