[v6] Merge common attribute handling code between libgccjit and c-family.

Message ID bmm.hmtzzcx8f0.gcc.gcc.imperio.207.6.0@forge-stage.sourceware.org
State New
Headers
Series [v6] Merge common attribute handling code between libgccjit and c-family. |

Commit Message

Guillaume Gomez via Sourceware Forge Oct. 2, 2026, 9:49 a.m. UTC
  From: Guillaume Gomez <contact@guillaume-gomez.fr>

gcc/ChangeLog:
	* Makefile.in: Compile new attr-handlers.cc file
	* attr-handlers.cc: New file.
	* attr-handlers.h: New file.

gcc/c-family/ChangeLog:

	* c-attribs.cc: (decl_or_type_attrs, validate_attr_args)
	(validate_attr_arg, handle_noinline_attribute)
	(handle_always_inline_attribute, handle_leaf_attribute)
	(handle_used_attribute, handle_retain_attribute)
	(handle_const_attribute, handle_section_attribute)
	(handle_weak_attribute, handle_alias_ifunc_attribute)
	(handle_alias_attribute, handle_visibility_attribute)
	(handle_fnspec_attribute, handle_returns_twice_attribute)
	(handle_pure_attribute, ignore_attribute, handle_novops_attribute)
	(handle_nothrow_attribute, handle_type_generic_attribute)
	(handle_target_attribute): Move to `attr-handlers.cc`.

gcc/jit/ChangeLog:

	* Make-lang.in: Compile new attr-handlers.cc file
	* dummy-frontend.cc: (handle_leaf_attribute, handle_const_attribute)
	(handle_pure_attribute, handle_novops_attribute)
	(handle_nothrow_attribute, handle_type_generic_attribute)
	(handle_returns_twice_attribute, ignore_attribute)
	(handle_fnspec_attribute, handle_visibility_attribute)
	(handle_always_inline_attribute, handle_noinline_attribute)
	(handle_weak_attribute, handle_target_attribute)
	(handle_used_attribute, handle_alias_ifunc_attribute)
	(handle_alias_attribute): Move to `attr-handlers.cc`.
---
This is my third attempt at removing duplicated code between `libgccjit` and `gcc/c-family` and it seems like I was able to make it work with the help of @antoyo for the Makefile files in particular.

So this is what I did: moving code from `gcc/c-family.cc` into `gcc/attr-handlers.cc`, then I remove the duplicated code in `jit/dummy-frontend.cc`. There is one exception though: since libgccjit implementation of the `malloc` attribute is a sub-part of the `gcc/c-family.cc` implementation, I created a new `handle_malloc_common` function which is called directly by libgccjit and called under a specific condition in `gcc/c-family.cc`.

There are still duplicated code attributes remaining in libgccjit, but the patch is already big enough as it is so I stopped at this point.



This is a forge pull request published on the gcc-patches mailing list mailing list
as requested by Guillaume Gomez via Sourceware Forge <forge-bot+imperio@forge-stage.sourceware.org>.
Forge discussion: https://forge.sourceware.org/gcc/gcc/pulls/207

Get it locally using:
```
git fetch forge-upstream "+refs/versioned_pull/207/*:refs/versioned_pull/207/*"
git switch -c "pr-207-v6" "refs/versioned_pull/207/6/head"
```
Or, download the patch at: https://forge.sourceware.org/gcc/gcc/pulls/207.diff
Created on: 2026-07-30 15:38:05+00:00
Latest update: 2026-10-02 09:49:19+00:00
Changes: 6 changed files, 973 additions, 1447 deletions
Head revision: imperio/gcc ref attr-dedup commit 8a16cf35521de45e2c0ffb804b2d828f31f3478f 
Base revision: gcc/gcc ref trunk commit fc54ab94ad257f9ef43a7287a60c21734a7a288f r17-3833-gfc54ab94ad257f
Merge base: fc54ab94ad257f9ef43a7287a60c21734a7a288f
Requested Reviewers: cohenarthur, dmalcolm, antoyo

Changed files:
- A: gcc/attr-handlers.cc
- A: gcc/attr-handlers.h
- M: gcc/Makefile.in
- M: gcc/c-family/c-attribs.cc
- M: gcc/jit/Make-lang.in
- M: gcc/jit/dummy-frontend.cc

 gcc/Makefile.in           |   2 +-
 gcc/attr-handlers.cc      | 882 ++++++++++++++++++++++++++++++++++++++
 gcc/attr-handlers.h       |  60 +++
 gcc/c-family/c-attribs.cc | 844 +-----------------------------------
 gcc/jit/Make-lang.in      |   1 +
 gcc/jit/dummy-frontend.cc | 631 +--------------------------
 6 files changed, 973 insertions(+), 1447 deletions(-)
 create mode 100644 gcc/attr-handlers.cc
 create mode 100644 gcc/attr-handlers.h


Range-diff against v5:
1:  341cc1d0ccdec ! 1:  8a16cf35521de Merge common attribute handling code between libgccjit and c-family.
    @@ gcc/attr-handlers.cc (new)
     +  /* If the two locations are different print a note pointing to
     +     the previous one.  */
     +  const location_t curloc = input_location;
    -+  const location_t prevloc =
    -+    DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
    ++  const location_t prevloc
    ++    = DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
     +
     +  /* Format the attribute specification for convenience.  */
     +  char newspec[80], prevspec[80];
  

Comments

Guillaume Gomez via Sourceware Forge Oct. 2, 2026, 9:49 a.m. UTC | #1
It was merged by @antoyo as commit 54df3a3d98b521ad0652b2fe23d9132bcf77d0fa. Closing then. Thanks everyone! I'll send follow-ups.

--
https://forge.sourceware.org/gcc/gcc/pulls/207#issuecomment-7639
  
Guillaume Gomez via Sourceware Forge Oct. 2, 2026, 9:50 a.m. UTC | #2
This is a summary of discussions relative to the merge request created by Guillaume Gomez (imperio) <contact@guillaume-gomez.fr> titled
Merge common attribute handling code between libgccjit and `gcc/c-family`
since its creation.

Description: This is my third attempt at removing duplicated code between `libgccjit` and `gcc/c-family` and it seems like I was able to make it work with the help of @antoyo for the Makefile files in particular.

So this is what I did: moving code from `gcc/c-family.cc` into `gcc/attr-handlers.cc`, then I remove the duplicated code in `jit/dummy-frontend.cc`. There is one exception though: since libgccjit implementation of the `malloc` attribute is a sub-part of the `gcc/c-family.cc` implementation, I created a new `handle_malloc_common` function which is called directly by libgccjit and called under a specific condition in `gcc/c-family.cc`.

There are still duplicated code attributes remaining in libgccjit, but the patch is already big enough as it is so I stopped at this point.

CC: David Malcolm <dmalcolm@redhat.com>, <josmyers@redhat.com>, <jit@gcc.gnu.org>

The full and up to date discussion can be found at https://forge.sourceware.org/gcc/gcc/pulls/207

The merge request has been closed without being merged directly on the forge repository.


On 2026-07-30 16:03:13+00:00, Guillaume Gomez (imperio) wrote:

Finally fixed formatting (from old code mostly ^^').


On 2026-08-18 22:30:18+00:00, David Malcolm (dmalcolm) wrote:

The overall idea looks good to me from a libgccjit maintainer point-of-view, though I didn't painstakingly check every hunk of the move.

@jsm28 : what do you think from a C maintainer/global review POV?


On 2026-08-30 19:38:39+00:00, Guillaume Gomez (imperio) wrote:

ping @jsm28


On 2026-09-01 16:26:31+00:00, Joseph Myers (jsm28) wrote:

The principle seems fine but the forge doesn't provide an obvious way to compare the moved code (the old version of c-attribs.cc with the new attr-handlers.cc file), and since CI is reporting conflicts with c-attribs.cc, clearly this pull request would need updating including updating the moved copy of any moved code that has changed in c-attribs.cc since work on this pull request started.


On 2026-09-01 20:06:57+00:00, Guillaume Gomez (imperio) wrote:

I'll take that as you globally approving the patch. Considering that it moves a lot of code around, it's very prone to bitrot. I'm fixing the merge conflict, but if another merge conflict happens before next review, I'll just wait for you to review the broken state as it's time consuming to keep up.


On 2026-09-01 20:18:21+00:00, Guillaume Gomez (imperio) wrote:

Fixed merge conflict. Ping @jsm28 

For the review, I can only recommend to check that the function in `attr-handlers.cc` has the same code as the one removed from `c-attribs.cc`. Not too sure how to make the review easier for you, though. Sorry. :-/

On 2026-09-16 15:46:56+00:00, Arthur Cohen (cohenarthur) <arthur.cohen@embecosm.com> approved the changes:
The code changes look good to me. Some of these functions will also be useful to the Rust frontend, so I'm in favor of the move and would like to see it merged.



On 2026-09-21 12:40:51+00:00, Guillaume Gomez (imperio) wrote:

Ping @jsm28


On 2026-09-23 21:12:27+00:00, Joseph Myers (jsm28) wrote:

Breaking a line after `DECL_P (` in the relocated `validate_attr_args` is not the normal style used. Other than that reformatting, the move of C front-end code is OK. Note that I have not reviewed functions relocated from the JIT front end such as `handle_transaction_pure_attribute`.


On 2026-09-24 09:33:12+00:00, Guillaume Gomez (imperio) wrote:

Thanks! Then ping @dmalcolm :)

On 2026-09-30 17:18:03+00:00, David Malcolm (dmalcolm) <dmalcolm@gcc.gnu.org> approved the changes:
Thanks for the patch.

Note that `handle_transaction_pure_attribute` is only used by libgccjit (c-attribs.cc uses `handle_tm_attribute`) so this probably shouldn't be in the shared file.

The patch introduces some minor behavior changes to libgccjit for the following, but I believe only `"pure"`, `"const"` and `"returns_twice"` are currently reachable (based on `fn_attribute_to_string` in jit-playback.cc)

