summaryrefslogtreecommitdiff
path: root/0172-Backport-SME-Allow-target-attributes-in-non-gnu-name.patch
diff options
context:
space:
mode:
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.patch2369
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[] =
++{
++ &lto_gnu_attribute_table,
++ &lto_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
+