Message ID | mptwmtzcous.fsf@arm.com |
---|---|
State | New |
Headers | show |
Series | Ping: [PATCH] Allow target attributes in non-gnu namespaces | expand |
On Thu, Nov 30, 2023 at 3:12 PM Richard Sandiford <richard.sandiford@arm.com> wrote: > > Ping OK. Thanks, Richard. > Richard Sandiford <richard.sandiford@arm.com> writes: > > This is a ping+rebase of the patch below. I've also optimised the > > handling of ignored attributes so that we don't register empty tables. > > There was also a typo in the jit changes (which I had tested, but the > > typo didn't seem to cause a failure). > > > > Retested on aarch64-linux-gnu & x86_64-linux-gnu. The original was > > also tested on the full target list in config-list.mk. > > > > Iain has already approved the D parts (thanks!). OK for the rest? > > > > And sorry to be pinging something when I'm behind on reviews myself... > > > > --- > > > > Currently there are four static sources of attributes: > > > > - LANG_HOOKS_ATTRIBUTE_TABLE > > - LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > > - LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE > > - TARGET_ATTRIBUTE_TABLE > > > > All of the attributes in these tables go in the "gnu" namespace. > > This means that they can use the traditional GNU __attribute__((...)) > > syntax and the standard [[gnu::...]] syntax. > > > > Standard attributes are registered dynamically with a null namespace. > > There are no supported attributes in other namespaces (clang, vendor > > namespaces, etc.). > > > > This patch tries to generalise things by making the namespace > > part of the attribute specification. > > > > It's usual for multiple attributes to be defined in the same namespace, > > so rather than adding the namespace to each individual definition, > > it seemed better to group attributes in the same namespace together. > > This would also allow us to reuse the same table for clang attributes > > that are written with the GNU syntax, or other similar situations > > where the attribute can be accessed via multiple "spellings". > > > > The patch therefore adds a scoped_attribute_specs that contains > > a namespace and a list of attributes in that namespace. > > > > It's still possible to have multiple scoped_attribute_specs > > for the same namespace. E.g. it makes sense to keep the > > C++-specific, C/C++-common, and format-related attributes in > > separate tables, even though they're all GNU attributes. > > > > Current lists of attributes are terminated by a null name. > > Rather than keep that for the new structure, it seemed neater > > to use an array_slice. This also makes the tables slighly more > > compact. > > > > In general, a target might want to support attributes in multiple > > namespaces. Rather than have a separate hook for each possibility > > (like the three langhooks above), it seemed better to make > > TARGET_ATTRIBUTE_TABLE a table of tables. Specifically, it's > > an array_slice of scoped_attribute_specs. > > > > We can do the same thing for langhooks, which allows the three hooks > > above to be merged into a single LANG_HOOKS_ATTRIBUTE_TABLE. > > It also allows the standard attributes to be registered statically > > and checked by the usual attribs.cc checks. > > > > The patch adds a TARGET_GNU_ATTRIBUTES helper for the common case > > in which a target wants a single table of gnu attributes. It can > > only be used if the table is free of preprocessor directives. > > > > There are probably other things we need to do to make vendor namespaces > > work smoothly. E.g. in principle it would be good to make exclusion > > sets namespace-aware. But to some extent we have that with standard > > vs. gnu attributes too. This patch is just supposed to be a first step. > > gcc/ > * attribs.h (scoped_attribute_specs): New structure. > (register_scoped_attributes): Take a reference to a > scoped_attribute_specs instead of separate namespace and array > parameters. > * plugin.h (register_scoped_attributes): Likewise. > * attribs.cc (register_scoped_attributes): Likewise. > (attribute_tables): Change into an array of scoped_attribute_specs > pointers. Reduce to 1 element for frontends and 1 element for targets. > (empty_attribute_table): Delete. > (check_attribute_tables): Update for changes to attribute_tables. > Use a hash_set to identify duplicates. > (handle_ignored_attributes_option): Update for above changes. > (init_attributes): Likewise. > (excl_pair): Delete. > (test_attribute_exclusions): Update for above changes. Don't > enforce symmetry for standard attributes in the top-level namespace. > * langhooks-def.h (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Likewise. > (LANG_HOOKS_INITIALIZER): Update accordingly. > (LANG_HOOKS_ATTRIBUTE_TABLE): Define to an empty constructor. > * langhooks.h (lang_hooks::common_attribute_table): Delete. > (lang_hooks::format_attribute_table): Likewise. > (lang_hooks::attribute_table): Redefine to an array of > scoped_attribute_specs pointers. > * target-def.h (TARGET_GNU_ATTRIBUTES): New macro. > * target.def (attribute_spec): Redefine to return an array of > scoped_attribute_specs pointers. > * tree-inline.cc (function_attribute_inlinable_p): Update accordingly. > * doc/tm.texi: Regenerate. > * config/aarch64/aarch64.cc (aarch64_attribute_table): Define using > TARGET_GNU_ATTRIBUTES. > * config/alpha/alpha.cc (vms_attribute_table): Likewise. > * config/avr/avr.cc (avr_attribute_table): Likewise. > * config/bfin/bfin.cc (bfin_attribute_table): Likewise. > * config/bpf/bpf.cc (bpf_attribute_table): Likewise. > * config/csky/csky.cc (csky_attribute_table): Likewise. > * config/epiphany/epiphany.cc (epiphany_attribute_table): Likewise. > * config/gcn/gcn.cc (gcn_attribute_table): Likewise. > * config/h8300/h8300.cc (h8300_attribute_table): Likewise. > * config/loongarch/loongarch.cc (loongarch_attribute_table): Likewise. > * config/m32c/m32c.cc (m32c_attribute_table): Likewise. > * config/m32r/m32r.cc (m32r_attribute_table): Likewise. > * config/m68k/m68k.cc (m68k_attribute_table): Likewise. > * config/mcore/mcore.cc (mcore_attribute_table): Likewise. > * config/microblaze/microblaze.cc (microblaze_attribute_table): > Likewise. > * config/mips/mips.cc (mips_attribute_table): Likewise. > * config/msp430/msp430.cc (msp430_attribute_table): Likewise. > * config/nds32/nds32.cc (nds32_attribute_table): Likewise. > * config/nvptx/nvptx.cc (nvptx_attribute_table): Likewise. > * config/riscv/riscv.cc (riscv_attribute_table): Likewise. > * config/rl78/rl78.cc (rl78_attribute_table): Likewise. > * config/rx/rx.cc (rx_attribute_table): Likewise. > * config/s390/s390.cc (s390_attribute_table): Likewise. > * config/sh/sh.cc (sh_attribute_table): Likewise. > * config/sparc/sparc.cc (sparc_attribute_table): Likewise. > * config/stormy16/stormy16.cc (xstormy16_attribute_table): Likewise. > * config/v850/v850.cc (v850_attribute_table): Likewise. > * config/visium/visium.cc (visium_attribute_table): Likewise. > * config/arc/arc.cc (arc_attribute_table): Likewise. Move further > down file. > * config/arm/arm.cc (arm_attribute_table): Update for above changes, > using... > (arm_gnu_attributes, arm_gnu_attribute_table): ...these new globals. > * config/i386/i386-options.h (ix86_attribute_table): Delete. > (ix86_gnu_attribute_table): Declare. > * config/i386/i386-options.cc (ix86_attribute_table): Replace with... > (ix86_gnu_attributes, ix86_gnu_attribute_table): ...these two globals. > * config/i386/i386.cc (ix86_attribute_table): Define as an array of > scoped_attribute_specs pointers. > * config/ia64/ia64.cc (ia64_attribute_table): Update for above changes, > using... > (ia64_gnu_attributes, ia64_gnu_attribute_table): ...these new globals. > * config/rs6000/rs6000.cc (rs6000_attribute_table): Update for above > changes, using... > (rs6000_gnu_attributes, rs6000_gnu_attribute_table): ...these new > globals. > > gcc/ada/ > * gcc-interface/gigi.h (gnat_internal_attribute_table): Change > type to scoped_attribute_specs. > * gcc-interface/utils.cc (gnat_internal_attribute_table): Likewise, > using... > (gnat_internal_attributes): ...this as the underlying array. > * gcc-interface/misc.cc (gnat_attribute_table): New global. > (LANG_HOOKS_ATTRIBUTE_TABLE): Use it. > > gcc/c-family/ > * c-common.h (c_common_attribute_table): Replace with... > (c_common_gnu_attribute_table): ...this. > (c_common_format_attribute_table): Change type to > scoped_attribute_specs. > * c-attribs.cc (c_common_attribute_table): Replace with... > (c_common_gnu_attributes, c_common_gnu_attribute_table): ...these > new globals. > (c_common_format_attribute_table): Change type to > scoped_attribute_specs, using... > (c_common_format_attributes): ...this as the underlying array. > > gcc/c/ > * c-tree.h (std_attribute_table): Declare. > * c-decl.cc (std_attribute_table): Change type to > scoped_attribute_specs, using... > (std_attributes): ...this as the underlying array. > (c_init_decl_processing): Remove call to register_scoped_attributes. > * c-objc-common.h (c_objc_attribute_table): New global. > (LANG_HOOKS_ATTRIBUTE_TABLE): Use it. > (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Delete. > > gcc/cp/ > * cp-tree.h (cxx_attribute_table): Delete. > (cxx_gnu_attribute_table, std_attribute_table): Declare. > * cp-objcp-common.h (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Delete. > (cp_objcp_attribute_table): New table. > (LANG_HOOKS_ATTRIBUTE_TABLE): Redefine. > * tree.cc (cxx_attribute_table): Replace with... > (cxx_gnu_attributes, cxx_gnu_attribute_table): ...these globals. > (std_attribute_table): Change type to scoped_attribute_specs, using... > (std_attributes): ...this as the underlying array. > (init_tree): Remove call to register_scoped_attributes. > > gcc/d/ > * d-tree.h (d_langhook_attribute_table): Replace with... > (d_langhook_gnu_attribute_table): ...this. > (d_langhook_common_attribute_table): Change type to > scoped_attribute_specs. > * d-attribs.cc (d_langhook_common_attribute_table): Change type to > scoped_attribute_specs, using... > (d_langhook_common_attributes): ...this as the underlying array. > (d_langhook_attribute_table): Replace with... > (d_langhook_gnu_attributes, d_langhook_gnu_attribute_table): ...these > new globals. > (uda_attribute_p): Update accordingly, and update for new > targetm.attribute_table type. > * d-lang.cc (d_langhook_attribute_table): New global. > (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > > gcc/fortran/ > * f95-lang.cc: Include attribs.h. > (gfc_attribute_table): Change to an array of scoped_attribute_specs > pointers, using... > (gfc_gnu_attributes, gfc_gnu_attribute_table): ...these new globals. > > gcc/jit/ > * dummy-frontend.cc (jit_format_attribute_table): Change type to > scoped_attribute_specs, using... > (jit_format_attributes): ...this as the underlying array. > (jit_attribute_table): Change to an array of scoped_attribute_specs > pointers, using... > (jit_gnu_attributes, jit_gnu_attribute_table): ...these new globals > for the original array. Include the format attributes. > (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_ATTRIBUTE_TABLE): Define. > > gcc/lto/ > * lto-lang.cc (lto_format_attribute_table): Change type to > scoped_attribute_specs, using... > (lto_format_attributes): ...this as the underlying array. > (lto_attribute_table): Change to an array of scoped_attribute_specs > pointers, using... > (lto_gnu_attributes, lto_gnu_attribute_table): ...these new globals > for the original array. Include the format attributes. > (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Delete. > (LANG_HOOKS_ATTRIBUTE_TABLE): Define. > --- > gcc/ada/gcc-interface/gigi.h | 2 +- > gcc/ada/gcc-interface/misc.cc | 7 +- > gcc/ada/gcc-interface/utils.cc | 8 +- > gcc/attribs.cc | 221 ++++++++++++---------------- > gcc/attribs.h | 12 +- > gcc/c-family/c-attribs.cc | 20 ++- > gcc/c-family/c-common.h | 4 +- > gcc/c/c-decl.cc | 12 +- > gcc/c/c-objc-common.h | 14 +- > gcc/c/c-tree.h | 2 + > gcc/config/aarch64/aarch64.cc | 7 +- > gcc/config/alpha/alpha.cc | 7 +- > gcc/config/arc/arc.cc | 74 +++++----- > gcc/config/arm/arm.cc | 15 +- > gcc/config/avr/avr.cc | 7 +- > gcc/config/bfin/bfin.cc | 7 +- > gcc/config/bpf/bpf.cc | 9 +- > gcc/config/csky/csky.cc | 7 +- > gcc/config/epiphany/epiphany.cc | 7 +- > gcc/config/gcn/gcn.cc | 8 +- > gcc/config/h8300/h8300.cc | 7 +- > gcc/config/i386/i386-options.cc | 10 +- > gcc/config/i386/i386-options.h | 2 +- > gcc/config/i386/i386.cc | 5 + > gcc/config/ia64/ia64.cc | 15 +- > gcc/config/loongarch/loongarch.cc | 8 +- > gcc/config/m32c/m32c.cc | 7 +- > gcc/config/m32r/m32r.cc | 7 +- > gcc/config/m68k/m68k.cc | 7 +- > gcc/config/mcore/mcore.cc | 7 +- > gcc/config/microblaze/microblaze.cc | 7 +- > gcc/config/mips/mips.cc | 7 +- > gcc/config/msp430/msp430.cc | 8 +- > gcc/config/nds32/nds32.cc | 9 +- > gcc/config/nvptx/nvptx.cc | 7 +- > gcc/config/riscv/riscv.cc | 9 +- > gcc/config/rl78/rl78.cc | 7 +- > gcc/config/rs6000/rs6000.cc | 13 +- > gcc/config/rx/rx.cc | 7 +- > gcc/config/s390/s390.cc | 9 +- > gcc/config/sh/sh.cc | 7 +- > gcc/config/sparc/sparc.cc | 7 +- > gcc/config/stormy16/stormy16.cc | 7 +- > gcc/config/v850/v850.cc | 7 +- > gcc/config/visium/visium.cc | 7 +- > gcc/cp/cp-objcp-common.h | 15 +- > gcc/cp/cp-tree.h | 3 +- > gcc/cp/tree.cc | 16 +- > gcc/d/d-attribs.cc | 35 ++--- > gcc/d/d-lang.cc | 8 +- > gcc/d/d-tree.h | 4 +- > gcc/doc/tm.texi | 33 ++++- > gcc/fortran/f95-lang.cc | 14 +- > gcc/jit/dummy-frontend.cc | 32 ++-- > gcc/langhooks-def.h | 6 +- > gcc/langhooks.h | 4 +- > gcc/lto/lto-lang.cc | 30 ++-- > gcc/plugin.h | 3 +- > gcc/target-def.h | 14 ++ > gcc/target.def | 35 ++++- > gcc/tree-inline.cc | 7 +- > 61 files changed, 494 insertions(+), 408 deletions(-) > > diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h > index eb5496f50db..63ccf311c23 100644 > --- a/gcc/ada/gcc-interface/gigi.h > +++ b/gcc/ada/gcc-interface/gigi.h > @@ -350,7 +350,7 @@ struct attrib > }; > > /* Table of machine-independent internal attributes. */ > -extern const struct attribute_spec gnat_internal_attribute_table[]; > +extern const struct scoped_attribute_specs gnat_internal_attribute_table; > > /* Define the entries in the standard data array. */ > enum standard_datatypes > diff --git a/gcc/ada/gcc-interface/misc.cc b/gcc/ada/gcc-interface/misc.cc > index 7d6d4466d56..01e8267f884 100644 > --- a/gcc/ada/gcc-interface/misc.cc > +++ b/gcc/ada/gcc-interface/misc.cc > @@ -1352,6 +1352,11 @@ get_lang_specific (tree node) > return TYPE_LANG_SPECIFIC (node); > } > > +const struct scoped_attribute_specs *const gnat_attribute_table[] = > +{ > + &gnat_internal_attribute_table > +}; > + > /* Definitions for our language-specific hooks. */ > > #undef LANG_HOOKS_NAME > @@ -1417,7 +1422,7 @@ get_lang_specific (tree node) > #undef LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO > #define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO gnat_get_fixed_point_type_info > #undef LANG_HOOKS_ATTRIBUTE_TABLE > -#define LANG_HOOKS_ATTRIBUTE_TABLE gnat_internal_attribute_table > +#define LANG_HOOKS_ATTRIBUTE_TABLE gnat_attribute_table > #undef LANG_HOOKS_BUILTIN_FUNCTION > #define LANG_HOOKS_BUILTIN_FUNCTION gnat_builtin_function > #undef LANG_HOOKS_INIT_TS > diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc > index 4e2ed173fbe..c38e0e6f57d 100644 > --- a/gcc/ada/gcc-interface/utils.cc > +++ b/gcc/ada/gcc-interface/utils.cc > @@ -136,7 +136,7 @@ static tree fake_attribute_handler (tree *, tree, tree, int, bool *); > > /* Table of machine-independent internal attributes for Ada. We support > this minimal set of attributes to accommodate the needs of builtins. */ > -const struct attribute_spec gnat_internal_attribute_table[] = > +static const attribute_spec gnat_internal_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -217,9 +217,11 @@ const struct attribute_spec gnat_internal_attribute_table[] = > /* This is handled entirely in the front end. */ > { "hardbool", 0, 0, false, true, false, true, > fake_attribute_handler, NULL }, > +}; > > - { NULL, 0, 0, false, false, false, false, > - NULL, NULL } > +const scoped_attribute_specs gnat_internal_attribute_table = > +{ > + "gnu", gnat_internal_attributes > }; > > /* Associates a GNAT tree node to a GCC tree node. It is used in > diff --git a/gcc/attribs.cc b/gcc/attribs.cc > index d1d9e5a28c1..6725fe78f2c 100644 > --- a/gcc/attribs.cc > +++ b/gcc/attribs.cc > @@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see > > /* Table of the tables of attributes (common, language, format, machine) > searched. */ > -static const struct attribute_spec *attribute_tables[4]; > +static array_slice<const scoped_attribute_specs *const> attribute_tables[2]; > > /* Substring representation. */ > > @@ -102,13 +102,6 @@ static const struct attribute_spec *lookup_scoped_attribute_spec (const_tree, > > static bool attributes_initialized = false; > > -/* Default empty table of attributes. */ > - > -static const struct attribute_spec empty_attribute_table[] = > -{ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > - > /* Return base name of the attribute. Ie '__attr__' is turned into 'attr'. > To avoid need for copying, we simply return length of the string. */ > > @@ -118,21 +111,19 @@ extract_attribute_substring (struct substring *str) > canonicalize_attr_name (str->str, str->length); > } > > -/* Insert an array of attributes ATTRIBUTES into a namespace. This > - array must be NULL terminated. NS is the name of attribute > - namespace. IGNORED_P is true iff all unknown attributes in this > - namespace should be ignored for the purposes of -Wattributes. The > - function returns the namespace into which the attributes have been > - registered. */ > +/* Insert SPECS into its namespace. IGNORED_P is true iff all unknown > + attributes in this namespace should be ignored for the purposes of > + -Wattributes. The function returns the namespace into which the > + attributes have been registered. */ > > scoped_attributes * > -register_scoped_attributes (const struct attribute_spec *attributes, > - const char *ns, bool ignored_p /*=false*/) > +register_scoped_attributes (const scoped_attribute_specs &specs, > + bool ignored_p /*=false*/) > { > scoped_attributes *result = NULL; > > /* See if we already have attributes in the namespace NS. */ > - result = find_attribute_namespace (ns); > + result = find_attribute_namespace (specs.ns); > > if (result == NULL) > { > @@ -143,7 +134,7 @@ register_scoped_attributes (const struct attribute_spec *attributes, > attributes_table.create (64); > > memset (&sa, 0, sizeof (sa)); > - sa.ns = ns; > + sa.ns = specs.ns; > sa.attributes.create (64); > sa.ignored_p = ignored_p; > result = attributes_table.safe_push (sa); > @@ -153,10 +144,10 @@ register_scoped_attributes (const struct attribute_spec *attributes, > result->ignored_p |= ignored_p; > > /* Really add the attributes to their namespace now. */ > - for (unsigned i = 0; attributes[i].name != NULL; ++i) > + for (const attribute_spec &attribute : specs.attributes) > { > - result->attributes.safe_push (attributes[i]); > - register_scoped_attribute (&attributes[i], result); > + result->attributes.safe_push (attribute); > + register_scoped_attribute (&attribute, result); > } > > gcc_assert (result != NULL); > @@ -183,49 +174,40 @@ find_attribute_namespace (const char* ns) > static void > check_attribute_tables (void) > { > - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) > - for (size_t 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); > + hash_set<pair_hash<nofree_string_hash, nofree_string_hash>> names; > > - gcc_assert (!(name[0] == '_' && name[1] == '_' > - && name[len - 1] == '_' && name[len - 2] == '_')); > + for (auto scoped_array : attribute_tables) > + for (auto scoped_attributes : scoped_array) > + for (const attribute_spec &attribute : scoped_attributes->attributes) > + { > + /* The name must not begin and end with __. */ > + const char *name = attribute.name; > + int len = strlen (name); > + > + gcc_assert (!(name[0] == '_' && name[1] == '_' > + && name[len - 1] == '_' && name[len - 2] == '_')); > > - /* The minimum and maximum lengths must be consistent. */ > - gcc_assert (attribute_tables[i][j].min_length >= 0); > + /* The minimum and maximum lengths must be consistent. */ > + gcc_assert (attribute.min_length >= 0); > > - gcc_assert (attribute_tables[i][j].max_length == -1 > - || (attribute_tables[i][j].max_length > - >= attribute_tables[i][j].min_length)); > + gcc_assert (attribute.max_length == -1 > + || attribute.max_length >= attribute.min_length); > > - /* An attribute cannot require both a DECL and a TYPE. */ > - gcc_assert (!attribute_tables[i][j].decl_required > - || !attribute_tables[i][j].type_required); > + /* An attribute cannot require both a DECL and a TYPE. */ > + gcc_assert (!attribute.decl_required > + || !attribute.type_required); > > /* If an attribute requires a function type, in particular > it requires a type. */ > - gcc_assert (!attribute_tables[i][j].function_type_required > - || attribute_tables[i][j].type_required); > - } > - > - /* Check that each name occurs just once in each table. */ > - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) > - for (size_t j = 0; attribute_tables[i][j].name != NULL; j++) > - for (size_t k = j + 1; attribute_tables[i][k].name != NULL; k++) > - gcc_assert (strcmp (attribute_tables[i][j].name, > - attribute_tables[i][k].name)); > - > - /* Check that no name occurs in more than one table. Names that > - begin with '*' are exempt, and may be overridden. */ > - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) > - for (size_t j = i + 1; j < ARRAY_SIZE (attribute_tables); j++) > - for (size_t k = 0; attribute_tables[i][k].name != NULL; k++) > - for (size_t l = 0; attribute_tables[j][l].name != NULL; l++) > - gcc_assert (attribute_tables[i][k].name[0] == '*' > - || strcmp (attribute_tables[i][k].name, > - attribute_tables[j][l].name)); > + gcc_assert (!attribute.function_type_required > + || attribute.type_required); > + > + /* Check that no name occurs more than once. Names that > + begin with '*' are exempt, and may be overridden. */ > + const char *ns = scoped_attributes->ns; > + if (name[0] != '*' && names.add ({ ns ? ns : "", name })) > + gcc_unreachable (); > + } > } > > /* Used to stash pointers to allocated memory so that we can free them at > @@ -281,7 +263,7 @@ handle_ignored_attributes_option (vec<char *> *v) > canonicalize_attr_name (vendor_start, vendor_len); > /* We perform all this hijinks so that we don't have to copy OPT. */ > tree vendor_id = get_identifier_with_length (vendor_start, vendor_len); > - const char *attr; > + array_slice<const attribute_spec> attrs; > /* In the "vendor::" case, we should ignore *any* attribute coming > from this attribute namespace. */ > if (attr_len > 0) > @@ -293,22 +275,23 @@ handle_ignored_attributes_option (vec<char *> *v) > } > canonicalize_attr_name (attr_start, attr_len); > tree attr_id = get_identifier_with_length (attr_start, attr_len); > - attr = IDENTIFIER_POINTER (attr_id); > + const char *attr = IDENTIFIER_POINTER (attr_id); > /* If we've already seen this vendor::attr, ignore it. Attempting to > register it twice would lead to a crash. */ > if (lookup_scoped_attribute_spec (vendor_id, attr_id)) > continue; > + /* Create a table with extra attributes which we will register. > + We can't free it here, so squirrel away the pointers. */ > + attribute_spec *table = new attribute_spec { > + attr, 0, -2, false, false, false, false, nullptr, nullptr > + }; > + ignored_attributes_table.safe_push (table); > + attrs = { table, 1 }; > } > - else > - attr = nullptr; > - /* Create a table with extra attributes which we will register. > - We can't free it here, so squirrel away the pointers. */ > - attribute_spec *table = new attribute_spec[2]; > - ignored_attributes_table.safe_push (table); > - table[0] = { attr, 0, -2, false, false, false, false, nullptr, nullptr }; > - table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, > - nullptr }; > - register_scoped_attributes (table, IDENTIFIER_POINTER (vendor_id), !attr); > + const scoped_attribute_specs scoped_specs = { > + IDENTIFIER_POINTER (vendor_id), attrs > + }; > + register_scoped_attributes (scoped_specs, attrs.empty ()); > } > } > > @@ -328,27 +311,18 @@ free_attr_data () > void > init_attributes (void) > { > - size_t i; > - > if (attributes_initialized) > return; > > - attribute_tables[0] = lang_hooks.common_attribute_table; > - attribute_tables[1] = lang_hooks.attribute_table; > - attribute_tables[2] = lang_hooks.format_attribute_table; > - attribute_tables[3] = targetm.attribute_table; > - > - /* Translate NULL pointers to pointers to the empty table. */ > - for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) > - if (attribute_tables[i] == NULL) > - attribute_tables[i] = empty_attribute_table; > + attribute_tables[0] = lang_hooks.attribute_table; > + attribute_tables[1] = targetm.attribute_table; > > if (flag_checking) > check_attribute_tables (); > > - for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i) > - /* Put all the GNU attributes into the "gnu" namespace. */ > - register_scoped_attributes (attribute_tables[i], "gnu"); > + for (auto scoped_array : attribute_tables) > + for (auto scoped_attributes : scoped_array) > + register_scoped_attributes (*scoped_attributes); > > vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes; > handle_ignored_attributes_option (ignored); > @@ -2642,10 +2616,6 @@ attr_access::array_as_string (tree type) const > namespace selftest > { > > -/* Helper types to verify the consistency attribute exclusions. */ > - > -typedef std::pair<const char *, const char *> excl_pair; > - > /* Self-test to verify that each attribute exclusion is symmetric, > meaning that if attribute A is encoded as incompatible with > attribute B then the opposite relationship is also encoded. > @@ -2660,55 +2630,54 @@ test_attribute_exclusions () > /* Iterate over the array of attribute tables first (with TI0 as > the index) and over the array of attribute_spec in each table > (with SI0 as the index). */ > - const size_t ntables = ARRAY_SIZE (attribute_tables); > + hash_set<excl_hash_traits> excl_set; > > - /* Set of pairs of mutually exclusive attributes. */ > - typedef hash_set<excl_hash_traits> exclusion_set; > - exclusion_set excl_set; > + for (auto scoped_array : attribute_tables) > + for (auto scoped_attributes : scoped_array) > + for (const attribute_spec &attribute : scoped_attributes->attributes) > + { > + const attribute_spec::exclusions *excl = attribute.exclude; > > - for (size_t ti0 = 0; ti0 != ntables; ++ti0) > - for (size_t s0 = 0; attribute_tables[ti0][s0].name; ++s0) > - { > - const attribute_spec::exclusions *excl > - = attribute_tables[ti0][s0].exclude; > + /* Skip each attribute that doesn't define exclusions. */ > + if (!excl) > + continue; > > - /* Skip each attribute that doesn't define exclusions. */ > - if (!excl) > - continue; > + /* Skip standard (non-GNU) attributes, since currently the > + exclusions are implicitly for GNU attributes only. > + Also, C++ likely and unlikely get rewritten to gnu::hot > + and gnu::cold, so symmetry isn't necessary there. */ > + if (!scoped_attributes->ns) > + continue; > > - const char *attr_name = attribute_tables[ti0][s0].name; > + const char *attr_name = attribute.name; > > - /* Iterate over the set of exclusions for every attribute > - (with EI0 as the index) adding the exclusions defined > - for each to the set. */ > - for (size_t ei0 = 0; excl[ei0].name; ++ei0) > - { > - const char *excl_name = excl[ei0].name; > + /* Iterate over the set of exclusions for every attribute > + (with EI0 as the index) adding the exclusions defined > + for each to the set. */ > + for (size_t ei0 = 0; excl[ei0].name; ++ei0) > + { > + const char *excl_name = excl[ei0].name; > > - if (!strcmp (attr_name, excl_name)) > - continue; > + if (!strcmp (attr_name, excl_name)) > + continue; > > - excl_set.add (excl_pair (attr_name, excl_name)); > - } > - } > + excl_set.add ({ attr_name, excl_name }); > + } > + } > > /* Traverse the set of mutually exclusive pairs of attributes > and verify that they are symmetric. */ > - for (exclusion_set::iterator it = excl_set.begin (); > - it != excl_set.end (); > - ++it) > - { > - if (!excl_set.contains (excl_pair ((*it).second, (*it).first))) > - { > - /* An exclusion for an attribute has been found that > - doesn't have a corresponding exclusion in the opposite > - direction. */ > - char desc[120]; > - sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric", > - (*it).first, (*it).second); > - fail (SELFTEST_LOCATION, desc); > - } > - } > + for (auto excl_pair : excl_set) > + if (!excl_set.contains ({ excl_pair.second, excl_pair.first })) > + { > + /* An exclusion for an attribute has been found that > + doesn't have a corresponding exclusion in the opposite > + direction. */ > + char desc[120]; > + sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric", > + excl_pair.first, excl_pair.second); > + fail (SELFTEST_LOCATION, desc); > + } > } > > void > diff --git a/gcc/attribs.h b/gcc/attribs.h > index 84a43658a70..fdeebff1cd9 100644 > --- a/gcc/attribs.h > +++ b/gcc/attribs.h > @@ -20,6 +20,13 @@ along with GCC; see the file COPYING3. If not see > #ifndef GCC_ATTRIBS_H > #define GCC_ATTRIBS_H > > +/* A set of attributes that belong to the same namespace, given by NS. */ > +struct scoped_attribute_specs > +{ > + const char *ns; > + array_slice<const attribute_spec> attributes; > +}; > + > extern const struct attribute_spec *lookup_attribute_spec (const_tree); > extern void free_attr_data (); > extern void init_attributes (void); > @@ -42,9 +49,8 @@ extern tree make_attribute (const char *, const char *, tree); > extern bool attribute_ignored_p (tree); > extern bool attribute_ignored_p (const attribute_spec *const); > > -extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, > - const char *, > - bool = false); > +extern struct scoped_attributes * > + register_scoped_attributes (const scoped_attribute_specs &, bool = false); > > extern char *sorted_attr_string (tree); > extern bool common_function_versions (tree, tree); > diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc > index a041c3b91eb..cf54ef68f20 100644 > --- a/gcc/c-family/c-attribs.cc > +++ b/gcc/c-family/c-attribs.cc > @@ -288,7 +288,7 @@ static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] = > /* Table of machine-independent attributes common to all C-like languages. > > Current list of processed common attributes: nonnull. */ > -const struct attribute_spec c_common_attribute_table[] = > +const struct attribute_spec c_common_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -574,23 +574,31 @@ const struct attribute_spec c_common_attribute_table[] = > { "fd_arg_write", 1, 1, false, true, true, false, > handle_fd_arg_attribute, NULL}, > { "null_terminated_string_arg", 1, 1, false, true, true, false, > - handle_null_terminated_string_arg_attribute, NULL}, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + handle_null_terminated_string_arg_attribute, NULL} > +}; > + > +const struct scoped_attribute_specs c_common_gnu_attribute_table = > +{ > + "gnu", c_common_gnu_attributes > }; > > /* Give the specifications for the format attributes, used by C and all > descendants. > > Current list of processed format attributes: format, format_arg. */ > -const struct attribute_spec c_common_format_attribute_table[] = > +const struct attribute_spec c_common_format_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "format", 3, 3, false, true, true, false, > handle_format_attribute, NULL }, > { "format_arg", 1, 1, false, true, true, false, > - handle_format_arg_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + handle_format_arg_attribute, NULL } > +}; > + > +const struct scoped_attribute_specs c_common_format_attribute_table = > +{ > + "gnu", c_common_format_attributes > }; > > /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index 1fdba7ef3ea..92ddad27806 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -821,8 +821,8 @@ enum conversion_safety { > extern struct visibility_flags visibility_options; > > /* Attribute table common to the C front ends. */ > -extern const struct attribute_spec c_common_attribute_table[]; > -extern const struct attribute_spec c_common_format_attribute_table[]; > +extern const struct scoped_attribute_specs c_common_gnu_attribute_table; > +extern const struct scoped_attribute_specs c_common_format_attribute_table; > > /* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc. > ID is the identifier to use, NAME is the string. > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index 0076725a61d..547bebe03c9 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -4635,7 +4635,7 @@ handle_std_noreturn_attribute (tree *node, tree name, tree args, > } > > /* Table of supported standard (C2x) attributes. */ > -const struct attribute_spec std_attribute_table[] = > +static const attribute_spec std_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -4650,8 +4650,12 @@ const struct attribute_spec std_attribute_table[] = > { "nodiscard", 0, 1, false, false, false, false, > handle_nodiscard_attribute, NULL }, > { "noreturn", 0, 0, false, false, false, false, > - handle_std_noreturn_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + handle_std_noreturn_attribute, NULL } > +}; > + > +const scoped_attribute_specs std_attribute_table = > +{ > + nullptr, std_attributes > }; > > /* Create the predefined scalar types of C, > @@ -4667,8 +4671,6 @@ c_init_decl_processing (void) > /* Initialize reserved words for parser. */ > c_parse_init (); > > - register_scoped_attributes (std_attribute_table, NULL); > - > current_function_decl = NULL_TREE; > > gcc_obstack_init (&parser_obstack); > diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h > index ede451cef6b..4f1925c8b07 100644 > --- a/gcc/c/c-objc-common.h > +++ b/gcc/c/c-objc-common.h > @@ -72,11 +72,15 @@ along with GCC; see the file COPYING3. If not see > #undef LANG_HOOKS_FINALIZE_EARLY_DEBUG > #define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug > > -/* Attribute hooks. */ > -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table > -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE > -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table > +static const scoped_attribute_specs *const c_objc_attribute_table[] = > +{ > + &std_attribute_table, > + &c_common_gnu_attribute_table, > + &c_common_format_attribute_table > +}; > + > +#undef LANG_HOOKS_ATTRIBUTE_TABLE > +#define LANG_HOOKS_ATTRIBUTE_TABLE c_objc_attribute_table > > #undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN > #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN c_dump_tree > diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h > index df6f1cefd02..69e154abdbd 100644 > --- a/gcc/c/c-tree.h > +++ b/gcc/c/c-tree.h > @@ -910,6 +910,8 @@ extern vec<tree> incomplete_record_decls; > > extern const char *c_get_sarif_source_language (const char *filename); > > +extern const struct scoped_attribute_specs std_attribute_table; > + > #if CHECKING_P > namespace selftest { > extern void run_c_tests (void); > diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc > index cb65ccc8465..920e17d3a95 100644 > --- a/gcc/config/aarch64/aarch64.cc > +++ b/gcc/config/aarch64/aarch64.cc > @@ -2839,7 +2839,7 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree name, tree, > } > > /* Table of machine attributes. */ > -static const struct attribute_spec aarch64_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -2850,9 +2850,8 @@ static const struct attribute_spec aarch64_attribute_table[] = > NULL }, > { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, > { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, > - { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL } > +}); > > typedef enum aarch64_cond_code > { > diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc > index db6b34be9cb..6aa93783226 100644 > --- a/gcc/config/alpha/alpha.cc > +++ b/gcc/config/alpha/alpha.cc > @@ -7482,14 +7482,13 @@ common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED, > return NULL_TREE; > } > > -static const struct attribute_spec vms_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (vms_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { COMMON_OBJECT, 0, 1, true, false, false, false, common_object_handler, > - NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + NULL } > +}); > > void > vms_output_aligned_decl_common(FILE *file, tree decl, const char *name, > diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc > index e209ad2d327..e87d7614feb 100644 > --- a/gcc/config/arc/arc.cc > +++ b/gcc/config/arc/arc.cc > @@ -187,44 +187,6 @@ static tree arc_handle_secure_attribute (tree *, tree, tree, int, bool *); > static tree arc_handle_uncached_attribute (tree *, tree, tree, int, bool *); > static tree arc_handle_aux_attribute (tree *, tree, tree, int, bool *); > > -/* Initialized arc_attribute_table to NULL since arc doesnot have any > - machine specific supported attributes. */ > -const struct attribute_spec arc_attribute_table[] = > -{ > - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > - affects_type_identity, handler, exclude } */ > - { "interrupt", 1, 1, true, false, false, true, > - arc_handle_interrupt_attribute, NULL }, > - /* Function calls made to this symbol must be done indirectly, because > - it may lie outside of the 21/25 bit addressing range of a normal function > - call. */ > - { "long_call", 0, 0, false, true, true, false, NULL, NULL }, > - /* Whereas these functions are always known to reside within the 25 bit > - addressing range of unconditionalized bl. */ > - { "medium_call", 0, 0, false, true, true, false, NULL, NULL }, > - /* And these functions are always known to reside within the 21 bit > - addressing range of blcc. */ > - { "short_call", 0, 0, false, true, true, false, NULL, NULL }, > - /* Function which are not having the prologue and epilogue generated > - by the compiler. */ > - { "naked", 0, 0, true, false, false, false, arc_handle_fndecl_attribute, > - NULL }, > - /* Functions calls made using jli instruction. The pointer in JLI > - table is found latter. */ > - { "jli_always", 0, 0, false, true, true, false, NULL, NULL }, > - /* Functions calls made using jli instruction. The pointer in JLI > - table is given as input parameter. */ > - { "jli_fixed", 1, 1, false, true, true, false, arc_handle_jli_attribute, > - NULL }, > - /* Call a function using secure-mode. */ > - { "secure_call", 1, 1, false, true, true, false, arc_handle_secure_attribute, > - NULL }, > - /* Bypass caches using .di flag. */ > - { "uncached", 0, 0, false, true, false, false, arc_handle_uncached_attribute, > - NULL }, > - { "aux", 0, 1, true, false, false, false, arc_handle_aux_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > static int arc_comp_type_attributes (const_tree, const_tree); > static void arc_file_start (void); > static void arc_internal_label (FILE *, const char *, unsigned long); > @@ -770,6 +732,42 @@ static rtx arc_legitimize_address_0 (rtx, rtx, machine_mode mode); > > #include "target-def.h" > > +TARGET_GNU_ATTRIBUTES (arc_attribute_table, > +{ > + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > + affects_type_identity, handler, exclude } */ > + { "interrupt", 1, 1, true, false, false, true, > + arc_handle_interrupt_attribute, NULL }, > + /* Function calls made to this symbol must be done indirectly, because > + it may lie outside of the 21/25 bit addressing range of a normal function > + call. */ > + { "long_call", 0, 0, false, true, true, false, NULL, NULL }, > + /* Whereas these functions are always known to reside within the 25 bit > + addressing range of unconditionalized bl. */ > + { "medium_call", 0, 0, false, true, true, false, NULL, NULL }, > + /* And these functions are always known to reside within the 21 bit > + addressing range of blcc. */ > + { "short_call", 0, 0, false, true, true, false, NULL, NULL }, > + /* Function which are not having the prologue and epilogue generated > + by the compiler. */ > + { "naked", 0, 0, true, false, false, false, arc_handle_fndecl_attribute, > + NULL }, > + /* Functions calls made using jli instruction. The pointer in JLI > + table is found latter. */ > + { "jli_always", 0, 0, false, true, true, false, NULL, NULL }, > + /* Functions calls made using jli instruction. The pointer in JLI > + table is given as input parameter. */ > + { "jli_fixed", 1, 1, false, true, true, false, arc_handle_jli_attribute, > + NULL }, > + /* Call a function using secure-mode. */ > + { "secure_call", 1, 1, false, true, true, false, arc_handle_secure_attribute, > + NULL }, > + /* Bypass caches using .di flag. */ > + { "uncached", 0, 0, false, true, false, false, arc_handle_uncached_attribute, > + NULL }, > + { "aux", 0, 1, true, false, false, false, arc_handle_aux_attribute, NULL } > +}); > + > #undef TARGET_ASM_ALIGNED_HI_OP > #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" > #undef TARGET_ASM_ALIGNED_SI_OP > diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc > index 620ef7bfb2f..ed2459128ff 100644 > --- a/gcc/config/arm/arm.cc > +++ b/gcc/config/arm/arm.cc > @@ -332,7 +332,7 @@ static rtx_insn *thumb1_md_asm_adjust (vec<rtx> &, vec<rtx> &, > static const char *arm_identify_fpu_from_isa (sbitmap); > > /* Table of machine attributes. */ > -static const struct attribute_spec arm_attribute_table[] = > +static const attribute_spec arm_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -380,8 +380,17 @@ static const struct attribute_spec arm_attribute_table[] = > arm_handle_cmse_nonsecure_entry, NULL }, > { "cmse_nonsecure_call", 0, 0, false, false, false, true, > arm_handle_cmse_nonsecure_call, NULL }, > - { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL } > +}; > + > +static const scoped_attribute_specs arm_gnu_attribute_table = > +{ > + "gnu", arm_gnu_attributes > +}; > + > +static const scoped_attribute_specs *const arm_attribute_table[] = > +{ > + &arm_gnu_attribute_table > }; > > /* Initialize the GCC target structure. */ > diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc > index 5e0217de36f..59d217efc45 100644 > --- a/gcc/config/avr/avr.cc > +++ b/gcc/config/avr/avr.cc > @@ -10442,7 +10442,7 @@ avr_eval_addr_attrib (rtx x) > > > /* AVR attributes. */ > -static const struct attribute_spec avr_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (avr_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -10467,9 +10467,8 @@ static const struct attribute_spec avr_attribute_table[] = > { "address", 1, 1, true, false, false, false, > avr_handle_addr_attribute, NULL }, > { "absdata", 0, 0, true, false, false, false, > - avr_handle_absdata_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + avr_handle_absdata_attribute, NULL } > +}); > > > /* Return true if we support address space AS for the architecture in effect > diff --git a/gcc/config/bfin/bfin.cc b/gcc/config/bfin/bfin.cc > index 5718babb6b2..c02136f5e0c 100644 > --- a/gcc/config/bfin/bfin.cc > +++ b/gcc/config/bfin/bfin.cc > @@ -4896,7 +4896,7 @@ bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name), > } > > /* Table of valid machine attributes. */ > -static const struct attribute_spec bfin_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (bfin_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -4921,9 +4921,8 @@ static const struct attribute_spec bfin_attribute_table[] = > bfin_handle_l1_data_attribute, NULL }, > { "l1_data_B", 0, 0, true, false, false, false, > bfin_handle_l1_data_attribute, NULL }, > - { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute, NULL } > +}); > > /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to > tell the assembler to generate pointers to function descriptors in > diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc > index 63637ece78e..c619865f1fc 100644 > --- a/gcc/config/bpf/bpf.cc > +++ b/gcc/config/bpf/bpf.cc > @@ -139,7 +139,7 @@ bpf_handle_preserve_access_index_attribute (tree *node, tree name, > > /* Target-specific attributes. */ > > -static const struct attribute_spec bpf_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (bpf_attribute_table, > { > /* Syntax: { name, min_len, max_len, decl_required, type_required, > function_type_required, affects_type_identity, handler, > @@ -156,11 +156,8 @@ static const struct attribute_spec bpf_attribute_table[] = > > /* Support for `naked' function attribute. */ > { "naked", 0, 1, false, false, false, false, > - bpf_handle_fndecl_attribute, NULL }, > - > - /* The last attribute spec is set to be NULL. */ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + bpf_handle_fndecl_attribute, NULL } > +}); > > #undef TARGET_ATTRIBUTE_TABLE > #define TARGET_ATTRIBUTE_TABLE bpf_attribute_table > diff --git a/gcc/config/csky/csky.cc b/gcc/config/csky/csky.cc > index 731f47cb2c0..ac089feea62 100644 > --- a/gcc/config/csky/csky.cc > +++ b/gcc/config/csky/csky.cc > @@ -211,16 +211,15 @@ const int csky_debugger_regno[FIRST_PSEUDO_REGISTER] = > /* Table of machine attributes. */ > static tree csky_handle_fndecl_attribute (tree *, tree, tree, int, bool *); > static tree csky_handle_isr_attribute (tree *, tree, tree, int, bool *); > -static const struct attribute_spec csky_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (csky_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "naked", 0, 0, true, false, false, false, csky_handle_fndecl_attribute, NULL }, > /* Interrupt Service Routines have special prologue and epilogue requirements. */ > { "interrupt", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL }, > - { "isr", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "isr", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL } > +}); > > /* A C structure for machine-specific, per-function data. > This is added to the cfun structure. */ > diff --git a/gcc/config/epiphany/epiphany.cc b/gcc/config/epiphany/epiphany.cc > index 68e748c688e..e10e64de823 100644 > --- a/gcc/config/epiphany/epiphany.cc > +++ b/gcc/config/epiphany/epiphany.cc > @@ -458,7 +458,7 @@ epiphany_init_reg_tables (void) > They unmask them while calling an interruptible > function, though. */ > > -static const struct attribute_spec epiphany_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (epiphany_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -468,9 +468,8 @@ static const struct attribute_spec epiphany_attribute_table[] = > epiphany_handle_forwarder_attribute, NULL }, > { "long_call", 0, 0, false, true, true, false, NULL, NULL }, > { "short_call", 0, 0, false, true, true, false, NULL, NULL }, > - { "disinterrupt", 0, 0, false, true, true, true, NULL, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "disinterrupt", 0, 0, false, true, true, true, NULL, NULL } > +}); > > /* Handle an "interrupt" attribute; arguments as in > struct attribute_spec.handler. */ > diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc > index 6a2aaefceca..795a852bb53 100644 > --- a/gcc/config/gcn/gcn.cc > +++ b/gcc/config/gcn/gcn.cc > @@ -357,14 +357,12 @@ gcn_handle_amdgpu_hsa_kernel_attribute (tree *node, tree name, > > Create target-specific __attribute__ types. */ > > -static const struct attribute_spec gcn_attribute_table[] = { > +TARGET_GNU_ATTRIBUTES (gcn_attribute_table, { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, > affects_type_identity } */ > {"amdgpu_hsa_kernel", 0, GCN_KERNEL_ARG_TYPES, false, true, > - true, true, gcn_handle_amdgpu_hsa_kernel_attribute, NULL}, > - /* End element. */ > - {NULL, 0, 0, false, false, false, false, NULL, NULL} > -}; > + true, true, gcn_handle_amdgpu_hsa_kernel_attribute, NULL} > +}); > > /* }}} */ > /* {{{ Registers and modes. */ > diff --git a/gcc/config/h8300/h8300.cc b/gcc/config/h8300/h8300.cc > index 4bbb1b711e8..5936cdca177 100644 > --- a/gcc/config/h8300/h8300.cc > +++ b/gcc/config/h8300/h8300.cc > @@ -4909,7 +4909,7 @@ h8300_insert_attributes (tree node, tree *attributes) > tiny_data: This variable lives in the tiny data area and can be > referenced with 16-bit absolute memory references. */ > > -static const struct attribute_spec h8300_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (h8300_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -4926,9 +4926,8 @@ static const struct attribute_spec h8300_attribute_table[] = > { "eightbit_data", 0, 0, true, false, false, false, > h8300_handle_eightbit_data_attribute, NULL }, > { "tiny_data", 0, 0, true, false, false, false, > - h8300_handle_tiny_data_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + h8300_handle_tiny_data_attribute, NULL } > +}); > > > /* Handle an attribute requiring a FUNCTION_DECL; arguments as in > diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc > index df7d24352d1..351c777c666 100644 > --- a/gcc/config/i386/i386-options.cc > +++ b/gcc/config/i386/i386-options.cc > @@ -3951,7 +3951,7 @@ handle_nodirect_extern_access_attribute (tree *pnode, tree name, > } > > /* Table of valid machine attributes. */ > -const struct attribute_spec ix86_attribute_table[] = > +static const attribute_spec ix86_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -4031,10 +4031,12 @@ const struct attribute_spec ix86_attribute_table[] = > { "cf_check", 0, 0, true, false, false, false, > ix86_handle_fndecl_attribute, NULL }, > { "nodirect_extern_access", 0, 0, true, false, false, false, > - handle_nodirect_extern_access_attribute, NULL }, > + handle_nodirect_extern_access_attribute, NULL } > +}; > > - /* End element. */ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > +const scoped_attribute_specs ix86_gnu_attribute_table = > +{ > + "gnu", ix86_gnu_attributes > }; > > #include "gt-i386-options.h" > diff --git a/gcc/config/i386/i386-options.h b/gcc/config/i386/i386-options.h > index 68666067fea..6274c594647 100644 > --- a/gcc/config/i386/i386-options.h > +++ b/gcc/config/i386/i386-options.h > @@ -82,7 +82,7 @@ void ix86_function_specific_print (FILE *, int, > struct cl_target_option *); > bool ix86_valid_target_attribute_p (tree, tree, tree, int); > > -extern const struct attribute_spec ix86_attribute_table[]; > +extern const struct scoped_attribute_specs ix86_gnu_attribute_table; > > > #endif /* GCC_I386_OPTIONS_H */ > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc > index 7b72aabf0da..e0eff9f1430 100644 > --- a/gcc/config/i386/i386.cc > +++ b/gcc/config/i386/i386.cc > @@ -25832,6 +25832,11 @@ ix86_run_selftests (void) > > #endif /* CHECKING_P */ > > +static const scoped_attribute_specs *const ix86_attribute_table[] = > +{ > + &ix86_gnu_attribute_table > +}; > + > /* Initialize the GCC target structure. */ > #undef TARGET_RETURN_IN_MEMORY > #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory > diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc > index c241e1a50fc..f7766c25622 100644 > --- a/gcc/config/ia64/ia64.cc > +++ b/gcc/config/ia64/ia64.cc > @@ -358,7 +358,7 @@ static bool ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d); > > > /* Table of valid machine attributes. */ > -static const struct attribute_spec ia64_attribute_table[] = > +static const attribute_spec ia64_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -370,8 +370,17 @@ static const struct attribute_spec ia64_attribute_table[] = > ia64_vms_common_object_attribute, NULL }, > #endif > { "version_id", 1, 1, true, false, false, false, > - ia64_handle_version_id_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + ia64_handle_version_id_attribute, NULL } > +}; > + > +static const scoped_attribute_specs ia64_gnu_attribute_table = > +{ > + "gnu", ia64_gnu_attributes > +}; > + > +static const scoped_attribute_specs *const ia64_attribute_table[] = > +{ > + &ia64_gnu_attribute_table > }; > > /* Initialize the GCC target structure. */ > diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc > index c782f571abc..bf73ab60072 100644 > --- a/gcc/config/loongarch/loongarch.cc > +++ b/gcc/config/loongarch/loongarch.cc > @@ -7812,15 +7812,13 @@ loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, > return NULL_TREE; > } > > -static const struct attribute_spec loongarch_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (loongarch_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "model", 1, 1, true, false, false, false, > - loongarch_handle_model_attribute, NULL }, > - /* The last attribute spec is set to be NULL. */ > - {} > -}; > + loongarch_handle_model_attribute, NULL } > +}); > > bool > loongarch_use_anchors_for_symbol_p (const_rtx symbol) > diff --git a/gcc/config/m32c/m32c.cc b/gcc/config/m32c/m32c.cc > index e18efc3c7f2..c63c75a6709 100644 > --- a/gcc/config/m32c/m32c.cc > +++ b/gcc/config/m32c/m32c.cc > @@ -2999,7 +2999,7 @@ current_function_special_page_vector (rtx x) > > #undef TARGET_ATTRIBUTE_TABLE > #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table > -static const struct attribute_spec m32c_attribute_table[] = { > +TARGET_GNU_ATTRIBUTES (m32c_attribute_table, { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "interrupt", 0, 0, false, false, false, false, interrupt_handler, NULL }, > @@ -3007,9 +3007,8 @@ static const struct attribute_spec m32c_attribute_table[] = { > { "fast_interrupt", 0, 0, false, false, false, false, > interrupt_handler, NULL }, > { "function_vector", 1, 1, true, false, false, false, > - function_vector_handler, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + function_vector_handler, NULL } > +}); > > #undef TARGET_COMP_TYPE_ATTRIBUTES > #define TARGET_COMP_TYPE_ATTRIBUTES m32c_comp_type_attributes > diff --git a/gcc/config/m32r/m32r.cc b/gcc/config/m32r/m32r.cc > index 63a1798da3d..1a9c8ef1391 100644 > --- a/gcc/config/m32r/m32r.cc > +++ b/gcc/config/m32r/m32r.cc > @@ -112,15 +112,14 @@ static HOST_WIDE_INT m32r_starting_frame_offset (void); > > /* M32R specific attributes. */ > > -static const struct attribute_spec m32r_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (m32r_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "interrupt", 0, 0, true, false, false, false, NULL, NULL }, > { "model", 1, 1, true, false, false, false, m32r_handle_model_attribute, > - NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + NULL } > +}); > > /* Initialize the GCC target structure. */ > #undef TARGET_ATTRIBUTE_TABLE > diff --git a/gcc/config/m68k/m68k.cc b/gcc/config/m68k/m68k.cc > index 145a92d8710..001cf5bd997 100644 > --- a/gcc/config/m68k/m68k.cc > +++ b/gcc/config/m68k/m68k.cc > @@ -361,7 +361,7 @@ static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int); > #undef TARGET_ASM_FINAL_POSTSCAN_INSN > #define TARGET_ASM_FINAL_POSTSCAN_INSN m68k_asm_final_postscan_insn > > -static const struct attribute_spec m68k_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (m68k_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -370,9 +370,8 @@ static const struct attribute_spec m68k_attribute_table[] = > { "interrupt_handler", 0, 0, true, false, false, false, > m68k_handle_fndecl_attribute, NULL }, > { "interrupt_thread", 0, 0, true, false, false, false, > - m68k_handle_fndecl_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + m68k_handle_fndecl_attribute, NULL } > +}); > > struct gcc_target targetm = TARGET_INITIALIZER; > > diff --git a/gcc/config/mcore/mcore.cc b/gcc/config/mcore/mcore.cc > index 6f1d7af7937..ca672547494 100644 > --- a/gcc/config/mcore/mcore.cc > +++ b/gcc/config/mcore/mcore.cc > @@ -151,16 +151,15 @@ static bool mcore_modes_tieable_p (machine_mode, machine_mode); > > /* MCore specific attributes. */ > > -static const struct attribute_spec mcore_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (mcore_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "dllexport", 0, 0, true, false, false, false, NULL, NULL }, > { "dllimport", 0, 0, true, false, false, false, NULL, NULL }, > { "naked", 0, 0, true, false, false, false, > - mcore_handle_naked_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + mcore_handle_naked_attribute, NULL } > +}); > > /* Initialize the GCC target structure. */ > #undef TARGET_ASM_EXTERNAL_LIBCALL > diff --git a/gcc/config/microblaze/microblaze.cc b/gcc/config/microblaze/microblaze.cc > index 60ad55120d2..3ea177b835e 100644 > --- a/gcc/config/microblaze/microblaze.cc > +++ b/gcc/config/microblaze/microblaze.cc > @@ -218,15 +218,14 @@ int break_handler; > int fast_interrupt; > int save_volatiles; > > -const struct attribute_spec microblaze_attribute_table[] = { > +TARGET_GNU_ATTRIBUTES (microblaze_attribute_table, { > /* name min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude */ > {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL }, > {"break_handler", 0, 0, true, false, false, false, NULL, NULL }, > {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL }, > - {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL } > +}); > > static int microblaze_interrupt_function_p (tree); > > diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc > index a304e1c5637..0cf49c13bf4 100644 > --- a/gcc/config/mips/mips.cc > +++ b/gcc/config/mips/mips.cc > @@ -611,7 +611,7 @@ static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int, > bool *); > > /* The value of TARGET_ATTRIBUTE_TABLE. */ > -static const struct attribute_spec mips_attribute_table[] = { > +TARGET_GNU_ATTRIBUTES (mips_attribute_table, { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "long_call", 0, 0, false, true, true, false, NULL, NULL }, > @@ -636,9 +636,8 @@ static const struct attribute_spec mips_attribute_table[] = { > mips_handle_use_shadow_register_set_attr, NULL }, > { "keep_interrupts_masked", 0, 0, false, true, true, false, NULL, NULL }, > { "use_debug_exception_return", 0, 0, false, true, true, false, NULL, NULL }, > - { "use_hazard_barrier_return", 0, 0, true, false, false, false, NULL, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "use_hazard_barrier_return", 0, 0, true, false, false, false, NULL, NULL } > +}); > > /* A table describing all the processors GCC knows about; see > mips-cpus.def for details. */ > diff --git a/gcc/config/msp430/msp430.cc b/gcc/config/msp430/msp430.cc > index 061a9c77961..85f499f175d 100644 > --- a/gcc/config/msp430/msp430.cc > +++ b/gcc/config/msp430/msp430.cc > @@ -2057,7 +2057,7 @@ static const struct attribute_spec::exclusions attr_either_exclusions[] = > #define TARGET_ATTRIBUTE_TABLE msp430_attribute_table > > /* Table of MSP430-specific attributes. */ > -const struct attribute_spec msp430_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (msp430_attribute_table, > { > /* { name, min_num_args, max_num_args, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -2075,10 +2075,8 @@ const struct attribute_spec msp430_attribute_table[] = > { ATTR_UPPER, 0, 0, true, false, false, false, msp430_section_attr, > attr_upper_exclusions }, > { ATTR_EITHER, 0, 0, true, false, false, false, msp430_section_attr, > - attr_either_exclusions }, > - > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > - }; > + attr_either_exclusions } > + }); > > #undef TARGET_HANDLE_GENERIC_ATTRIBUTE > #define TARGET_HANDLE_GENERIC_ATTRIBUTE msp430_handle_generic_attribute > diff --git a/gcc/config/nds32/nds32.cc b/gcc/config/nds32/nds32.cc > index 1f8de2a514a..e0a73985b66 100644 > --- a/gcc/config/nds32/nds32.cc > +++ b/gcc/config/nds32/nds32.cc > @@ -288,7 +288,7 @@ static const int nds32_reg_alloc_order_for_speed[] = > }; > > /* Defining target-specific uses of __attribute__. */ > -static const struct attribute_spec nds32_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (nds32_attribute_table, > { > /* Syntax: { name, min_len, max_len, decl_required, type_required, > function_type_required, affects_type_identity, handler, > @@ -326,11 +326,8 @@ static const struct attribute_spec nds32_attribute_table[] = > > /* FOR BACKWARD COMPATIBILITY, > this attribute also tells no prologue/epilogue. */ > - { "no_prologue", 0, 0, false, false, false, false, NULL, NULL }, > - > - /* The last attribute spec is set to be NULL. */ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + { "no_prologue", 0, 0, false, false, false, false, NULL, NULL } > +}); > > > /* ------------------------------------------------------------------------ */ > diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc > index 634c31673be..d5497631429 100644 > --- a/gcc/config/nvptx/nvptx.cc > +++ b/gcc/config/nvptx/nvptx.cc > @@ -5834,16 +5834,15 @@ nvptx_handle_shared_attribute (tree *node, tree name, tree ARG_UNUSED (args), > } > > /* Table of valid machine attributes. */ > -static const struct attribute_spec nvptx_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (nvptx_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "kernel", 0, 0, true, false, false, false, nvptx_handle_kernel_attribute, > NULL }, > { "shared", 0, 0, true, false, false, false, nvptx_handle_shared_attribute, > - NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + NULL } > +}); > > /* Limit vector alignments to BIGGEST_ALIGNMENT. */ > > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index e36b5fb9bd0..154d80b48e7 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -421,7 +421,7 @@ static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); > static void riscv_legitimize_poly_move (machine_mode, rtx, rtx, rtx); > > /* Defining target-specific uses of __attribute__. */ > -static const struct attribute_spec riscv_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (riscv_attribute_table, > { > /* Syntax: { name, min_len, max_len, decl_required, type_required, > function_type_required, affects_type_identity, handler, > @@ -437,11 +437,8 @@ static const struct attribute_spec riscv_attribute_table[] = > /* The following two are used for the built-in properties of the Vector type > and are not used externally */ > {"RVV sizeless type", 4, 4, false, true, false, true, NULL, NULL}, > - {"RVV type", 0, 0, false, true, false, true, NULL, NULL}, > - > - /* The last attribute spec is set to be NULL. */ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + {"RVV type", 0, 0, false, true, false, true, NULL, NULL} > +}); > > /* Order for the CLOBBERs/USEs of gpr_save. */ > static const unsigned gpr_save_reg_order[] = { > diff --git a/gcc/config/rl78/rl78.cc b/gcc/config/rl78/rl78.cc > index 0cbd6bf780a..b2e9b04b691 100644 > --- a/gcc/config/rl78/rl78.cc > +++ b/gcc/config/rl78/rl78.cc > @@ -898,7 +898,7 @@ rl78_handle_vector_attribute (tree * node, > #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table > > /* Table of RL78-specific attributes. */ > -const struct attribute_spec rl78_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (rl78_attribute_table, > { > /* Name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude. */ > @@ -911,9 +911,8 @@ const struct attribute_spec rl78_attribute_table[] = > { "saddr", 0, 0, true, false, false, false, > rl78_handle_saddr_attribute, NULL }, > { "vector", 1, -1, true, false, false, false, > - rl78_handle_vector_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + rl78_handle_vector_attribute, NULL } > +}); > > > > diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc > index 5f56c3ed85b..cc3f97ae4c5 100644 > --- a/gcc/config/rs6000/rs6000.cc > +++ b/gcc/config/rs6000/rs6000.cc > @@ -1255,7 +1255,7 @@ static const char alt_reg_names[][8] = > > /* Table of valid machine attributes. */ > > -static const struct attribute_spec rs6000_attribute_table[] = > +static const attribute_spec rs6000_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -1272,7 +1272,16 @@ static const struct attribute_spec rs6000_attribute_table[] = > #ifdef SUBTARGET_ATTRIBUTE_TABLE > SUBTARGET_ATTRIBUTE_TABLE, > #endif > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > +}; > + > +static const scoped_attribute_specs rs6000_gnu_attribute_table = > +{ > + "gnu", rs6000_gnu_attributes > +}; > + > +static const scoped_attribute_specs *const rs6000_attribute_table[] = > +{ > + &rs6000_gnu_attribute_table > }; > > #ifndef TARGET_PROFILE_KERNEL > diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc > index 245c6a4413d..0754e286552 100644 > --- a/gcc/config/rx/rx.cc > +++ b/gcc/config/rx/rx.cc > @@ -2760,7 +2760,7 @@ rx_handle_vector_attribute (tree * node, > } > > /* Table of RX specific attributes. */ > -const struct attribute_spec rx_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (rx_attribute_table, > { > /* Name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude. */ > @@ -2771,9 +2771,8 @@ const struct attribute_spec rx_attribute_table[] = > { "naked", 0, 0, true, false, false, false, > rx_handle_func_attribute, NULL }, > { "vector", 1, -1, true, false, false, false, > - rx_handle_vector_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + rx_handle_vector_attribute, NULL } > +}); > > /* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */ > > diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc > index 64f56d8effa..a8205385451 100644 > --- a/gcc/config/s390/s390.cc > +++ b/gcc/config/s390/s390.cc > @@ -1303,7 +1303,7 @@ s390_handle_string_attribute (tree *node, tree name ATTRIBUTE_UNUSED, > return NULL_TREE; > } > > -static const struct attribute_spec s390_attribute_table[] = { > +TARGET_GNU_ATTRIBUTES (s390_attribute_table, { > { "hotpatch", 2, 2, true, false, false, false, > s390_handle_hotpatch_attribute, NULL }, > { "s390_vector_bool", 0, 0, false, true, false, true, > @@ -1319,11 +1319,8 @@ static const struct attribute_spec s390_attribute_table[] = { > { "function_return_reg", 1, 1, true, false, false, false, > s390_handle_string_attribute, NULL }, > { "function_return_mem", 1, 1, true, false, false, false, > - s390_handle_string_attribute, NULL }, > - > - /* End element. */ > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + s390_handle_string_attribute, NULL } > +}); > > /* Return the alignment for LABEL. We default to the -falign-labels > value except for the literal pool base label. */ > diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc > index 6ec2eecf754..8c378b28b6d 100644 > --- a/gcc/config/sh/sh.cc > +++ b/gcc/config/sh/sh.cc > @@ -329,7 +329,7 @@ static bool sh_hard_regno_mode_ok (unsigned int, machine_mode); > static bool sh_modes_tieable_p (machine_mode, machine_mode); > static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t); > > -static const struct attribute_spec sh_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (sh_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -348,9 +348,8 @@ static const struct attribute_spec sh_attribute_table[] = > { "resbank", 0, 0, true, false, false, false, > sh_handle_resbank_handler_attribute, NULL }, > { "function_vector", 1, 1, true, false, false, false, > - sh2a_handle_function_vector_handler_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + sh2a_handle_function_vector_handler_attribute, NULL } > +}); > > /* Initialize the GCC target structure. */ > #undef TARGET_ATTRIBUTE_TABLE > diff --git a/gcc/config/sparc/sparc.cc b/gcc/config/sparc/sparc.cc > index 82e57952414..a78dedc8075 100644 > --- a/gcc/config/sparc/sparc.cc > +++ b/gcc/config/sparc/sparc.cc > @@ -721,13 +721,12 @@ static HARD_REG_SET sparc_zero_call_used_regs (HARD_REG_SET); > > #ifdef SUBTARGET_ATTRIBUTE_TABLE > /* Table of valid machine attributes. */ > -static const struct attribute_spec sparc_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (sparc_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > do_diagnostic, handler, exclude } */ > - SUBTARGET_ATTRIBUTE_TABLE, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + SUBTARGET_ATTRIBUTE_TABLE > +}); > #endif > > char sparc_hard_reg_printed[8]; > diff --git a/gcc/config/stormy16/stormy16.cc b/gcc/config/stormy16/stormy16.cc > index 10887153906..071043b4128 100644 > --- a/gcc/config/stormy16/stormy16.cc > +++ b/gcc/config/stormy16/stormy16.cc > @@ -2377,7 +2377,7 @@ static tree xstormy16_handle_interrupt_attribute > static tree xstormy16_handle_below100_attribute > (tree *, tree, tree, int, bool *); > > -static const struct attribute_spec xstormy16_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (xstormy16_attribute_table, > { > /* name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude. */ > @@ -2386,9 +2386,8 @@ static const struct attribute_spec xstormy16_attribute_table[] = > { "BELOW100", 0, 0, false, false, false, false, > xstormy16_handle_below100_attribute, NULL }, > { "below100", 0, 0, false, false, false, false, > - xstormy16_handle_below100_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + xstormy16_handle_below100_attribute, NULL } > +}); > > /* Handle an "interrupt" attribute; > arguments as in struct attribute_spec.handler. */ > diff --git a/gcc/config/v850/v850.cc b/gcc/config/v850/v850.cc > index 416c2841a5c..50c91c68b8b 100644 > --- a/gcc/config/v850/v850.cc > +++ b/gcc/config/v850/v850.cc > @@ -3114,7 +3114,7 @@ v850_adjust_insn_length (rtx_insn *insn, int length) > > /* V850 specific attributes. */ > > -static const struct attribute_spec v850_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (v850_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -3127,9 +3127,8 @@ static const struct attribute_spec v850_attribute_table[] = > { "tda", 0, 0, true, false, false, false, > v850_handle_data_area_attribute, NULL }, > { "zda", 0, 0, true, false, false, false, > - v850_handle_data_area_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > -}; > + v850_handle_data_area_attribute, NULL } > +}); > > static void > v850_option_override (void) > diff --git a/gcc/config/visium/visium.cc b/gcc/config/visium/visium.cc > index 5fadbc80be0..4a1877c2ac1 100644 > --- a/gcc/config/visium/visium.cc > +++ b/gcc/config/visium/visium.cc > @@ -145,14 +145,13 @@ static inline bool current_function_has_lr_slot (void); > > /* Supported attributes: > interrupt -- specifies this function is an interrupt handler. */ > -static const struct attribute_spec visium_attribute_table[] = > +TARGET_GNU_ATTRIBUTES (visium_attribute_table, > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "interrupt", 0, 0, true, false, false, false, visium_handle_interrupt_attr, > - NULL}, > - { NULL, 0, 0, false, false, false, false, NULL, NULL }, > -}; > + NULL} > +}); > > static struct machine_function *visium_init_machine_status (void); > > diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h > index 1408301a300..d3fa002593f 100644 > --- a/gcc/cp/cp-objcp-common.h > +++ b/gcc/cp/cp-objcp-common.h > @@ -122,13 +122,16 @@ extern tree cxx_simulate_record_decl (location_t, const char *, > #undef LANG_HOOKS_FINALIZE_EARLY_DEBUG > #define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug > > -/* Attribute hooks. */ > -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table > -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE > -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table > +static const scoped_attribute_specs *const cp_objcp_attribute_table[] = > +{ > + &std_attribute_table, > + &cxx_gnu_attribute_table, > + &c_common_gnu_attribute_table, > + &c_common_format_attribute_table > +}; > + > #undef LANG_HOOKS_ATTRIBUTE_TABLE > -#define LANG_HOOKS_ATTRIBUTE_TABLE cxx_attribute_table > +#define LANG_HOOKS_ATTRIBUTE_TABLE cp_objcp_attribute_table > > #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P > #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P cp_var_mod_type_p > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 98b29e9cf81..0a543c5f14c 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -8000,7 +8000,8 @@ extern tree maybe_dummy_object (tree, tree *); > extern bool is_dummy_object (const_tree); > extern bool is_byte_access_type (tree); > extern bool is_byte_access_type_not_plain_char (tree); > -extern const struct attribute_spec cxx_attribute_table[]; > +extern const struct scoped_attribute_specs cxx_gnu_attribute_table; > +extern const struct scoped_attribute_specs std_attribute_table; > extern tree make_ptrmem_cst (tree, tree); > extern tree cp_build_type_attribute_variant (tree, tree); > extern tree cp_build_reference_type (tree, bool); > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 417c92ba76f..fd99d64ca47 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -5072,7 +5072,7 @@ handle_likeliness_attribute (tree *node, tree name, tree args, > } > > /* Table of valid C++ attributes. */ > -const struct attribute_spec cxx_attribute_table[] = > +static const attribute_spec cxx_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -5080,11 +5080,15 @@ const struct attribute_spec cxx_attribute_table[] = > handle_init_priority_attribute, NULL }, > { "abi_tag", 1, -1, false, false, false, true, > handle_abi_tag_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > +}; > + > +const scoped_attribute_specs cxx_gnu_attribute_table = > +{ > + "gnu", cxx_gnu_attributes > }; > > /* Table of C++ standard attributes. */ > -const struct attribute_spec std_attribute_table[] = > +static const attribute_spec std_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -5105,10 +5109,11 @@ const struct attribute_spec std_attribute_table[] = > { "pre", 0, -1, false, false, false, false, > handle_contract_attribute, NULL }, > { "post", 0, -1, false, false, false, false, > - handle_contract_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + handle_contract_attribute, NULL } > }; > > +const scoped_attribute_specs std_attribute_table = { nullptr, std_attributes }; > + > /* Handle an "init_priority" attribute; arguments as in > struct attribute_spec.handler. */ > static tree > @@ -5704,7 +5709,6 @@ void > init_tree (void) > { > list_hash_table = hash_table<list_hasher>::create_ggc (61); > - register_scoped_attributes (std_attribute_table, NULL); > } > > /* Returns the kind of special function that DECL (a FUNCTION_DECL) > diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc > index c0dc0e24ded..f6411058072 100644 > --- a/gcc/d/d-attribs.cc > +++ b/gcc/d/d-attribs.cc > @@ -162,7 +162,7 @@ extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = > > /* Table of machine-independent attributes. > For internal use (marking of built-ins) only. */ > -const attribute_spec d_langhook_common_attribute_table[] = > +static const attribute_spec d_langhook_common_attributes[] = > { > ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, > handle_noreturn_attribute, attr_noreturn_exclusions), > @@ -190,11 +190,15 @@ const attribute_spec d_langhook_common_attribute_table[] = > handle_fnspec_attribute, NULL), > ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false, > handle_omp_declare_simd_attribute, NULL), > - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), > +}; > + > +const scoped_attribute_specs d_langhook_common_attribute_table = > +{ > + "gnu", d_langhook_common_attributes > }; > > /* Table of D language attributes exposed by `gcc.attribute' UDAs. */ > -const attribute_spec d_langhook_attribute_table[] = > +static const attribute_spec d_langhook_gnu_attributes[] = > { > ATTR_SPEC ("noinline", 0, 0, true, false, false, false, > d_handle_noinline_attribute, attr_noinline_exclusions), > @@ -238,9 +242,12 @@ const attribute_spec d_langhook_attribute_table[] = > d_handle_used_attribute, NULL), > ATTR_SPEC ("visibility", 1, 1, false, false, false, false, > d_handle_visibility_attribute, NULL), > - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), > }; > > +const scoped_attribute_specs d_langhook_gnu_attribute_table = > +{ > + "gnu", d_langhook_gnu_attributes > +}; > > /* Insert the type attribute ATTRNAME with value VALUE into TYPE. > Returns a new variant of the original type declaration. */ > @@ -283,20 +290,14 @@ uda_attribute_p (const char *name) > > /* Search both our language, and target attribute tables. > Common and format attributes are kept internal. */ > - for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++) > - { > - if (get_identifier (p->name) == ident) > - return true; > - } > + for (const attribute_spec &p : d_langhook_gnu_attributes) > + if (get_identifier (p.name) == ident) > + return true; > > - if (targetm.attribute_table) > - { > - for (const attribute_spec *p = targetm.attribute_table; p->name; p++) > - { > - if (get_identifier (p->name) == ident) > - return true; > - } > - } > + for (auto scoped_attributes : targetm.attribute_table) > + for (const attribute_spec &p : scoped_attributes->attributes) > + if (get_identifier (p.name) == ident) > + return true; > > return false; > } > diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc > index 61fc1608b40..dcbffec3752 100644 > --- a/gcc/d/d-lang.cc > +++ b/gcc/d/d-lang.cc > @@ -1927,6 +1927,12 @@ d_get_sarif_source_language (const char *) > return "d"; > } > > +const scoped_attribute_specs *const d_langhook_attribute_table[] = > +{ > + &d_langhook_gnu_attribute_table, > + &d_langhook_common_attribute_table, > +}; > + > /* Definitions for our language-specific hooks. */ > > #undef LANG_HOOKS_NAME > @@ -1938,7 +1944,6 @@ d_get_sarif_source_language (const char *) > #undef LANG_HOOKS_HANDLE_OPTION > #undef LANG_HOOKS_POST_OPTIONS > #undef LANG_HOOKS_PARSE_FILE > -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > #undef LANG_HOOKS_ATTRIBUTE_TABLE > #undef LANG_HOOKS_GET_ALIAS_SET > #undef LANG_HOOKS_TYPES_COMPATIBLE_P > @@ -1971,7 +1976,6 @@ d_get_sarif_source_language (const char *) > #define LANG_HOOKS_HANDLE_OPTION d_handle_option > #define LANG_HOOKS_POST_OPTIONS d_post_options > #define LANG_HOOKS_PARSE_FILE d_parse_file > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE d_langhook_common_attribute_table > #define LANG_HOOKS_ATTRIBUTE_TABLE d_langhook_attribute_table > #define LANG_HOOKS_GET_ALIAS_SET d_get_alias_set > #define LANG_HOOKS_TYPES_COMPATIBLE_P d_types_compatible_p > diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h > index d19c3f50bd9..46a28737daa 100644 > --- a/gcc/d/d-tree.h > +++ b/gcc/d/d-tree.h > @@ -520,8 +520,8 @@ extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE); > extern void apply_user_attributes (Dsymbol *, tree); > > /* In d-builtins.cc. */ > -extern const attribute_spec d_langhook_attribute_table[]; > -extern const attribute_spec d_langhook_common_attribute_table[]; > +extern const struct scoped_attribute_specs d_langhook_gnu_attribute_table; > +extern const struct scoped_attribute_specs d_langhook_common_attribute_table; > extern Type *build_frontend_type (tree); > > extern tree d_builtin_function (tree); > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi > index d83ca73b1af..abc23b2bb73 100644 > --- a/gcc/doc/tm.texi > +++ b/gcc/doc/tm.texi > @@ -10528,12 +10528,33 @@ 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-core.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. > +@deftypevr {Target Hook} {array_slice<const struct scoped_attribute_specs *const>} TARGET_ATTRIBUTE_TABLE > +If defined, this target hook provides an array of > +@samp{scoped_attribute_spec}s (defined in @file{attribs.h}) that specify the > +machine-specific attributes for this target. The information includes some > +of the restrictions on the entities to which these attributes are applied > +and the arguments that the attributes take. > + > +In C and C++, these attributes are associated with two syntaxes: > +the traditional GNU @code{__attribute__} syntax and the standard > +@samp{[[]]} syntax. Attributes that support the GNU syntax must be > +placed in the @code{gnu} namespace. Such attributes can then also be > +written @samp{[[gnu::@dots{}]]}. Attributes that use only the standard > +syntax should be placed in whichever namespace the attribute specification > +requires. For example, a target might choose to support vendor-specific > +@samp{[[]]} attributes that the vendor places in their own namespace. > + > +Targets that only define attributes in the @code{gnu} namespace > +can uase the following shorthand to define the table: > + > +@smallexample > +TARGET_GNU_ATTRIBUTES (@var{cpu_attribute_table}, @{ > + @{ "@var{attribute1}", @dots{} @}, > + @{ "@var{attribute2}", @dots{} @}, > + @dots{}, > + @{ "@var{attributen}", @dots{} @}, > +@}); > +@end smallexample > @end deftypevr > > @deftypefn {Target Hook} bool TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P (const_tree @var{name}) > diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc > index 350e6e379eb..99dd76226a2 100644 > --- a/gcc/fortran/f95-lang.cc > +++ b/gcc/fortran/f95-lang.cc > @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see > #include "cpp.h" > #include "trans-types.h" > #include "trans-const.h" > +#include "attribs.h" > > /* Language-dependent contents of an identifier. */ > > @@ -87,7 +88,7 @@ gfc_handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *) > } > > /* Table of valid Fortran attributes. */ > -static const struct attribute_spec gfc_attribute_table[] = > +static const attribute_spec gfc_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -97,7 +98,16 @@ static const struct attribute_spec gfc_attribute_table[] = > gfc_handle_omp_declare_target_attribute, NULL }, > { "oacc function", 0, -1, true, false, false, false, > gfc_handle_omp_declare_target_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > +}; > + > +static const scoped_attribute_specs gfc_gnu_attribute_table = > +{ > + "gnu", gfc_gnu_attributes > +}; > + > +static const scoped_attribute_specs *const gfc_attribute_table[] = > +{ > + &gfc_gnu_attribute_table > }; > > /* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, > diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc > index a729086bafb..61cc0e1ae66 100644 > --- a/gcc/jit/dummy-frontend.cc > +++ b/gcc/jit/dummy-frontend.cc > @@ -87,7 +87,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = > }; > > /* Table of machine-independent attributes supported in libgccjit. */ > -const struct attribute_spec jit_attribute_table[] = > +static const attribute_spec jit_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -128,22 +128,36 @@ const struct attribute_spec jit_attribute_table[] = > /* For internal use only. The leading '*' both prevents its usage in > source code and signals that it may be overridden by machine tables. */ > { "*tm regparm", 0, 0, false, true, true, false, > - ignore_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + ignore_attribute, NULL } > +}; > + > +static const scoped_attribute_specs jit_gnu_attribute_table = > +{ > + "gnu", jit_gnu_attributes > }; > > /* Give the specifications for the format attributes, used by C and all > descendants. */ > > -const struct attribute_spec jit_format_attribute_table[] = > +static const attribute_spec jit_format_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > { "format", 3, 3, false, true, true, false, > handle_format_attribute, NULL }, > { "format_arg", 1, 1, false, true, true, false, > - handle_format_arg_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + handle_format_arg_attribute, NULL } > +}; > + > +static const scoped_attribute_specs jit_format_attribute_table = > +{ > + "gnu", jit_format_attributes > +}; > + > +static const scoped_attribute_specs *const jit_attribute_table[] = > +{ > + &jit_gnu_attribute_table, > + &jit_format_attribute_table > }; > > /* Attribute handlers. */ > @@ -719,10 +733,8 @@ jit_langhook_getdecls (void) > #define LANG_HOOKS_GETDECLS jit_langhook_getdecls > > /* Attribute hooks. */ > -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE jit_attribute_table > -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE > -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE jit_format_attribute_table > +#undef LANG_HOOKS_ATTRIBUTE_TABLE > +#define LANG_HOOKS_ATTRIBUTE_TABLE jit_attribute_table > > #undef LANG_HOOKS_DEEP_UNSHARING > #define LANG_HOOKS_DEEP_UNSHARING true > diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h > index c6d18526360..c9cb65759c2 100644 > --- a/gcc/langhooks-def.h > +++ b/gcc/langhooks-def.h > @@ -153,9 +153,7 @@ extern const char *lhd_get_sarif_source_language (const char *); > #define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE lhd_get_sarif_source_language > > /* Attribute hooks. */ > -#define LANG_HOOKS_ATTRIBUTE_TABLE NULL > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE NULL > -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE NULL > +#define LANG_HOOKS_ATTRIBUTE_TABLE {} > > /* Tree inlining hooks. */ > #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \ > @@ -367,8 +365,6 @@ extern void lhd_end_section (void); > LANG_HOOKS_PRINT_ERROR_FUNCTION, \ > LANG_HOOKS_TO_TARGET_CHARSET, \ > LANG_HOOKS_ATTRIBUTE_TABLE, \ > - LANG_HOOKS_COMMON_ATTRIBUTE_TABLE, \ > - LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE, \ > LANG_HOOKS_TREE_INLINING_INITIALIZER, \ > LANG_HOOKS_TREE_DUMP_INITIALIZER, \ > LANG_HOOKS_DECLS, \ > diff --git a/gcc/langhooks.h b/gcc/langhooks.h > index cca75285fc2..2785a0070fc 100644 > --- a/gcc/langhooks.h > +++ b/gcc/langhooks.h > @@ -532,9 +532,7 @@ struct lang_hooks > table of attributes specific to the language, a table of > attributes common to two or more languages (to allow easy > sharing), and a table of attributes for checking formats. */ > - const struct attribute_spec *attribute_table; > - const struct attribute_spec *common_attribute_table; > - const struct attribute_spec *format_attribute_table; > + array_slice<const struct scoped_attribute_specs *const> attribute_table; > > struct lang_hooks_for_tree_inlining tree_inlining; > > diff --git a/gcc/lto/lto-lang.cc b/gcc/lto/lto-lang.cc > index 14d419c2013..a8adf110b20 100644 > --- a/gcc/lto/lto-lang.cc > +++ b/gcc/lto/lto-lang.cc > @@ -94,7 +94,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = > }; > > /* Table of machine-independent attributes supported in GIMPLE. */ > -const struct attribute_spec lto_attribute_table[] = > +static const attribute_spec lto_gnu_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -135,14 +135,18 @@ const struct attribute_spec lto_attribute_table[] = > /* For internal use only. The leading '*' both prevents its usage in > source code and signals that it may be overridden by machine tables. */ > { "*tm regparm", 0, 0, false, true, true, false, > - ignore_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > + ignore_attribute, NULL } > +}; > + > +static const scoped_attribute_specs lto_gnu_attribute_table = > +{ > + "gnu", lto_gnu_attributes > }; > > /* Give the specifications for the format attributes, used by C and all > descendants. */ > > -const struct attribute_spec lto_format_attribute_table[] = > +static const attribute_spec lto_format_attributes[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > affects_type_identity, handler, exclude } */ > @@ -150,7 +154,17 @@ const struct attribute_spec lto_format_attribute_table[] = > handle_format_attribute, NULL }, > { "format_arg", 1, 1, false, true, true, false, > handle_format_arg_attribute, NULL }, > - { NULL, 0, 0, false, false, false, false, NULL, NULL } > +}; > + > +static const scoped_attribute_specs lto_format_attribute_table = > +{ > + "gnu", lto_format_attributes > +}; > + > +static const scoped_attribute_specs *const lto_attribute_table[] = > +{ > + <o_gnu_attribute_table, > + <o_format_attribute_table > }; > > enum built_in_attribute > @@ -1463,10 +1477,8 @@ static void lto_init_ts (void) > #define LANG_HOOKS_EH_PERSONALITY lto_eh_personality > > /* Attribute hooks. */ > -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE > -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE lto_attribute_table > -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE > -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE lto_format_attribute_table > +#undef LANG_HOOKS_ATTRIBUTE_TABLE > +#define LANG_HOOKS_ATTRIBUTE_TABLE lto_attribute_table > > #undef LANG_HOOKS_BEGIN_SECTION > #define LANG_HOOKS_BEGIN_SECTION lto_obj_begin_section > diff --git a/gcc/plugin.h b/gcc/plugin.h > index ee0a53ec4c9..f306adfb3b9 100644 > --- a/gcc/plugin.h > +++ b/gcc/plugin.h > @@ -201,8 +201,7 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED, > > extern void register_attribute (const struct attribute_spec *attr); > /* The default argument for the third parameter is given in attribs.h. */ > -extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, > - const char *, > +extern struct scoped_attributes* register_scoped_attributes (const struct scoped_attribute_spec &, > bool); > > #endif /* PLUGIN_H */ > diff --git a/gcc/target-def.h b/gcc/target-def.h > index 847698a1e59..d03b039ab24 100644 > --- a/gcc/target-def.h > +++ b/gcc/target-def.h > @@ -118,6 +118,20 @@ > #define TARGET_FUNCTION_INCOMING_ARG TARGET_FUNCTION_ARG > #endif > > +/* Declare a target attribute table called NAME that only has GNU attributes. > + There should be no null trailing element. E.g.: > + > + TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, > + { > + { "aarch64_vector_pcs", ... }, > + ... > + }); */ > + > +#define TARGET_GNU_ATTRIBUTES(NAME, ...) \ > + static const attribute_spec NAME##_2[] = __VA_ARGS__; \ > + static const scoped_attribute_specs NAME##_1 = { "gnu", NAME##_2 }; \ > + static const scoped_attribute_specs *const NAME[] = { &NAME##_1 } > + > #include "target-hooks-def.h" > > #include "hooks.h" > diff --git a/gcc/target.def b/gcc/target.def > index 0996da0f71a..06c5d3b5c2e 100644 > --- a/gcc/target.def > +++ b/gcc/target.def > @@ -2218,15 +2218,36 @@ merging.", > merge_type_attributes) > > /* Table of machine attributes and functions to handle them. > - Ignored if NULL. */ > + Ignored if empty. */ > DEFHOOKPOD > (attribute_table, > - "If defined, this target hook points to an array of @samp{struct\n\ > -attribute_spec} (defined in @file{tree-core.h}) specifying the machine\n\ > -specific attributes for this target and some of the restrictions on the\n\ > -entities to which these attributes are applied and the arguments they\n\ > -take.", > - const struct attribute_spec *, NULL) > + "If defined, this target hook provides an array of\n\ > +@samp{scoped_attribute_spec}s (defined in @file{attribs.h}) that specify the\n\ > +machine-specific attributes for this target. The information includes some\n\ > +of the restrictions on the entities to which these attributes are applied\n\ > +and the arguments that the attributes take.\n\ > +\n\ > +In C and C++, these attributes are associated with two syntaxes:\n\ > +the traditional GNU @code{__attribute__} syntax and the standard\n\ > +@samp{[[]]} syntax. Attributes that support the GNU syntax must be\n\ > +placed in the @code{gnu} namespace. Such attributes can then also be\n\ > +written @samp{[[gnu::@dots{}]]}. Attributes that use only the standard\n\ > +syntax should be placed in whichever namespace the attribute specification\n\ > +requires. For example, a target might choose to support vendor-specific\n\ > +@samp{[[]]} attributes that the vendor places in their own namespace.\n\ > +\n\ > +Targets that only define attributes in the @code{gnu} namespace\n\ > +can uase the following shorthand to define the table:\n\ > +\n\ > +@smallexample\n\ > +TARGET_GNU_ATTRIBUTES (@var{cpu_attribute_table}, @{\n\ > + @{ \"@var{attribute1}\", @dots{} @},\n\ > + @{ \"@var{attribute2}\", @dots{} @},\n\ > + @dots{},\n\ > + @{ \"@var{attributen}\", @dots{} @},\n\ > +@});\n\ > +@end smallexample", > + array_slice<const struct scoped_attribute_specs *const>, {}) > > /* Return true iff attribute NAME expects a plain identifier as its first > argument. */ > diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc > index 00d05102e7a..2831a0368f6 100644 > --- a/gcc/tree-inline.cc > +++ b/gcc/tree-inline.cc > @@ -4094,17 +4094,16 @@ inline_forbidden_p (tree fndecl) > static bool > function_attribute_inlinable_p (const_tree fndecl) > { > - if (targetm.attribute_table) > + for (auto scoped_attributes : targetm.attribute_table) > { > const_tree a; > > for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a)) > { > const_tree name = get_attribute_name (a); > - int i; > > - for (i = 0; targetm.attribute_table[i].name != NULL; i++) > - if (is_attribute_p (targetm.attribute_table[i].name, name)) > + for (const attribute_spec &attribute : scoped_attributes->attributes) > + if (is_attribute_p (attribute.name, name)) > return targetm.function_attribute_inlinable_p (fndecl); > } > }
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index eb5496f50db..63ccf311c23 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -350,7 +350,7 @@ struct attrib }; /* Table of machine-independent internal attributes. */ -extern const struct attribute_spec gnat_internal_attribute_table[]; +extern const struct scoped_attribute_specs gnat_internal_attribute_table; /* Define the entries in the standard data array. */ enum standard_datatypes diff --git a/gcc/ada/gcc-interface/misc.cc b/gcc/ada/gcc-interface/misc.cc index 7d6d4466d56..01e8267f884 100644 --- a/gcc/ada/gcc-interface/misc.cc +++ b/gcc/ada/gcc-interface/misc.cc @@ -1352,6 +1352,11 @@ get_lang_specific (tree node) return TYPE_LANG_SPECIFIC (node); } +const struct scoped_attribute_specs *const gnat_attribute_table[] = +{ + &gnat_internal_attribute_table +}; + /* Definitions for our language-specific hooks. */ #undef LANG_HOOKS_NAME @@ -1417,7 +1422,7 @@ get_lang_specific (tree node) #undef LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO #define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO gnat_get_fixed_point_type_info #undef LANG_HOOKS_ATTRIBUTE_TABLE -#define LANG_HOOKS_ATTRIBUTE_TABLE gnat_internal_attribute_table +#define LANG_HOOKS_ATTRIBUTE_TABLE gnat_attribute_table #undef LANG_HOOKS_BUILTIN_FUNCTION #define LANG_HOOKS_BUILTIN_FUNCTION gnat_builtin_function #undef LANG_HOOKS_INIT_TS diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index 4e2ed173fbe..c38e0e6f57d 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -136,7 +136,7 @@ static tree fake_attribute_handler (tree *, tree, tree, int, bool *); /* Table of machine-independent internal attributes for Ada. We support this minimal set of attributes to accommodate the needs of builtins. */ -const struct attribute_spec gnat_internal_attribute_table[] = +static const attribute_spec gnat_internal_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -217,9 +217,11 @@ const struct attribute_spec gnat_internal_attribute_table[] = /* This is handled entirely in the front end. */ { "hardbool", 0, 0, false, true, false, true, fake_attribute_handler, NULL }, +}; - { NULL, 0, 0, false, false, false, false, - NULL, NULL } +const scoped_attribute_specs gnat_internal_attribute_table = +{ + "gnu", gnat_internal_attributes }; /* Associates a GNAT tree node to a GCC tree node. It is used in diff --git a/gcc/attribs.cc b/gcc/attribs.cc index d1d9e5a28c1..6725fe78f2c 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see /* Table of the tables of attributes (common, language, format, machine) searched. */ -static const struct attribute_spec *attribute_tables[4]; +static array_slice<const scoped_attribute_specs *const> attribute_tables[2]; /* Substring representation. */ @@ -102,13 +102,6 @@ static const struct attribute_spec *lookup_scoped_attribute_spec (const_tree, static bool attributes_initialized = false; -/* Default empty table of attributes. */ - -static const struct attribute_spec empty_attribute_table[] = -{ - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; - /* Return base name of the attribute. Ie '__attr__' is turned into 'attr'. To avoid need for copying, we simply return length of the string. */ @@ -118,21 +111,19 @@ extract_attribute_substring (struct substring *str) canonicalize_attr_name (str->str, str->length); } -/* Insert an array of attributes ATTRIBUTES into a namespace. This - array must be NULL terminated. NS is the name of attribute - namespace. IGNORED_P is true iff all unknown attributes in this - namespace should be ignored for the purposes of -Wattributes. The - function returns the namespace into which the attributes have been - registered. */ +/* Insert SPECS into its namespace. IGNORED_P is true iff all unknown + attributes in this namespace should be ignored for the purposes of + -Wattributes. The function returns the namespace into which the + attributes have been registered. */ scoped_attributes * -register_scoped_attributes (const struct attribute_spec *attributes, - const char *ns, bool ignored_p /*=false*/) +register_scoped_attributes (const scoped_attribute_specs &specs, + bool ignored_p /*=false*/) { scoped_attributes *result = NULL; /* See if we already have attributes in the namespace NS. */ - result = find_attribute_namespace (ns); + result = find_attribute_namespace (specs.ns); if (result == NULL) { @@ -143,7 +134,7 @@ register_scoped_attributes (const struct attribute_spec *attributes, attributes_table.create (64); memset (&sa, 0, sizeof (sa)); - sa.ns = ns; + sa.ns = specs.ns; sa.attributes.create (64); sa.ignored_p = ignored_p; result = attributes_table.safe_push (sa); @@ -153,10 +144,10 @@ register_scoped_attributes (const struct attribute_spec *attributes, result->ignored_p |= ignored_p; /* Really add the attributes to their namespace now. */ - for (unsigned i = 0; attributes[i].name != NULL; ++i) + for (const attribute_spec &attribute : specs.attributes) { - result->attributes.safe_push (attributes[i]); - register_scoped_attribute (&attributes[i], result); + result->attributes.safe_push (attribute); + register_scoped_attribute (&attribute, result); } gcc_assert (result != NULL); @@ -183,49 +174,40 @@ find_attribute_namespace (const char* ns) static void check_attribute_tables (void) { - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) - for (size_t 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); + hash_set<pair_hash<nofree_string_hash, nofree_string_hash>> names; - gcc_assert (!(name[0] == '_' && name[1] == '_' - && name[len - 1] == '_' && name[len - 2] == '_')); + for (auto scoped_array : attribute_tables) + for (auto scoped_attributes : scoped_array) + for (const attribute_spec &attribute : scoped_attributes->attributes) + { + /* The name must not begin and end with __. */ + const char *name = attribute.name; + int len = strlen (name); + + gcc_assert (!(name[0] == '_' && name[1] == '_' + && name[len - 1] == '_' && name[len - 2] == '_')); - /* The minimum and maximum lengths must be consistent. */ - gcc_assert (attribute_tables[i][j].min_length >= 0); + /* The minimum and maximum lengths must be consistent. */ + gcc_assert (attribute.min_length >= 0); - gcc_assert (attribute_tables[i][j].max_length == -1 - || (attribute_tables[i][j].max_length - >= attribute_tables[i][j].min_length)); + gcc_assert (attribute.max_length == -1 + || attribute.max_length >= attribute.min_length); - /* An attribute cannot require both a DECL and a TYPE. */ - gcc_assert (!attribute_tables[i][j].decl_required - || !attribute_tables[i][j].type_required); + /* An attribute cannot require both a DECL and a TYPE. */ + gcc_assert (!attribute.decl_required + || !attribute.type_required); /* If an attribute requires a function type, in particular it requires a type. */ - gcc_assert (!attribute_tables[i][j].function_type_required - || attribute_tables[i][j].type_required); - } - - /* Check that each name occurs just once in each table. */ - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) - for (size_t j = 0; attribute_tables[i][j].name != NULL; j++) - for (size_t k = j + 1; attribute_tables[i][k].name != NULL; k++) - gcc_assert (strcmp (attribute_tables[i][j].name, - attribute_tables[i][k].name)); - - /* Check that no name occurs in more than one table. Names that - begin with '*' are exempt, and may be overridden. */ - for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) - for (size_t j = i + 1; j < ARRAY_SIZE (attribute_tables); j++) - for (size_t k = 0; attribute_tables[i][k].name != NULL; k++) - for (size_t l = 0; attribute_tables[j][l].name != NULL; l++) - gcc_assert (attribute_tables[i][k].name[0] == '*' - || strcmp (attribute_tables[i][k].name, - attribute_tables[j][l].name)); + gcc_assert (!attribute.function_type_required + || attribute.type_required); + + /* Check that no name occurs more than once. Names that + begin with '*' are exempt, and may be overridden. */ + const char *ns = scoped_attributes->ns; + if (name[0] != '*' && names.add ({ ns ? ns : "", name })) + gcc_unreachable (); + } } /* Used to stash pointers to allocated memory so that we can free them at @@ -281,7 +263,7 @@ handle_ignored_attributes_option (vec<char *> *v) canonicalize_attr_name (vendor_start, vendor_len); /* We perform all this hijinks so that we don't have to copy OPT. */ tree vendor_id = get_identifier_with_length (vendor_start, vendor_len); - const char *attr; + array_slice<const attribute_spec> attrs; /* In the "vendor::" case, we should ignore *any* attribute coming from this attribute namespace. */ if (attr_len > 0) @@ -293,22 +275,23 @@ handle_ignored_attributes_option (vec<char *> *v) } canonicalize_attr_name (attr_start, attr_len); tree attr_id = get_identifier_with_length (attr_start, attr_len); - attr = IDENTIFIER_POINTER (attr_id); + const char *attr = IDENTIFIER_POINTER (attr_id); /* If we've already seen this vendor::attr, ignore it. Attempting to register it twice would lead to a crash. */ if (lookup_scoped_attribute_spec (vendor_id, attr_id)) continue; + /* Create a table with extra attributes which we will register. + We can't free it here, so squirrel away the pointers. */ + attribute_spec *table = new attribute_spec { + attr, 0, -2, false, false, false, false, nullptr, nullptr + }; + ignored_attributes_table.safe_push (table); + attrs = { table, 1 }; } - else - attr = nullptr; - /* Create a table with extra attributes which we will register. - We can't free it here, so squirrel away the pointers. */ - attribute_spec *table = new attribute_spec[2]; - ignored_attributes_table.safe_push (table); - table[0] = { attr, 0, -2, false, false, false, false, nullptr, nullptr }; - table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, - nullptr }; - register_scoped_attributes (table, IDENTIFIER_POINTER (vendor_id), !attr); + const scoped_attribute_specs scoped_specs = { + IDENTIFIER_POINTER (vendor_id), attrs + }; + register_scoped_attributes (scoped_specs, attrs.empty ()); } } @@ -328,27 +311,18 @@ free_attr_data () void init_attributes (void) { - size_t i; - if (attributes_initialized) return; - attribute_tables[0] = lang_hooks.common_attribute_table; - attribute_tables[1] = lang_hooks.attribute_table; - attribute_tables[2] = lang_hooks.format_attribute_table; - attribute_tables[3] = targetm.attribute_table; - - /* Translate NULL pointers to pointers to the empty table. */ - for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) - if (attribute_tables[i] == NULL) - attribute_tables[i] = empty_attribute_table; + attribute_tables[0] = lang_hooks.attribute_table; + attribute_tables[1] = targetm.attribute_table; if (flag_checking) check_attribute_tables (); - for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i) - /* Put all the GNU attributes into the "gnu" namespace. */ - register_scoped_attributes (attribute_tables[i], "gnu"); + for (auto scoped_array : attribute_tables) + for (auto scoped_attributes : scoped_array) + register_scoped_attributes (*scoped_attributes); vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes; handle_ignored_attributes_option (ignored); @@ -2642,10 +2616,6 @@ attr_access::array_as_string (tree type) const namespace selftest { -/* Helper types to verify the consistency attribute exclusions. */ - -typedef std::pair<const char *, const char *> excl_pair; - /* Self-test to verify that each attribute exclusion is symmetric, meaning that if attribute A is encoded as incompatible with attribute B then the opposite relationship is also encoded. @@ -2660,55 +2630,54 @@ test_attribute_exclusions () /* Iterate over the array of attribute tables first (with TI0 as the index) and over the array of attribute_spec in each table (with SI0 as the index). */ - const size_t ntables = ARRAY_SIZE (attribute_tables); + hash_set<excl_hash_traits> excl_set; - /* Set of pairs of mutually exclusive attributes. */ - typedef hash_set<excl_hash_traits> exclusion_set; - exclusion_set excl_set; + for (auto scoped_array : attribute_tables) + for (auto scoped_attributes : scoped_array) + for (const attribute_spec &attribute : scoped_attributes->attributes) + { + const attribute_spec::exclusions *excl = attribute.exclude; - for (size_t ti0 = 0; ti0 != ntables; ++ti0) - for (size_t s0 = 0; attribute_tables[ti0][s0].name; ++s0) - { - const attribute_spec::exclusions *excl - = attribute_tables[ti0][s0].exclude; + /* Skip each attribute that doesn't define exclusions. */ + if (!excl) + continue; - /* Skip each attribute that doesn't define exclusions. */ - if (!excl) - continue; + /* Skip standard (non-GNU) attributes, since currently the + exclusions are implicitly for GNU attributes only. + Also, C++ likely and unlikely get rewritten to gnu::hot + and gnu::cold, so symmetry isn't necessary there. */ + if (!scoped_attributes->ns) + continue; - const char *attr_name = attribute_tables[ti0][s0].name; + const char *attr_name = attribute.name; - /* Iterate over the set of exclusions for every attribute - (with EI0 as the index) adding the exclusions defined - for each to the set. */ - for (size_t ei0 = 0; excl[ei0].name; ++ei0) - { - const char *excl_name = excl[ei0].name; + /* Iterate over the set of exclusions for every attribute + (with EI0 as the index) adding the exclusions defined + for each to the set. */ + for (size_t ei0 = 0; excl[ei0].name; ++ei0) + { + const char *excl_name = excl[ei0].name; - if (!strcmp (attr_name, excl_name)) - continue; + if (!strcmp (attr_name, excl_name)) + continue; - excl_set.add (excl_pair (attr_name, excl_name)); - } - } + excl_set.add ({ attr_name, excl_name }); + } + } /* Traverse the set of mutually exclusive pairs of attributes and verify that they are symmetric. */ - for (exclusion_set::iterator it = excl_set.begin (); - it != excl_set.end (); - ++it) - { - if (!excl_set.contains (excl_pair ((*it).second, (*it).first))) - { - /* An exclusion for an attribute has been found that - doesn't have a corresponding exclusion in the opposite - direction. */ - char desc[120]; - sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric", - (*it).first, (*it).second); - fail (SELFTEST_LOCATION, desc); - } - } + for (auto excl_pair : excl_set) + if (!excl_set.contains ({ excl_pair.second, excl_pair.first })) + { + /* An exclusion for an attribute has been found that + doesn't have a corresponding exclusion in the opposite + direction. */ + char desc[120]; + sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric", + excl_pair.first, excl_pair.second); + fail (SELFTEST_LOCATION, desc); + } } void diff --git a/gcc/attribs.h b/gcc/attribs.h index 84a43658a70..fdeebff1cd9 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -20,6 +20,13 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ATTRIBS_H #define GCC_ATTRIBS_H +/* A set of attributes that belong to the same namespace, given by NS. */ +struct scoped_attribute_specs +{ + const char *ns; + array_slice<const attribute_spec> attributes; +}; + extern const struct attribute_spec *lookup_attribute_spec (const_tree); extern void free_attr_data (); extern void init_attributes (void); @@ -42,9 +49,8 @@ extern tree make_attribute (const char *, const char *, tree); extern bool attribute_ignored_p (tree); extern bool attribute_ignored_p (const attribute_spec *const); -extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, - const char *, - bool = false); +extern struct scoped_attributes * + register_scoped_attributes (const scoped_attribute_specs &, bool = false); extern char *sorted_attr_string (tree); extern bool common_function_versions (tree, tree); diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index a041c3b91eb..cf54ef68f20 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -288,7 +288,7 @@ static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] = /* Table of machine-independent attributes common to all C-like languages. Current list of processed common attributes: nonnull. */ -const struct attribute_spec c_common_attribute_table[] = +const struct attribute_spec c_common_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -574,23 +574,31 @@ const struct attribute_spec c_common_attribute_table[] = { "fd_arg_write", 1, 1, false, true, true, false, handle_fd_arg_attribute, NULL}, { "null_terminated_string_arg", 1, 1, false, true, true, false, - handle_null_terminated_string_arg_attribute, NULL}, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + handle_null_terminated_string_arg_attribute, NULL} +}; + +const struct scoped_attribute_specs c_common_gnu_attribute_table = +{ + "gnu", c_common_gnu_attributes }; /* Give the specifications for the format attributes, used by C and all descendants. Current list of processed format attributes: format, format_arg. */ -const struct attribute_spec c_common_format_attribute_table[] = +const struct attribute_spec c_common_format_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "format", 3, 3, false, true, true, false, handle_format_attribute, NULL }, { "format_arg", 1, 1, false, true, true, false, - handle_format_arg_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + handle_format_arg_attribute, NULL } +}; + +const struct scoped_attribute_specs c_common_format_attribute_table = +{ + "gnu", c_common_format_attributes }; /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 1fdba7ef3ea..92ddad27806 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -821,8 +821,8 @@ enum conversion_safety { extern struct visibility_flags visibility_options; /* Attribute table common to the C front ends. */ -extern const struct attribute_spec c_common_attribute_table[]; -extern const struct attribute_spec c_common_format_attribute_table[]; +extern const struct scoped_attribute_specs c_common_gnu_attribute_table; +extern const struct scoped_attribute_specs c_common_format_attribute_table; /* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc. ID is the identifier to use, NAME is the string. diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 0076725a61d..547bebe03c9 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4635,7 +4635,7 @@ handle_std_noreturn_attribute (tree *node, tree name, tree args, } /* Table of supported standard (C2x) attributes. */ -const struct attribute_spec std_attribute_table[] = +static const attribute_spec std_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -4650,8 +4650,12 @@ const struct attribute_spec std_attribute_table[] = { "nodiscard", 0, 1, false, false, false, false, handle_nodiscard_attribute, NULL }, { "noreturn", 0, 0, false, false, false, false, - handle_std_noreturn_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + handle_std_noreturn_attribute, NULL } +}; + +const scoped_attribute_specs std_attribute_table = +{ + nullptr, std_attributes }; /* Create the predefined scalar types of C, @@ -4667,8 +4671,6 @@ c_init_decl_processing (void) /* Initialize reserved words for parser. */ c_parse_init (); - register_scoped_attributes (std_attribute_table, NULL); - current_function_decl = NULL_TREE; gcc_obstack_init (&parser_obstack); diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h index ede451cef6b..4f1925c8b07 100644 --- a/gcc/c/c-objc-common.h +++ b/gcc/c/c-objc-common.h @@ -72,11 +72,15 @@ along with GCC; see the file COPYING3. If not see #undef LANG_HOOKS_FINALIZE_EARLY_DEBUG #define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug -/* Attribute hooks. */ -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table +static const scoped_attribute_specs *const c_objc_attribute_table[] = +{ + &std_attribute_table, + &c_common_gnu_attribute_table, + &c_common_format_attribute_table +}; + +#undef LANG_HOOKS_ATTRIBUTE_TABLE +#define LANG_HOOKS_ATTRIBUTE_TABLE c_objc_attribute_table #undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN c_dump_tree diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index df6f1cefd02..69e154abdbd 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -910,6 +910,8 @@ extern vec<tree> incomplete_record_decls; extern const char *c_get_sarif_source_language (const char *filename); +extern const struct scoped_attribute_specs std_attribute_table; + #if CHECKING_P namespace selftest { extern void run_c_tests (void); diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index cb65ccc8465..920e17d3a95 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -2839,7 +2839,7 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree name, tree, } /* Table of machine attributes. */ -static const struct attribute_spec aarch64_attribute_table[] = +TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -2850,9 +2850,8 @@ static const struct attribute_spec aarch64_attribute_table[] = NULL }, { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, - { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL } +}); typedef enum aarch64_cond_code { diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc index db6b34be9cb..6aa93783226 100644 --- a/gcc/config/alpha/alpha.cc +++ b/gcc/config/alpha/alpha.cc @@ -7482,14 +7482,13 @@ common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED, return NULL_TREE; } -static const struct attribute_spec vms_attribute_table[] = +TARGET_GNU_ATTRIBUTES (vms_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { COMMON_OBJECT, 0, 1, true, false, false, false, common_object_handler, - NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + NULL } +}); void vms_output_aligned_decl_common(FILE *file, tree decl, const char *name, diff --git a/gcc/config/arc/arc.cc b/gcc/config/arc/arc.cc index e209ad2d327..e87d7614feb 100644 --- a/gcc/config/arc/arc.cc +++ b/gcc/config/arc/arc.cc @@ -187,44 +187,6 @@ static tree arc_handle_secure_attribute (tree *, tree, tree, int, bool *); static tree arc_handle_uncached_attribute (tree *, tree, tree, int, bool *); static tree arc_handle_aux_attribute (tree *, tree, tree, int, bool *); -/* Initialized arc_attribute_table to NULL since arc doesnot have any - machine specific supported attributes. */ -const struct attribute_spec arc_attribute_table[] = -{ - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, - affects_type_identity, handler, exclude } */ - { "interrupt", 1, 1, true, false, false, true, - arc_handle_interrupt_attribute, NULL }, - /* Function calls made to this symbol must be done indirectly, because - it may lie outside of the 21/25 bit addressing range of a normal function - call. */ - { "long_call", 0, 0, false, true, true, false, NULL, NULL }, - /* Whereas these functions are always known to reside within the 25 bit - addressing range of unconditionalized bl. */ - { "medium_call", 0, 0, false, true, true, false, NULL, NULL }, - /* And these functions are always known to reside within the 21 bit - addressing range of blcc. */ - { "short_call", 0, 0, false, true, true, false, NULL, NULL }, - /* Function which are not having the prologue and epilogue generated - by the compiler. */ - { "naked", 0, 0, true, false, false, false, arc_handle_fndecl_attribute, - NULL }, - /* Functions calls made using jli instruction. The pointer in JLI - table is found latter. */ - { "jli_always", 0, 0, false, true, true, false, NULL, NULL }, - /* Functions calls made using jli instruction. The pointer in JLI - table is given as input parameter. */ - { "jli_fixed", 1, 1, false, true, true, false, arc_handle_jli_attribute, - NULL }, - /* Call a function using secure-mode. */ - { "secure_call", 1, 1, false, true, true, false, arc_handle_secure_attribute, - NULL }, - /* Bypass caches using .di flag. */ - { "uncached", 0, 0, false, true, false, false, arc_handle_uncached_attribute, - NULL }, - { "aux", 0, 1, true, false, false, false, arc_handle_aux_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; static int arc_comp_type_attributes (const_tree, const_tree); static void arc_file_start (void); static void arc_internal_label (FILE *, const char *, unsigned long); @@ -770,6 +732,42 @@ static rtx arc_legitimize_address_0 (rtx, rtx, machine_mode mode); #include "target-def.h" +TARGET_GNU_ATTRIBUTES (arc_attribute_table, +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, + affects_type_identity, handler, exclude } */ + { "interrupt", 1, 1, true, false, false, true, + arc_handle_interrupt_attribute, NULL }, + /* Function calls made to this symbol must be done indirectly, because + it may lie outside of the 21/25 bit addressing range of a normal function + call. */ + { "long_call", 0, 0, false, true, true, false, NULL, NULL }, + /* Whereas these functions are always known to reside within the 25 bit + addressing range of unconditionalized bl. */ + { "medium_call", 0, 0, false, true, true, false, NULL, NULL }, + /* And these functions are always known to reside within the 21 bit + addressing range of blcc. */ + { "short_call", 0, 0, false, true, true, false, NULL, NULL }, + /* Function which are not having the prologue and epilogue generated + by the compiler. */ + { "naked", 0, 0, true, false, false, false, arc_handle_fndecl_attribute, + NULL }, + /* Functions calls made using jli instruction. The pointer in JLI + table is found latter. */ + { "jli_always", 0, 0, false, true, true, false, NULL, NULL }, + /* Functions calls made using jli instruction. The pointer in JLI + table is given as input parameter. */ + { "jli_fixed", 1, 1, false, true, true, false, arc_handle_jli_attribute, + NULL }, + /* Call a function using secure-mode. */ + { "secure_call", 1, 1, false, true, true, false, arc_handle_secure_attribute, + NULL }, + /* Bypass caches using .di flag. */ + { "uncached", 0, 0, false, true, false, false, arc_handle_uncached_attribute, + NULL }, + { "aux", 0, 1, true, false, false, false, arc_handle_aux_attribute, NULL } +}); + #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" #undef TARGET_ASM_ALIGNED_SI_OP diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 620ef7bfb2f..ed2459128ff 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -332,7 +332,7 @@ static rtx_insn *thumb1_md_asm_adjust (vec<rtx> &, vec<rtx> &, static const char *arm_identify_fpu_from_isa (sbitmap); /* Table of machine attributes. */ -static const struct attribute_spec arm_attribute_table[] = +static const attribute_spec arm_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -380,8 +380,17 @@ static const struct attribute_spec arm_attribute_table[] = arm_handle_cmse_nonsecure_entry, NULL }, { "cmse_nonsecure_call", 0, 0, false, false, false, true, arm_handle_cmse_nonsecure_call, NULL }, - { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL } +}; + +static const scoped_attribute_specs arm_gnu_attribute_table = +{ + "gnu", arm_gnu_attributes +}; + +static const scoped_attribute_specs *const arm_attribute_table[] = +{ + &arm_gnu_attribute_table }; /* Initialize the GCC target structure. */ diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 5e0217de36f..59d217efc45 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -10442,7 +10442,7 @@ avr_eval_addr_attrib (rtx x) /* AVR attributes. */ -static const struct attribute_spec avr_attribute_table[] = +TARGET_GNU_ATTRIBUTES (avr_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -10467,9 +10467,8 @@ static const struct attribute_spec avr_attribute_table[] = { "address", 1, 1, true, false, false, false, avr_handle_addr_attribute, NULL }, { "absdata", 0, 0, true, false, false, false, - avr_handle_absdata_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + avr_handle_absdata_attribute, NULL } +}); /* Return true if we support address space AS for the architecture in effect diff --git a/gcc/config/bfin/bfin.cc b/gcc/config/bfin/bfin.cc index 5718babb6b2..c02136f5e0c 100644 --- a/gcc/config/bfin/bfin.cc +++ b/gcc/config/bfin/bfin.cc @@ -4896,7 +4896,7 @@ bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name), } /* Table of valid machine attributes. */ -static const struct attribute_spec bfin_attribute_table[] = +TARGET_GNU_ATTRIBUTES (bfin_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -4921,9 +4921,8 @@ static const struct attribute_spec bfin_attribute_table[] = bfin_handle_l1_data_attribute, NULL }, { "l1_data_B", 0, 0, true, false, false, false, bfin_handle_l1_data_attribute, NULL }, - { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute, NULL } +}); /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to tell the assembler to generate pointers to function descriptors in diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index 63637ece78e..c619865f1fc 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -139,7 +139,7 @@ bpf_handle_preserve_access_index_attribute (tree *node, tree name, /* Target-specific attributes. */ -static const struct attribute_spec bpf_attribute_table[] = +TARGET_GNU_ATTRIBUTES (bpf_attribute_table, { /* Syntax: { name, min_len, max_len, decl_required, type_required, function_type_required, affects_type_identity, handler, @@ -156,11 +156,8 @@ static const struct attribute_spec bpf_attribute_table[] = /* Support for `naked' function attribute. */ { "naked", 0, 1, false, false, false, false, - bpf_handle_fndecl_attribute, NULL }, - - /* The last attribute spec is set to be NULL. */ - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + bpf_handle_fndecl_attribute, NULL } +}); #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE bpf_attribute_table diff --git a/gcc/config/csky/csky.cc b/gcc/config/csky/csky.cc index 731f47cb2c0..ac089feea62 100644 --- a/gcc/config/csky/csky.cc +++ b/gcc/config/csky/csky.cc @@ -211,16 +211,15 @@ const int csky_debugger_regno[FIRST_PSEUDO_REGISTER] = /* Table of machine attributes. */ static tree csky_handle_fndecl_attribute (tree *, tree, tree, int, bool *); static tree csky_handle_isr_attribute (tree *, tree, tree, int, bool *); -static const struct attribute_spec csky_attribute_table[] = +TARGET_GNU_ATTRIBUTES (csky_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "naked", 0, 0, true, false, false, false, csky_handle_fndecl_attribute, NULL }, /* Interrupt Service Routines have special prologue and epilogue requirements. */ { "interrupt", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL }, - { "isr", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "isr", 0, 1, false, false, false, false, csky_handle_isr_attribute, NULL } +}); /* A C structure for machine-specific, per-function data. This is added to the cfun structure. */ diff --git a/gcc/config/epiphany/epiphany.cc b/gcc/config/epiphany/epiphany.cc index 68e748c688e..e10e64de823 100644 --- a/gcc/config/epiphany/epiphany.cc +++ b/gcc/config/epiphany/epiphany.cc @@ -458,7 +458,7 @@ epiphany_init_reg_tables (void) They unmask them while calling an interruptible function, though. */ -static const struct attribute_spec epiphany_attribute_table[] = +TARGET_GNU_ATTRIBUTES (epiphany_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -468,9 +468,8 @@ static const struct attribute_spec epiphany_attribute_table[] = epiphany_handle_forwarder_attribute, NULL }, { "long_call", 0, 0, false, true, true, false, NULL, NULL }, { "short_call", 0, 0, false, true, true, false, NULL, NULL }, - { "disinterrupt", 0, 0, false, true, true, true, NULL, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "disinterrupt", 0, 0, false, true, true, true, NULL, NULL } +}); /* Handle an "interrupt" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 6a2aaefceca..795a852bb53 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -357,14 +357,12 @@ gcn_handle_amdgpu_hsa_kernel_attribute (tree *node, tree name, Create target-specific __attribute__ types. */ -static const struct attribute_spec gcn_attribute_table[] = { +TARGET_GNU_ATTRIBUTES (gcn_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ {"amdgpu_hsa_kernel", 0, GCN_KERNEL_ARG_TYPES, false, true, - true, true, gcn_handle_amdgpu_hsa_kernel_attribute, NULL}, - /* End element. */ - {NULL, 0, 0, false, false, false, false, NULL, NULL} -}; + true, true, gcn_handle_amdgpu_hsa_kernel_attribute, NULL} +}); /* }}} */ /* {{{ Registers and modes. */ diff --git a/gcc/config/h8300/h8300.cc b/gcc/config/h8300/h8300.cc index 4bbb1b711e8..5936cdca177 100644 --- a/gcc/config/h8300/h8300.cc +++ b/gcc/config/h8300/h8300.cc @@ -4909,7 +4909,7 @@ h8300_insert_attributes (tree node, tree *attributes) tiny_data: This variable lives in the tiny data area and can be referenced with 16-bit absolute memory references. */ -static const struct attribute_spec h8300_attribute_table[] = +TARGET_GNU_ATTRIBUTES (h8300_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -4926,9 +4926,8 @@ static const struct attribute_spec h8300_attribute_table[] = { "eightbit_data", 0, 0, true, false, false, false, h8300_handle_eightbit_data_attribute, NULL }, { "tiny_data", 0, 0, true, false, false, false, - h8300_handle_tiny_data_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + h8300_handle_tiny_data_attribute, NULL } +}); /* Handle an attribute requiring a FUNCTION_DECL; arguments as in diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc index df7d24352d1..351c777c666 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -3951,7 +3951,7 @@ handle_nodirect_extern_access_attribute (tree *pnode, tree name, } /* Table of valid machine attributes. */ -const struct attribute_spec ix86_attribute_table[] = +static const attribute_spec ix86_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -4031,10 +4031,12 @@ const struct attribute_spec ix86_attribute_table[] = { "cf_check", 0, 0, true, false, false, false, ix86_handle_fndecl_attribute, NULL }, { "nodirect_extern_access", 0, 0, true, false, false, false, - handle_nodirect_extern_access_attribute, NULL }, + handle_nodirect_extern_access_attribute, NULL } +}; - /* End element. */ - { NULL, 0, 0, false, false, false, false, NULL, NULL } +const scoped_attribute_specs ix86_gnu_attribute_table = +{ + "gnu", ix86_gnu_attributes }; #include "gt-i386-options.h" diff --git a/gcc/config/i386/i386-options.h b/gcc/config/i386/i386-options.h index 68666067fea..6274c594647 100644 --- a/gcc/config/i386/i386-options.h +++ b/gcc/config/i386/i386-options.h @@ -82,7 +82,7 @@ void ix86_function_specific_print (FILE *, int, struct cl_target_option *); bool ix86_valid_target_attribute_p (tree, tree, tree, int); -extern const struct attribute_spec ix86_attribute_table[]; +extern const struct scoped_attribute_specs ix86_gnu_attribute_table; #endif /* GCC_I386_OPTIONS_H */ diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 7b72aabf0da..e0eff9f1430 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -25832,6 +25832,11 @@ ix86_run_selftests (void) #endif /* CHECKING_P */ +static const scoped_attribute_specs *const ix86_attribute_table[] = +{ + &ix86_gnu_attribute_table +}; + /* Initialize the GCC target structure. */ #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc index c241e1a50fc..f7766c25622 100644 --- a/gcc/config/ia64/ia64.cc +++ b/gcc/config/ia64/ia64.cc @@ -358,7 +358,7 @@ static bool ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d); /* Table of valid machine attributes. */ -static const struct attribute_spec ia64_attribute_table[] = +static const attribute_spec ia64_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -370,8 +370,17 @@ static const struct attribute_spec ia64_attribute_table[] = ia64_vms_common_object_attribute, NULL }, #endif { "version_id", 1, 1, true, false, false, false, - ia64_handle_version_id_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + ia64_handle_version_id_attribute, NULL } +}; + +static const scoped_attribute_specs ia64_gnu_attribute_table = +{ + "gnu", ia64_gnu_attributes +}; + +static const scoped_attribute_specs *const ia64_attribute_table[] = +{ + &ia64_gnu_attribute_table }; /* Initialize the GCC target structure. */ diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index c782f571abc..bf73ab60072 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -7812,15 +7812,13 @@ loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, return NULL_TREE; } -static const struct attribute_spec loongarch_attribute_table[] = +TARGET_GNU_ATTRIBUTES (loongarch_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "model", 1, 1, true, false, false, false, - loongarch_handle_model_attribute, NULL }, - /* The last attribute spec is set to be NULL. */ - {} -}; + loongarch_handle_model_attribute, NULL } +}); bool loongarch_use_anchors_for_symbol_p (const_rtx symbol) diff --git a/gcc/config/m32c/m32c.cc b/gcc/config/m32c/m32c.cc index e18efc3c7f2..c63c75a6709 100644 --- a/gcc/config/m32c/m32c.cc +++ b/gcc/config/m32c/m32c.cc @@ -2999,7 +2999,7 @@ current_function_special_page_vector (rtx x) #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table -static const struct attribute_spec m32c_attribute_table[] = { +TARGET_GNU_ATTRIBUTES (m32c_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "interrupt", 0, 0, false, false, false, false, interrupt_handler, NULL }, @@ -3007,9 +3007,8 @@ static const struct attribute_spec m32c_attribute_table[] = { { "fast_interrupt", 0, 0, false, false, false, false, interrupt_handler, NULL }, { "function_vector", 1, 1, true, false, false, false, - function_vector_handler, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + function_vector_handler, NULL } +}); #undef TARGET_COMP_TYPE_ATTRIBUTES #define TARGET_COMP_TYPE_ATTRIBUTES m32c_comp_type_attributes diff --git a/gcc/config/m32r/m32r.cc b/gcc/config/m32r/m32r.cc index 63a1798da3d..1a9c8ef1391 100644 --- a/gcc/config/m32r/m32r.cc +++ b/gcc/config/m32r/m32r.cc @@ -112,15 +112,14 @@ static HOST_WIDE_INT m32r_starting_frame_offset (void); /* M32R specific attributes. */ -static const struct attribute_spec m32r_attribute_table[] = +TARGET_GNU_ATTRIBUTES (m32r_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "interrupt", 0, 0, true, false, false, false, NULL, NULL }, { "model", 1, 1, true, false, false, false, m32r_handle_model_attribute, - NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + NULL } +}); /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE diff --git a/gcc/config/m68k/m68k.cc b/gcc/config/m68k/m68k.cc index 145a92d8710..001cf5bd997 100644 --- a/gcc/config/m68k/m68k.cc +++ b/gcc/config/m68k/m68k.cc @@ -361,7 +361,7 @@ static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int); #undef TARGET_ASM_FINAL_POSTSCAN_INSN #define TARGET_ASM_FINAL_POSTSCAN_INSN m68k_asm_final_postscan_insn -static const struct attribute_spec m68k_attribute_table[] = +TARGET_GNU_ATTRIBUTES (m68k_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -370,9 +370,8 @@ static const struct attribute_spec m68k_attribute_table[] = { "interrupt_handler", 0, 0, true, false, false, false, m68k_handle_fndecl_attribute, NULL }, { "interrupt_thread", 0, 0, true, false, false, false, - m68k_handle_fndecl_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + m68k_handle_fndecl_attribute, NULL } +}); struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/mcore/mcore.cc b/gcc/config/mcore/mcore.cc index 6f1d7af7937..ca672547494 100644 --- a/gcc/config/mcore/mcore.cc +++ b/gcc/config/mcore/mcore.cc @@ -151,16 +151,15 @@ static bool mcore_modes_tieable_p (machine_mode, machine_mode); /* MCore specific attributes. */ -static const struct attribute_spec mcore_attribute_table[] = +TARGET_GNU_ATTRIBUTES (mcore_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "dllexport", 0, 0, true, false, false, false, NULL, NULL }, { "dllimport", 0, 0, true, false, false, false, NULL, NULL }, { "naked", 0, 0, true, false, false, false, - mcore_handle_naked_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + mcore_handle_naked_attribute, NULL } +}); /* Initialize the GCC target structure. */ #undef TARGET_ASM_EXTERNAL_LIBCALL diff --git a/gcc/config/microblaze/microblaze.cc b/gcc/config/microblaze/microblaze.cc index 60ad55120d2..3ea177b835e 100644 --- a/gcc/config/microblaze/microblaze.cc +++ b/gcc/config/microblaze/microblaze.cc @@ -218,15 +218,14 @@ int break_handler; int fast_interrupt; int save_volatiles; -const struct attribute_spec microblaze_attribute_table[] = { +TARGET_GNU_ATTRIBUTES (microblaze_attribute_table, { /* name min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude */ {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL }, {"break_handler", 0, 0, true, false, false, false, NULL, NULL }, {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL }, - {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL } +}); static int microblaze_interrupt_function_p (tree); diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index a304e1c5637..0cf49c13bf4 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -611,7 +611,7 @@ static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int, bool *); /* The value of TARGET_ATTRIBUTE_TABLE. */ -static const struct attribute_spec mips_attribute_table[] = { +TARGET_GNU_ATTRIBUTES (mips_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "long_call", 0, 0, false, true, true, false, NULL, NULL }, @@ -636,9 +636,8 @@ static const struct attribute_spec mips_attribute_table[] = { mips_handle_use_shadow_register_set_attr, NULL }, { "keep_interrupts_masked", 0, 0, false, true, true, false, NULL, NULL }, { "use_debug_exception_return", 0, 0, false, true, true, false, NULL, NULL }, - { "use_hazard_barrier_return", 0, 0, true, false, false, false, NULL, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "use_hazard_barrier_return", 0, 0, true, false, false, false, NULL, NULL } +}); /* A table describing all the processors GCC knows about; see mips-cpus.def for details. */ diff --git a/gcc/config/msp430/msp430.cc b/gcc/config/msp430/msp430.cc index 061a9c77961..85f499f175d 100644 --- a/gcc/config/msp430/msp430.cc +++ b/gcc/config/msp430/msp430.cc @@ -2057,7 +2057,7 @@ static const struct attribute_spec::exclusions attr_either_exclusions[] = #define TARGET_ATTRIBUTE_TABLE msp430_attribute_table /* Table of MSP430-specific attributes. */ -const struct attribute_spec msp430_attribute_table[] = +TARGET_GNU_ATTRIBUTES (msp430_attribute_table, { /* { name, min_num_args, max_num_args, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -2075,10 +2075,8 @@ const struct attribute_spec msp430_attribute_table[] = { ATTR_UPPER, 0, 0, true, false, false, false, msp430_section_attr, attr_upper_exclusions }, { ATTR_EITHER, 0, 0, true, false, false, false, msp430_section_attr, - attr_either_exclusions }, - - { NULL, 0, 0, false, false, false, false, NULL, NULL } - }; + attr_either_exclusions } + }); #undef TARGET_HANDLE_GENERIC_ATTRIBUTE #define TARGET_HANDLE_GENERIC_ATTRIBUTE msp430_handle_generic_attribute diff --git a/gcc/config/nds32/nds32.cc b/gcc/config/nds32/nds32.cc index 1f8de2a514a..e0a73985b66 100644 --- a/gcc/config/nds32/nds32.cc +++ b/gcc/config/nds32/nds32.cc @@ -288,7 +288,7 @@ static const int nds32_reg_alloc_order_for_speed[] = }; /* Defining target-specific uses of __attribute__. */ -static const struct attribute_spec nds32_attribute_table[] = +TARGET_GNU_ATTRIBUTES (nds32_attribute_table, { /* Syntax: { name, min_len, max_len, decl_required, type_required, function_type_required, affects_type_identity, handler, @@ -326,11 +326,8 @@ static const struct attribute_spec nds32_attribute_table[] = /* FOR BACKWARD COMPATIBILITY, this attribute also tells no prologue/epilogue. */ - { "no_prologue", 0, 0, false, false, false, false, NULL, NULL }, - - /* The last attribute spec is set to be NULL. */ - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + { "no_prologue", 0, 0, false, false, false, false, NULL, NULL } +}); /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc index 634c31673be..d5497631429 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -5834,16 +5834,15 @@ nvptx_handle_shared_attribute (tree *node, tree name, tree ARG_UNUSED (args), } /* Table of valid machine attributes. */ -static const struct attribute_spec nvptx_attribute_table[] = +TARGET_GNU_ATTRIBUTES (nvptx_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "kernel", 0, 0, true, false, false, false, nvptx_handle_kernel_attribute, NULL }, { "shared", 0, 0, true, false, false, false, nvptx_handle_shared_attribute, - NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + NULL } +}); /* Limit vector alignments to BIGGEST_ALIGNMENT. */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index e36b5fb9bd0..154d80b48e7 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -421,7 +421,7 @@ static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); static void riscv_legitimize_poly_move (machine_mode, rtx, rtx, rtx); /* Defining target-specific uses of __attribute__. */ -static const struct attribute_spec riscv_attribute_table[] = +TARGET_GNU_ATTRIBUTES (riscv_attribute_table, { /* Syntax: { name, min_len, max_len, decl_required, type_required, function_type_required, affects_type_identity, handler, @@ -437,11 +437,8 @@ static const struct attribute_spec riscv_attribute_table[] = /* The following two are used for the built-in properties of the Vector type and are not used externally */ {"RVV sizeless type", 4, 4, false, true, false, true, NULL, NULL}, - {"RVV type", 0, 0, false, true, false, true, NULL, NULL}, - - /* The last attribute spec is set to be NULL. */ - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + {"RVV type", 0, 0, false, true, false, true, NULL, NULL} +}); /* Order for the CLOBBERs/USEs of gpr_save. */ static const unsigned gpr_save_reg_order[] = { diff --git a/gcc/config/rl78/rl78.cc b/gcc/config/rl78/rl78.cc index 0cbd6bf780a..b2e9b04b691 100644 --- a/gcc/config/rl78/rl78.cc +++ b/gcc/config/rl78/rl78.cc @@ -898,7 +898,7 @@ rl78_handle_vector_attribute (tree * node, #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table /* Table of RL78-specific attributes. */ -const struct attribute_spec rl78_attribute_table[] = +TARGET_GNU_ATTRIBUTES (rl78_attribute_table, { /* Name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude. */ @@ -911,9 +911,8 @@ const struct attribute_spec rl78_attribute_table[] = { "saddr", 0, 0, true, false, false, false, rl78_handle_saddr_attribute, NULL }, { "vector", 1, -1, true, false, false, false, - rl78_handle_vector_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + rl78_handle_vector_attribute, NULL } +}); diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 5f56c3ed85b..cc3f97ae4c5 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -1255,7 +1255,7 @@ static const char alt_reg_names[][8] = /* Table of valid machine attributes. */ -static const struct attribute_spec rs6000_attribute_table[] = +static const attribute_spec rs6000_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -1272,7 +1272,16 @@ static const struct attribute_spec rs6000_attribute_table[] = #ifdef SUBTARGET_ATTRIBUTE_TABLE SUBTARGET_ATTRIBUTE_TABLE, #endif - { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +static const scoped_attribute_specs rs6000_gnu_attribute_table = +{ + "gnu", rs6000_gnu_attributes +}; + +static const scoped_attribute_specs *const rs6000_attribute_table[] = +{ + &rs6000_gnu_attribute_table }; #ifndef TARGET_PROFILE_KERNEL diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc index 245c6a4413d..0754e286552 100644 --- a/gcc/config/rx/rx.cc +++ b/gcc/config/rx/rx.cc @@ -2760,7 +2760,7 @@ rx_handle_vector_attribute (tree * node, } /* Table of RX specific attributes. */ -const struct attribute_spec rx_attribute_table[] = +TARGET_GNU_ATTRIBUTES (rx_attribute_table, { /* Name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude. */ @@ -2771,9 +2771,8 @@ const struct attribute_spec rx_attribute_table[] = { "naked", 0, 0, true, false, false, false, rx_handle_func_attribute, NULL }, { "vector", 1, -1, true, false, false, false, - rx_handle_vector_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + rx_handle_vector_attribute, NULL } +}); /* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */ diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 64f56d8effa..a8205385451 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -1303,7 +1303,7 @@ s390_handle_string_attribute (tree *node, tree name ATTRIBUTE_UNUSED, return NULL_TREE; } -static const struct attribute_spec s390_attribute_table[] = { +TARGET_GNU_ATTRIBUTES (s390_attribute_table, { { "hotpatch", 2, 2, true, false, false, false, s390_handle_hotpatch_attribute, NULL }, { "s390_vector_bool", 0, 0, false, true, false, true, @@ -1319,11 +1319,8 @@ static const struct attribute_spec s390_attribute_table[] = { { "function_return_reg", 1, 1, true, false, false, false, s390_handle_string_attribute, NULL }, { "function_return_mem", 1, 1, true, false, false, false, - s390_handle_string_attribute, NULL }, - - /* End element. */ - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + s390_handle_string_attribute, NULL } +}); /* Return the alignment for LABEL. We default to the -falign-labels value except for the literal pool base label. */ diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc index 6ec2eecf754..8c378b28b6d 100644 --- a/gcc/config/sh/sh.cc +++ b/gcc/config/sh/sh.cc @@ -329,7 +329,7 @@ static bool sh_hard_regno_mode_ok (unsigned int, machine_mode); static bool sh_modes_tieable_p (machine_mode, machine_mode); static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t); -static const struct attribute_spec sh_attribute_table[] = +TARGET_GNU_ATTRIBUTES (sh_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -348,9 +348,8 @@ static const struct attribute_spec sh_attribute_table[] = { "resbank", 0, 0, true, false, false, false, sh_handle_resbank_handler_attribute, NULL }, { "function_vector", 1, 1, true, false, false, false, - sh2a_handle_function_vector_handler_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + sh2a_handle_function_vector_handler_attribute, NULL } +}); /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE diff --git a/gcc/config/sparc/sparc.cc b/gcc/config/sparc/sparc.cc index 82e57952414..a78dedc8075 100644 --- a/gcc/config/sparc/sparc.cc +++ b/gcc/config/sparc/sparc.cc @@ -721,13 +721,12 @@ static HARD_REG_SET sparc_zero_call_used_regs (HARD_REG_SET); #ifdef SUBTARGET_ATTRIBUTE_TABLE /* Table of valid machine attributes. */ -static const struct attribute_spec sparc_attribute_table[] = +TARGET_GNU_ATTRIBUTES (sparc_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, do_diagnostic, handler, exclude } */ - SUBTARGET_ATTRIBUTE_TABLE, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + SUBTARGET_ATTRIBUTE_TABLE +}); #endif char sparc_hard_reg_printed[8]; diff --git a/gcc/config/stormy16/stormy16.cc b/gcc/config/stormy16/stormy16.cc index 10887153906..071043b4128 100644 --- a/gcc/config/stormy16/stormy16.cc +++ b/gcc/config/stormy16/stormy16.cc @@ -2377,7 +2377,7 @@ static tree xstormy16_handle_interrupt_attribute static tree xstormy16_handle_below100_attribute (tree *, tree, tree, int, bool *); -static const struct attribute_spec xstormy16_attribute_table[] = +TARGET_GNU_ATTRIBUTES (xstormy16_attribute_table, { /* name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude. */ @@ -2386,9 +2386,8 @@ static const struct attribute_spec xstormy16_attribute_table[] = { "BELOW100", 0, 0, false, false, false, false, xstormy16_handle_below100_attribute, NULL }, { "below100", 0, 0, false, false, false, false, - xstormy16_handle_below100_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + xstormy16_handle_below100_attribute, NULL } +}); /* Handle an "interrupt" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/config/v850/v850.cc b/gcc/config/v850/v850.cc index 416c2841a5c..50c91c68b8b 100644 --- a/gcc/config/v850/v850.cc +++ b/gcc/config/v850/v850.cc @@ -3114,7 +3114,7 @@ v850_adjust_insn_length (rtx_insn *insn, int length) /* V850 specific attributes. */ -static const struct attribute_spec v850_attribute_table[] = +TARGET_GNU_ATTRIBUTES (v850_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -3127,9 +3127,8 @@ static const struct attribute_spec v850_attribute_table[] = { "tda", 0, 0, true, false, false, false, v850_handle_data_area_attribute, NULL }, { "zda", 0, 0, true, false, false, false, - v850_handle_data_area_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } -}; + v850_handle_data_area_attribute, NULL } +}); static void v850_option_override (void) diff --git a/gcc/config/visium/visium.cc b/gcc/config/visium/visium.cc index 5fadbc80be0..4a1877c2ac1 100644 --- a/gcc/config/visium/visium.cc +++ b/gcc/config/visium/visium.cc @@ -145,14 +145,13 @@ static inline bool current_function_has_lr_slot (void); /* Supported attributes: interrupt -- specifies this function is an interrupt handler. */ -static const struct attribute_spec visium_attribute_table[] = +TARGET_GNU_ATTRIBUTES (visium_attribute_table, { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "interrupt", 0, 0, true, false, false, false, visium_handle_interrupt_attr, - NULL}, - { NULL, 0, 0, false, false, false, false, NULL, NULL }, -}; + NULL} +}); static struct machine_function *visium_init_machine_status (void); diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 1408301a300..d3fa002593f 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -122,13 +122,16 @@ extern tree cxx_simulate_record_decl (location_t, const char *, #undef LANG_HOOKS_FINALIZE_EARLY_DEBUG #define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug -/* Attribute hooks. */ -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table +static const scoped_attribute_specs *const cp_objcp_attribute_table[] = +{ + &std_attribute_table, + &cxx_gnu_attribute_table, + &c_common_gnu_attribute_table, + &c_common_format_attribute_table +}; + #undef LANG_HOOKS_ATTRIBUTE_TABLE -#define LANG_HOOKS_ATTRIBUTE_TABLE cxx_attribute_table +#define LANG_HOOKS_ATTRIBUTE_TABLE cp_objcp_attribute_table #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P cp_var_mod_type_p diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 98b29e9cf81..0a543c5f14c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8000,7 +8000,8 @@ extern tree maybe_dummy_object (tree, tree *); extern bool is_dummy_object (const_tree); extern bool is_byte_access_type (tree); extern bool is_byte_access_type_not_plain_char (tree); -extern const struct attribute_spec cxx_attribute_table[]; +extern const struct scoped_attribute_specs cxx_gnu_attribute_table; +extern const struct scoped_attribute_specs std_attribute_table; extern tree make_ptrmem_cst (tree, tree); extern tree cp_build_type_attribute_variant (tree, tree); extern tree cp_build_reference_type (tree, bool); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 417c92ba76f..fd99d64ca47 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -5072,7 +5072,7 @@ handle_likeliness_attribute (tree *node, tree name, tree args, } /* Table of valid C++ attributes. */ -const struct attribute_spec cxx_attribute_table[] = +static const attribute_spec cxx_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -5080,11 +5080,15 @@ const struct attribute_spec cxx_attribute_table[] = handle_init_priority_attribute, NULL }, { "abi_tag", 1, -1, false, false, false, true, handle_abi_tag_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +const scoped_attribute_specs cxx_gnu_attribute_table = +{ + "gnu", cxx_gnu_attributes }; /* Table of C++ standard attributes. */ -const struct attribute_spec std_attribute_table[] = +static const attribute_spec std_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -5105,10 +5109,11 @@ const struct attribute_spec std_attribute_table[] = { "pre", 0, -1, false, false, false, false, handle_contract_attribute, NULL }, { "post", 0, -1, false, false, false, false, - handle_contract_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + handle_contract_attribute, NULL } }; +const scoped_attribute_specs std_attribute_table = { nullptr, std_attributes }; + /* Handle an "init_priority" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -5704,7 +5709,6 @@ void init_tree (void) { list_hash_table = hash_table<list_hasher>::create_ggc (61); - register_scoped_attributes (std_attribute_table, NULL); } /* Returns the kind of special function that DECL (a FUNCTION_DECL) diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index c0dc0e24ded..f6411058072 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -162,7 +162,7 @@ extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = /* Table of machine-independent attributes. For internal use (marking of built-ins) only. */ -const attribute_spec d_langhook_common_attribute_table[] = +static const attribute_spec d_langhook_common_attributes[] = { ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, handle_noreturn_attribute, attr_noreturn_exclusions), @@ -190,11 +190,15 @@ const attribute_spec d_langhook_common_attribute_table[] = handle_fnspec_attribute, NULL), ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false, handle_omp_declare_simd_attribute, NULL), - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), +}; + +const scoped_attribute_specs d_langhook_common_attribute_table = +{ + "gnu", d_langhook_common_attributes }; /* Table of D language attributes exposed by `gcc.attribute' UDAs. */ -const attribute_spec d_langhook_attribute_table[] = +static const attribute_spec d_langhook_gnu_attributes[] = { ATTR_SPEC ("noinline", 0, 0, true, false, false, false, d_handle_noinline_attribute, attr_noinline_exclusions), @@ -238,9 +242,12 @@ const attribute_spec d_langhook_attribute_table[] = d_handle_used_attribute, NULL), ATTR_SPEC ("visibility", 1, 1, false, false, false, false, d_handle_visibility_attribute, NULL), - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; +const scoped_attribute_specs d_langhook_gnu_attribute_table = +{ + "gnu", d_langhook_gnu_attributes +}; /* Insert the type attribute ATTRNAME with value VALUE into TYPE. Returns a new variant of the original type declaration. */ @@ -283,20 +290,14 @@ uda_attribute_p (const char *name) /* Search both our language, and target attribute tables. Common and format attributes are kept internal. */ - for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++) - { - if (get_identifier (p->name) == ident) - return true; - } + for (const attribute_spec &p : d_langhook_gnu_attributes) + if (get_identifier (p.name) == ident) + return true; - if (targetm.attribute_table) - { - for (const attribute_spec *p = targetm.attribute_table; p->name; p++) - { - if (get_identifier (p->name) == ident) - return true; - } - } + for (auto scoped_attributes : targetm.attribute_table) + for (const attribute_spec &p : scoped_attributes->attributes) + if (get_identifier (p.name) == ident) + return true; return false; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 61fc1608b40..dcbffec3752 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1927,6 +1927,12 @@ d_get_sarif_source_language (const char *) return "d"; } +const scoped_attribute_specs *const d_langhook_attribute_table[] = +{ + &d_langhook_gnu_attribute_table, + &d_langhook_common_attribute_table, +}; + /* Definitions for our language-specific hooks. */ #undef LANG_HOOKS_NAME @@ -1938,7 +1944,6 @@ d_get_sarif_source_language (const char *) #undef LANG_HOOKS_HANDLE_OPTION #undef LANG_HOOKS_POST_OPTIONS #undef LANG_HOOKS_PARSE_FILE -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #undef LANG_HOOKS_ATTRIBUTE_TABLE #undef LANG_HOOKS_GET_ALIAS_SET #undef LANG_HOOKS_TYPES_COMPATIBLE_P @@ -1971,7 +1976,6 @@ d_get_sarif_source_language (const char *) #define LANG_HOOKS_HANDLE_OPTION d_handle_option #define LANG_HOOKS_POST_OPTIONS d_post_options #define LANG_HOOKS_PARSE_FILE d_parse_file -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE d_langhook_common_attribute_table #define LANG_HOOKS_ATTRIBUTE_TABLE d_langhook_attribute_table #define LANG_HOOKS_GET_ALIAS_SET d_get_alias_set #define LANG_HOOKS_TYPES_COMPATIBLE_P d_types_compatible_p diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index d19c3f50bd9..46a28737daa 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -520,8 +520,8 @@ extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE); extern void apply_user_attributes (Dsymbol *, tree); /* In d-builtins.cc. */ -extern const attribute_spec d_langhook_attribute_table[]; -extern const attribute_spec d_langhook_common_attribute_table[]; +extern const struct scoped_attribute_specs d_langhook_gnu_attribute_table; +extern const struct scoped_attribute_specs d_langhook_common_attribute_table; extern Type *build_frontend_type (tree); extern tree d_builtin_function (tree); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index d83ca73b1af..abc23b2bb73 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -10528,12 +10528,33 @@ 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-core.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. +@deftypevr {Target Hook} {array_slice<const struct scoped_attribute_specs *const>} TARGET_ATTRIBUTE_TABLE +If defined, this target hook provides an array of +@samp{scoped_attribute_spec}s (defined in @file{attribs.h}) that specify the +machine-specific attributes for this target. The information includes some +of the restrictions on the entities to which these attributes are applied +and the arguments that the attributes take. + +In C and C++, these attributes are associated with two syntaxes: +the traditional GNU @code{__attribute__} syntax and the standard +@samp{[[]]} syntax. Attributes that support the GNU syntax must be +placed in the @code{gnu} namespace. Such attributes can then also be +written @samp{[[gnu::@dots{}]]}. Attributes that use only the standard +syntax should be placed in whichever namespace the attribute specification +requires. For example, a target might choose to support vendor-specific +@samp{[[]]} attributes that the vendor places in their own namespace. + +Targets that only define attributes in the @code{gnu} namespace +can uase the following shorthand to define the table: + +@smallexample +TARGET_GNU_ATTRIBUTES (@var{cpu_attribute_table}, @{ + @{ "@var{attribute1}", @dots{} @}, + @{ "@var{attribute2}", @dots{} @}, + @dots{}, + @{ "@var{attributen}", @dots{} @}, +@}); +@end smallexample @end deftypevr @deftypefn {Target Hook} bool TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P (const_tree @var{name}) diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index 350e6e379eb..99dd76226a2 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "cpp.h" #include "trans-types.h" #include "trans-const.h" +#include "attribs.h" /* Language-dependent contents of an identifier. */ @@ -87,7 +88,7 @@ gfc_handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *) } /* Table of valid Fortran attributes. */ -static const struct attribute_spec gfc_attribute_table[] = +static const attribute_spec gfc_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -97,7 +98,16 @@ static const struct attribute_spec gfc_attribute_table[] = gfc_handle_omp_declare_target_attribute, NULL }, { "oacc function", 0, -1, true, false, false, false, gfc_handle_omp_declare_target_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +static const scoped_attribute_specs gfc_gnu_attribute_table = +{ + "gnu", gfc_gnu_attributes +}; + +static const scoped_attribute_specs *const gfc_attribute_table[] = +{ + &gfc_gnu_attribute_table }; /* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index a729086bafb..61cc0e1ae66 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -87,7 +87,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = }; /* Table of machine-independent attributes supported in libgccjit. */ -const struct attribute_spec jit_attribute_table[] = +static const attribute_spec jit_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -128,22 +128,36 @@ const struct attribute_spec jit_attribute_table[] = /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, false, - ignore_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + ignore_attribute, NULL } +}; + +static const scoped_attribute_specs jit_gnu_attribute_table = +{ + "gnu", jit_gnu_attributes }; /* Give the specifications for the format attributes, used by C and all descendants. */ -const struct attribute_spec jit_format_attribute_table[] = +static const attribute_spec jit_format_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ { "format", 3, 3, false, true, true, false, handle_format_attribute, NULL }, { "format_arg", 1, 1, false, true, true, false, - handle_format_arg_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + handle_format_arg_attribute, NULL } +}; + +static const scoped_attribute_specs jit_format_attribute_table = +{ + "gnu", jit_format_attributes +}; + +static const scoped_attribute_specs *const jit_attribute_table[] = +{ + &jit_gnu_attribute_table, + &jit_format_attribute_table }; /* Attribute handlers. */ @@ -719,10 +733,8 @@ jit_langhook_getdecls (void) #define LANG_HOOKS_GETDECLS jit_langhook_getdecls /* Attribute hooks. */ -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE jit_attribute_table -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE jit_format_attribute_table +#undef LANG_HOOKS_ATTRIBUTE_TABLE +#define LANG_HOOKS_ATTRIBUTE_TABLE jit_attribute_table #undef LANG_HOOKS_DEEP_UNSHARING #define LANG_HOOKS_DEEP_UNSHARING true diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index c6d18526360..c9cb65759c2 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -153,9 +153,7 @@ extern const char *lhd_get_sarif_source_language (const char *); #define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE lhd_get_sarif_source_language /* Attribute hooks. */ -#define LANG_HOOKS_ATTRIBUTE_TABLE NULL -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE NULL -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE NULL +#define LANG_HOOKS_ATTRIBUTE_TABLE {} /* Tree inlining hooks. */ #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P \ @@ -367,8 +365,6 @@ extern void lhd_end_section (void); LANG_HOOKS_PRINT_ERROR_FUNCTION, \ LANG_HOOKS_TO_TARGET_CHARSET, \ LANG_HOOKS_ATTRIBUTE_TABLE, \ - LANG_HOOKS_COMMON_ATTRIBUTE_TABLE, \ - LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE, \ LANG_HOOKS_TREE_INLINING_INITIALIZER, \ LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_DECLS, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index cca75285fc2..2785a0070fc 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -532,9 +532,7 @@ struct lang_hooks table of attributes specific to the language, a table of attributes common to two or more languages (to allow easy sharing), and a table of attributes for checking formats. */ - const struct attribute_spec *attribute_table; - const struct attribute_spec *common_attribute_table; - const struct attribute_spec *format_attribute_table; + array_slice<const struct scoped_attribute_specs *const> attribute_table; struct lang_hooks_for_tree_inlining tree_inlining; diff --git a/gcc/lto/lto-lang.cc b/gcc/lto/lto-lang.cc index 14d419c2013..a8adf110b20 100644 --- a/gcc/lto/lto-lang.cc +++ b/gcc/lto/lto-lang.cc @@ -94,7 +94,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = }; /* Table of machine-independent attributes supported in GIMPLE. */ -const struct attribute_spec lto_attribute_table[] = +static const attribute_spec lto_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -135,14 +135,18 @@ const struct attribute_spec lto_attribute_table[] = /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, false, - ignore_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } + ignore_attribute, NULL } +}; + +static const scoped_attribute_specs lto_gnu_attribute_table = +{ + "gnu", lto_gnu_attributes }; /* Give the specifications for the format attributes, used by C and all descendants. */ -const struct attribute_spec lto_format_attribute_table[] = +static const attribute_spec lto_format_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -150,7 +154,17 @@ const struct attribute_spec lto_format_attribute_table[] = handle_format_attribute, NULL }, { "format_arg", 1, 1, false, true, true, false, handle_format_arg_attribute, NULL }, - { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +static const scoped_attribute_specs lto_format_attribute_table = +{ + "gnu", lto_format_attributes +}; + +static const scoped_attribute_specs *const lto_attribute_table[] = +{ + <o_gnu_attribute_table, + <o_format_attribute_table }; enum built_in_attribute @@ -1463,10 +1477,8 @@ static void lto_init_ts (void) #define LANG_HOOKS_EH_PERSONALITY lto_eh_personality /* Attribute hooks. */ -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE lto_attribute_table -#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE -#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE lto_format_attribute_table +#undef LANG_HOOKS_ATTRIBUTE_TABLE +#define LANG_HOOKS_ATTRIBUTE_TABLE lto_attribute_table #undef LANG_HOOKS_BEGIN_SECTION #define LANG_HOOKS_BEGIN_SECTION lto_obj_begin_section diff --git a/gcc/plugin.h b/gcc/plugin.h index ee0a53ec4c9..f306adfb3b9 100644 --- a/gcc/plugin.h +++ b/gcc/plugin.h @@ -201,8 +201,7 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED, extern void register_attribute (const struct attribute_spec *attr); /* The default argument for the third parameter is given in attribs.h. */ -extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, - const char *, +extern struct scoped_attributes* register_scoped_attributes (const struct scoped_attribute_spec &, bool); #endif /* PLUGIN_H */ diff --git a/gcc/target-def.h b/gcc/target-def.h index 847698a1e59..d03b039ab24 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -118,6 +118,20 @@ #define TARGET_FUNCTION_INCOMING_ARG TARGET_FUNCTION_ARG #endif +/* Declare a target attribute table called NAME that only has GNU attributes. + There should be no null trailing element. E.g.: + + TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, + { + { "aarch64_vector_pcs", ... }, + ... + }); */ + +#define TARGET_GNU_ATTRIBUTES(NAME, ...) \ + static const attribute_spec NAME##_2[] = __VA_ARGS__; \ + static const scoped_attribute_specs NAME##_1 = { "gnu", NAME##_2 }; \ + static const scoped_attribute_specs *const NAME[] = { &NAME##_1 } + #include "target-hooks-def.h" #include "hooks.h" diff --git a/gcc/target.def b/gcc/target.def index 0996da0f71a..06c5d3b5c2e 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2218,15 +2218,36 @@ merging.", merge_type_attributes) /* Table of machine attributes and functions to handle them. - Ignored if NULL. */ + Ignored if empty. */ DEFHOOKPOD (attribute_table, - "If defined, this target hook points to an array of @samp{struct\n\ -attribute_spec} (defined in @file{tree-core.h}) specifying the machine\n\ -specific attributes for this target and some of the restrictions on the\n\ -entities to which these attributes are applied and the arguments they\n\ -take.", - const struct attribute_spec *, NULL) + "If defined, this target hook provides an array of\n\ +@samp{scoped_attribute_spec}s (defined in @file{attribs.h}) that specify the\n\ +machine-specific attributes for this target. The information includes some\n\ +of the restrictions on the entities to which these attributes are applied\n\ +and the arguments that the attributes take.\n\ +\n\ +In C and C++, these attributes are associated with two syntaxes:\n\ +the traditional GNU @code{__attribute__} syntax and the standard\n\ +@samp{[[]]} syntax. Attributes that support the GNU syntax must be\n\ +placed in the @code{gnu} namespace. Such attributes can then also be\n\ +written @samp{[[gnu::@dots{}]]}. Attributes that use only the standard\n\ +syntax should be placed in whichever namespace the attribute specification\n\ +requires. For example, a target might choose to support vendor-specific\n\ +@samp{[[]]} attributes that the vendor places in their own namespace.\n\ +\n\ +Targets that only define attributes in the @code{gnu} namespace\n\ +can uase the following shorthand to define the table:\n\ +\n\ +@smallexample\n\ +TARGET_GNU_ATTRIBUTES (@var{cpu_attribute_table}, @{\n\ + @{ \"@var{attribute1}\", @dots{} @},\n\ + @{ \"@var{attribute2}\", @dots{} @},\n\ + @dots{},\n\ + @{ \"@var{attributen}\", @dots{} @},\n\ +@});\n\ +@end smallexample", + array_slice<const struct scoped_attribute_specs *const>, {}) /* Return true iff attribute NAME expects a plain identifier as its first argument. */ diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 00d05102e7a..2831a0368f6 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -4094,17 +4094,16 @@ inline_forbidden_p (tree fndecl) static bool function_attribute_inlinable_p (const_tree fndecl) { - if (targetm.attribute_table) + for (auto scoped_attributes : targetm.attribute_table) { const_tree a; for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a)) { const_tree name = get_attribute_name (a); - int i; - for (i = 0; targetm.attribute_table[i].name != NULL; i++) - if (is_attribute_p (targetm.attribute_table[i].name, name)) + for (const attribute_spec &attribute : scoped_attributes->attributes) + if (is_attribute_p (attribute.name, name)) return targetm.function_attribute_inlinable_p (fndecl); } }