* "pure" in libgccjit with a non-FUNCTION_DECL used to ICE with gcc_unreachable but now emits a warning.  Would be an improvement.
* "pure" in libgccjit with a void-returning function (e.g. via GCC_JIT_FN_ATTRIBUTE_PURE) now warns when it didn't before.  This could lead to previously-compiling gcc_jit_contexts failing after the patch.  A behavior change, but I don't think it's a problem.
* "const" in libgccjit on a void-returning function (e.g. via GCC_JIT_FN_ATTRIBUTE_CONST): gains a warning, so a similar behavior change.  I think it's OK, for the same reasons.
* "returns_twice" in libgccjit on a non-FUNCTION-DECL used to ICE with gcc_unreachable but now emits a warning (an improvement); not reachable from public jit API
* "nothrow" same as "returns_twice", but reachable from API for builtins

dummy-frontend.cc can lose its definition of ATTR_EXCL after this patch (but we can defer this to a followup).

So I think this is OK from my POV, but @jsm28 might want you to drop the move of `handle_transaction_pure_attribute`.   Patch is probably good enough as-is if this has already been tested thoroughly (bootstrap + make check-jit; check-gcc/check-c++), given how much of a pain this is causing you.  Hence marking as "approved" but note the above.




On 2026-09-30 18:30:53+00:00, Guillaume Gomez (imperio) wrote:

Moved `handle_transaction_pure_attribute` back to `dummy-frontend.cc`.


On 2026-09-30 18:33:14+00:00, Guillaume Gomez (imperio) wrote:

Thanks for the review @dmalcolm ! I re-ran the testsuites (jit, C++ and C front-ends) and no new issue.

On 2026-09-30 19:12:32+00:00, Antoni Boucher (antoyo) commented on the code:


> +++ gcc/jit/dummy-frontend.cc
> @@ -494,3 +279,3 @@
>  /* Handle a "transaction_pure" attribute.  */
>  
> -static tree
> +tree
Please add back the `static` here.
> +++ gcc/jit/dummy-frontend.cc
> @@ -494,3 +279,3 @@
>  /* Handle a "transaction_pure" attribute.  */
>  
> -static tree
> +tree
Done!

On 2026-10-01 14:08:18+00:00, Antoni Boucher (antoyo) commented on the code:


