diff options
author | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
commit | 73127104a245052cd5cf29cdaaca3e5c32c70348 (patch) | |
tree | 8e28b63e478c43c252f18b49836dff7313affe54 /0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch | |
parent | 49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff) |
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch')
-rw-r--r-- | 0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch | 2369 |
1 files changed, 2369 insertions, 0 deletions
diff --git a/0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch b/0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch new file mode 100644 index 0000000..5f5b8f3 --- /dev/null +++ b/0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch @@ -0,0 +1,2369 @@ +From 82d654912e3671055034e789a8f7110f6d87d447 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Sat, 2 Dec 2023 13:49:52 +0000 +Subject: [PATCH 073/157] [Backport][SME] Allow target attributes in non-gnu + namespaces + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=7fa24687aa3a683fd105ce5ff6b176f48dca3b6c + +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/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 +- + 60 files changed, 491 insertions(+), 403 deletions(-) + +diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h +index bd559d176..6ababfcbb 100644 +--- a/gcc/ada/gcc-interface/gigi.h ++++ b/gcc/ada/gcc-interface/gigi.h +@@ -349,7 +349,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 2caa83ff8..8dd055772 100644 +--- a/gcc/ada/gcc-interface/misc.cc ++++ b/gcc/ada/gcc-interface/misc.cc +@@ -1339,6 +1339,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 +@@ -1404,7 +1409,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 049cf74eb..ef8524fa9 100644 +--- a/gcc/ada/gcc-interface/utils.cc ++++ b/gcc/ada/gcc-interface/utils.cc +@@ -134,7 +134,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 } */ +@@ -207,9 +207,11 @@ const struct attribute_spec gnat_internal_attribute_table[] = + fake_attribute_handler, NULL }, + { "format_arg", 1, 1, false, true, true, false, + 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 16d05b1da..656ea739e 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 +@@ -280,7 +262,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) +@@ -292,22 +274,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 ()); + } + } + +@@ -327,27 +310,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); +@@ -2551,10 +2525,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. +@@ -2569,55 +2539,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 5b6f63ede..0856f98fb 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 111a33f40..d5c0392b7 100644 +--- a/gcc/c-family/c-attribs.cc ++++ b/gcc/c-family/c-attribs.cc +@@ -282,7 +282,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 } */ +@@ -554,23 +554,31 @@ const struct attribute_spec c_common_attribute_table[] = + { "*dealloc", 1, 2, true, false, false, false, + handle_dealloc_attribute, NULL }, + { "tainted_args", 0, 0, true, false, false, false, +- handle_tainted_args_attribute, NULL }, +- { NULL, 0, 0, false, false, false, false, NULL, NULL } ++ handle_tainted_args_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 3d5b9c40e..d1503c5a7 100644 +--- a/gcc/c-family/c-common.h ++++ b/gcc/c-family/c-common.h +@@ -819,8 +819,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 619a20909..9d87a8cdb 100644 +--- a/gcc/c/c-decl.cc ++++ b/gcc/c/c-decl.cc +@@ -4460,7 +4460,7 @@ handle_nodiscard_attribute (tree *node, tree name, tree /*args*/, + return NULL_TREE; + } + /* 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 } */ +@@ -4471,8 +4471,12 @@ const struct attribute_spec std_attribute_table[] = + { "maybe_unused", 0, 0, false, false, false, false, + handle_unused_attribute, NULL }, + { "nodiscard", 0, 1, false, false, false, false, +- handle_nodiscard_attribute, NULL }, +- { NULL, 0, 0, false, false, false, false, NULL, NULL } ++ handle_nodiscard_attribute, NULL } ++}; ++ ++const scoped_attribute_specs std_attribute_table = ++{ ++ nullptr, std_attributes + }; + + /* Create the predefined scalar types of C, +@@ -4488,8 +4492,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 0b60df975..bc3dded23 100644 +--- a/gcc/c/c-objc-common.h ++++ b/gcc/c/c-objc-common.h +@@ -70,11 +70,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 c70f0ba5a..654bd4094 100644 +--- a/gcc/c/c-tree.h ++++ b/gcc/c/c-tree.h +@@ -835,6 +835,8 @@ set_c_expr_source_range (c_expr *expr, + /* In c-fold.cc */ + extern vec<tree> incomplete_record_decls; + ++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 4194dfc70..114252a3c 100644 +--- a/gcc/config/aarch64/aarch64.cc ++++ b/gcc/config/aarch64/aarch64.cc +@@ -2986,7 +2986,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 } */ +@@ -2997,9 +2997,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 } ++}); + + /* An ISA extension in the co-processor and main instruction set space. */ + struct aarch64_option_extension +diff --git a/gcc/config/alpha/alpha.cc b/gcc/config/alpha/alpha.cc +index 66c17149d..7fb491918 100644 +--- a/gcc/config/alpha/alpha.cc ++++ b/gcc/config/alpha/alpha.cc +@@ -7475,14 +7475,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 fbc17e684..1c6adcab4 100644 +--- a/gcc/config/arc/arc.cc ++++ b/gcc/config/arc/arc.cc +@@ -230,44 +230,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); +@@ -819,6 +781,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 c72e9c0b0..3bdc7e18e 100644 +--- a/gcc/config/arm/arm.cc ++++ b/gcc/config/arm/arm.cc +@@ -329,7 +329,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 } */ +@@ -377,8 +377,17 @@ static const struct attribute_spec arm_attribute_table[] = + arm_handle_cmse_nonsecure_entry, NULL }, + { "cmse_nonsecure_call", 0, 0, true, 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 1b5a95410..7b37278ca 100644 +--- a/gcc/config/avr/avr.cc ++++ b/gcc/config/avr/avr.cc +@@ -9723,7 +9723,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 } */ +@@ -9748,9 +9748,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 b2a9142f5..fbc5c84d1 100644 +--- a/gcc/config/bfin/bfin.cc ++++ b/gcc/config/bfin/bfin.cc +@@ -4895,7 +4895,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 } */ +@@ -4920,9 +4920,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 6a0e3bbca..0343af9c7 100644 +--- a/gcc/config/bpf/bpf.cc ++++ b/gcc/config/bpf/bpf.cc +@@ -146,7 +146,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, +@@ -159,11 +159,8 @@ static const struct attribute_spec bpf_attribute_table[] = + /* CO-RE support: attribute to mark that all accesses to the declared + struct/union/array should be recorded. */ + { "preserve_access_index", 0, -1, false, true, false, true, +- bpf_handle_preserve_access_index_attribute, NULL }, +- +- /* The last attribute spec is set to be NULL. */ +- { NULL, 0, 0, false, false, false, false, NULL, NULL } +-}; ++ bpf_handle_preserve_access_index_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 e315e09a8..b511fafe5 100644 +--- a/gcc/config/csky/csky.cc ++++ b/gcc/config/csky/csky.cc +@@ -211,16 +211,15 @@ const int csky_dbx_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 62636b1ec..8a7c0a988 100644 +--- a/gcc/config/epiphany/epiphany.cc ++++ b/gcc/config/epiphany/epiphany.cc +@@ -460,7 +460,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 } */ +@@ -470,9 +470,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 e2cbdd1ac..0b049abcc 100644 +--- a/gcc/config/gcn/gcn.cc ++++ b/gcc/config/gcn/gcn.cc +@@ -363,14 +363,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 78cf15f15..a0fa689de 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 86932d719..991661fe4 100644 +--- a/gcc/config/i386/i386-options.cc ++++ b/gcc/config/i386/i386-options.cc +@@ -3875,7 +3875,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 } */ +@@ -3955,10 +3955,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 ce4034f62..a7bdb22c0 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 83a0d8abb..ade965927 100644 +--- a/gcc/config/i386/i386.cc ++++ b/gcc/config/i386/i386.cc +@@ -24293,6 +24293,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 f9fb681a3..b9ced1c46 100644 +--- a/gcc/config/ia64/ia64.cc ++++ b/gcc/config/ia64/ia64.cc +@@ -357,7 +357,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 } */ +@@ -369,8 +369,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/m32c/m32c.cc b/gcc/config/m32c/m32c.cc +index 11ca9a43a..a8f6523df 100644 +--- a/gcc/config/m32c/m32c.cc ++++ b/gcc/config/m32c/m32c.cc +@@ -2996,7 +2996,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 }, +@@ -3004,9 +3004,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 bca768172..78a17f0a1 100644 +--- a/gcc/config/m32r/m32r.cc ++++ b/gcc/config/m32r/m32r.cc +@@ -111,15 +111,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 62898dafe..effb6db8d 100644 +--- a/gcc/config/m68k/m68k.cc ++++ b/gcc/config/m68k/m68k.cc +@@ -360,7 +360,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 } */ +@@ -369,9 +369,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 28e707496..e497b0f44 100644 +--- a/gcc/config/mcore/mcore.cc ++++ b/gcc/config/mcore/mcore.cc +@@ -150,16 +150,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 f32effecf..6b14d3e29 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 02d11ddbf..5474ca152 100644 +--- a/gcc/config/mips/mips.cc ++++ b/gcc/config/mips/mips.cc +@@ -607,7 +607,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 }, +@@ -629,9 +629,8 @@ static const struct attribute_spec mips_attribute_table[] = { + { "use_shadow_register_set", 0, 1, false, true, true, false, + 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 }, +- { NULL, 0, 0, false, false, false, false, NULL, NULL } +-}; ++ { "use_debug_exception_return", 0, 0, false, true, true, 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 7a378ceac..f58855978 100644 +--- a/gcc/config/msp430/msp430.cc ++++ b/gcc/config/msp430/msp430.cc +@@ -2055,7 +2055,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 } */ +@@ -2073,10 +2073,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 27530495f..519b11e4c 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 7f2103ba6..9a3e418f4 100644 +--- a/gcc/config/nvptx/nvptx.cc ++++ b/gcc/config/nvptx/nvptx.cc +@@ -5817,16 +5817,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 9cf79beba..f5a27bdc9 100644 +--- a/gcc/config/riscv/riscv.cc ++++ b/gcc/config/riscv/riscv.cc +@@ -336,7 +336,7 @@ static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *); + static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); + + /* 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, +@@ -347,11 +347,8 @@ static const struct attribute_spec riscv_attribute_table[] = + riscv_handle_fndecl_attribute, NULL }, + /* This attribute generates prologue/epilogue for interrupt handlers. */ + { "interrupt", 0, 1, false, true, true, false, +- riscv_handle_type_attribute, NULL }, +- +- /* The last attribute spec is set to be NULL. */ +- { NULL, 0, 0, false, false, false, false, NULL, NULL } +-}; ++ riscv_handle_type_attribute, 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 b3727c0a8..97386c7ea 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 55d4ce751..46e3d1a12 100644 +--- a/gcc/config/rs6000/rs6000.cc ++++ b/gcc/config/rs6000/rs6000.cc +@@ -1276,7 +1276,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 } */ +@@ -1293,7 +1293,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 412a3a354..2f1178b00 100644 +--- a/gcc/config/rx/rx.cc ++++ b/gcc/config/rx/rx.cc +@@ -2759,7 +2759,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. */ +@@ -2770,9 +2770,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 f1599a5c5..dcdf7dad0 100644 +--- a/gcc/config/s390/s390.cc ++++ b/gcc/config/s390/s390.cc +@@ -1247,7 +1247,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, +@@ -1263,11 +1263,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 74d61c43b..5717b7ab8 100644 +--- a/gcc/config/sh/sh.cc ++++ b/gcc/config/sh/sh.cc +@@ -328,7 +328,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 } */ +@@ -347,9 +347,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 27db12e6b..61bf302db 100644 +--- a/gcc/config/sparc/sparc.cc ++++ b/gcc/config/sparc/sparc.cc +@@ -719,13 +719,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 fabf09ab9..3adc0212a 100644 +--- a/gcc/config/stormy16/stormy16.cc ++++ b/gcc/config/stormy16/stormy16.cc +@@ -2202,7 +2202,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. */ +@@ -2211,9 +2211,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 c7d432990..b7bbfb810 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 35b46ced9..b572603bb 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 3c04e5c02..ff0d0883a 100644 +--- a/gcc/cp/cp-objcp-common.h ++++ b/gcc/cp/cp-objcp-common.h +@@ -123,13 +123,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 64b3196d1..52d19faa3 100644 +--- a/gcc/cp/cp-tree.h ++++ b/gcc/cp/cp-tree.h +@@ -7897,7 +7897,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 a7933ad2c..6cfc7a2d7 100644 +--- a/gcc/cp/tree.cc ++++ b/gcc/cp/tree.cc +@@ -5004,7 +5004,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 } */ +@@ -5012,11 +5012,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 } */ +@@ -5031,10 +5035,11 @@ const struct attribute_spec std_attribute_table[] = + { "unlikely", 0, 0, false, false, false, false, + handle_likeliness_attribute, attr_cold_hot_exclusions }, + { "noreturn", 0, 0, true, false, false, false, +- handle_noreturn_attribute, attr_noreturn_exclusions }, +- { NULL, 0, 0, false, false, false, false, NULL, NULL } ++ handle_noreturn_attribute, attr_noreturn_exclusions } + }; + ++const scoped_attribute_specs std_attribute_table = { nullptr, std_attributes }; ++ + /* Handle an "init_priority" attribute; arguments as in + struct attribute_spec.handler. */ + static tree +@@ -5617,7 +5622,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 c271de0c7..e402c0c11 100644 +--- a/gcc/d/d-attribs.cc ++++ b/gcc/d/d-attribs.cc +@@ -157,7 +157,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), +@@ -183,11 +183,15 @@ const attribute_spec d_langhook_common_attribute_table[] = + handle_type_generic_attribute, NULL), + ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, + handle_fnspec_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), +@@ -223,9 +227,12 @@ const attribute_spec d_langhook_attribute_table[] = + d_handle_restrict_attribute, NULL), + ATTR_SPEC ("used", 0, 0, true, false, false, false, + d_handle_used_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. */ +@@ -270,20 +277,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 f078f24fc..da9d6d4a2 100644 +--- a/gcc/d/d-lang.cc ++++ b/gcc/d/d-lang.cc +@@ -1938,6 +1938,12 @@ d_enum_underlying_base_type (const_tree type) + return TREE_TYPE (type); + } + ++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 +@@ -1949,7 +1955,6 @@ d_enum_underlying_base_type (const_tree type) + #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 +@@ -1981,7 +1986,6 @@ d_enum_underlying_base_type (const_tree type) + #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 aedbdd80a..d4245b63b 100644 +--- a/gcc/d/d-tree.h ++++ b/gcc/d/d-tree.h +@@ -496,8 +496,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 4f93facf7..95d96ce1b 100644 +--- a/gcc/doc/tm.texi ++++ b/gcc/doc/tm.texi +@@ -10427,12 +10427,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 468a0b7e3..27ffc7511 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 + }; + + #undef LANG_HOOKS_NAME +diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc +index 84ff359bf..5f9f5336c 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. */ +@@ -722,10 +736,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 e22639517..11998e40f 100644 +--- a/gcc/langhooks-def.h ++++ b/gcc/langhooks-def.h +@@ -151,9 +151,7 @@ extern void lhd_finalize_early_debug (void); + #define LANG_HOOKS_FINALIZE_EARLY_DEBUG lhd_finalize_early_debug + + /* 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 \ +@@ -365,8 +363,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 4731f089a..5954f58e8 100644 +--- a/gcc/langhooks.h ++++ b/gcc/langhooks.h +@@ -530,9 +530,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 8d58d924d..601e92e86 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 +@@ -1453,10 +1467,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 ff999c405..e29651d35 100644 +--- a/gcc/plugin.h ++++ b/gcc/plugin.h +@@ -198,8 +198,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 f81f8fe3b..70fb393f3 100644 +--- a/gcc/target-def.h ++++ b/gcc/target-def.h +@@ -114,6 +114,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 60096c60c..6cdc09fc2 100644 +--- a/gcc/target.def ++++ b/gcc/target.def +@@ -2199,15 +2199,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 f50dbbc52..67879c2c8 100644 +--- a/gcc/tree-inline.cc ++++ b/gcc/tree-inline.cc +@@ -4105,17 +4105,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); + } + } +-- +2.33.0 + |