From: Guillaume Gomez <[email protected]>
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: Move code into `attr-handlers.cc`
gcc/jit/ChangeLog:
* Make-lang.in: Compile new attr-handlers.cc file
* dummy-frontend.cc: Remove code duplicated with `attr-handlers.cc`
---
gcc/Makefile.in | 2 +-
gcc/attr-handlers.cc | 896 ++++++++++++++++++++++++++++++++++++++
gcc/attr-handlers.h | 61 +++
gcc/c-family/c-attribs.cc | 844 +----------------------------------
gcc/jit/Make-lang.in | 1 +
gcc/jit/dummy-frontend.cc | 646 +--------------------------
6 files changed, 988 insertions(+), 1462 deletions(-)
create mode 100644 gcc/attr-handlers.cc
create mode 100644 gcc/attr-handlers.h
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ee2f9022eab7f..260622b8dd0cf 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..adbbe7df44303
--- /dev/null
+++ b/gcc/attr-handlers.cc
@@ -0,0 +1,896 @@
+/* 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 "transaction_pure" attribute. */
+
+tree
+handle_transaction_pure_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);
+
+ 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..0f6ba12af4058
--- /dev/null
+++ b/gcc/attr-handlers.h
@@ -0,0 +1,61 @@
+/* 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_transaction_pure_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 d668ab96630af..1999c8aa0b6a6 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,13 +114,10 @@ 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_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,
@@ -142,7 +128,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,
@@ -150,21 +135,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,
@@ -185,7 +166,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 *);
@@ -207,13 +187,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),
@@ -227,27 +200,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),
@@ -279,18 +231,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[] =
{
@@ -299,42 +239,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),
@@ -968,137 +872,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
@@ -1724,25 +1497,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. */
@@ -1803,31 +1557,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. */
@@ -1851,29 +1580,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. */
@@ -1939,33 +1645,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. */
@@ -2004,28 +1683,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. */
@@ -2104,43 +1761,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. */
@@ -2603,85 +2223,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. */
@@ -3027,35 +2568,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
@@ -3236,97 +2748,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. */
@@ -3337,16 +2758,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. */
@@ -3597,105 +3008,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. */
@@ -3845,6 +3157,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)
@@ -4209,19 +3527,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. */
@@ -4327,24 +3632,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. */
@@ -4374,32 +3661,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. */
@@ -4672,31 +3933,6 @@ handle_tm_wrap_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. */
@@ -6182,24 +5418,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. */
@@ -6332,54 +5550,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..7f259897670ee 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,22 @@ 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 +88,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 +161,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 +190,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 +255,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,233 +275,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
-handle_transaction_pure_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);
-
- 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 +296,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). */
--
2.54.0