PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted
PR c/81566 - invalid attribute aligned accepted on functions
gcc/ada/ChangeLog:
PR c/81544
* gcc-interface/utils.c (gnat_internal_attribute_table): Initialize
new member of struct attribute_spec.
gcc/c/ChangeLog:
PR c/81544
* c-decl.c (c_decl_attributes): Look up existing declaration and
pass it to decl_attributes.
gcc/c-family/ChangeLog:
PR c/81544
PR c/81566
* c-attribs.c (attr_aligned_exclusions): New array.
(attr_alloc_exclusions, attr_cold_hot_exclusions): Same.
(attr_common_exclusions, attr_const_pure_exclusions): Same.
(attr_gnu_inline_exclusions, attr_inline_exclusions): Same.
(attr_noreturn_exclusions, attr_returns_twice_exclusions): Same.
(attr_warn_unused_result_exclusions): Same.
(handle_hot_attribute, handle_cold_attribute): Simplify.
(handle_const_attribute): Warn on function returning void.
(handle_pure_attribute): Same.
(handle_aligned_attribute): Diagnose conflicting attribute
specifications.
* c-warn.c (diagnose_mismatched_attributes): Simplify.
gcc/cp/ChangeLog:
PR c/81544
* cp-tree.h (decls_match): Add default argument.
* decl.c (decls_match): Avoid calling into the target back end
and triggering an error.
* decl2.c (cplus_decl_attributes): Look up existing declaration and
pass it to decl_attributes.
* tree.c (cxx_attribute_table): Initialize new member of struct
attribute_spec.
gcc/fortran/ChangeLog:
PR c/81544
* f95-lang.c (gfc_attribute_table): Initialize new member of struct
attribute_spec.
gcc/lto/ChangeLog:
PR c/81544
* lto-lang.c (lto_attribute_table): Initialize new member of struct
attribute_spec.
gcc/ChangeLog:
PR c/81544
* attribs.c (empty_attribute_table): Initialize new member of
struct attribute_spec.
(decl_attributes): Add argument. Handle mutually exclusive
combinations of attributes.
(selftests::test_attribute_exclusions): New function.
(selftests::attribute_c_tests): Ditto.
* attribs.h (decl_attributes): Add default argument.
* selftest.h (attribute_c_tests): Declare.
* selftest-run-tests.c (selftest::run_tests): Call attribute_c_tests.
* tree-core.h (attribute_spec::exclusions, exclude): New type and
member.
* doc/extend.texi (Common Function Attributes): Update const and pure.
gcc/testsuite/ChangeLog:
PR c/81544
* c-c++-common/Wattributes-2.c: New test.
* c-c++-common/Wattributes.c: New test.
* c-c++-common/attributes-3.c: Adjust.
* gcc.dg/Wattributes-6.c: New test.
* gcc.dg/Wattributes-7.c: New test.
* gcc.dg/attr-noinline.c
* gcc.dg/pr44964.c: Same.
* gcc.dg/torture/pr42363.c: Same.
* gcc.dg/tree-ssa/ssa-ccp-2.c: Same.
From-SVN: r255469
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * attribs.c (empty_attribute_table): Initialize new member of
+ struct attribute_spec.
+ (decl_attributes): Add argument. Handle mutually exclusive
+ combinations of attributes.
+ (selftests::test_attribute_exclusions): New function.
+ (selftests::attribute_c_tests): Ditto.
+ * attribs.h (decl_attributes): Add default argument.
+ * selftest.h (attribute_c_tests): Declare.
+ * selftest-run-tests.c (selftest::run_tests): Call attribute_c_tests.
+ * tree-core.h (attribute_spec::exclusions, exclude): New type and
+ member.
+ * doc/extend.texi (Common Function Attributes): Update const and pure.
+ * config/alpha/alpha.c (vms_attribute_table): Initialize new member
+ of struct attribute_spec.
+ * config/arc/arc.c (arc_attribute_table): Same.
+ * config/arm/arm.c (arm_attribute_table): Same.
+ * config/avr/avr.c ( avr_attribute_table): Same.
+ * config/bfin/bfin.c (bfin_attribute_table): Same.
+ * config/cr16/cr16.c (cr16_attribute_table): Same.
+ * config/epiphany/epiphany.c (epiphany_attribute_table): Same.
+ * config/h8300/h8300.c (h8300_attribute_table): Same.
+ * config/i386/i386.c (ix86_attribute_table): Same.
+ * config/ia64/ia64.c (ia64_attribute_table): Same.
+ * config/m32c/m32c.c (m32c_attribute_table): Same.
+ * config/m32r/m32r.c (m32r_attribute_table): Same.
+ * config/m68k/m68k.c (m68k_attribute_table): Same.
+ * config/mcore/mcore.c (mcore_attribute_table): Same.
+ * config/microblaze/microblaze.c (microblaze_attribute_table): Same.
+ * config/mips/mips.c (mips_attribute_table): Same.
+ * config/msp430/msp430.c (msp430_attribute_table): Same.
+ * config/nds32/nds32.c (nds32_attribute_table): Same.
+ * config/nvptx/nvptx.c (nvptx_attribute_table): Same.
+ * config/powerpcspe/powerpcspe.c (rs6000_attribute_table): Same.
+ * config/rl78/rl78.c (rl78__attribute_table): Same.
+ * config/rs6000/rs6000.c (rs6000_attribute_table): Same.
+ * onfig/rx/rx.c (rx_attribute_table): Same.
+ * config/s390/s390.c (s390_handle_vectorbool_attribute): Same.
+ * config/sh/sh.c (sh_attribute_table): Same.
+ * config/sparc/sparc.c (sparc_attribute_table): Same.
+ * config/spu/spu.c (spu_attribute_table): Same.
+ * config/stormy16/stormy16.c (xstormy16_attribute_table): Same.
+ * config/v850/v850.c (v850_attribute_table): Same.
+ * config/visium/visium.c (visium_attribute_table): Same.
+
2017-12-07 Tamar Christina <tamar.christina@arm.com>
PR target/82641
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * gcc-interface/utils.c (gnat_internal_attribute_table): Initialize
+ new member of struct attribute_spec.
+
2017-12-06 Simon Wright <simon@pushface.org>
PR ada/66205
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
{ "const", 0, 0, true, false, false, handle_const_attribute,
- false },
+ false, NULL },
{ "nothrow", 0, 0, true, false, false, handle_nothrow_attribute,
- false },
+ false, NULL },
{ "pure", 0, 0, true, false, false, handle_pure_attribute,
- false },
+ false, NULL },
{ "no vops", 0, 0, true, false, false, handle_novops_attribute,
- false },
+ false, NULL },
{ "nonnull", 0, -1, false, true, true, handle_nonnull_attribute,
- false },
+ false, NULL },
{ "sentinel", 0, 1, false, true, true, handle_sentinel_attribute,
- false },
+ false, NULL },
{ "noreturn", 0, 0, true, false, false, handle_noreturn_attribute,
- false },
+ false, NULL },
{ "noinline", 0, 0, true, false, false, handle_noinline_attribute,
- false },
+ false, NULL },
{ "noclone", 0, 0, true, false, false, handle_noclone_attribute,
- false },
+ false, NULL },
{ "leaf", 0, 0, true, false, false, handle_leaf_attribute,
- false },
+ false, NULL },
{ "always_inline",0, 0, true, false, false, handle_always_inline_attribute,
- false },
+ false, NULL },
{ "malloc", 0, 0, true, false, false, handle_malloc_attribute,
- false },
+ false, NULL },
{ "type generic", 0, 0, false, true, true, handle_type_generic_attribute,
- false },
+ false, NULL },
{ "vector_size", 1, 1, false, true, false, handle_vector_size_attribute,
- false },
+ false, NULL },
{ "vector_type", 0, 0, false, true, false, handle_vector_type_attribute,
- false },
- { "may_alias", 0, 0, false, true, false, NULL, false },
+ false, NULL },
+ { "may_alias", 0, 0, false, true, false, NULL, false, NULL },
/* ??? format and format_arg are heavy and not supported, which actually
prevents support for stdio builtins, which we however declare as part
of the common builtins.def contents. */
- { "format", 3, 3, false, true, true, fake_attribute_handler, false },
- { "format_arg", 1, 1, false, true, true, fake_attribute_handler, false },
+ { "format", 3, 3, false, true, true, fake_attribute_handler, false,
+ NULL },
+ { "format_arg", 1, 1, false, true, true, fake_attribute_handler, false,
+ NULL },
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Associates a GNAT tree node to a GCC tree node. It is used in
#include "stor-layout.h"
#include "langhooks.h"
#include "plugin.h"
+#include "selftest.h"
+#include "hash-set.h"
/* Table of the tables of attributes (common, language, format, machine)
searched. */
static const struct attribute_spec empty_attribute_table[] =
{
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Return base name of the attribute. Ie '__attr__' is turned into 'attr'.
return get_identifier ("gnu");
}
+/* Check LAST_DECL and NODE of the same symbol for attributes that are
+ recorded in SPEC to be mutually exclusive with ATTRNAME, diagnose
+ them, and return true if any have been found. NODE can be a DECL
+ or a TYPE. */
+
+static bool
+diag_attr_exclusions (tree last_decl, tree node, tree attrname,
+ const attribute_spec *spec)
+{
+ const attribute_spec::exclusions *excl = spec->exclude;
+
+ tree_code code = TREE_CODE (node);
+
+ if ((code == FUNCTION_DECL && !excl->function
+ && (!excl->type || !spec->affects_type_identity))
+ || (code == VAR_DECL && !excl->variable
+ && (!excl->type || !spec->affects_type_identity))
+ || (((code == TYPE_DECL || RECORD_OR_UNION_TYPE_P (node)) && !excl->type)))
+ return false;
+
+ /* True if an attribute that's mutually exclusive with ATTRNAME
+ has been found. */
+ bool found = false;
+
+ if (last_decl && last_decl != node && TREE_TYPE (last_decl) != node)
+ {
+ /* Check both the last DECL and its type for conflicts with
+ the attribute being added to the current decl or type. */
+ found |= diag_attr_exclusions (last_decl, last_decl, attrname, spec);
+ tree decl_type = TREE_TYPE (last_decl);
+ found |= diag_attr_exclusions (last_decl, decl_type, attrname, spec);
+ }
+
+ /* NODE is either the current DECL to which the attribute is being
+ applied or its TYPE. For the former, consider the attributes on
+ both the DECL and its type. */
+ tree attrs[2];
+
+ if (DECL_P (node))
+ {
+ attrs[0] = DECL_ATTRIBUTES (node);
+ attrs[1] = TYPE_ATTRIBUTES (TREE_TYPE (node));
+ }
+ else
+ {
+ attrs[0] = TYPE_ATTRIBUTES (node);
+ attrs[1] = NULL_TREE;
+ }
+
+ /* Iterate over the mutually exclusive attribute names and verify
+ that the symbol doesn't contain it. */
+ for (unsigned i = 0; i != sizeof attrs / sizeof *attrs; ++i)
+ {
+ if (!attrs[i])
+ continue;
+
+ for ( ; excl->name; ++excl)
+ {
+ /* Avoid checking the attribute against itself. */
+ if (is_attribute_p (excl->name, attrname))
+ continue;
+
+ if (!lookup_attribute (excl->name, attrs[i]))
+ continue;
+
+ found = true;
+
+ /* Print a note? */
+ bool note = last_decl != NULL_TREE;
+
+ if (TREE_CODE (node) == FUNCTION_DECL
+ && DECL_BUILT_IN (node))
+ note &= warning (OPT_Wattributes,
+ "ignoring attribute %qE in declaration of "
+ "a built-in function %qD because it conflicts "
+ "with attribute %qs",
+ attrname, node, excl->name);
+ else
+ note &= warning (OPT_Wattributes,
+ "ignoring attribute %qE because "
+ "it conflicts with attribute %qs",
+ attrname, excl->name);
+
+ if (note)
+ inform (DECL_SOURCE_LOCATION (last_decl),
+ "previous declaration here");
+ }
+ }
+
+ return found;
+}
/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
a decl attribute to the declaration rather than to its type). */
tree
-decl_attributes (tree *node, tree attributes, int flags)
+decl_attributes (tree *node, tree attributes, int flags,
+ tree last_decl /* = NULL_TREE */)
{
tree a;
tree returned_attrs = NULL_TREE;
targetm.insert_attributes (*node, &attributes);
+ /* Note that attributes on the same declaration are not necessarily
+ in the same order as in the source. */
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree ns = get_attribute_namespace (a);
tree *anode = node;
const struct attribute_spec *spec =
lookup_scoped_attribute_spec (ns, name);
- bool no_add_attrs = 0;
int fn_ptr_quals = 0;
tree fn_ptr_tmp = NULL_TREE;
| (int) ATTR_FLAG_ARRAY_NEXT))
{
/* Pass on this attribute to be tried again. */
- returned_attrs = tree_cons (name, args, returned_attrs);
+ tree attr = tree_cons (name, args, NULL_TREE);
+ returned_attrs = chainon (returned_attrs, attr);
continue;
}
else
else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
{
/* Pass on this attribute to be tried again. */
- returned_attrs = tree_cons (name, args, returned_attrs);
+ tree attr = tree_cons (name, args, NULL_TREE);
+ returned_attrs = chainon (returned_attrs, attr);
continue;
}
continue;
}
+ bool no_add_attrs = false;
+
if (spec->handler != NULL)
{
int cxx11_flag =
cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
- returned_attrs = chainon ((*spec->handler) (anode, name, args,
- flags|cxx11_flag,
- &no_add_attrs),
- returned_attrs);
+ /* Pass in an array of the current declaration followed
+ by the last pushed/merged declaration if one exists.
+ If the handler changes CUR_AND_LAST_DECL[0] replace
+ *ANODE with its value. */
+ tree cur_and_last_decl[] = { *anode, last_decl };
+ tree ret = (spec->handler) (cur_and_last_decl, name, args,
+ flags|cxx11_flag, &no_add_attrs);
+
+ *anode = cur_and_last_decl[0];
+ if (ret == error_mark_node)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ no_add_attrs = true;
+ }
+ else
+ returned_attrs = chainon (ret, returned_attrs);
+ }
+
+ /* If the attribute was successfully handled on its own and is
+ about to be added check for exclusions with other attributes
+ on the current declation as well as the last declaration of
+ the same symbol already processed (if one exists). */
+ bool built_in = flags & ATTR_FLAG_BUILT_IN;
+ if (spec->exclude
+ && !no_add_attrs
+ && (flag_checking || !built_in))
+ {
+ /* Always check attributes on user-defined functions.
+ Check them on built-ins only when -fchecking is set.
+ Ignore __builtin_unreachable -- it's both const and
+ noreturn. */
+
+ if (!built_in
+ || !DECL_P (*anode)
+ || (DECL_FUNCTION_CODE (*anode) != BUILT_IN_UNREACHABLE
+ && (DECL_FUNCTION_CODE (*anode)
+ != BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE)))
+ {
+ bool no_add = diag_attr_exclusions (last_decl, *anode, name, spec);
+ if (!no_add && anode != node)
+ no_add = diag_attr_exclusions (last_decl, *node, name, spec);
+ no_add_attrs |= no_add;
+ }
}
/* Layout the decl in case anything changed. */
return list;
}
+
+#if CHECKING_P
+
+namespace selftest
+{
+
+/* Helper types to verify the consistency attribute exclusions. */
+
+typedef std::pair<const char *, const char *> excl_pair;
+
+struct excl_hash_traits: typed_noop_remove<excl_pair>
+{
+ typedef excl_pair value_type;
+ typedef value_type compare_type;
+
+ static hashval_t hash (const value_type &x)
+ {
+ hashval_t h1 = htab_hash_string (x.first);
+ hashval_t h2 = htab_hash_string (x.second);
+ return h1 ^ h2;
+ }
+
+ static bool equal (const value_type &x, const value_type &y)
+ {
+ return !strcmp (x.first, y.first) && !strcmp (x.second, y.second);
+ }
+
+ static void mark_deleted (value_type &x)
+ {
+ x = value_type (NULL, NULL);
+ }
+
+ static void mark_empty (value_type &x)
+ {
+ x = value_type ("", "");
+ }
+
+ static bool is_deleted (const value_type &x)
+ {
+ return !x.first && !x.second;
+ }
+
+ static bool is_empty (const value_type &x)
+ {
+ return !*x.first && !*x.second;
+ }
+};
+
+
+/* Self-test to verify that each attribute exclusion is symmetric,
+ meaning that if attribute A is encoded as incompatible with
+ attribute B then the opposite relationship is also encoded.
+ This test also detects most cases of misspelled attribute names
+ in exclusions. */
+
+static void
+test_attribute_exclusions ()
+{
+ /* Iterate over the array of attribute tables first (with TI0 as
+ the index) and over the array of attribute_spec in each table
+ (with SI0 as the index). */
+ const size_t ntables = ARRAY_SIZE (attribute_tables);
+
+ /* Set of pairs of mutually exclusive attributes. */
+ typedef hash_set<excl_pair, excl_hash_traits> exclusion_set;
+ exclusion_set excl_set;
+
+ for (size_t ti0 = 0; ti0 != ntables; ++ti0)
+ for (size_t s0 = 0; attribute_tables[ti0][s0].name; ++s0)
+ {
+ const attribute_spec::exclusions *excl
+ = attribute_tables[ti0][s0].exclude;
+
+ /* Skip each attribute that doesn't define exclusions. */
+ if (!excl)
+ continue;
+
+ const char *attr_name = attribute_tables[ti0][s0].name;
+
+ /* Iterate over the set of exclusions for every attribute
+ (with EI0 as the index) adding the exclusions defined
+ for each to the set. */
+ for (size_t ei0 = 0; excl[ei0].name; ++ei0)
+ {
+ const char *excl_name = excl[ei0].name;
+
+ if (!strcmp (attr_name, excl_name))
+ continue;
+
+ excl_set.add (excl_pair (attr_name, excl_name));
+ }
+ }
+
+ /* Traverse the set of mutually exclusive pairs of attributes
+ and verify that they are symmetric. */
+ for (exclusion_set::iterator it = excl_set.begin ();
+ it != excl_set.end ();
+ ++it)
+ {
+ if (!excl_set.contains (excl_pair ((*it).second, (*it).first)))
+ {
+ /* An exclusion for an attribute has been found that
+ doesn't have a corresponding exclusion in the opposite
+ direction. */
+ char desc[120];
+ sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric",
+ (*it).first, (*it).second);
+ fail (SELFTEST_LOCATION, desc);
+ }
+ }
+}
+
+void
+attribute_c_tests ()
+{
+ test_attribute_exclusions ();
+}
+
+} /* namespace selftest */
+
+#endif /* CHECKING_P */
from tree.h. Depending on these flags, some attributes may be
returned to be applied at a later stage (for example, to apply
a decl attribute to the declaration rather than to its type). */
-extern tree decl_attributes (tree *, tree, int);
+extern tree decl_attributes (tree *, tree, int, tree = NULL_TREE);
extern bool cxx11_attribute_p (const_tree);
extern tree get_attribute_name (const_tree);
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
do_diagnostic } */
{ "leaf", 0, 0, true, false, false,
- handle_leaf_attribute, false },
+ handle_leaf_attribute, false, NULL },
{ "const", 0, 0, true, false, false,
- handle_const_attribute, false },
+ handle_const_attribute, false, NULL },
{ "pure", 0, 0, true, false, false,
- handle_pure_attribute, false },
+ handle_pure_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute, false },
+ handle_nothrow_attribute, false, NULL },
{ "returns_twice", 0, 0, true, false, false,
- handle_returns_twice_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ handle_returns_twice_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Attribute handlers. */
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ PR c/81566
+ * c-attribs.c (attr_aligned_exclusions): New array.
+ (attr_alloc_exclusions, attr_cold_hot_exclusions): Same.
+ (attr_common_exclusions, attr_const_pure_exclusions): Same.
+ (attr_gnu_inline_exclusions, attr_inline_exclusions): Same.
+ (attr_noreturn_exclusions, attr_returns_twice_exclusions): Same.
+ (attr_warn_unused_result_exclusions): Same.
+ (handle_hot_attribute, handle_cold_attribute): Simplify.
+ (handle_const_attribute): Warn on function returning void.
+ (handle_pure_attribute): Same.
+ (handle_aligned_attribute): Diagnose conflicting attribute
+ specifications.
+ * c-warn.c (diagnose_mismatched_attributes): Simplify.
+
2017-12-06 David Malcolm <dmalcolm@redhat.com>
PR c/83236
static tree handle_patchable_function_entry_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_aligned_exclusions[] =
+{
+ /* Attribute name exclusion applies to:
+ function, type, variable */
+ ATTR_EXCL ("aligned", true, false, false),
+ ATTR_EXCL ("packed", true, false, false),
+ ATTR_EXCL (NULL, false, false, false)
+};
+
+static 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),
+ ATTR_EXCL ("nocommon", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_inline_exclusions[] =
+{
+ ATTR_EXCL ("noinline", 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_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[] =
+{
+ ATTR_EXCL ("noreturn", 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)
+};
+
/* Table of machine-independent attributes common to all C-like languages.
All attributes referencing arguments should be additionally processed
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
{ "packed", 0, 0, false, false, false,
- handle_packed_attribute , false},
+ handle_packed_attribute, false,
+ attr_aligned_exclusions },
{ "nocommon", 0, 0, true, false, false,
- handle_nocommon_attribute, false},
+ handle_nocommon_attribute, false,
+ attr_common_exclusions },
{ "common", 0, 0, true, false, false,
- handle_common_attribute, false },
+ handle_common_attribute, false,
+ attr_common_exclusions },
/* FIXME: logically, noreturn attributes should be listed as
"false, true, true" and apply to function types. But implementing this
would require all the places in the compiler that use TREE_THIS_VOLATILE
on a decl to identify non-returning functions to be located and fixed
to check the function type instead. */
{ "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute, false },
+ handle_noreturn_attribute, false,
+ attr_noreturn_exclusions },
{ "volatile", 0, 0, true, false, false,
- handle_noreturn_attribute, false },
+ handle_noreturn_attribute, false, NULL },
{ "stack_protect", 0, 0, true, false, false,
- handle_stack_protect_attribute, false },
+ handle_stack_protect_attribute, false, NULL },
{ "noinline", 0, 0, true, false, false,
- handle_noinline_attribute, false },
+ handle_noinline_attribute, false,
+ attr_noinline_exclusions },
{ "noclone", 0, 0, true, false, false,
- handle_noclone_attribute, false },
+ handle_noclone_attribute, false, NULL },
{ "no_icf", 0, 0, true, false, false,
- handle_noicf_attribute, false },
+ handle_noicf_attribute, false, NULL },
{ "noipa", 0, 0, true, false, false,
- handle_noipa_attribute, false },
+ handle_noipa_attribute, false, NULL },
{ "leaf", 0, 0, true, false, false,
- handle_leaf_attribute, false },
+ handle_leaf_attribute, false, NULL },
{ "always_inline", 0, 0, true, false, false,
- handle_always_inline_attribute, false },
+ handle_always_inline_attribute, false,
+ attr_inline_exclusions },
{ "gnu_inline", 0, 0, true, false, false,
- handle_gnu_inline_attribute, false },
+ handle_gnu_inline_attribute, false,
+ attr_inline_exclusions },
{ "artificial", 0, 0, true, false, false,
- handle_artificial_attribute, false },
+ handle_artificial_attribute, false, NULL },
{ "flatten", 0, 0, true, false, false,
- handle_flatten_attribute, false },
+ handle_flatten_attribute, false, NULL },
{ "used", 0, 0, true, false, false,
- handle_used_attribute, false },
+ handle_used_attribute, false, NULL },
{ "unused", 0, 0, false, false, false,
- handle_unused_attribute, false },
+ handle_unused_attribute, false, NULL },
{ "externally_visible", 0, 0, true, false, false,
- handle_externally_visible_attribute, false },
+ handle_externally_visible_attribute, false, NULL },
{ "no_reorder", 0, 0, true, false, false,
- handle_no_reorder_attribute, false },
+ handle_no_reorder_attribute, false, NULL },
/* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false,
- handle_const_attribute, false },
+ handle_const_attribute, false,
+ attr_const_pure_exclusions },
{ "scalar_storage_order", 1, 1, false, false, false,
- handle_scalar_storage_order_attribute, false },
+ handle_scalar_storage_order_attribute, false, NULL },
{ "transparent_union", 0, 0, false, false, false,
- handle_transparent_union_attribute, false },
+ handle_transparent_union_attribute, false, NULL },
{ "constructor", 0, 1, true, false, false,
- handle_constructor_attribute, false },
+ handle_constructor_attribute, false, NULL },
{ "destructor", 0, 1, true, false, false,
- handle_destructor_attribute, false },
+ handle_destructor_attribute, false, NULL },
{ "mode", 1, 1, false, true, false,
- handle_mode_attribute, false },
+ handle_mode_attribute, false, NULL },
{ "section", 1, 1, true, false, false,
- handle_section_attribute, false },
+ handle_section_attribute, false, NULL },
{ "aligned", 0, 1, false, false, false,
- handle_aligned_attribute, false },
+ handle_aligned_attribute, false,
+ attr_aligned_exclusions },
{ "warn_if_not_aligned", 0, 1, false, false, false,
handle_warn_if_not_aligned_attribute,
- false },
+ false, NULL },
{ "weak", 0, 0, true, false, false,
- handle_weak_attribute, false },
+ handle_weak_attribute, false, NULL },
{ "noplt", 0, 0, true, false, false,
- handle_noplt_attribute, false },
+ handle_noplt_attribute, false, NULL },
{ "ifunc", 1, 1, true, false, false,
- handle_ifunc_attribute, false },
+ handle_ifunc_attribute, false, NULL },
{ "alias", 1, 1, true, false, false,
- handle_alias_attribute, false },
+ handle_alias_attribute, false, NULL },
{ "weakref", 0, 1, true, false, false,
- handle_weakref_attribute, false },
+ handle_weakref_attribute, false, NULL },
{ "no_instrument_function", 0, 0, true, false, false,
handle_no_instrument_function_attribute,
- false },
+ false, NULL },
{ "no_profile_instrument_function", 0, 0, true, false, false,
handle_no_profile_instrument_function_attribute,
- false },
+ false, NULL },
{ "malloc", 0, 0, true, false, false,
- handle_malloc_attribute, false },
+ handle_malloc_attribute, false,
+ attr_alloc_exclusions },
{ "returns_twice", 0, 0, true, false, false,
- handle_returns_twice_attribute, false },
+ handle_returns_twice_attribute, false,
+ attr_returns_twice_exclusions },
{ "no_stack_limit", 0, 0, true, false, false,
- handle_no_limit_stack_attribute, false },
+ handle_no_limit_stack_attribute, false, NULL },
{ "pure", 0, 0, true, false, false,
- handle_pure_attribute, false },
+ handle_pure_attribute, false,
+ attr_const_pure_exclusions },
{ "transaction_callable", 0, 0, false, true, false,
- handle_tm_attribute, false },
+ handle_tm_attribute, false, NULL },
{ "transaction_unsafe", 0, 0, false, true, false,
- handle_tm_attribute, true },
+ handle_tm_attribute, true, NULL },
{ "transaction_safe", 0, 0, false, true, false,
- handle_tm_attribute, true },
+ handle_tm_attribute, true, NULL },
{ "transaction_safe_dynamic", 0, 0, true, false, false,
- handle_tm_attribute, false },
+ handle_tm_attribute, false, NULL },
{ "transaction_may_cancel_outer", 0, 0, false, true, false,
- handle_tm_attribute, false },
+ handle_tm_attribute, false, NULL },
/* ??? These two attributes didn't make the transition from the
Intel language document to the multi-vendor language document. */
{ "transaction_pure", 0, 0, false, true, false,
- handle_tm_attribute, false },
+ handle_tm_attribute, false, NULL },
{ "transaction_wrap", 1, 1, true, false, false,
- handle_tm_wrap_attribute, false },
+ handle_tm_wrap_attribute, false, NULL },
/* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */
{ "no vops", 0, 0, true, false, false,
- handle_novops_attribute, false },
+ handle_novops_attribute, false, NULL },
{ "deprecated", 0, 1, false, false, false,
- handle_deprecated_attribute, false },
+ handle_deprecated_attribute, false, NULL },
{ "vector_size", 1, 1, false, true, false,
- handle_vector_size_attribute, true },
+ handle_vector_size_attribute, true, NULL },
{ "visibility", 1, 1, false, false, false,
- handle_visibility_attribute, false },
+ handle_visibility_attribute, false, NULL },
{ "tls_model", 1, 1, true, false, false,
- handle_tls_model_attribute, false },
+ handle_tls_model_attribute, false, NULL },
{ "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute, false },
+ handle_nonnull_attribute, false, NULL },
{ "nonstring", 0, 0, true, false, false,
- handle_nonstring_attribute, false },
+ handle_nonstring_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute, false },
- { "may_alias", 0, 0, false, true, false, NULL, false },
+ handle_nothrow_attribute, false, NULL },
+ { "may_alias", 0, 0, false, true, false, NULL, false, NULL },
{ "cleanup", 1, 1, true, false, false,
- handle_cleanup_attribute, false },
+ handle_cleanup_attribute, false, NULL },
{ "warn_unused_result", 0, 0, false, true, true,
- handle_warn_unused_result_attribute, false },
+ handle_warn_unused_result_attribute, false,
+ attr_warn_unused_result_exclusions },
{ "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute, false },
+ handle_sentinel_attribute, false, NULL },
/* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */
{ "type generic", 0, 0, false, true, true,
- handle_type_generic_attribute, false },
+ handle_type_generic_attribute, false, NULL },
{ "alloc_size", 1, 2, false, true, true,
- handle_alloc_size_attribute, false },
+ handle_alloc_size_attribute, false,
+ attr_alloc_exclusions },
{ "cold", 0, 0, true, false, false,
- handle_cold_attribute, false },
+ handle_cold_attribute, false,
+ attr_cold_hot_exclusions },
{ "hot", 0, 0, true, false, false,
- handle_hot_attribute, false },
+ handle_hot_attribute, false,
+ attr_cold_hot_exclusions },
{ "no_address_safety_analysis",
0, 0, true, false, false,
handle_no_address_safety_analysis_attribute,
- false },
+ false, NULL },
{ "no_sanitize", 1, 1, true, false, false,
handle_no_sanitize_attribute,
- false },
+ false, NULL },
{ "no_sanitize_address", 0, 0, true, false, false,
handle_no_sanitize_address_attribute,
- false },
+ false, NULL },
{ "no_sanitize_thread", 0, 0, true, false, false,
handle_no_sanitize_thread_attribute,
- false },
+ false, NULL },
{ "no_sanitize_undefined", 0, 0, true, false, false,
handle_no_sanitize_undefined_attribute,
- false },
+ false, NULL },
{ "asan odr indicator", 0, 0, true, false, false,
handle_asan_odr_indicator_attribute,
- false },
+ false, NULL },
{ "warning", 1, 1, true, false, false,
- handle_error_attribute, false },
+ handle_error_attribute, false, NULL },
{ "error", 1, 1, true, false, false,
- handle_error_attribute, false },
+ handle_error_attribute, false, NULL },
{ "target", 1, -1, true, false, false,
- handle_target_attribute, false },
+ handle_target_attribute, false, NULL },
{ "target_clones", 1, -1, true, false, false,
- handle_target_clones_attribute, false },
+ handle_target_clones_attribute, false, NULL },
{ "optimize", 1, -1, true, false, false,
- handle_optimize_attribute, false },
+ handle_optimize_attribute, false, NULL },
/* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true,
- ignore_attribute, false },
+ ignore_attribute, false, NULL },
{ "no_split_stack", 0, 0, true, false, false,
- handle_no_split_stack_attribute, false },
+ handle_no_split_stack_attribute, false, NULL },
/* For internal use (marking of builtins and runtime functions) only.
The name contains space to prevent its usage in source code. */
{ "fn spec", 1, 1, false, true, true,
- handle_fnspec_attribute, false },
+ handle_fnspec_attribute, false, NULL },
{ "warn_unused", 0, 0, false, false, false,
- handle_warn_unused_attribute, false },
+ handle_warn_unused_attribute, false, NULL },
{ "returns_nonnull", 0, 0, false, true, true,
- handle_returns_nonnull_attribute, false },
+ handle_returns_nonnull_attribute, false, NULL },
{ "omp declare simd", 0, -1, true, false, false,
- handle_omp_declare_simd_attribute, false },
+ handle_omp_declare_simd_attribute, false, NULL },
+ { "cilk simd function", 0, -1, true, false, false,
+ handle_omp_declare_simd_attribute, false, NULL },
{ "simd", 0, 1, true, false, false,
- handle_simd_attribute, false },
+ handle_simd_attribute, false, NULL },
{ "omp declare target", 0, 0, true, false, false,
- handle_omp_declare_target_attribute, false },
+ handle_omp_declare_target_attribute, false, NULL },
{ "omp declare target link", 0, 0, true, false, false,
- handle_omp_declare_target_attribute, false },
+ handle_omp_declare_target_attribute, false, NULL },
{ "alloc_align", 1, 1, false, true, true,
- handle_alloc_align_attribute, false },
+ handle_alloc_align_attribute, false,
+ attr_alloc_exclusions },
{ "assume_aligned", 1, 2, false, true, true,
- handle_assume_aligned_attribute, false },
+ handle_assume_aligned_attribute, false, NULL },
{ "designated_init", 0, 0, false, true, false,
- handle_designated_init_attribute, false },
+ handle_designated_init_attribute, false, NULL },
{ "bnd_variable_size", 0, 0, true, false, false,
- handle_bnd_variable_size_attribute, false },
+ handle_bnd_variable_size_attribute, false, NULL },
{ "bnd_legacy", 0, 0, true, false, false,
- handle_bnd_legacy, false },
+ handle_bnd_legacy, false, NULL },
{ "bnd_instrument", 0, 0, true, false, false,
- handle_bnd_instrument, false },
+ handle_bnd_instrument, false, NULL },
{ "fallthrough", 0, 0, false, false, false,
- handle_fallthrough_attribute, false },
+ handle_fallthrough_attribute, false, NULL },
{ "patchable_function_entry", 1, 2, true, false, false,
handle_patchable_function_entry_attribute,
- false },
- { "nocf_check", 0, 0, false, true, true,
- handle_nocf_check_attribute, true },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { "nocf_check", 0, 0, false, true, true,
+ handle_nocf_check_attribute, true, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Give the specifications for the format attributes, used by C and all
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
{ "format", 3, 3, false, true, true,
- handle_format_attribute, false },
+ handle_format_attribute, false, NULL },
{ "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ handle_format_arg_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain
if (TREE_CODE (*node) == FUNCTION_DECL
|| TREE_CODE (*node) == LABEL_DECL)
{
- if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with attribute %qs", name, "cold");
- *no_add_attrs = true;
- }
- /* Most of the rest of the hot processing is done later with
- lookup_attribute. */
+ /* Attribute hot processing is done later with lookup_attribute. */
}
else
{
if (TREE_CODE (*node) == FUNCTION_DECL
|| TREE_CODE (*node) == LABEL_DECL)
{
- if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored due to conflict "
- "with attribute %qs", name, "hot");
- *no_add_attrs = true;
- }
- /* Most of the rest of the cold processing is done later with
- lookup_attribute. */
+ /* Attribute cold processing is done later with lookup_attribute. */
}
else
{
static tree
handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
- int ARG_UNUSED (flags), bool *no_add_attrs)
+ int flags, bool *no_add_attrs)
{
tree type = TREE_TYPE (*node);
*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_aligned_attribute. */
static tree
-common_handle_aligned_attribute (tree *node, tree args, int flags,
+common_handle_aligned_attribute (tree *node, tree name, tree args, int flags,
bool *no_add_attrs,
bool warn_if_not_aligned_p)
{
tree decl = NULL_TREE;
tree *type = NULL;
- int is_type = 0;
+ bool is_type = false;
tree align_expr;
- int i;
+
+ /* The last (already pushed) declaration with all validated attributes
+ merged in or the current about-to-be-pushed one if one hasn't been
+ yet. */
+ tree last_decl = node[1] ? node[1] : *node;
if (args)
{
is_type = TREE_CODE (*node) == TYPE_DECL;
}
else if (TYPE_P (*node))
- type = node, is_type = 1;
+ type = node, is_type = true;
+
+ /* Log2 of specified alignment. */
+ int pow2align = check_user_alignment (align_expr, true);
+
+ /* The alignment in bits corresponding to the specified alignment. */
+ unsigned bitalign = (1U << pow2align) * BITS_PER_UNIT;
+
+ /* The alignment of the current declaration and that of the last
+ pushed declaration, determined on demand below. */
+ unsigned curalign = 0;
+ unsigned lastalign = 0;
- if ((i = check_user_alignment (align_expr, true)) == -1
- || !check_cxx_fundamental_alignment_constraints (*node, i, flags))
+ if (pow2align == -1
+ || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags))
*no_add_attrs = true;
else if (is_type)
{
if (warn_if_not_aligned_p)
{
- SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+ SET_TYPE_WARN_IF_NOT_ALIGN (*type, bitalign);
warn_if_not_aligned_p = false;
}
else
{
- SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT);
+ SET_TYPE_ALIGN (*type, bitalign);
TYPE_USER_ALIGN (*type) = 1;
}
}
error ("alignment may not be specified for %q+D", decl);
*no_add_attrs = true;
}
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ && ((curalign = DECL_ALIGN (decl)) > bitalign
+ || ((lastalign = DECL_ALIGN (last_decl)) > bitalign)))
+ {
+ /* Either a prior attribute on the same declaration or one
+ on a prior declaration of the same function specifies
+ stricter alignment than this attribute. */
+ bool note = lastalign != 0;
+ if (lastalign)
+ curalign = lastalign;
+
+ curalign /= BITS_PER_UNIT;
+ bitalign /= BITS_PER_UNIT;
+
+ if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
+ warning (OPT_Wattributes,
+ "ignoring attribute %<%E (%u)%> because it conflicts with "
+ "attribute %<%E (%u)%>", name, bitalign, name, curalign);
+ else
+ error ("alignment for %q+D must be at least %d", decl, curalign);
+
+ if (note)
+ inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here");
+
+ *no_add_attrs = true;
+ }
else if (DECL_USER_ALIGN (decl)
- && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
+ && DECL_ALIGN (decl) > bitalign)
/* C++-11 [dcl.align/4]:
When multiple alignment-specifiers are specified for an
*no_add_attrs = true;
else if (!warn_if_not_aligned_p
&& TREE_CODE (decl) == FUNCTION_DECL
- && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT)
+ && DECL_ALIGN (decl) > bitalign)
{
/* Don't warn function alignment here if warn_if_not_aligned_p is
true. It will be warned later. */
{
if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl))
{
- SET_DECL_WARN_IF_NOT_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+ SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign);
warn_if_not_aligned_p = false;
}
}
else
{
- SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
+ SET_DECL_ALIGN (decl, bitalign);
DECL_USER_ALIGN (decl) = 1;
}
}
struct attribute_spec.handler. */
static tree
-handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+handle_aligned_attribute (tree *node, tree name, tree args,
int flags, bool *no_add_attrs)
{
- return common_handle_aligned_attribute (node, args, flags,
+ return common_handle_aligned_attribute (node, name, args, flags,
no_add_attrs, false);
}
struct attribute_spec.handler. */
static tree
-handle_warn_if_not_aligned_attribute (tree *node, tree ARG_UNUSED (name),
+handle_warn_if_not_aligned_attribute (tree *node, tree name,
tree args, int flags,
bool *no_add_attrs)
{
- return common_handle_aligned_attribute (node, args, flags,
+ return common_handle_aligned_attribute (node, name, args, flags,
no_add_attrs, true);
}
int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
- DECL_PURE_P (*node) = 1;
- /* ??? TODO: Support types. */
+ {
+ 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);
newdecl);
/* Diagnose inline __attribute__ ((noinline)) which is silly. */
+ const char *noinline = "noinline";
+
if (DECL_DECLARED_INLINE_P (newdecl)
&& DECL_UNINLINABLE (olddecl)
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
+ && lookup_attribute (noinline, DECL_ATTRIBUTES (olddecl)))
warned |= warning (OPT_Wattributes, "inline declaration of %qD follows "
- "declaration with attribute noinline", newdecl);
+ "declaration with attribute %qs", newdecl, noinline);
else if (DECL_DECLARED_INLINE_P (olddecl)
&& DECL_UNINLINABLE (newdecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
- "noinline follows inline declaration ", newdecl);
- else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))
- && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl)))
- warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
- "%qs follows declaration with attribute %qs",
- newdecl, "noinline", "always_inline");
- else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl))
- && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
- warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
- "%qs follows declaration with attribute %qs",
- newdecl, "always_inline", "noinline");
- else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl))
- && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl)))
- warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
- "%qs follows declaration with attribute %qs",
- newdecl, "cold", "hot");
- else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl))
- && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl)))
- warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
- "%qs follows declaration with attribute %qs",
- newdecl, "hot", "cold");
+ "%qs follows inline declaration ", newdecl, noinline);
+
return warned;
}
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * c-decl.c (c_decl_attributes): Look up existing declaration and
+ pass it to decl_attributes.
+
2017-12-06 David Malcolm <dmalcolm@redhat.com>
PR c/83236
attributes = tree_cons (get_identifier ("omp declare target"),
NULL_TREE, attributes);
}
- return decl_attributes (node, attributes, flags);
+
+ /* Look up the current declaration with all the attributes merged
+ so far so that attributes on the current declaration that's
+ about to be pushed that conflict with the former can be detected,
+ diagnosed, and rejected as appropriate. */
+ tree last_decl = lookup_name (DECL_NAME (*node));
+ if (!last_decl)
+ last_decl = lookup_name_in_scope (DECL_NAME (*node), external_scope);
+
+ return decl_attributes (node, attributes, flags, last_decl);
}
static const struct attribute_spec vms_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { COMMON_OBJECT, 0, 1, true, false, false, common_object_handler, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ affects_type_identity, exclusions } */
+ { COMMON_OBJECT, 0, 1, true, false, false, common_object_handler, false,
+ NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
void
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
- { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute, true },
+ { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute,
+ true, NULL },
/* Function calls made to this symbol must be done indirectly, because
it may lie outside of the 21/25 bit addressing range of a normal function
call. */
- { "long_call", 0, 0, false, true, true, NULL, false },
+ { "long_call", 0, 0, false, true, true, NULL, false, NULL },
/* Whereas these functions are always known to reside within the 25 bit
addressing range of unconditionalized bl. */
- { "medium_call", 0, 0, false, true, true, NULL, false },
+ { "medium_call", 0, 0, false, true, true, NULL, false, NULL },
/* And these functions are always known to reside within the 21 bit
addressing range of blcc. */
- { "short_call", 0, 0, false, true, true, NULL, false },
+ { "short_call", 0, 0, false, true, true, NULL, false, NULL },
/* Function which are not having the prologue and epilogue generated
by the compiler. */
- { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false,
+ NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
static int arc_comp_type_attributes (const_tree, const_tree);
static void arc_file_start (void);
static const struct attribute_spec arm_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
/* Function calls made to this symbol must be done indirectly, because
it may lie outside of the 26 bit addressing range of a normal function
call. */
- { "long_call", 0, 0, false, true, true, NULL, false },
+ { "long_call", 0, 0, false, true, true, NULL, false, NULL },
/* Whereas these functions are always known to reside within the 26 bit
addressing range. */
- { "short_call", 0, 0, false, true, true, NULL, false },
+ { "short_call", 0, 0, false, true, true, NULL, false, NULL },
/* Specify the procedure call conventions for a function. */
{ "pcs", 1, 1, false, true, true, arm_handle_pcs_attribute,
- false },
+ false, NULL },
/* Interrupt Service Routines have special prologue and epilogue requirements. */
{ "isr", 0, 1, false, false, false, arm_handle_isr_attribute,
- false },
+ false, NULL },
{ "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute,
- false },
+ false, NULL },
{ "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute,
- false },
+ false, NULL },
#ifdef ARM_PE
/* ARM/PE has three new attributes:
interfacearm - ?
them with spaces. We do NOT support this. Instead, use __declspec
multiple times.
*/
- { "dllimport", 0, 0, true, false, false, NULL, false },
- { "dllexport", 0, 0, true, false, false, NULL, false },
+ { "dllimport", 0, 0, true, false, false, NULL, false, NULL },
+ { "dllexport", 0, 0, true, false, false, NULL, false, NULL },
{ "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute,
- false },
+ false, NULL },
#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
- { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false },
- { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false },
+ { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false,
+ NULL },
+ { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false,
+ NULL },
{ "notshared", 0, 0, false, true, false, arm_handle_notshared_attribute,
- false },
+ false, NULL },
#endif
/* ARMv8-M Security Extensions support. */
{ "cmse_nonsecure_entry", 0, 0, true, false, false,
- arm_handle_cmse_nonsecure_entry, false },
+ arm_handle_cmse_nonsecure_entry, false, NULL },
{ "cmse_nonsecure_call", 0, 0, true, false, false,
- arm_handle_cmse_nonsecure_call, true },
- { NULL, 0, 0, false, false, false, NULL, false }
+ arm_handle_cmse_nonsecure_call, true, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Initialize the GCC target structure. */
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
{ "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute,
- false },
+ false, NULL },
{ "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute,
- false },
+ false, NULL },
{ "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute,
- false },
+ false, NULL },
{ "no_gccisr", 0, 0, true, false, false, avr_handle_fndecl_attribute,
- false },
+ false, NULL },
{ "naked", 0, 0, false, true, true, avr_handle_fntype_attribute,
- false },
+ false, NULL },
{ "OS_task", 0, 0, false, true, true, avr_handle_fntype_attribute,
- false },
+ false, NULL },
{ "OS_main", 0, 0, false, true, true, avr_handle_fntype_attribute,
- false },
+ false, NULL },
{ "io", 0, 1, true, false, false, avr_handle_addr_attribute,
- false },
+ false, NULL },
{ "io_low", 0, 1, true, false, false, avr_handle_addr_attribute,
- false },
+ false, NULL },
{ "address", 1, 1, true, false, false, avr_handle_addr_attribute,
- false },
+ false, NULL },
{ "absdata", 0, 0, true, false, false, avr_handle_absdata_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
static const struct attribute_spec bfin_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "interrupt_handler", 0, 0, false, true, true, handle_int_attribute,
- false },
+ false, NULL },
{ "exception_handler", 0, 0, false, true, true, handle_int_attribute,
- false },
- { "nmi_handler", 0, 0, false, true, true, handle_int_attribute, false },
- { "nesting", 0, 0, false, true, true, NULL, false },
- { "kspisusp", 0, 0, false, true, true, NULL, false },
- { "saveall", 0, 0, false, true, true, NULL, false },
+ false, NULL },
+ { "nmi_handler", 0, 0, false, true, true, handle_int_attribute, false,
+ NULL },
+ { "nesting", 0, 0, false, true, true, NULL, false, NULL },
+ { "kspisusp", 0, 0, false, true, true, NULL, false, NULL },
+ { "saveall", 0, 0, false, true, true, NULL, false, NULL },
{ "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute,
- false },
+ false, NULL },
{ "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute,
- false },
+ false, NULL },
{ "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute,
- false },
+ false, NULL },
{ "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
- false },
+ false, NULL },
{ "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
- false },
+ false, NULL },
{ "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
- false },
- { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
static const struct attribute_spec cr16_attribute_table[] = {
/* ISRs have special prologue and epilogue requirements. */
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity }. */
- {"interrupt", 0, 0, false, true, true, NULL, false},
- {NULL, 0, 0, false, false, false, NULL, false}
+ affects_type_identity, exclusions }. */
+ {"interrupt", 0, 0, false, true, true, NULL, false, NULL},
+ {NULL, 0, 0, false, false, false, NULL, false, NULL}
};
/* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive
static const struct attribute_spec epiphany_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
- { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
- { "long_call", 0, 0, false, true, true, NULL, false },
- { "short_call", 0, 0, false, true, true, NULL, false },
- { "disinterrupt", 0, 0, false, true, true, NULL, true },
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity, exclusions } */
+ { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true, NULL },
+ { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false, NULL },
+ { "long_call", 0, 0, false, true, true, NULL, false, NULL },
+ { "short_call", 0, 0, false, true, true, NULL, false, NULL },
+ { "disinterrupt", 0, 0, false, true, true, NULL, true, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Handle an "interrupt" attribute; arguments as in
static const struct attribute_spec h8300_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "interrupt_handler", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
+ h8300_handle_fndecl_attribute, false, NULL },
{ "saveall", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
+ h8300_handle_fndecl_attribute, false, NULL },
{ "OS_Task", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
+ h8300_handle_fndecl_attribute, false, NULL },
{ "monitor", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
+ h8300_handle_fndecl_attribute, false, NULL },
{ "function_vector", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
+ h8300_handle_fndecl_attribute, false, NULL },
{ "eightbit_data", 0, 0, true, false, false,
- h8300_handle_eightbit_data_attribute, false },
+ h8300_handle_eightbit_data_attribute, false, NULL },
{ "tiny_data", 0, 0, true, false, false,
- h8300_handle_tiny_data_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ h8300_handle_tiny_data_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
static const struct attribute_spec ix86_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
/* Stdcall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "stdcall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* Fastcall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* Thiscall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "thiscall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* Cdecl attribute says the callee is a normal C declaration */
{ "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* Regparm attribute specifies how many integer arguments are to be
passed in registers. */
{ "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* Sseregparm attribute says we are using x86_64 calling conventions
for FP arguments. */
{ "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute,
- true },
+ true, NULL },
/* The transactional memory builtins are implicitly regparm or fastcall
depending on the ABI. Override the generic do-nothing attribute that
these builtins were declared with. */
{ "*tm regparm", 0, 0, false, true, true, ix86_handle_tm_regparm_attribute,
- true },
+ true, NULL },
/* force_align_arg_pointer says this function realigns the stack at entry. */
{ (const char *)&ix86_force_align_arg_pointer_string, 0, 0,
- false, true, true, ix86_handle_force_align_arg_pointer_attribute, false },
+ false, true, true, ix86_handle_force_align_arg_pointer_attribute, false,
+ NULL },
#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
- { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false },
- { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false },
+ { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false, NULL },
+ { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false, NULL },
{ "shared", 0, 0, true, false, false, ix86_handle_shared_attribute,
- false },
+ false, NULL },
#endif
{ "ms_struct", 0, 0, false, false, false, ix86_handle_struct_attribute,
- false },
+ false, NULL },
{ "gcc_struct", 0, 0, false, false, false, ix86_handle_struct_attribute,
- false },
+ false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE,
#endif
/* ms_abi and sysv_abi calling convention function attributes. */
- { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true },
- { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true },
- { "ms_abi va_list", 0, 0, false, false, false, NULL, false },
- { "sysv_abi va_list", 0, 0, false, false, false, NULL, false },
+ { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true, NULL },
+ { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true,
+ NULL },
+ { "ms_abi va_list", 0, 0, false, false, false, NULL, false, NULL },
+ { "sysv_abi va_list", 0, 0, false, false, false, NULL, false, NULL },
{ "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute,
- false },
+ false, NULL },
{ "callee_pop_aggregate_return", 1, 1, false, true, true,
- ix86_handle_callee_pop_aggregate_return, true },
+ ix86_handle_callee_pop_aggregate_return, true, NULL },
{ "interrupt", 0, 0, false, true, true,
- ix86_handle_interrupt_attribute, false },
+ ix86_handle_interrupt_attribute, false, NULL },
{ "no_caller_saved_registers", 0, 0, false, true, true,
- ix86_handle_no_caller_saved_registers_attribute, false },
+ ix86_handle_no_caller_saved_registers_attribute, false, NULL },
{ "naked", 0, 0, true, false, false,
- ix86_handle_fndecl_attribute, false },
+ ix86_handle_fndecl_attribute, false, NULL },
/* End element. */
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Implement targetm.vectorize.builtin_vectorization_cost. */
static const struct attribute_spec ia64_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "syscall_linkage", 0, 0, false, true, true, NULL, false },
+ affects_type_identity, exclusions } */
+ { "syscall_linkage", 0, 0, false, true, true, NULL, false, NULL },
{ "model", 1, 1, true, false, false, ia64_handle_model_attribute,
- false },
+ false, NULL },
#if TARGET_ABI_OPEN_VMS
{ "common_object", 1, 1, true, false, false,
- ia64_vms_common_object_attribute, false },
+ ia64_vms_common_object_attribute, false, NULL },
#endif
{ "version_id", 1, 1, true, false, false,
- ia64_handle_version_id_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ ia64_handle_version_id_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE m32c_attribute_table
static const struct attribute_spec m32c_attribute_table[] = {
- {"interrupt", 0, 0, false, false, false, interrupt_handler, false},
- {"bank_switch", 0, 0, false, false, false, interrupt_handler, false},
- {"fast_interrupt", 0, 0, false, false, false, interrupt_handler, false},
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity, exclusions } */
+ {"interrupt", 0, 0, false, false, false, interrupt_handler, false, NULL},
+ {"bank_switch", 0, 0, false, false, false, interrupt_handler, false, NULL},
+ {"fast_interrupt", 0, 0, false, false, false, interrupt_handler, false, NULL},
{"function_vector", 1, 1, true, false, false, function_vector_handler,
- false},
- {0, 0, 0, 0, 0, 0, 0, false}
+ false, NULL},
+ {0, 0, 0, 0, 0, 0, 0, false, NULL}
};
#undef TARGET_COMP_TYPE_ATTRIBUTES
static const struct attribute_spec m32r_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "interrupt", 0, 0, true, false, false, NULL, false },
+ affects_type_identity, exclusions } */
+ { "interrupt", 0, 0, true, false, false, NULL, false, NULL },
{ "model", 1, 1, true, false, false, m32r_handle_model_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Initialize the GCC target structure. */
static const struct attribute_spec m68k_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "interrupt", 0, 0, true, false, false, m68k_handle_fndecl_attribute,
false },
{ "interrupt_handler", 0, 0, true, false, false,
- m68k_handle_fndecl_attribute, false },
+ m68k_handle_fndecl_attribute, false, NULL },
{ "interrupt_thread", 0, 0, true, false, false,
- m68k_handle_fndecl_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ m68k_handle_fndecl_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
struct gcc_target targetm = TARGET_INITIALIZER;
static const struct attribute_spec mcore_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "dllexport", 0, 0, true, false, false, NULL, false },
- { "dllimport", 0, 0, true, false, false, NULL, false },
+ affects_type_identity, exclusions } */
+ { "dllexport", 0, 0, true, false, false, NULL, false, NULL },
+ { "dllimport", 0, 0, true, false, false, NULL, false, NULL },
{ "naked", 0, 0, true, false, false, mcore_handle_naked_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Initialize the GCC target structure. */
const struct attribute_spec microblaze_attribute_table[] = {
/* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
- affects_type_identity */
+ affects_type_identity, exclusions */
{"interrupt_handler", 0, 0, true, false, false, NULL,
- false },
+ false, NULL },
{"break_handler", 0, 0, true, false, false, NULL,
- false },
+ false, NULL },
{"fast_interrupt", 0, 0, true, false, false, NULL,
- false },
+ false, NULL },
{"save_volatiles" , 0, 0, true, false, false, NULL,
- false },
+ false, NULL },
{ NULL, 0, 0, false, false, false, NULL,
- false }
+ false, NULL }
};
static int microblaze_interrupt_function_p (tree);
static const struct attribute_spec mips_attribute_table[] = {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
om_diagnostic } */
- { "long_call", 0, 0, false, true, true, NULL, false },
- { "short_call", 0, 0, false, true, true, NULL, false },
- { "far", 0, 0, false, true, true, NULL, false },
- { "near", 0, 0, false, true, true, NULL, false },
+ { "long_call", 0, 0, false, true, true, NULL, false, NULL },
+ { "short_call", 0, 0, false, true, true, NULL, false, NULL },
+ { "far", 0, 0, false, true, true, NULL, false, NULL },
+ { "near", 0, 0, false, true, true, NULL, false, NULL },
/* We would really like to treat "mips16" and "nomips16" as type
attributes, but GCC doesn't provide the hooks we need to support
the right conversion rules. As declaration attributes, they affect
code generation but don't carry other semantics. */
- { "mips16", 0, 0, true, false, false, NULL, false },
- { "nomips16", 0, 0, true, false, false, NULL, false },
- { "micromips", 0, 0, true, false, false, NULL, false },
- { "nomicromips", 0, 0, true, false, false, NULL, false },
- { "nocompression", 0, 0, true, false, false, NULL, false },
+ { "mips16", 0, 0, true, false, false, NULL, false, NULL },
+ { "nomips16", 0, 0, true, false, false, NULL, false, NULL },
+ { "micromips", 0, 0, true, false, false, NULL, false, NULL },
+ { "nomicromips", 0, 0, true, false, false, NULL, false, NULL },
+ { "nocompression", 0, 0, true, false, false, NULL, false, NULL },
/* Allow functions to be specified as interrupt handlers */
{ "interrupt", 0, 1, false, true, true, mips_handle_interrupt_attr,
- false },
+ false, NULL },
{ "use_shadow_register_set", 0, 1, false, true, true,
- mips_handle_use_shadow_register_set_attr, false },
- { "keep_interrupts_masked", 0, 0, false, true, true, NULL, false },
- { "use_debug_exception_return", 0, 0, false, true, true, NULL, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ mips_handle_use_shadow_register_set_attr, false, NULL },
+ { "keep_interrupts_masked", 0, 0, false, true, true, NULL, false, NULL },
+ { "use_debug_exception_return", 0, 0, false, true, true, NULL, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* A table describing all the processors GCC knows about; see
/* Name min_num_args type_req, affects_type_identity
max_num_args, fn_type_req
decl_req handler. */
- { ATTR_INTR, 0, 1, true, false, false, msp430_attr, false },
- { ATTR_NAKED, 0, 0, true, false, false, msp430_attr, false },
- { ATTR_REENT, 0, 0, true, false, false, msp430_attr, false },
- { ATTR_CRIT, 0, 0, true, false, false, msp430_attr, false },
- { ATTR_WAKEUP, 0, 0, true, false, false, msp430_attr, false },
-
- { ATTR_LOWER, 0, 0, true, false, false, msp430_section_attr, false },
- { ATTR_UPPER, 0, 0, true, false, false, msp430_section_attr, false },
- { ATTR_EITHER, 0, 0, true, false, false, msp430_section_attr, false },
-
- { ATTR_NOINIT, 0, 0, true, false, false, msp430_data_attr, false },
- { ATTR_PERSIST, 0, 0, true, false, false, msp430_data_attr, false },
-
- { NULL, 0, 0, false, false, false, NULL, false }
+ { ATTR_INTR, 0, 1, true, false, false, msp430_attr, false, NULL },
+ { ATTR_NAKED, 0, 0, true, false, false, msp430_attr, false, NULL },
+ { ATTR_REENT, 0, 0, true, false, false, msp430_attr, false, NULL },
+ { ATTR_CRIT, 0, 0, true, false, false, msp430_attr, false, NULL },
+ { ATTR_WAKEUP, 0, 0, true, false, false, msp430_attr, false, NULL },
+
+ { ATTR_LOWER, 0, 0, true, false, false, msp430_section_attr, false,
+ NULL },
+ { ATTR_UPPER, 0, 0, true, false, false, msp430_section_attr, false,
+ NULL },
+ { ATTR_EITHER, 0, 0, true, false, false, msp430_section_attr, false,
+ NULL },
+
+ { ATTR_NOINIT, 0, 0, true, false, false, msp430_data_attr, false,
+ NULL },
+ { ATTR_PERSIST, 0, 0, true, false, false, msp430_data_attr, false,
+ NULL },
+
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
#undef TARGET_ASM_FUNCTION_PROLOGUE
function_type_required, handler, affects_type_identity } */
/* The interrupt vid: [0-63]+ (actual vector number starts from 9 to 72). */
- { "interrupt", 1, 64, false, false, false, NULL, false },
+ { "interrupt", 1, 64, false, false, false, NULL, false, NULL },
/* The exception vid: [1-8]+ (actual vector number starts from 1 to 8). */
- { "exception", 1, 8, false, false, false, NULL, false },
+ { "exception", 1, 8, false, false, false, NULL, false, NULL },
/* Argument is user's interrupt numbers. The vector number is always 0. */
- { "reset", 1, 1, false, false, false, NULL, false },
+ { "reset", 1, 1, false, false, false, NULL, false, NULL },
/* The attributes describing isr nested type. */
- { "nested", 0, 0, false, false, false, NULL, false },
- { "not_nested", 0, 0, false, false, false, NULL, false },
- { "nested_ready", 0, 0, false, false, false, NULL, false },
+ { "nested", 0, 0, false, false, false, NULL, false, NULL },
+ { "not_nested", 0, 0, false, false, false, NULL, false, NULL },
+ { "nested_ready", 0, 0, false, false, false, NULL, false, NULL },
/* The attributes describing isr register save scheme. */
- { "save_all", 0, 0, false, false, false, NULL, false },
- { "partial_save", 0, 0, false, false, false, NULL, false },
+ { "save_all", 0, 0, false, false, false, NULL, false, NULL },
+ { "partial_save", 0, 0, false, false, false, NULL, false, NULL },
/* The attributes used by reset attribute. */
- { "nmi", 1, 1, false, false, false, NULL, false },
- { "warm", 1, 1, false, false, false, NULL, false },
+ { "nmi", 1, 1, false, false, false, NULL, false, NULL },
+ { "warm", 1, 1, false, false, false, NULL, false, NULL },
/* The attribute telling no prologue/epilogue. */
- { "naked", 0, 0, false, false, false, NULL, false },
+ { "naked", 0, 0, false, false, false, NULL, false, NULL },
/* The last attribute spec is set to be NULL. */
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
static const struct attribute_spec nvptx_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "kernel", 0, 0, true, false, false, nvptx_handle_kernel_attribute, false },
- { "shared", 0, 0, true, false, false, nvptx_handle_shared_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ affects_type_identity, exclusions } */
+ { "kernel", 0, 0, true, false, false, nvptx_handle_kernel_attribute, false,
+ NULL },
+ { "shared", 0, 0, true, false, false, nvptx_handle_shared_attribute, false,
+ NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Limit vector alignments to BIGGEST_ALIGNMENT. */
static const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute,
- false },
+ false, NULL },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
- false },
+ false, NULL },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
- false },
+ false, NULL },
{ "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
- false },
+ false, NULL },
{ "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
- false },
+ false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE,
#endif
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
#ifndef TARGET_PROFILE_KERNEL
/* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity. */
{ "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
- false },
+ false, NULL },
{ "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
- false },
+ false, NULL },
{ "naked", 0, 0, true, false, false, rl78_handle_naked_attribute,
- false },
+ false, NULL },
{ "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
static const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute,
- false },
+ false, NULL },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
- false },
+ false, NULL },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
- false },
+ false, NULL },
{ "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
- false },
+ false, NULL },
{ "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
- false },
+ false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE,
#endif
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
#ifndef TARGET_PROFILE_KERNEL
const struct attribute_spec rx_attribute_table[] =
{
/* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity. */
+ affects_type_identity, exclusions. */
{ "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
- false },
+ false, NULL },
{ "interrupt", 0, -1, true, false, false, rx_handle_func_attribute,
- false },
+ false, NULL },
{ "naked", 0, 0, true, false, false, rx_handle_func_attribute,
- false },
+ false, NULL },
{ "vector", 1, -1, true, false, false, rx_handle_vector_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */
}
static const struct attribute_spec s390_attribute_table[] = {
- { "hotpatch", 2, 2, true, false, false, s390_handle_hotpatch_attribute, false },
- { "s390_vector_bool", 0, 0, false, true, false, s390_handle_vectorbool_attribute, true },
+ { "hotpatch", 2, 2, true, false, false,
+ s390_handle_hotpatch_attribute, false, NULL },
+ { "s390_vector_bool", 0, 0, false, true, false,
+ s390_handle_vectorbool_attribute, true, NULL },
/* End element. */
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Return the alignment for LABEL. We default to the -falign-labels
static const struct attribute_spec sh_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "interrupt_handler", 0, 0, true, false, false,
- sh_handle_interrupt_handler_attribute, false },
+ sh_handle_interrupt_handler_attribute, false, NULL },
{ "sp_switch", 1, 1, true, false, false,
- sh_handle_sp_switch_attribute, false },
+ sh_handle_sp_switch_attribute, false, NULL },
{ "trap_exit", 1, 1, true, false, false,
- sh_handle_trap_exit_attribute, false },
+ sh_handle_trap_exit_attribute, false, NULL },
{ "renesas", 0, 0, false, true, false,
- sh_handle_renesas_attribute, false },
+ sh_handle_renesas_attribute, false, NULL },
{ "trapa_handler", 0, 0, true, false, false,
- sh_handle_interrupt_handler_attribute, false },
+ sh_handle_interrupt_handler_attribute, false, NULL },
{ "nosave_low_regs", 0, 0, true, false, false,
- sh_handle_interrupt_handler_attribute, false },
+ sh_handle_interrupt_handler_attribute, false, NULL },
{ "resbank", 0, 0, true, false, false,
- sh_handle_resbank_handler_attribute, false },
+ sh_handle_resbank_handler_attribute, false, NULL },
{ "function_vector", 1, 1, true, false, false,
- sh2a_handle_function_vector_handler_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ sh2a_handle_function_vector_handler_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
/* Initialize the GCC target structure. */
static const struct attribute_spec sparc_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- do_diagnostic } */
+ do_diagnostic, exclusions } */
SUBTARGET_ATTRIBUTE_TABLE,
- { NULL, 0, 0, false, false, false, NULL, false }
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
#endif
\f
static const struct attribute_spec spu_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "naked", 0, 0, true, false, false, spu_handle_fndecl_attribute,
- false },
+ false, NULL },
{ "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute,
- false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* TARGET overrides. */
static const struct attribute_spec xstormy16_attribute_table[] =
{
/* name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity. */
+ affects_type_identity, exclusions. */
{ "interrupt", 0, 0, false, true, true,
- xstormy16_handle_interrupt_attribute , false },
+ xstormy16_handle_interrupt_attribute , false, NULL },
{ "BELOW100", 0, 0, false, false, false,
- xstormy16_handle_below100_attribute, false },
+ xstormy16_handle_below100_attribute, false, NULL },
{ "below100", 0, 0, false, false, false,
- xstormy16_handle_below100_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ xstormy16_handle_below100_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Handle an "interrupt" attribute;
static const struct attribute_spec v850_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "interrupt_handler", 0, 0, true, false, false,
- v850_handle_interrupt_attribute, false },
+ v850_handle_interrupt_attribute, false, NULL },
{ "interrupt", 0, 0, true, false, false,
- v850_handle_interrupt_attribute, false },
+ v850_handle_interrupt_attribute, false, NULL },
{ "sda", 0, 0, true, false, false,
- v850_handle_data_area_attribute, false },
+ v850_handle_data_area_attribute, false, NULL },
{ "tda", 0, 0, true, false, false,
- v850_handle_data_area_attribute, false },
+ v850_handle_data_area_attribute, false, NULL },
{ "zda", 0, 0, true, false, false,
- v850_handle_data_area_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ v850_handle_data_area_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
\f
static void
static const struct attribute_spec visium_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
- {NULL, 0, 0, false, false, false, NULL, false}
+ affects_type_identity, exclusions } */
+ {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false,
+ NULL},
+ {NULL, 0, 0, false, false, false, NULL, false, NULL},
};
static struct machine_function *visium_init_machine_status (void);
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * cp-tree.h (decls_match): Add default argument.
+ * decl.c (decls_match): Avoid calling into the target back end
+ and triggering an error.
+ * decl2.c (cplus_decl_attributes): Look up existing declaration and
+ pass it to decl_attributes.
+ * tree.c (cxx_attribute_table): Initialize new member of struct
+ attribute_spec.
+
2017-12-06 Jakub Jelinek <jakub@redhat.com>
PR c++/80259
extern bool note_iteration_stmt_body_start (void);
extern void note_iteration_stmt_body_end (bool);
extern tree make_lambda_name (void);
-extern int decls_match (tree, tree);
+extern int decls_match (tree, tree, bool = true);
extern bool maybe_version_functions (tree, tree);
extern tree duplicate_decls (tree, tree, bool);
extern tree declare_local_label (tree);
`const int&'. */
int
-decls_match (tree newdecl, tree olddecl)
+decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
{
int types_match;
if (types_match
&& !DECL_EXTERN_C_P (newdecl)
&& !DECL_EXTERN_C_P (olddecl)
+ && record_versions
&& maybe_version_functions (newdecl, olddecl))
return 0;
}
attributes, flags);
}
else
- decl_attributes (decl, attributes, flags);
+ {
+ tree last_decl = (DECL_P (*decl) && DECL_NAME (*decl)
+ ? lookup_name (DECL_NAME (*decl)) : NULL_TREE);
+
+ if (last_decl && TREE_CODE (last_decl) == OVERLOAD)
+ for (ovl_iterator iter (last_decl, true); ; ++iter)
+ {
+ if (!iter)
+ {
+ last_decl = NULL_TREE;
+ break;
+ }
+
+ if (TREE_CODE (*iter) == OVERLOAD)
+ continue;
+
+ if (decls_match (*decl, *iter, /*record_decls=*/false))
+ {
+ last_decl = *iter;
+ break;
+ }
+ }
+
+ decl_attributes (decl, attributes, flags, last_decl);
+ }
if (TREE_CODE (*decl) == TYPE_DECL)
SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
const struct attribute_spec cxx_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "init_priority", 1, 1, true, false, false,
- handle_init_priority_attribute, false },
+ handle_init_priority_attribute, false, NULL },
{ "abi_tag", 1, -1, false, false, false,
- handle_abi_tag_attribute, true },
- { NULL, 0, 0, false, false, false, NULL, false }
+ handle_abi_tag_attribute, true, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Table of C++ standard attributes. */
const struct attribute_spec std_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "maybe_unused", 0, 0, false, false, false,
- handle_unused_attribute, false },
+ handle_unused_attribute, false, NULL },
{ "nodiscard", 0, 0, false, false, false,
- handle_nodiscard_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ handle_nodiscard_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Handle an "init_priority" attribute; arguments as in
@cindex @code{const} function attribute
@cindex functions that have no side effects
Many functions do not examine any values except their arguments, and
-have no effects except the return value. Basically this is just slightly
-more strict class than the @code{pure} attribute below, since function is not
-allowed to read global memory.
+have no effects except to return a value. Calls to such functions lend
+themselves to optimization such as common subexpression elimination.
+The @code{const} attribute imposes greater restrictions on a function's
+definition than the similar @code{pure} attribute below because it prohibits
+the function from reading global variables. Consequently, the presence of
+the attribute on a function declarations allows GCC to emit more efficient
+code for some calls to the function. Decorating the same function with
+both the @code{const} and the @code{pure} attribute is diagnnosed.
@cindex pointer arguments
Note that a function that has pointer arguments and examines the data
@cindex functions that have no side effects
Many functions have no effects except the return value and their
return value depends only on the parameters and/or global variables.
-Such a function can be subject
+Calls to such functions can be subject
to common subexpression elimination and loop optimization just as an
arithmetic operator would be. These functions should be declared
with the attribute @code{pure}. For example,
depending on volatile memory or other system resource, that may change between
two consecutive calls (such as @code{feof} in a multithreading environment).
+The @code{pure} attribute imposes similar but looser restrictions on
+a function's defintion than the @code{const} attribute: it allows the
+function to read global variables. Decorating the same function with
+both the @code{pure} and the @code{const} attribute is diagnosed.
+
@item returns_nonnull
@cindex @code{returns_nonnull} function attribute
The @code{returns_nonnull} attribute specifies that the function
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * f95-lang.c (gfc_attribute_table): Initialize new member of struct
+ attribute_spec.
+
2017-12-03 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/36313
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */
{ "omp declare target", 0, 0, true, false, false,
- gfc_handle_omp_declare_target_attribute, false },
+ gfc_handle_omp_declare_target_attribute, false, NULL },
{ "omp declare target link", 0, 0, true, false, false,
- gfc_handle_omp_declare_target_attribute, false },
+ gfc_handle_omp_declare_target_attribute, false, NULL },
{ "oacc function", 0, -1, true, false, false,
- gfc_handle_omp_declare_target_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ gfc_handle_omp_declare_target_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
#undef LANG_HOOKS_NAME
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * lto-lang.c (lto_attribute_table): Initialize new member of struct
+ attribute_spec.
+
2017-11-30 Jakub Jelinek <jakub@redhat.com>
* lto.c (create_subid_section_table): Use ; instead of ;;.
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
static tree handle_format_arg_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 ("noreturn", true, true, true),
+ 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),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_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)
+};
+
/* Table of machine-independent attributes supported in GIMPLE. */
const struct attribute_spec lto_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- do_diagnostic } */
+ do_diagnostic, exclusions } */
{ "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute, false },
+ handle_noreturn_attribute, false,
+ attr_noreturn_exclusions },
{ "leaf", 0, 0, true, false, false,
- handle_leaf_attribute, false },
+ handle_leaf_attribute, false, NULL },
/* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false,
- handle_const_attribute, false },
+ handle_const_attribute, false,
+ attr_const_pure_exclusions },
{ "malloc", 0, 0, true, false, false,
- handle_malloc_attribute, false },
+ handle_malloc_attribute, false, NULL },
{ "pure", 0, 0, true, false, false,
- handle_pure_attribute, false },
+ handle_pure_attribute, false,
+ attr_const_pure_exclusions },
{ "no vops", 0, 0, true, false, false,
- handle_novops_attribute, false },
+ handle_novops_attribute, false, NULL },
{ "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute, false },
+ handle_nonnull_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute, false },
+ handle_nothrow_attribute, false, NULL },
{ "patchable_function_entry", 1, 2, true, false, false,
handle_patchable_function_entry_attribute,
- false },
+ false, NULL },
{ "returns_twice", 0, 0, true, false, false,
- handle_returns_twice_attribute, false },
+ handle_returns_twice_attribute, false,
+ attr_returns_twice_exclusions },
{ "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute, false },
+ handle_sentinel_attribute, false, NULL },
{ "type generic", 0, 0, false, true, true,
- handle_type_generic_attribute, false },
+ handle_type_generic_attribute, false, NULL },
{ "fn spec", 1, 1, false, true, true,
- handle_fnspec_attribute, false },
+ handle_fnspec_attribute, false, NULL },
{ "transaction_pure", 0, 0, false, true, true,
- handle_transaction_pure_attribute, false },
+ handle_transaction_pure_attribute, false, NULL },
/* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true,
- ignore_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ ignore_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
/* Give the specifications for the format attributes, used by C and all
const struct attribute_spec lto_format_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
+ affects_type_identity, exclusions } */
{ "format", 3, 3, false, true, true,
- handle_format_attribute, false },
+ handle_format_attribute, false, NULL },
{ "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ handle_format_arg_attribute, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL, false, NULL }
};
enum built_in_attribute
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
+ if (TREE_CODE (*node) != FUNCTION_DECL
+ || !DECL_BUILT_IN (*node))
+ inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name);
+
tree type = TREE_TYPE (*node);
/* See FIXME comment on noreturn in c_common_attribute_table. */
#include "target.h"
#include "langhooks.h"
#include "options.h"
+#include "stringpool.h"
+#include "attribs.h"
/* This function needed to be split out from selftest.c as it references
tests from the whole source tree, and so is within
spellcheck_c_tests ();
spellcheck_tree_c_tests ();
tree_cfg_c_tests ();
+ attribute_c_tests ();
/* This one relies on most of the above. */
function_tests_c_tests ();
/* Declarations for specific families of tests (by source file), in
alphabetical order. */
+extern void attribute_c_tests ();
extern void bitmap_c_tests ();
extern void sbitmap_c_tests ();
extern void diagnostic_c_tests ();
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * c-c++-common/Wattributes-2.c: New test.
+ * c-c++-common/Wattributes.c: New test.
+ * c-c++-common/attributes-3.c: Adjust.
+ * gcc.dg/Wattributes-6.c: New test.
+ * gcc.dg/Wattributes-7.c: New test.
+ * gcc.dg/attr-noinline.c
+ * gcc.dg/pr44964.c: Same.
+ * gcc.dg/torture/pr42363.c: Same.
+ * gcc.dg/tree-ssa/ssa-ccp-2.c: Same.
+
2017-12-07 Tamar Christina <tamar.christina@arm.com>
PR target/82641
extern inline int fn1 (void); /* { dg-warning "inline declaration of" } */
extern inline int fn2 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((noinline)) int fn2 (void); /* { dg-warning "attribute noinline follows inline declaration" } */
+extern __attribute__((noinline)) int fn2 (void); /* { dg-warning "attribute .noinline. follows inline declaration" } */
extern __attribute__((always_inline)) int fn3 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((noinline)) int fn3 (void); /* { dg-warning "attribute .noinline. follows declaration with attribute .always_inline." } */
+extern __attribute__((noinline)) int fn3 (void); /* { dg-warning "attribute .noinline." } */
extern __attribute__((noinline)) int fn4 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "attribute .always_inline. follows declaration with attribute .noinline." } */
+extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "attribute .always_inline." } */
extern __attribute__((hot)) int fn5 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((cold)) int fn5 (void); /* { dg-warning "attribute .cold. follows declaration with attribute .hot." } */
+extern __attribute__((cold)) int fn5 (void); /* { dg-warning "attribute .cold." } */
extern __attribute__((cold)) int fn6 (void); /* { dg-message "previous declaration" } */
-extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot. follows declaration with attribute .cold." } */
+extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot." } */
static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */
-static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute noinline" } */
+static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute .noinline." } */
static inline void function_declaration_noinline_after(void) {t();} /* { dg-message "note: previous definition" } */
static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */
-static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute noinline" } */
+static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute .noinline." } */
static void function_declaration_noinline_inline_before(void) {t();}
/* { dg-options "-fkeep-inline-functions -O" } */
static inline __attribute__ ((const))
-void baz (int i)
+int baz (int i)
{
+ return i;
}
static __attribute__ ((always_inline))
return i + 1;
}
-/* This might be regarded as pure and folded, rather than inlined.
- It's pure evil. */
+/* This might be regarded as pure and folded, rather than inlined,
+ but because it's pure evil it's diagnosed and the noreturn attribute
+ is dropped. The const attribute is dropped as well because it's
+ mutually exclusive with pure. */
static int __attribute__ ((pure, const, noreturn))
-barf (void)
-{
+barf (void) {
+ /* { dg-warning "ignoring attribute .const." "const" { target *-*-* } .-1 } */
+ /* { dg-warning "ignoring attribute .noreturn." "noreturn" { target *-*-* } .-2 } */
} /* { dg-warning "does return" } */
static int __attribute__ ((pure, const))
-bark (void)
-{
+bark (void) { /* { dg-warning "ignoring attribute .const." } */
barf ();
}
int test99 (int *intarr)
{
- extern int foo9 (int) __attribute__ ((pure));
+ extern int foo99 (int) __attribute__ ((pure));
int h, v;
g9 = 9;
- h = foo9 (g9);
+ h = foo99 (g9);
v = g9;
if (v != 9)
link_error ();
return g9;
}
-extern int foo99 (int);
+/* foo9 is const because of its declaration in test9. */
+extern int foo9 (int);
int test999 (int *arr)
{
v1 = g9;
if (v1 != 9)
link_error ();
- l = foo99 (l);
+ l = foo9 (l);
return v1 + l;
}
+/* foo99 is pure because of its declaration in test99. */
+extern int foo9 (int);
int test9999 (void)
{
int flags, bool *no_add_attrs);
/* Specifies if attribute affects type's identity. */
bool affects_type_identity;
+
+ /* Specifies the name of an attribute that's mutually exclusive with
+ this one, and whether the relationship applies to the function,
+ variable, or type form of the attribute. */
+ struct exclusions {
+ const char *name;
+ bool function;
+ bool variable;
+ bool type;
+ };
+
+ /* An array of attribute exclusions describing names of other attributes
+ that this attribute is mutually exclusive with. */
+ const exclusions *exclude;
};
/* These functions allow a front-end to perform a manual layout of a
+2017-12-07 Martin Sebor <msebor@redhat.com>
+
+ PR c/81544
+ * include/ext/mt_allocator.h (_M_destroy_thread_key): Remove
+ attribute const.
+
2017-12-05 Jason Merrill <jason@redhat.com>
Jonathan Wakely <jwakely@redhat.com>
}
// XXX GLIBCXX_ABI Deprecated
- _GLIBCXX_CONST void
+ void
_M_destroy_thread_key(void*) throw ();
size_t