> +++ gcc/attr-handlers.cc
> @@ -0,0 +204,4 @@
> +     the previous one.  */
> +  const location_t curloc = input_location;
> +  const location_t prevloc = DECL_P (
> +    node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
The format checker doesn't error on this, but the original formatting was:
```c
const location_t prevloc = 		
	    DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
```
> +++ gcc/attr-handlers.cc
> @@ -0,0 +204,4 @@
> +     the previous one.  */
> +  const location_t curloc = input_location;
> +  const location_t prevloc = DECL_P (
> +    node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
Done!

On 2026-10-01 17:49:26+00:00, Antoni Boucher (antoyo) approved the changes:




On 2026-10-02 09:49:18+00:00, Guillaume Gomez (imperio) wrote:

It was merged by @antoyo as commit 54df3a3d98b521ad0652b2fe23d9132bcf77d0fa. Closing then. Thanks everyone! I'll send follow-ups.
  

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c718585e6071f..617255b0bc496 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1329,7 +1329,7 @@  C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
   c-family/c-semantics.o c-family/c-ada-spec.o \
   c-family/c-ubsan.o c-family/known-headers.o \
   c-family/c-attribs.o c-family/c-warn.o c-family/c-spellcheck.o \
-  c-family/c-type-mismatch.o
+  c-family/c-type-mismatch.o attr-handlers.o
 
 # Analyzer object files
 ANALYZER_OBJS = \
diff --git a/gcc/attr-handlers.cc b/gcc/attr-handlers.cc
new file mode 100644
index 0000000000000..103f2aab65754
--- /dev/null
+++ b/gcc/attr-handlers.cc
@@ -0,0 +1,882 @@ 
+/* Language-independent attribute handlers shared across front ends.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "function.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "attr-handlers.h"
+#include "diagnostic-core.h"
+#include "options.h"
+#include "cgraph.h"
+#include "varasm.h"
+#include "common/common-target.h"
+#include "tree-pretty-print.h"
+
+/* Helper to define attribute exclusions.  */
+#define ATTR_EXCL(name, function, type, variable)	\
+  { name, function, type, variable }
+
+/* Define attributes that are mutually exclusive with one another.  */
+const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+{
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL ("returns_twice", true, true, true),
+  ATTR_EXCL ("warn_unused_result", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
+{
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc.  */
+const struct attribute_spec::exclusions attr_alloc_exclusions[] =
+{
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
+{
+  ATTR_EXCL ("const", true, true, true),
+  ATTR_EXCL ("alloc_align", true, true, true),
+  ATTR_EXCL ("alloc_size", true, true, true),
+  ATTR_EXCL ("malloc", true, true, true),
+  ATTR_EXCL ("noreturn", true, true, true),
+  ATTR_EXCL ("pure", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
+const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
+{
+  ATTR_EXCL ("noinline", true, true, true),
+  ATTR_EXCL ("target_clones", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+  ATTR_EXCL ("cold", true, true, true),
+  ATTR_EXCL ("hot", true, true, true),
+  ATTR_EXCL (NULL, false, false, false)
+};
+
+const struct attribute_spec::exclusions attr_noinline_exclusions[] =
+{
+  ATTR_EXCL ("always_inline", true, true, true),
+  ATTR_EXCL ("gnu_inline", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+const struct attribute_spec::exclusions attr_target_exclusions[] =
+{
+  ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
+	     TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+/* Exclusions that apply to attributes that put declarations in specific
+   sections.  */
+const struct attribute_spec::exclusions attr_section_exclusions[] =
+{
+  ATTR_EXCL ("noinit", true, true, true),
+  ATTR_EXCL ("persistent", true, true, true),
+  ATTR_EXCL ("section", true, true, true),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+/* Return the first of DECL or TYPE attributes installed in NODE if it's
+   a DECL, or TYPE attributes if it's a TYPE, or null otherwise.  */
+
+static tree
+decl_or_type_attrs (tree node)
+{
+  if (DECL_P (node))
+    {
+      if (tree attrs = DECL_ATTRIBUTES (node))
+	return attrs;
+
+      tree type = TREE_TYPE (node);
+      if (type == error_mark_node)
+	return NULL_TREE;
+      return TYPE_ATTRIBUTES (type);
+    }
+
+  if (TYPE_P (node))
+    return TYPE_ATTRIBUTES (node);
+
+  return NULL_TREE;
+}
+
+/* Given a pair of NODEs for arbitrary DECLs or TYPEs, validate one or
+   two integral or string attribute arguments NEWARGS to be applied to
+   NODE[0] for the absence of conflicts with the same attribute arguments
+   already applied to NODE[1]. Issue a warning for conflicts and return
+   false.  Otherwise, when no conflicts are found, return true.  */
+
+bool
+validate_attr_args (tree node[2], tree name, tree newargs[2])
+{
+  /* First validate the arguments against those already applied to
+     the same declaration (or type).  */
+  tree self[2] = { node[0], node[0] };
+  if (node[0] != node[1] && !validate_attr_args (self, name, newargs))
+    return false;
+
+  if (!node[1])
+    return true;
+
+  /* Extract the same attribute from the previous declaration or type.  */
+  tree prevattr = decl_or_type_attrs (node[1]);
+  const char* const namestr = IDENTIFIER_POINTER (name);
+  prevattr = lookup_attribute (namestr, prevattr);
+  if (!prevattr)
+    return true;
+
+  /* Extract one or both attribute arguments.  */
+  tree prevargs[2];
+  prevargs[0] = TREE_VALUE (TREE_VALUE (prevattr));
+  prevargs[1] = TREE_CHAIN (TREE_VALUE (prevattr));
+  if (prevargs[1])
+    prevargs[1] = TREE_VALUE (prevargs[1]);
+
+  /* Both arguments must be equal or, for the second pair, neither must
+     be provided to succeed.  */
+  bool arg1eq, arg2eq;
+  if (TREE_CODE (newargs[0]) == INTEGER_CST)
+    {
+      arg1eq = tree_int_cst_equal (newargs[0], prevargs[0]);
+      if (newargs[1] && prevargs[1])
+	arg2eq = tree_int_cst_equal (newargs[1], prevargs[1]);
+      else
+	arg2eq = newargs[1] == prevargs[1];
+    }
+  else if (TREE_CODE (newargs[0]) == STRING_CST)
+    {
+      const char *s0 = TREE_STRING_POINTER (newargs[0]);
+      const char *s1 = TREE_STRING_POINTER (prevargs[0]);
+      arg1eq = strcmp (s0, s1) == 0;
+      if (newargs[1] && prevargs[1])
+	{
+	  s0 = TREE_STRING_POINTER (newargs[1]);
+	  s1 = TREE_STRING_POINTER (prevargs[1]);
+	  arg2eq = strcmp (s0, s1) == 0;
+	}
+      else
+	arg2eq = newargs[1] == prevargs[1];
+    }
+  else
+    gcc_unreachable ();
+
+  if (arg1eq && arg2eq)
+    return true;
+
+  /* If the two locations are different print a note pointing to
+     the previous one.  */
+  const location_t curloc = input_location;
+  const location_t prevloc
+    = DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
+
+  /* Format the attribute specification for convenience.  */
+  char newspec[80], prevspec[80];
+  if (newargs[1])
+    snprintf (newspec, sizeof newspec, "%s (%s, %s)", namestr,
+	      print_generic_expr_to_str (newargs[0]),
+	      print_generic_expr_to_str (newargs[1]));
+  else
+    snprintf (newspec, sizeof newspec, "%s (%s)", namestr,
+	      print_generic_expr_to_str (newargs[0]));
+
+  if (prevargs[1])
+    snprintf (prevspec, sizeof prevspec, "%s (%s, %s)", namestr,
+	      print_generic_expr_to_str (prevargs[0]),
+	      print_generic_expr_to_str (prevargs[1]));
+  else
+    snprintf (prevspec, sizeof prevspec, "%s (%s)", namestr,
+	      print_generic_expr_to_str (prevargs[0]));
+
+  if (warning_at (curloc, OPT_Wattributes,
+		  "ignoring attribute %qs because it conflicts "
+		  "with previous %qs",
+		  newspec, prevspec)
+      && curloc != prevloc)
+    inform (prevloc, "previous declaration here");
+
+  return false;
+}
+
+/* Convenience wrapper for validate_attr_args to validate a single
+   attribute argument.  Used by handlers for attributes that take
+   just a single argument.  */
+
+bool
+validate_attr_arg (tree node[2], tree name, tree newarg)
+{
+  tree argarray[2] = { newarg, NULL_TREE };
+  return validate_attr_args (node, name, argarray);
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler, except that IS_ALIAS tells us
+   whether this is an alias as opposed to ifunc attribute.  */
+
+tree
+handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
+			      bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      && (!is_alias || !VAR_P (decl)))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+      /* A static variable declaration is always a tentative definition,
+	 but the alias is a non-tentative definition which overrides.  */
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+    {
+      error ("%q+D defined both normally and as %qE attribute", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if (!is_alias
+	   && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
+	       || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
+    {
+      error ("weak %q+D cannot be defined %qE", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Note that the very first time we process a nested declaration,
+     decl_function_context will not be set.  Indeed, *would* never
+     be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
+     we do below.  After such frobbery, pushdecl would set the context.
+     In any case, this is never what we want.  */
+  else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+	{
+	  error ("attribute %qE argument not a string", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+      id = get_identifier (TREE_STRING_POINTER (id));
+      /* This counts as a use of the object pointed to.  */
+      TREE_USED (id) = 1;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	DECL_INITIAL (decl) = error_mark_node;
+      else
+	TREE_STATIC (decl) = 1;
+
+      if (!is_alias)
+	{
+	  /* ifuncs are also aliases, so set that attribute too.  */
+	  DECL_ATTRIBUTES (decl)
+	    = tree_cons (get_identifier ("alias"), args,
+			 DECL_ATTRIBUTES (decl));
+	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
+					      NULL, DECL_ATTRIBUTES (decl));
+	}
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  if (decl_in_symtab_p (*node))
+    {
+      struct symtab_node *n = symtab_node::get (decl);
+      if (n && n->refuse_visibility_changes)
+	error ("%+qD declared %qs after being used",
+	       decl, is_alias ? "alias" : "ifunc");
+    }
+
+  return NULL_TREE;
+}
+
+/* Ignore the given attribute.  Used when this attribute may be usefully
+   overridden by the target, but is not used generically.  */
+
+tree
+ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
+		  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+		  bool *no_add_attrs)
+{
+  *no_add_attrs = true;
+  return NULL_TREE;
+}
+
+/* Handle a "leaf" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_leaf_attribute (tree *node, tree name,
+		       tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  if (!TREE_PUBLIC (*node))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on unit local "
+	       "functions", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+			int flags, bool *no_add_attrs)
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment on noreturn in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_READONLY (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = (build_qualified_type
+	 (build_pointer_type
+	  (build_type_variant (TREE_TYPE (type), 1,
+			       TREE_THIS_VOLATILE (TREE_TYPE (type)))),
+	  TYPE_QUALS (type)));
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  /* void __builtin_unreachable (void) is const.  Accept other such
+     built-ins but warn on user-defined functions that return void.  */
+  if (!(flags & ATTR_FLAG_BUILT_IN)
+      && TREE_CODE (*node) == FUNCTION_DECL
+      && VOID_TYPE_P (TREE_TYPE (type)))
+    warning (OPT_Wattributes, "%qE attribute on function "
+	     "returning %<void%>", name);
+
+  return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      tree type = TREE_TYPE (*node);
+      if (VOID_TYPE_P (TREE_TYPE (type)))
+	warning (OPT_Wattributes, "%qE attribute on function "
+		 "returning %<void%>", name);
+
+      DECL_PURE_P (*node) = 1;
+      /* ??? TODO: Support types.  */
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "no vops" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
+			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			 bool *ARG_UNUSED (no_add_attrs))
+{
+  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+  DECL_IS_NOVOPS (*node) = 1;
+  return NULL_TREE;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+			  int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_NOTHROW (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "type_generic" attribute.  */
+
+tree
+handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
+			       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			       bool * ARG_UNUSED (no_add_attrs))
+{
+  /* Ensure we have a function type.  */
+  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+  /* Ensure we have a variadic function.  */
+  gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+  return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute.  */
+
+tree
+handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+			 int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_IS_RETURNS_TWICE (*node) = 1;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "fn spec" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
+			 tree args, int ARG_UNUSED (flags),
+			 bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+  gcc_assert (args
+	      && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+	      && !TREE_CHAIN (args));
+  return NULL_TREE;
+}
+
+/* Handle an "visibility" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_visibility_attribute (tree *node, tree name, tree args,
+			     int ARG_UNUSED (flags),
+			     bool *ARG_UNUSED (no_add_attrs))
+{
+  tree decl = *node;
+  tree id = TREE_VALUE (args);
+  enum symbol_visibility vis;
+
+  if (TYPE_P (*node))
+    {
+      if (TREE_CODE (*node) == ENUMERAL_TYPE)
+	/* OK.  */;
+      else if (!RECORD_OR_UNION_TYPE_P (*node))
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
+		   name);
+	  return NULL_TREE;
+	}
+      else if (TYPE_FIELDS (*node))
+	{
+	  error ("%qE attribute ignored because %qT is already defined",
+		 name, *node);
+	  return NULL_TREE;
+	}
+    }
+  else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (id) != STRING_CST)
+    {
+      error ("visibility argument not a string");
+      return NULL_TREE;
+    }
+
+  /*  If this is a type, set the visibility on the type decl.  */
+  if (TYPE_P (decl))
+    {
+      decl = TYPE_NAME (decl);
+      if (!decl)
+	return NULL_TREE;
+      if (TREE_CODE (decl) == IDENTIFIER_NODE)
+	{
+	   warning (OPT_Wattributes, "%qE attribute ignored on types",
+		    name);
+	   return NULL_TREE;
+	}
+    }
+
+  if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
+    vis = VISIBILITY_DEFAULT;
+  else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
+    vis = VISIBILITY_INTERNAL;
+  else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
+    vis = VISIBILITY_HIDDEN;
+  else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
+    vis = VISIBILITY_PROTECTED;
+  else
+    {
+      error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
+	     name, "default", "hidden", "protected", "internal");
+      vis = VISIBILITY_DEFAULT;
+    }
+
+  if (DECL_VISIBILITY_SPECIFIED (decl)
+      && vis != DECL_VISIBILITY (decl))
+    {
+      tree attributes = (TYPE_P (*node)
+			 ? TYPE_ATTRIBUTES (*node)
+			 : DECL_ATTRIBUTES (decl));
+      if (lookup_attribute ("visibility", attributes))
+	error ("%qD redeclared with different visibility", decl);
+      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+	       && lookup_attribute ("dllimport", attributes))
+	error ("%qD was declared %qs which implies default visibility",
+	       decl, "dllimport");
+      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+	       && lookup_attribute ("dllexport", attributes))
+	error ("%qD was declared %qs which implies default visibility",
+	       decl, "dllexport");
+    }
+
+  DECL_VISIBILITY (decl) = vis;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  /* Go ahead and attach the attribute to the node as well.  This is needed
+     so we can determine whether we have VISIBILITY_DEFAULT because the
+     visibility was not specified, or because it was explicitly overridden
+     from the containing scope.  */
+
+  return NULL_TREE;
+}
+
+/* Handle a "always_inline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_always_inline_attribute (tree *node, tree name,
+				tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags),
+				bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      /* Set the attribute and mark it for disregarding inline
+	 limits.  */
+      DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "noinline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_noinline_attribute (tree *node, tree name,
+			   tree ARG_UNUSED (args),
+			   int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_UNINLINABLE (*node) = 1;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "weak" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_weak_attribute (tree *node, tree name,
+		       tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags),
+		       bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (*node))
+    {
+      warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+      *no_add_attrs = true;
+    }
+  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
+    {
+      error ("indirect function %q+D cannot be declared weak", *node);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if (VAR_OR_FUNCTION_DECL_P (*node))
+    declare_weak (*node);
+  else
+    warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+  return NULL_TREE;
+}
+
+/* Handle a "target" attribute.  */
+
+tree
+handle_target_attribute (tree *node, tree name, tree args, int flags,
+			 bool *no_add_attrs)
+{
+  /* Ensure we have a function declaration.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+						      flags))
+    *no_add_attrs = true;
+
+  /* Check that there's no empty string in values of the attribute.  */
+  for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
+    {
+      tree value = TREE_VALUE (t);
+      if (TREE_CODE (value) == STRING_CST
+	  && TREE_STRING_LENGTH (value) == 1
+	  && TREE_STRING_POINTER (value)[0] == '\0')
+	{
+	  warning (OPT_Wattributes, "empty string in attribute %<target%>");
+	  *no_add_attrs = true;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if (TREE_CODE (node) == FUNCTION_DECL
+      || (VAR_P (node) && TREE_STATIC (node))
+      || (TREE_CODE (node) == TYPE_DECL))
+    {
+      TREE_USED (node) = 1;
+      DECL_PRESERVE_P (node) = 1;
+      if (VAR_P (node))
+	DECL_READ_P (node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle an "alias" or "ifunc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_alias_attribute (tree *node, tree name, tree args,
+			int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+}
+
+/* Handle a "section" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_section_attribute (tree *node, tree name, tree args,
+			  int flags, bool *no_add_attrs)
+{
+  tree decl = *node;
+  tree res = NULL_TREE;
+  tree argval = TREE_VALUE (args);
+  const char* new_section_name;
+
+  if (!targetm_common.have_named_sections)
+    {
+      error_at (DECL_SOURCE_LOCATION (*node),
+		"section attributes are not supported for this target");
+      goto fail;
+    }
+
+  if (!VAR_OR_FUNCTION_DECL_P (decl))
+    {
+      error ("section attribute not allowed for %q+D", *node);
+      goto fail;
+    }
+
+  if (TREE_CODE (argval) != STRING_CST)
+    {
+      error ("section attribute argument not a string constant");
+      goto fail;
+    }
+
+  if (VAR_P (decl)
+      && current_function_decl != NULL_TREE
+      && !TREE_STATIC (decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"section attribute cannot be specified for local variables");
+      goto fail;
+    }
+
+  new_section_name = TREE_STRING_POINTER (argval);
+
+  /* The decl may have already been given a section attribute
+     from a previous declaration.  Ensure they match.  */
+  if (const char* const old_section_name = DECL_SECTION_NAME (decl))
+    if (strcmp (old_section_name, new_section_name) != 0)
+      {
+	error ("section of %q+D conflicts with previous declaration",
+	       *node);
+	goto fail;
+      }
+
+  if (VAR_P (decl)
+      && !targetm.have_tls && targetm.emutls.tmpl_section
+      && DECL_THREAD_LOCAL_P (decl))
+    {
+      error ("section of %q+D cannot be overridden", *node);
+      goto fail;
+    }
+
+  if (!validate_attr_arg (node, name, argval))
+    goto fail;
+
+  res = targetm.handle_generic_attribute (node, name, args, flags,
+					  no_add_attrs);
+
+  /* If the back end confirms the attribute can be added then continue onto
+     final processing.  */
+  if (!(*no_add_attrs))
+    {
+      set_decl_section_name (decl, new_section_name);
+      return res;
+    }
+
+fail:
+  *no_add_attrs = true;
+  return res;
+}
+
+/* Handle a "retain" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
+			 int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if (SUPPORTS_SHF_GNU_RETAIN
+      && (TREE_CODE (node) == FUNCTION_DECL
+	  || (VAR_P (node) && TREE_STATIC (node))))
+    ;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Part of the `malloc` attribute handling which is shared by libgccjit and
+   the C-family front-end.  */
+
+tree
+handle_malloc_common (tree *node, tree name, tree ARG_UNUSED (args),
+		      int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored; valid only "
+	       "for functions", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  tree rettype = TREE_TYPE (TREE_TYPE (*node));
+  if (!POINTER_TYPE_P (rettype))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored on functions "
+	       "returning %qT; valid only for pointer return types",
+	       name, rettype);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  DECL_IS_MALLOC (*node) = 1;
+  return NULL_TREE;
+}
diff --git a/gcc/attr-handlers.h b/gcc/attr-handlers.h
new file mode 100644
index 0000000000000..5e0dc2f6bb8ac
--- /dev/null
+++ b/gcc/attr-handlers.h
@@ -0,0 +1,60 @@ 
+/* Language-independent attribute handlers shared across front ends.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ATTR_HANDLERS_H
+#define GCC_ATTR_HANDLERS_H
+
+/* Attribute exclusion tables used by `c-family` and `libgccjit`.  */
+extern const struct attribute_spec::exclusions attr_noreturn_exclusions[];
+extern const struct attribute_spec::exclusions attr_returns_twice_exclusions[];
+extern const struct attribute_spec::exclusions attr_alloc_exclusions[];
+extern const struct attribute_spec::exclusions attr_const_pure_exclusions[];
+extern const struct attribute_spec::exclusions attr_always_inline_exclusions[];
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[];
+extern const struct attribute_spec::exclusions attr_noinline_exclusions[];
+extern const struct attribute_spec::exclusions attr_target_exclusions[];
+extern const struct attribute_spec::exclusions attr_section_exclusions[];
+
+/* Shared helpers used by the handlers.  */
+extern bool validate_attr_args (tree node[2], tree name, tree newargs[2]);
+extern bool validate_attr_arg (tree node[2], tree name, tree newarg);
+
+/* Attribute handlers.  */
+extern tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
+extern tree handle_malloc_common (tree *, tree, tree, int, bool *);
+extern tree handle_alias_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_always_inline_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_const_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_retain_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_section_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_target_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_used_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_visibility_attribute (tree *, tree, tree, int, bool *);
+extern tree handle_weak_attribute (tree *, tree, tree, int, bool *);
+extern tree ignore_attribute (tree *, tree, tree, int, bool *);
+
+#endif // GCC_ATTR_HANDLERS_H
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index b3d5407ec0b3b..42198a9f8d30f 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "calls.h"
 #include "attribs.h"
+#include "attr-handlers.h"
 #include "varasm.h"
 #include "trans-mem.h"
 #include "c-objc.h"
@@ -73,26 +74,20 @@  static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_stack_protector_function_attribute (tree *, tree,
 							tree, int, bool *);
 static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
-static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
 static tree handle_symver_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
-static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
-static tree handle_always_inline_attribute (tree *, tree, tree, int,
-					    bool *);
 static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_artificial_attribute (tree *, tree, tree, int, bool *);
 static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
 static tree handle_error_attribute (tree *, tree, tree, int, bool *);
-static tree handle_used_attribute (tree *, tree, tree, int, bool *);
 static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *);
 static tree handle_externally_visible_attribute (tree *, tree, tree, int,
 						 bool *);
 static tree handle_no_reorder_attribute (tree *, tree, tree, int,
 						 bool *);
-static tree handle_const_attribute (tree *, tree, tree, int, bool *);
 static tree handle_transparent_union_attribute (tree *, tree, tree,
 						int, bool *);
 static tree handle_scalar_storage_order_attribute (tree *, tree, tree,
@@ -100,7 +95,6 @@  static tree handle_scalar_storage_order_attribute (tree *, tree, tree,
 static tree handle_constructor_attribute (tree *, tree, tree, int, bool *);
 static tree handle_destructor_attribute (tree *, tree, tree, int, bool *);
 static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
-static tree handle_section_attribute (tree *, tree, tree, int, bool *);
 static tree handle_special_var_sec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
 						  int, bool *);
@@ -108,14 +102,9 @@  static tree handle_strict_flex_array_attribute (tree *, tree, tree,
 						 int, bool *);
 static tree handle_counted_by_attribute (tree *, tree, tree,
 					   int, bool *);
-static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
-static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
 static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *);
-static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
 static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ;
-static tree handle_visibility_attribute (tree *, tree, tree, int,
-					 bool *);
 static tree handle_tls_model_attribute (tree *, tree, tree, int,
 					bool *);
 static tree handle_no_instrument_function_attribute (tree *, tree,
@@ -125,14 +114,11 @@  static tree handle_no_profile_instrument_function_attribute (tree *, tree,
 static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_dealloc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_tainted_args_attribute (tree *, tree, tree, int, bool *);
-static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
 					     bool *);
-static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
 static tree handle_tm_attribute (tree *, tree, tree, int, bool *);
 static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *);
 static tree handle_callback_only_attribute (tree *, tree, tree, int, bool *);
-static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
 static tree handle_unavailable_attribute (tree *, tree, tree, int,
 					  bool *);
 static tree handle_vector_size_attribute (tree *, tree, tree, int,
@@ -143,7 +129,6 @@  static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nonnull_if_nonzero_attribute (tree *, tree, tree, int,
 						 bool *);
 static tree handle_nonstring_attribute (tree *, tree, tree, int, bool *);
-static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
 static tree handle_expected_throw_attribute (tree *, tree, tree, int, bool *);
 static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
@@ -151,21 +136,17 @@  static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
 static tree handle_access_attribute (tree *, tree, tree, int, bool *);
 
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
-static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *);
 static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
 static tree handle_assume_attribute (tree *, tree, tree, int, bool *);
-static tree handle_target_attribute (tree *, tree, tree, int, bool *);
 static tree handle_target_version_attribute (tree *, tree, tree, int, bool *);
 static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *);
 static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
-static tree ignore_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
 static tree handle_zero_call_used_regs_attribute (tree *, tree, tree, int,
 						  bool *);
 static tree handle_argspec_attribute (tree *, tree, tree, int, bool *);
-static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *);
 static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *);
 static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int,
@@ -186,7 +167,6 @@  static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *);
 static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int,
 						    bool *);
 static tree handle_hardbool_attribute (tree *, tree, tree, int, bool *);
-static tree handle_retain_attribute (tree *, tree, tree, int, bool *);
 static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *);
 static tree handle_flag_enum_attribute (tree *, tree, tree, int, bool *);
 static tree handle_null_terminated_string_arg_attribute (tree *, tree, tree, int, bool *);
@@ -211,13 +191,6 @@  extern const struct attribute_spec::exclusions attr_aligned_exclusions[] =
   ATTR_EXCL (NULL, false, false, false)
 };
 
-extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
-{
-  ATTR_EXCL ("cold", true, true, true),
-  ATTR_EXCL ("hot", true, true, true),
-  ATTR_EXCL (NULL, false, false, false)
-};
-
 static const struct attribute_spec::exclusions attr_common_exclusions[] =
 {
   ATTR_EXCL ("common", true, true, true),
@@ -231,27 +204,6 @@  static const struct attribute_spec::exclusions attr_inline_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
-static const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
-{
-  ATTR_EXCL ("noinline", true, true, true),
-  ATTR_EXCL ("target_clones", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
-{
-  ATTR_EXCL ("always_inline", true, true, true),
-  ATTR_EXCL ("gnu_inline", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_target_exclusions[] =
-{
-  ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
-	     TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
 static const struct attribute_spec::exclusions attr_target_clones_exclusions[] =
 {
   ATTR_EXCL ("always_inline", true, true, true),
@@ -283,18 +235,6 @@  static const struct attribute_spec::exclusions attr_simd_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
-extern const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
-{
-  ATTR_EXCL ("alloc_align", true, true, true),
-  ATTR_EXCL ("alloc_size", true, true, true),
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("malloc", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL ("returns_twice", true, true, true),
-  ATTR_EXCL ("warn_unused_result", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
 static const struct attribute_spec::exclusions
 attr_warn_unused_result_exclusions[] =
 {
@@ -303,42 +243,6 @@  attr_warn_unused_result_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
-static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
-{
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc.  */
-static const struct attribute_spec::exclusions attr_alloc_exclusions[] =
-{
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
-{
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("alloc_align", true, true, true),
-  ATTR_EXCL ("alloc_size", true, true, true),
-  ATTR_EXCL ("malloc", true, true, true),
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL (NULL, false, false, false)
-};
-
-/* Exclusions that apply to attributes that put declarations in specific
-   sections.  */
-static const struct attribute_spec::exclusions attr_section_exclusions[] =
-{
-  ATTR_EXCL ("noinit", true, true, true),
-  ATTR_EXCL ("persistent", true, true, true),
-  ATTR_EXCL ("section", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
 static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] =
 {
   ATTR_EXCL ("stack_protect", true, false, false),
@@ -974,137 +878,6 @@  positional_argument (const_tree fn, const_tree atname, tree &pos,
   return build_int_cst (TREE_TYPE (pos), ipos);
 }
 
-/* Return the first of DECL or TYPE attributes installed in NODE if it's
-   a DECL, or TYPE attributes if it's a TYPE, or null otherwise.  */
-
-static tree
-decl_or_type_attrs (tree node)
-{
-  if (DECL_P (node))
-    {
-      if (tree attrs = DECL_ATTRIBUTES (node))
-	return attrs;
-
-      tree type = TREE_TYPE (node);
-      if (type == error_mark_node)
-	return NULL_TREE;
-      return TYPE_ATTRIBUTES (type);
-    }
-
-  if (TYPE_P (node))
-    return TYPE_ATTRIBUTES (node);
-
-  return NULL_TREE;
-}
-
-/* Given a pair of NODEs for arbitrary DECLs or TYPEs, validate one or
-   two integral or string attribute arguments NEWARGS to be applied to
-   NODE[0] for the absence of conflicts with the same attribute arguments
-   already applied to NODE[1]. Issue a warning for conflicts and return
-   false.  Otherwise, when no conflicts are found, return true.  */
-
-static bool
-validate_attr_args (tree node[2], tree name, tree newargs[2])
-{
-  /* First validate the arguments against those already applied to
-     the same declaration (or type).  */
-  tree self[2] = { node[0], node[0] };
-  if (node[0] != node[1] && !validate_attr_args (self, name, newargs))
-    return false;
-
-  if (!node[1])
-    return true;
-
-  /* Extract the same attribute from the previous declaration or type.  */
-  tree prevattr = decl_or_type_attrs (node[1]);
-  const char* const namestr = IDENTIFIER_POINTER (name);
-  prevattr = lookup_attribute (namestr, prevattr);
-  if (!prevattr)
-    return true;
-
-  /* Extract one or both attribute arguments.  */
-  tree prevargs[2];
-  prevargs[0] = TREE_VALUE (TREE_VALUE (prevattr));
-  prevargs[1] = TREE_CHAIN (TREE_VALUE (prevattr));
-  if (prevargs[1])
-    prevargs[1] = TREE_VALUE (prevargs[1]);
-
-  /* Both arguments must be equal or, for the second pair, neither must
-     be provided to succeed.  */
-  bool arg1eq, arg2eq;
-  if (TREE_CODE (newargs[0]) == INTEGER_CST)
-    {
-      arg1eq = tree_int_cst_equal (newargs[0], prevargs[0]);
-      if (newargs[1] && prevargs[1])
-	arg2eq = tree_int_cst_equal (newargs[1], prevargs[1]);
-      else
-	arg2eq = newargs[1] == prevargs[1];
-    }
-  else if (TREE_CODE (newargs[0]) == STRING_CST)
-    {
-      const char *s0 = TREE_STRING_POINTER (newargs[0]);
-      const char *s1 = TREE_STRING_POINTER (prevargs[0]);
-      arg1eq = strcmp (s0, s1) == 0;
-      if (newargs[1] && prevargs[1])
-	{
-	  s0 = TREE_STRING_POINTER (newargs[1]);
-	  s1 = TREE_STRING_POINTER (prevargs[1]);
-	  arg2eq = strcmp (s0, s1) == 0;
-	}
-      else
-	arg2eq = newargs[1] == prevargs[1];
-    }
-  else
-    gcc_unreachable ();
-
-  if (arg1eq && arg2eq)
-    return true;
-
-  /* If the two locations are different print a note pointing to
-     the previous one.  */
-  const location_t curloc = input_location;
-  const location_t prevloc =
-    DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
-
-  /* Format the attribute specification for convenience.  */
-  char newspec[80], prevspec[80];
-  if (newargs[1])
-    snprintf (newspec, sizeof newspec, "%s (%s, %s)", namestr,
-	      print_generic_expr_to_str (newargs[0]),
-	      print_generic_expr_to_str (newargs[1]));
-  else
-    snprintf (newspec, sizeof newspec, "%s (%s)", namestr,
-	      print_generic_expr_to_str (newargs[0]));
-
-  if (prevargs[1])
-    snprintf (prevspec, sizeof prevspec, "%s (%s, %s)", namestr,
-	      print_generic_expr_to_str (prevargs[0]),
-	      print_generic_expr_to_str (prevargs[1]));
-  else
-    snprintf (prevspec, sizeof prevspec, "%s (%s)", namestr,
-	      print_generic_expr_to_str (prevargs[0]));
-
-  if (warning_at (curloc, OPT_Wattributes,
-		  "ignoring attribute %qs because it conflicts "
-		  "with previous %qs",
-		  newspec, prevspec)
-      && curloc != prevloc)
-    inform (prevloc, "previous declaration here");
-
-  return false;
-}
-
-/* Convenience wrapper for validate_attr_args to validate a single
-   attribute argument.  Used by handlers for attributes that take
-   just a single argument.  */
-
-static bool
-validate_attr_arg (tree node[2], tree name, tree newarg)
-{
-  tree argarray[2] = { newarg, NULL_TREE };
-  return validate_attr_args (node, name, argarray);
-}
-
 /* Attribute handlers common to C front ends.  */
 
 /* Handle a "signed_bool_precision" attribute; arguments as in
@@ -1730,25 +1503,6 @@  handle_strub_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-/* Handle a "noinline" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_noinline_attribute (tree *node, tree name,
-			   tree ARG_UNUSED (args),
-			   int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_UNINLINABLE (*node) = 1;
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "noclone" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1809,31 +1563,6 @@  handle_noicf_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-
-/* Handle a "always_inline" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_always_inline_attribute (tree *node, tree name,
-				tree ARG_UNUSED (args),
-				int ARG_UNUSED (flags),
-				bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    {
-      /* Set the attribute and mark it for disregarding inline
-	 limits.  */
-      DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "gnu_inline" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1857,29 +1586,6 @@  handle_gnu_inline_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-/* Handle a "leaf" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_leaf_attribute (tree *node, tree name,
-		       tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) != FUNCTION_DECL)
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  if (!TREE_PUBLIC (*node))
-    {
-      warning (OPT_Wattributes, "%qE attribute has no effect on unit local "
-	       "functions", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle an "artificial" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1945,33 +1651,6 @@  handle_error_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Handle a "used" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  tree node = *pnode;
-
-  if (TREE_CODE (node) == FUNCTION_DECL
-      || (VAR_P (node) && TREE_STATIC (node))
-      || (TREE_CODE (node) == TYPE_DECL))
-    {
-      TREE_USED (node) = 1;
-      DECL_PRESERVE_P (node) = 1;
-      if (VAR_P (node))
-	DECL_READ_P (node) = 1;
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "unused" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -2010,28 +1689,6 @@  handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
-/* Handle a "retain" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
-			 int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  tree node = *pnode;
-
-  if (SUPPORTS_SHF_GNU_RETAIN
-      && (TREE_CODE (node) == FUNCTION_DECL
-	  || (VAR_P (node) && TREE_STATIC (node))))
-    ;
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle an "uninitialized" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -2110,43 +1767,6 @@  handle_no_reorder_attribute (tree *pnode,
   return NULL_TREE;
 }
 
-/* Handle a "const" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-			int flags, bool *no_add_attrs)
-{
-  tree type = TREE_TYPE (*node);
-
-  /* See FIXME comment on noreturn in c_common_attribute_table.  */
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    TREE_READONLY (*node) = 1;
-  else if (TREE_CODE (type) == POINTER_TYPE
-	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-    TREE_TYPE (*node)
-      = (build_qualified_type
-	 (build_pointer_type
-	  (build_type_variant (TREE_TYPE (type), 1,
-			       TREE_THIS_VOLATILE (TREE_TYPE (type)))),
-	  TYPE_QUALS (type)));
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  /* void __builtin_unreachable(void) is const.  Accept other such
-     built-ins but warn on user-defined functions that return void.  */
-  if (!(flags & ATTR_FLAG_BUILT_IN)
-      && TREE_CODE (*node) == FUNCTION_DECL
-      && VOID_TYPE_P (TREE_TYPE (type)))
-    warning (OPT_Wattributes, "%qE attribute on function "
-	     "returning %<void%>", name);
-
-  return NULL_TREE;
-}
-
 /* Handle a "scalar_storage_order" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -2609,85 +2229,6 @@  handle_mode_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Handle a "section" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_section_attribute (tree *node, tree name, tree args,
-			  int flags, bool *no_add_attrs)
-{
-  tree decl = *node;
-  tree res = NULL_TREE;
-  tree argval = TREE_VALUE (args);
-  const char* new_section_name;
-
-  if (!targetm_common.have_named_sections)
-    {
-      error_at (DECL_SOURCE_LOCATION (*node),
-		"section attributes are not supported for this target");
-      goto fail;
-    }
-
-  if (!VAR_OR_FUNCTION_DECL_P (decl))
-    {
-      error ("section attribute not allowed for %q+D", *node);
-      goto fail;
-    }
-
-  if (TREE_CODE (argval) != STRING_CST)
-    {
-      error ("section attribute argument not a string constant");
-      goto fail;
-    }
-
-  if (VAR_P (decl)
-      && current_function_decl != NULL_TREE
-      && !TREE_STATIC (decl))
-    {
-      error_at (DECL_SOURCE_LOCATION (decl),
-		"section attribute cannot be specified for local variables");
-      goto fail;
-    }
-
-  new_section_name = TREE_STRING_POINTER (argval);
-
-  /* The decl may have already been given a section attribute
-     from a previous declaration.  Ensure they match.  */
-  if (const char* const old_section_name = DECL_SECTION_NAME (decl))
-    if (strcmp (old_section_name, new_section_name) != 0)
-      {
-	error ("section of %q+D conflicts with previous declaration",
-	       *node);
-	goto fail;
-      }
-
-  if (VAR_P (decl)
-      && !targetm.have_tls && targetm.emutls.tmpl_section
-      && DECL_THREAD_LOCAL_P (decl))
-    {
-      error ("section of %q+D cannot be overridden", *node);
-      goto fail;
-    }
-
-  if (!validate_attr_arg (node, name, argval))
-    goto fail;
-
-  res = targetm.handle_generic_attribute (node, name, args, flags,
-					  no_add_attrs);
-
-  /* If the back end confirms the attribute can be added then continue onto
-     final processing.  */
-  if (!(*no_add_attrs))
-    {
-      set_decl_section_name (decl, new_section_name);
-      return res;
-    }
-
-fail:
-  *no_add_attrs = true;
-  return res;
-}
-
 /* Common codes shared by handle_warn_if_not_aligned_attribute and
    handle_aligned_attribute.  */
 
@@ -3033,35 +2574,6 @@  handle_counted_by_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-/* Handle a "weak" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_weak_attribute (tree *node, tree name,
-		       tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags),
-		       bool * ARG_UNUSED (no_add_attrs))
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL
-      && DECL_DECLARED_INLINE_P (*node))
-    {
-      warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
-      *no_add_attrs = true;
-    }
-  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
-    {
-      error ("indirect function %q+D cannot be declared weak", *node);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-  else if (VAR_OR_FUNCTION_DECL_P (*node))
-    declare_weak (*node);
-  else
-    warning (OPT_Wattributes, "%qE attribute ignored", name);
-
-  return NULL_TREE;
-}
-
 /* Handle a "noinit" or "persistent" attribute; arguments as in
    struct attribute_spec.handler.
    This generic handler is used for "special variable sections" that allow the
@@ -3242,97 +2754,6 @@  handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   return NULL_TREE;
 }
 
-
-/* Handle an "alias" or "ifunc" attribute; arguments as in
-   struct attribute_spec.handler, except that IS_ALIAS tells us
-   whether this is an alias as opposed to ifunc attribute.  */
-
-static tree
-handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
-			      bool *no_add_attrs)
-{
-  tree decl = *node;
-
-  if (TREE_CODE (decl) != FUNCTION_DECL
-      && (!is_alias || !VAR_P (decl)))
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
-      || (TREE_CODE (decl) != FUNCTION_DECL
-	  && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
-      /* A static variable declaration is always a tentative definition,
-	 but the alias is a non-tentative definition which overrides.  */
-      || (TREE_CODE (decl) != FUNCTION_DECL
-	  && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
-    {
-      error ("%q+D defined both normally and as %qE attribute", decl, name);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-  else if (!is_alias
-	   && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
-	       || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
-    {
-      error ("weak %q+D cannot be defined %qE", decl, name);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-
-  /* Note that the very first time we process a nested declaration,
-     decl_function_context will not be set.  Indeed, *would* never
-     be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
-     we do below.  After such frobbery, pushdecl would set the context.
-     In any case, this is never what we want.  */
-  else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
-    {
-      tree id;
-
-      id = TREE_VALUE (args);
-      if (TREE_CODE (id) != STRING_CST)
-	{
-	  error ("attribute %qE argument not a string", name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-      id = get_identifier (TREE_STRING_POINTER (id));
-      /* This counts as a use of the object pointed to.  */
-      TREE_USED (id) = 1;
-
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-	DECL_INITIAL (decl) = error_mark_node;
-      else
-	TREE_STATIC (decl) = 1;
-
-      if (!is_alias)
-	{
-	  /* ifuncs are also aliases, so set that attribute too.  */
-	  DECL_ATTRIBUTES (decl)
-	    = tree_cons (get_identifier ("alias"), args,
-			 DECL_ATTRIBUTES (decl));
-	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
-					      NULL, DECL_ATTRIBUTES (decl));
-	}
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  if (decl_in_symtab_p (*node))
-    {
-      struct symtab_node *n = symtab_node::get (decl);
-      if (n && n->refuse_visibility_changes)
-	error ("%+qD declared %qs after being used",
-	       decl, is_alias ? "alias" : "ifunc");
-    }
-
-
-  return NULL_TREE;
-}
-
 /* Handle an "alias" or "ifunc" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -3343,16 +2764,6 @@  handle_ifunc_attribute (tree *node, tree name, tree args,
   return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs);
 }
 
-/* Handle an "alias" or "ifunc" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_alias_attribute (tree *node, tree name, tree args,
-			int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
-}
-
 /* Handle the "copy" attribute NAME by copying the set of attributes
    from the symbol referenced by ARGS to the declaration of *NODE.  */
 
@@ -3603,105 +3014,6 @@  handle_weakref_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Handle an "visibility" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_visibility_attribute (tree *node, tree name, tree args,
-			     int ARG_UNUSED (flags),
-			     bool *ARG_UNUSED (no_add_attrs))
-{
-  tree decl = *node;
-  tree id = TREE_VALUE (args);
-  enum symbol_visibility vis;
-
-  if (TYPE_P (*node))
-    {
-      if (TREE_CODE (*node) == ENUMERAL_TYPE)
-	/* OK */;
-      else if (!RECORD_OR_UNION_TYPE_P (*node))
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
-		   name);
-	  return NULL_TREE;
-	}
-      else if (TYPE_FIELDS (*node))
-	{
-	  error ("%qE attribute ignored because %qT is already defined",
-		 name, *node);
-	  return NULL_TREE;
-	}
-    }
-  else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (id) != STRING_CST)
-    {
-      error ("visibility argument not a string");
-      return NULL_TREE;
-    }
-
-  /*  If this is a type, set the visibility on the type decl.  */
-  if (TYPE_P (decl))
-    {
-      decl = TYPE_NAME (decl);
-      if (!decl)
-	return NULL_TREE;
-      if (TREE_CODE (decl) == IDENTIFIER_NODE)
-	{
-	   warning (OPT_Wattributes, "%qE attribute ignored on types",
-		    name);
-	   return NULL_TREE;
-	}
-    }
-
-  if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
-    vis = VISIBILITY_DEFAULT;
-  else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
-    vis = VISIBILITY_INTERNAL;
-  else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
-    vis = VISIBILITY_HIDDEN;
-  else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
-    vis = VISIBILITY_PROTECTED;
-  else
-    {
-      error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
-	     name, "default", "hidden", "protected", "internal");
-      vis = VISIBILITY_DEFAULT;
-    }
-
-  if (DECL_VISIBILITY_SPECIFIED (decl)
-      && vis != DECL_VISIBILITY (decl))
-    {
-      tree attributes = (TYPE_P (*node)
-			 ? TYPE_ATTRIBUTES (*node)
-			 : DECL_ATTRIBUTES (decl));
-      if (lookup_attribute ("visibility", attributes))
-	error ("%qD redeclared with different visibility", decl);
-      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-	       && lookup_attribute ("dllimport", attributes))
-	error ("%qD was declared %qs which implies default visibility",
-	       decl, "dllimport");
-      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-	       && lookup_attribute ("dllexport", attributes))
-	error ("%qD was declared %qs which implies default visibility",
-	       decl, "dllexport");
-    }
-
-  DECL_VISIBILITY (decl) = vis;
-  DECL_VISIBILITY_SPECIFIED (decl) = 1;
-
-  /* Go ahead and attach the attribute to the node as well.  This is needed
-     so we can determine whether we have VISIBILITY_DEFAULT because the
-     visibility was not specified, or because it was explicitly overridden
-     from the containing scope.  */
-
-  return NULL_TREE;
-}
-
 /* Handle an "tls_model" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -3851,6 +3163,12 @@  handle_malloc_attribute (tree *node, tree name, tree args, int flags,
     /* Recursive call.  */
     return NULL_TREE;
 
+  /* The argument-less form (declaring the function malloc-like) is shared
+     with libgccjit; the deallocator-argument form below is
+     specific to the C family.  */
+  if (!args)
+    return handle_malloc_common (node, name, args, flags, no_add_attrs);
+
   tree fndecl = *node;
 
   if (TREE_CODE (*node) != FUNCTION_DECL)
@@ -4215,19 +3533,6 @@  handle_argspec_attribute (tree *, tree, tree args, int, bool *)
   return NULL_TREE;
 }
 
-/* Handle the internal-only "fn spec" attribute.  */
-
-static tree
-handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
-			 tree args, int ARG_UNUSED (flags),
-			 bool *no_add_attrs ATTRIBUTE_UNUSED)
-{
-  gcc_assert (args
-	      && TREE_CODE (TREE_VALUE (args)) == STRING_CST
-	      && !TREE_CHAIN (args));
-  return NULL_TREE;
-}
-
 /* Handle a "warn_unused" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -4333,24 +3638,6 @@  handle_non_overlapping_attribute (tree *, tree, tree, int, bool *)
   return NULL_TREE;
 }
 
-/* Handle a "returns_twice" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-			 int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_IS_RETURNS_TWICE (*node) = 1;
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "no_limit_stack" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -4380,32 +3667,6 @@  handle_no_limit_stack_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-/* Handle a "pure" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    {
-      tree type = TREE_TYPE (*node);
-      if (VOID_TYPE_P (TREE_TYPE (type)))
-	warning (OPT_Wattributes, "%qE attribute on function "
-		 "returning %<void%>", name);
-
-      DECL_PURE_P (*node) = 1;
-      /* ??? TODO: Support types.  */
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle an "unsequenced" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -4827,31 +4088,6 @@  handle_callback_only_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Ignore the given attribute.  Used when this attribute may be usefully
-   overridden by the target, but is not used generically.  */
-
-static tree
-ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
-		  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-		  bool *no_add_attrs)
-{
-  *no_add_attrs = true;
-  return NULL_TREE;
-}
-
-/* Handle a "no vops" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
-			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			 bool *ARG_UNUSED (no_add_attrs))
-{
-  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
-  DECL_IS_NOVOPS (*node) = 1;
-  return NULL_TREE;
-}
-
 /* Handle a "deprecated" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -6353,24 +5589,6 @@  build_attr_access_from_parms (tree parms, bool skip_voidptr)
   return tree_cons (name, attrargs, nnlist);
 }
 
-/* Handle a "nothrow" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-			  int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    TREE_NOTHROW (*node) = 1;
-  /* ??? TODO: Support types.  */
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
 
 /* Handle a "nothrow" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -6503,54 +5721,6 @@  handle_sentinel_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
-/* Handle a "type_generic" attribute.  */
-
-static tree
-handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
-			       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			       bool * ARG_UNUSED (no_add_attrs))
-{
-  /* Ensure we have a function type.  */
-  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
-
-  /* Ensure we have a variadic function.  */
-  gcc_assert (!prototype_p (*node) || stdarg_p (*node));
-
-  return NULL_TREE;
-}
-
-/* Handle a "target" attribute.  */
-
-static tree
-handle_target_attribute (tree *node, tree name, tree args, int flags,
-			 bool *no_add_attrs)
-{
-  /* Ensure we have a function declaration.  */
-  if (TREE_CODE (*node) != FUNCTION_DECL)
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  else if (! targetm.target_option.valid_attribute_p (*node, name, args,
-						      flags))
-    *no_add_attrs = true;
-
-  /* Check that there's no empty string in values of the attribute.  */
-  for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
-    {
-      tree value = TREE_VALUE (t);
-      if (TREE_CODE (value) == STRING_CST
-	  && TREE_STRING_LENGTH (value) == 1
-	  && TREE_STRING_POINTER (value)[0] == '\0')
-	{
-	  warning (OPT_Wattributes, "empty string in attribute %<target%>");
-	  *no_add_attrs = true;
-	}
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "target_version" attribute.  */
 
 static tree
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
index eb1c996606270..3c13448d9bc69 100644
--- a/gcc/jit/Make-lang.in
+++ b/gcc/jit/Make-lang.in
@@ -131,6 +131,7 @@  jit.serial = $(LIBGCCJIT_FILENAME)
 .PHONY: jit
 
 JIT_OBJS = attribs.o \
+	attr-handlers.o \
 	jit/dummy-frontend.o \
 	jit/libgccjit.o \
 	jit/jit-logging.o \
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 4df9eada65bd2..14f8135578680 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -30,6 +30,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "attr-handlers.h"
 #include "cgraph.h"
 #include "target.h"
 #include "diagnostics/text-sink.h"
@@ -40,109 +41,23 @@  along with GCC; see the file COPYING3.  If not see
 
 using namespace gcc::jit;
 
-/* Attribute handling.  */
+/* Attribute handling.  These are the libgccjit-specific attribute handlers;
+   the handlers shared with the C family live in gcc/attr-handlers.cc.  */
 
-static tree handle_alias_attribute (tree *, tree, tree, int, bool *);
-static tree handle_always_inline_attribute (tree *, tree, tree, int,
-					    bool *);
 static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
-static tree handle_const_attribute (tree *, tree, tree, int, bool *);
-static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
 static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
 static tree handle_format_attribute (tree *, tree, tree, int, bool *);
-static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
-static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
-static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
-static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
-static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
 						       int, bool *);
-static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
-static tree handle_target_attribute (tree *, tree, tree, int, bool *);
 static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
-static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
-static tree handle_used_attribute (tree *, tree, tree, int, bool *);
-static tree handle_visibility_attribute (tree *, tree, tree, int,
-					 bool *);
-static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
-
-static tree ignore_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)	\
   { name, function, type, variable }
 
-/* Define attributes that are mutually exclusive with one another.  */
-static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
-{
-  ATTR_EXCL ("alloc_align", true, true, true),
-  ATTR_EXCL ("alloc_size", true, true, true),
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("malloc", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL ("returns_twice", true, true, true),
-  ATTR_EXCL ("warn_unused_result", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
-{
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc.  */
-static const struct attribute_spec::exclusions attr_alloc_exclusions[] =
-{
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
-{
-  ATTR_EXCL ("const", true, true, true),
-  ATTR_EXCL ("alloc_align", true, true, true),
-  ATTR_EXCL ("alloc_size", true, true, true),
-  ATTR_EXCL ("malloc", true, true, true),
-  ATTR_EXCL ("noreturn", true, true, true),
-  ATTR_EXCL ("pure", true, true, true),
-  ATTR_EXCL (NULL, false, false, false)
-};
-
-static const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
-{
-  ATTR_EXCL ("noinline", true, true, true),
-  ATTR_EXCL ("target_clones", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
-{
-  ATTR_EXCL ("cold", true, true, true),
-  ATTR_EXCL ("hot", true, true, true),
-  ATTR_EXCL (NULL, false, false, false)
-};
-
-static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
-{
-  ATTR_EXCL ("always_inline", true, true, true),
-  ATTR_EXCL ("gnu_inline", true, true, true),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
-static const struct attribute_spec::exclusions attr_target_exclusions[] =
-{
-  ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
-             TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
-  ATTR_EXCL (NULL, false, false, false),
-};
-
 /* These variables act as a cache for the target builtins. This is needed in
    order to be able to type-check the calls since we can only get those types
    in the playback phase while we need them in the recording phase.  */
@@ -174,7 +89,7 @@  static const attribute_spec jit_gnu_attributes[] =
   { "leaf",		      0, 0, true,  false, false, false,
 			      handle_leaf_attribute, NULL },
   { "malloc",		      0, 0, true,  false, false, false,
-			      handle_malloc_attribute, attr_alloc_exclusions },
+			      handle_malloc_common, attr_alloc_exclusions },
   { "noreturn",		      0, 0, true,  false, false, false,
 			      handle_noreturn_attribute,
 			      attr_noreturn_exclusions },
@@ -247,6 +162,11 @@  static const scoped_attribute_specs *const jit_attribute_table[] =
 
 /* Attribute handlers.  */
 
+/* Attribute handlers specific to libgccjit.  If the attribute handler code
+   is the same as the one in `c-family/c-attribs.cc`, please move the
+   handler into `attr-handlers.cc`.  */
+
+
 /* Handle a "noreturn" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -271,107 +191,6 @@  handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
-/* Handle a "leaf" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_leaf_attribute (tree *node, tree name,
-		       tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) != FUNCTION_DECL)
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  if (!TREE_PUBLIC (*node))
-    {
-      warning (OPT_Wattributes, "%qE attribute has no effect on unit local functions", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
-/* Handle a "const" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-			int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  tree type = TREE_TYPE (*node);
-
-  /* See FIXME comment on noreturn in c_common_attribute_table.  */
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    TREE_READONLY (*node) = 1;
-  else if (TREE_CODE (type) == POINTER_TYPE
-	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-    TREE_TYPE (*node)
-      = (build_qualified_type
-	 (build_pointer_type
-	  (build_type_variant (TREE_TYPE (type), 1,
-			       TREE_THIS_VOLATILE (TREE_TYPE (type)))),
-	  TYPE_QUALS (type)));
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
-
-/* Handle a "malloc" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_malloc_attribute (tree *node, tree ARG_UNUSED (name),
-			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			 bool * ARG_UNUSED (no_add_attrs))
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL
-      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
-    DECL_IS_MALLOC (*node) = 1;
-  else
-    gcc_unreachable ();
-
-  return NULL_TREE;
-}
-
-
-/* Handle a "pure" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_pure_attribute (tree *node, tree ARG_UNUSED (name),
-		       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-		       bool * ARG_UNUSED (no_add_attrs))
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_PURE_P (*node) = 1;
-  else
-    gcc_unreachable ();
-
-  return NULL_TREE;
-}
-
-
-/* Handle a "no vops" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
-			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			 bool *ARG_UNUSED (no_add_attrs))
-{
-  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
-  DECL_IS_NOVOPS (*node) = 1;
-  return NULL_TREE;
-}
-
-
 /* Helper for nonnull attribute handling; fetch the operand number
    from the attribute argument list.  */
 
@@ -437,24 +256,6 @@  handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
-
-/* Handle a "nothrow" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name),
-			  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			  bool * ARG_UNUSED (no_add_attrs))
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    TREE_NOTHROW (*node) = 1;
-  else
-    gcc_unreachable ();
-
-  return NULL_TREE;
-}
-
-
 /* Handle a "sentinel" attribute.  */
 
 static tree
@@ -475,22 +276,6 @@  handle_sentinel_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   return NULL_TREE;
 }
 
-/* Handle a "type_generic" attribute.  */
-
-static tree
-handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
-			       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			       bool * ARG_UNUSED (no_add_attrs))
-{
-  /* Ensure we have a function type.  */
-  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
-
-  /* Ensure we have a variadic function.  */
-  gcc_assert (!prototype_p (*node) || stdarg_p (*node));
-
-  return NULL_TREE;
-}
-
 /* Handle a "transaction_pure" attribute.  */
 
 static tree
@@ -505,203 +290,6 @@  handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
-/* Handle a "returns_twice" attribute.  */
-
-static tree
-handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name),
-				tree ARG_UNUSED (args),
-				int ARG_UNUSED (flags),
-				bool * ARG_UNUSED (no_add_attrs))
-{
-  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
-
-  DECL_IS_RETURNS_TWICE (*node) = 1;
-
-  return NULL_TREE;
-}
-
-static tree
-handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *)
-{
-  /* Nothing to be done here.  */
-  return NULL_TREE;
-}
-
-/* Ignore the given attribute.  Used when this attribute may be usefully
-   overridden by the target, but is not used generically.  */
-
-static tree
-ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
-		  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-		  bool *no_add_attrs)
-{
-  *no_add_attrs = true;
-  return NULL_TREE;
-}
-
-/* Handle a "format" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_format_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
-			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			 bool *no_add_attrs)
-{
-  *no_add_attrs = true;
-  return NULL_TREE;
-}
-
-
-/* Handle a "format_arg" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-tree
-handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
-			     tree ARG_UNUSED (args), int ARG_UNUSED (flags),
-			     bool *no_add_attrs)
-{
-  *no_add_attrs = true;
-  return NULL_TREE;
-}
-
-
-/* Handle a "fn spec" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
-			 tree args, int ARG_UNUSED (flags),
-			 bool *no_add_attrs ATTRIBUTE_UNUSED)
-{
-  gcc_assert (args
-	      && TREE_CODE (TREE_VALUE (args)) == STRING_CST
-	      && !TREE_CHAIN (args));
-  return NULL_TREE;
-}
-
-/* Handle an "visibility" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_visibility_attribute (tree *node, tree name, tree args,
-			     int ARG_UNUSED (flags),
-			     bool *ARG_UNUSED (no_add_attrs))
-{
-  tree decl = *node;
-  tree id = TREE_VALUE (args);
-  enum symbol_visibility vis;
-
-  if (TYPE_P (*node))
-    {
-      if (TREE_CODE (*node) == ENUMERAL_TYPE)
-	/* OK.  */;
-      else if (!RECORD_OR_UNION_TYPE_P (*node))
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
-		   name);
-	  return NULL_TREE;
-	}
-      else if (TYPE_FIELDS (*node))
-	{
-	  error ("%qE attribute ignored because %qT is already defined",
-		 name, *node);
-	  return NULL_TREE;
-	}
-    }
-  else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (id) != STRING_CST)
-    {
-      error ("visibility argument not a string");
-      return NULL_TREE;
-    }
-
-  /*  If this is a type, set the visibility on the type decl.  */
-  if (TYPE_P (decl))
-    {
-      decl = TYPE_NAME (decl);
-      if (!decl)
-	return NULL_TREE;
-      if (TREE_CODE (decl) == IDENTIFIER_NODE)
-	{
-	   warning (OPT_Wattributes, "%qE attribute ignored on types",
-		    name);
-	   return NULL_TREE;
-	}
-    }
-
-  if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
-    vis = VISIBILITY_DEFAULT;
-  else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
-    vis = VISIBILITY_INTERNAL;
-  else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
-    vis = VISIBILITY_HIDDEN;
-  else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
-    vis = VISIBILITY_PROTECTED;
-  else
-    {
-      error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
-	     name, "default", "hidden", "protected", "internal");
-      vis = VISIBILITY_DEFAULT;
-    }
-
-  if (DECL_VISIBILITY_SPECIFIED (decl)
-      && vis != DECL_VISIBILITY (decl))
-    {
-      tree attributes = (TYPE_P (*node)
-			 ? TYPE_ATTRIBUTES (*node)
-			 : DECL_ATTRIBUTES (decl));
-      if (lookup_attribute ("visibility", attributes))
-	error ("%qD redeclared with different visibility", decl);
-      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-	       && lookup_attribute ("dllimport", attributes))
-	error ("%qD was declared %qs which implies default visibility",
-	       decl, "dllimport");
-      else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-	       && lookup_attribute ("dllexport", attributes))
-	error ("%qD was declared %qs which implies default visibility",
-	       decl, "dllexport");
-    }
-
-  DECL_VISIBILITY (decl) = vis;
-  DECL_VISIBILITY_SPECIFIED (decl) = 1;
-
-  /* Go ahead and attach the attribute to the node as well.  This is needed
-     so we can determine whether we have VISIBILITY_DEFAULT because the
-     visibility was not specified, or because it was explicitly overridden
-     from the containing scope.  */
-
-  return NULL_TREE;
-}
-
-/* Handle a "always_inline" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_always_inline_attribute (tree *node, tree name,
-				tree ARG_UNUSED (args),
-				int ARG_UNUSED (flags),
-				bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    {
-      /* Set the attribute and mark it for disregarding inline
-	 limits.  */
-      DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  return NULL_TREE;
-}
-
 /* Handle a "cold" and attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -723,211 +311,36 @@  handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
-/* Handle a "noinline" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
 static tree
-handle_noinline_attribute (tree *node, tree name,
-			   tree ARG_UNUSED (args),
-			   int ARG_UNUSED (flags), bool *no_add_attrs)
+handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *)
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    DECL_UNINLINABLE (*node) = 1;
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
+  /* Nothing to be done here.  */
   return NULL_TREE;
 }
 
-/* Handle a "weak" attribute; arguments as in
+/* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 
 static tree
-handle_weak_attribute (tree *node, tree name,
-		       tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags),
-		       bool * ARG_UNUSED (no_add_attrs))
-{
-  if (TREE_CODE (*node) == FUNCTION_DECL
-      && DECL_DECLARED_INLINE_P (*node))
-    {
-      warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
-      *no_add_attrs = true;
-    }
-  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
-    {
-      error ("indirect function %q+D cannot be declared weak", *node);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-  else if (VAR_OR_FUNCTION_DECL_P (*node))
-    declare_weak (*node);
-  else
-    warning (OPT_Wattributes, "%qE attribute ignored", name);
-
-  return NULL_TREE;
-}
-
-/* Handle a "target" attribute.  */
-
-static tree
-handle_target_attribute (tree *node, tree name, tree args, int flags,
+handle_format_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
+			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
 			 bool *no_add_attrs)
 {
-  /* Ensure we have a function declaration.  */
-  if (TREE_CODE (*node) != FUNCTION_DECL)
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  else if (! targetm.target_option.valid_attribute_p (*node, name, args,
-						      flags))
-    *no_add_attrs = true;
-
-  /* Check that there's no empty string in values of the attribute.  */
-  for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
-    {
-      tree value = TREE_VALUE (t);
-      if (TREE_CODE (value) == STRING_CST
-	  && TREE_STRING_LENGTH (value) == 1
-	  && TREE_STRING_POINTER (value)[0] == '\0')
-	{
-	  warning (OPT_Wattributes, "empty string in attribute %<target%>");
-	  *no_add_attrs = true;
-	}
-    }
-
-  return NULL_TREE;
-}
-
-/* Handle a "used" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-static tree
-handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
-		       int ARG_UNUSED (flags), bool *no_add_attrs)
-{
-  tree node = *pnode;
-
-  if (TREE_CODE (node) == FUNCTION_DECL
-      || (VAR_P (node) && TREE_STATIC (node))
-      || (TREE_CODE (node) == TYPE_DECL))
-    {
-      TREE_USED (node) = 1;
-      DECL_PRESERVE_P (node) = 1;
-      if (VAR_P (node))
-	DECL_READ_P (node) = 1;
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
+  *no_add_attrs = true;
   return NULL_TREE;
 }
 
-/* Handle an "alias" or "ifunc" attribute; arguments as in
-   struct attribute_spec.handler, except that IS_ALIAS tells us
-   whether this is an alias as opposed to ifunc attribute.  */
 
-static tree
-handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
-			      bool *no_add_attrs)
-{
-  tree decl = *node;
-
-  if (TREE_CODE (decl) != FUNCTION_DECL
-      && (!is_alias || !VAR_P (decl)))
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-  else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
-      || (TREE_CODE (decl) != FUNCTION_DECL
-	  && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
-      /* A static variable declaration is always a tentative definition,
-	 but the alias is a non-tentative definition which overrides.  */
-      || (TREE_CODE (decl) != FUNCTION_DECL
-	  && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
-    {
-      error ("%q+D defined both normally and as %qE attribute", decl, name);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-  else if (!is_alias
-	   && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
-	       || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
-    {
-      error ("weak %q+D cannot be defined %qE", decl, name);
-      *no_add_attrs = true;
-      return NULL_TREE;
-    }
-
-  /* Note that the very first time we process a nested declaration,
-     decl_function_context will not be set.  Indeed, *would* never
-     be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
-     we do below.  After such frobbery, pushdecl would set the context.
-     In any case, this is never what we want.  */
-  else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
-    {
-      tree id;
-
-      id = TREE_VALUE (args);
-      if (TREE_CODE (id) != STRING_CST)
-	{
-	  error ("attribute %qE argument not a string", name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-      id = get_identifier (TREE_STRING_POINTER (id));
-      /* This counts as a use of the object pointed to.  */
-      TREE_USED (id) = 1;
-
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-	DECL_INITIAL (decl) = error_mark_node;
-      else
-	TREE_STATIC (decl) = 1;
-
-      if (!is_alias)
-	{
-	  /* ifuncs are also aliases, so set that attribute too.  */
-	  DECL_ATTRIBUTES (decl)
-	    = tree_cons (get_identifier ("alias"), args,
-			 DECL_ATTRIBUTES (decl));
-	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
-					      NULL, DECL_ATTRIBUTES (decl));
-	}
-    }
-  else
-    {
-      warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
-    }
-
-  if (decl_in_symtab_p (*node))
-    {
-      struct symtab_node *n = symtab_node::get (decl);
-      if (n && n->refuse_visibility_changes)
-	error ("%+qD declared %qs after being used",
-	       decl, is_alias ? "alias" : "ifunc");
-    }
-
-
-  return NULL_TREE;
-}
-
-/* Handle an "alias" or "ifunc" attribute; arguments as in
+/* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
 
-static tree
-handle_alias_attribute (tree *node, tree name, tree args,
-			int ARG_UNUSED (flags), bool *no_add_attrs)
+tree
+handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
+			     tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			     bool *no_add_attrs)
 {
-  return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
+  *no_add_attrs = true;
+  return NULL_TREE;
 }
 
 /* (end of attribute-handling).  */