PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted

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
This commit is contained in:
Martin Sebor 2017-12-07 16:32:03 +00:00 committed by Martin Sebor
parent 1d8b0222b1
commit 5d9ae53d70
62 changed files with 1113 additions and 474 deletions

View File

@ -1,3 +1,50 @@
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> 2017-12-07 Tamar Christina <tamar.christina@arm.com>
PR target/82641 PR target/82641

View File

@ -1,3 +1,9 @@
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> 2017-12-06 Simon Wright <simon@pushface.org>
PR ada/66205 PR ada/66205

View File

@ -110,45 +110,47 @@ const struct attribute_spec gnat_internal_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity } */
{ "const", 0, 0, true, false, false, handle_const_attribute, { "const", 0, 0, true, false, false, handle_const_attribute,
false }, false, NULL },
{ "nothrow", 0, 0, true, false, false, handle_nothrow_attribute, { "nothrow", 0, 0, true, false, false, handle_nothrow_attribute,
false }, false, NULL },
{ "pure", 0, 0, true, false, false, handle_pure_attribute, { "pure", 0, 0, true, false, false, handle_pure_attribute,
false }, false, NULL },
{ "no vops", 0, 0, true, false, false, handle_novops_attribute, { "no vops", 0, 0, true, false, false, handle_novops_attribute,
false }, false, NULL },
{ "nonnull", 0, -1, false, true, true, handle_nonnull_attribute, { "nonnull", 0, -1, false, true, true, handle_nonnull_attribute,
false }, false, NULL },
{ "sentinel", 0, 1, false, true, true, handle_sentinel_attribute, { "sentinel", 0, 1, false, true, true, handle_sentinel_attribute,
false }, false, NULL },
{ "noreturn", 0, 0, true, false, false, handle_noreturn_attribute, { "noreturn", 0, 0, true, false, false, handle_noreturn_attribute,
false }, false, NULL },
{ "noinline", 0, 0, true, false, false, handle_noinline_attribute, { "noinline", 0, 0, true, false, false, handle_noinline_attribute,
false }, false, NULL },
{ "noclone", 0, 0, true, false, false, handle_noclone_attribute, { "noclone", 0, 0, true, false, false, handle_noclone_attribute,
false }, false, NULL },
{ "leaf", 0, 0, true, false, false, handle_leaf_attribute, { "leaf", 0, 0, true, false, false, handle_leaf_attribute,
false }, false, NULL },
{ "always_inline",0, 0, true, false, false, handle_always_inline_attribute, { "always_inline",0, 0, true, false, false, handle_always_inline_attribute,
false }, false, NULL },
{ "malloc", 0, 0, true, false, false, handle_malloc_attribute, { "malloc", 0, 0, true, false, false, handle_malloc_attribute,
false }, false, NULL },
{ "type generic", 0, 0, false, true, true, handle_type_generic_attribute, { "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, { "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, { "vector_type", 0, 0, false, true, false, handle_vector_type_attribute,
false }, false, NULL },
{ "may_alias", 0, 0, false, true, false, NULL, false }, { "may_alias", 0, 0, false, true, false, NULL, false, NULL },
/* ??? format and format_arg are heavy and not supported, which actually /* ??? format and format_arg are heavy and not supported, which actually
prevents support for stdio builtins, which we however declare as part prevents support for stdio builtins, which we however declare as part
of the common builtins.def contents. */ of the common builtins.def contents. */
{ "format", 3, 3, false, true, true, fake_attribute_handler, false }, { "format", 3, 3, false, true, true, fake_attribute_handler, false,
{ "format_arg", 1, 1, 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 /* Associates a GNAT tree node to a GCC tree node. It is used in

View File

@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h" #include "stor-layout.h"
#include "langhooks.h" #include "langhooks.h"
#include "plugin.h" #include "plugin.h"
#include "selftest.h"
#include "hash-set.h"
/* Table of the tables of attributes (common, language, format, machine) /* Table of the tables of attributes (common, language, format, machine)
searched. */ searched. */
@ -94,7 +96,7 @@ static bool attributes_initialized = false;
static const struct attribute_spec empty_attribute_table[] = 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 base name of the attribute. Ie '__attr__' is turned into 'attr'.
@ -343,6 +345,97 @@ get_attribute_namespace (const_tree attr)
return get_identifier ("gnu"); 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, /* 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, which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
@ -354,7 +447,8 @@ get_attribute_namespace (const_tree attr)
a decl attribute to the declaration rather than to its type). */ a decl attribute to the declaration rather than to its type). */
tree 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 a;
tree returned_attrs = NULL_TREE; tree returned_attrs = NULL_TREE;
@ -433,6 +527,8 @@ decl_attributes (tree *node, tree attributes, int flags)
targetm.insert_attributes (*node, &attributes); 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)) for (a = attributes; a; a = TREE_CHAIN (a))
{ {
tree ns = get_attribute_namespace (a); tree ns = get_attribute_namespace (a);
@ -441,7 +537,6 @@ decl_attributes (tree *node, tree attributes, int flags)
tree *anode = node; tree *anode = node;
const struct attribute_spec *spec = const struct attribute_spec *spec =
lookup_scoped_attribute_spec (ns, name); lookup_scoped_attribute_spec (ns, name);
bool no_add_attrs = 0;
int fn_ptr_quals = 0; int fn_ptr_quals = 0;
tree fn_ptr_tmp = NULL_TREE; tree fn_ptr_tmp = NULL_TREE;
@ -490,7 +585,8 @@ decl_attributes (tree *node, tree attributes, int flags)
| (int) ATTR_FLAG_ARRAY_NEXT)) | (int) ATTR_FLAG_ARRAY_NEXT))
{ {
/* Pass on this attribute to be tried again. */ /* 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;
} }
else else
@ -535,7 +631,8 @@ decl_attributes (tree *node, tree attributes, int flags)
else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
{ {
/* Pass on this attribute to be tried again. */ /* 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;
} }
@ -557,15 +654,56 @@ decl_attributes (tree *node, tree attributes, int flags)
continue; continue;
} }
bool no_add_attrs = false;
if (spec->handler != NULL) if (spec->handler != NULL)
{ {
int cxx11_flag = int cxx11_flag =
cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0; cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
returned_attrs = chainon ((*spec->handler) (anode, name, args, /* Pass in an array of the current declaration followed
flags|cxx11_flag, by the last pushed/merged declaration if one exists.
&no_add_attrs), If the handler changes CUR_AND_LAST_DECL[0] replace
returned_attrs); *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. */ /* Layout the decl in case anything changed. */
@ -1647,3 +1785,124 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
return list; 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 */

View File

@ -31,7 +31,7 @@ extern void init_attributes (void);
from tree.h. Depending on these flags, some attributes may be from tree.h. Depending on these flags, some attributes may be
returned to be applied at a later stage (for example, to apply returned to be applied at a later stage (for example, to apply
a decl attribute to the declaration rather than to its type). */ 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 bool cxx11_attribute_p (const_tree);
extern tree get_attribute_name (const_tree); extern tree get_attribute_name (const_tree);

View File

@ -450,16 +450,16 @@ const struct attribute_spec brig_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
do_diagnostic } */ do_diagnostic } */
{ "leaf", 0, 0, true, false, false, { "leaf", 0, 0, true, false, false,
handle_leaf_attribute, false }, handle_leaf_attribute, false, NULL },
{ "const", 0, 0, true, false, false, { "const", 0, 0, true, false, false,
handle_const_attribute, false }, handle_const_attribute, false, NULL },
{ "pure", 0, 0, true, false, false, { "pure", 0, 0, true, false, false,
handle_pure_attribute, false }, handle_pure_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false, { "nothrow", 0, 0, true, false, false,
handle_nothrow_attribute, false }, handle_nothrow_attribute, false, NULL },
{ "returns_twice", 0, 0, true, false, false, { "returns_twice", 0, 0, true, false, false,
handle_returns_twice_attribute, false }, handle_returns_twice_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Attribute handlers. */ /* Attribute handlers. */

View File

@ -1,3 +1,20 @@
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> 2017-12-06 David Malcolm <dmalcolm@redhat.com>
PR c/83236 PR c/83236

View File

@ -150,6 +150,93 @@ static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
static tree handle_patchable_function_entry_attribute (tree *, tree, tree, static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
int, bool *); 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. /* Table of machine-independent attributes common to all C-like languages.
All attributes referencing arguments should be additionally processed All attributes referencing arguments should be additionally processed
@ -161,214 +248,233 @@ const struct attribute_spec c_common_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity } */
{ "packed", 0, 0, false, false, false, { "packed", 0, 0, false, false, false,
handle_packed_attribute , false}, handle_packed_attribute, false,
attr_aligned_exclusions },
{ "nocommon", 0, 0, true, false, false, { "nocommon", 0, 0, true, false, false,
handle_nocommon_attribute, false}, handle_nocommon_attribute, false,
attr_common_exclusions },
{ "common", 0, 0, true, false, false, { "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 /* FIXME: logically, noreturn attributes should be listed as
"false, true, true" and apply to function types. But implementing this "false, true, true" and apply to function types. But implementing this
would require all the places in the compiler that use TREE_THIS_VOLATILE 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 on a decl to identify non-returning functions to be located and fixed
to check the function type instead. */ to check the function type instead. */
{ "noreturn", 0, 0, true, false, false, { "noreturn", 0, 0, true, false, false,
handle_noreturn_attribute, false }, handle_noreturn_attribute, false,
attr_noreturn_exclusions },
{ "volatile", 0, 0, true, false, false, { "volatile", 0, 0, true, false, false,
handle_noreturn_attribute, false }, handle_noreturn_attribute, false, NULL },
{ "stack_protect", 0, 0, true, false, false, { "stack_protect", 0, 0, true, false, false,
handle_stack_protect_attribute, false }, handle_stack_protect_attribute, false, NULL },
{ "noinline", 0, 0, true, false, false, { "noinline", 0, 0, true, false, false,
handle_noinline_attribute, false }, handle_noinline_attribute, false,
attr_noinline_exclusions },
{ "noclone", 0, 0, true, false, false, { "noclone", 0, 0, true, false, false,
handle_noclone_attribute, false }, handle_noclone_attribute, false, NULL },
{ "no_icf", 0, 0, true, false, false, { "no_icf", 0, 0, true, false, false,
handle_noicf_attribute, false }, handle_noicf_attribute, false, NULL },
{ "noipa", 0, 0, true, false, false, { "noipa", 0, 0, true, false, false,
handle_noipa_attribute, false }, handle_noipa_attribute, false, NULL },
{ "leaf", 0, 0, true, false, false, { "leaf", 0, 0, true, false, false,
handle_leaf_attribute, false }, handle_leaf_attribute, false, NULL },
{ "always_inline", 0, 0, true, false, false, { "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, { "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, { "artificial", 0, 0, true, false, false,
handle_artificial_attribute, false }, handle_artificial_attribute, false, NULL },
{ "flatten", 0, 0, true, false, false, { "flatten", 0, 0, true, false, false,
handle_flatten_attribute, false }, handle_flatten_attribute, false, NULL },
{ "used", 0, 0, true, false, false, { "used", 0, 0, true, false, false,
handle_used_attribute, false }, handle_used_attribute, false, NULL },
{ "unused", 0, 0, false, false, false, { "unused", 0, 0, false, false, false,
handle_unused_attribute, false }, handle_unused_attribute, false, NULL },
{ "externally_visible", 0, 0, true, false, false, { "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, { "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. */ /* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false, { "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, { "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, { "transparent_union", 0, 0, false, false, false,
handle_transparent_union_attribute, false }, handle_transparent_union_attribute, false, NULL },
{ "constructor", 0, 1, true, false, false, { "constructor", 0, 1, true, false, false,
handle_constructor_attribute, false }, handle_constructor_attribute, false, NULL },
{ "destructor", 0, 1, true, false, false, { "destructor", 0, 1, true, false, false,
handle_destructor_attribute, false }, handle_destructor_attribute, false, NULL },
{ "mode", 1, 1, false, true, false, { "mode", 1, 1, false, true, false,
handle_mode_attribute, false }, handle_mode_attribute, false, NULL },
{ "section", 1, 1, true, false, false, { "section", 1, 1, true, false, false,
handle_section_attribute, false }, handle_section_attribute, false, NULL },
{ "aligned", 0, 1, false, false, false, { "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, { "warn_if_not_aligned", 0, 1, false, false, false,
handle_warn_if_not_aligned_attribute, handle_warn_if_not_aligned_attribute,
false }, false, NULL },
{ "weak", 0, 0, true, false, false, { "weak", 0, 0, true, false, false,
handle_weak_attribute, false }, handle_weak_attribute, false, NULL },
{ "noplt", 0, 0, true, false, false, { "noplt", 0, 0, true, false, false,
handle_noplt_attribute, false }, handle_noplt_attribute, false, NULL },
{ "ifunc", 1, 1, true, false, false, { "ifunc", 1, 1, true, false, false,
handle_ifunc_attribute, false }, handle_ifunc_attribute, false, NULL },
{ "alias", 1, 1, true, false, false, { "alias", 1, 1, true, false, false,
handle_alias_attribute, false }, handle_alias_attribute, false, NULL },
{ "weakref", 0, 1, true, false, false, { "weakref", 0, 1, true, false, false,
handle_weakref_attribute, false }, handle_weakref_attribute, false, NULL },
{ "no_instrument_function", 0, 0, true, false, false, { "no_instrument_function", 0, 0, true, false, false,
handle_no_instrument_function_attribute, handle_no_instrument_function_attribute,
false }, false, NULL },
{ "no_profile_instrument_function", 0, 0, true, false, false, { "no_profile_instrument_function", 0, 0, true, false, false,
handle_no_profile_instrument_function_attribute, handle_no_profile_instrument_function_attribute,
false }, false, NULL },
{ "malloc", 0, 0, true, false, false, { "malloc", 0, 0, true, false, false,
handle_malloc_attribute, false }, handle_malloc_attribute, false,
attr_alloc_exclusions },
{ "returns_twice", 0, 0, true, false, false, { "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, { "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, { "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, { "transaction_callable", 0, 0, false, true, false,
handle_tm_attribute, false }, handle_tm_attribute, false, NULL },
{ "transaction_unsafe", 0, 0, false, true, false, { "transaction_unsafe", 0, 0, false, true, false,
handle_tm_attribute, true }, handle_tm_attribute, true, NULL },
{ "transaction_safe", 0, 0, false, true, false, { "transaction_safe", 0, 0, false, true, false,
handle_tm_attribute, true }, handle_tm_attribute, true, NULL },
{ "transaction_safe_dynamic", 0, 0, true, false, false, { "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, { "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 /* ??? These two attributes didn't make the transition from the
Intel language document to the multi-vendor language document. */ Intel language document to the multi-vendor language document. */
{ "transaction_pure", 0, 0, false, true, false, { "transaction_pure", 0, 0, false, true, false,
handle_tm_attribute, false }, handle_tm_attribute, false, NULL },
{ "transaction_wrap", 1, 1, true, false, false, { "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 /* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */ to prevent its usage in source code. */
{ "no vops", 0, 0, true, false, false, { "no vops", 0, 0, true, false, false,
handle_novops_attribute, false }, handle_novops_attribute, false, NULL },
{ "deprecated", 0, 1, false, false, false, { "deprecated", 0, 1, false, false, false,
handle_deprecated_attribute, false }, handle_deprecated_attribute, false, NULL },
{ "vector_size", 1, 1, false, true, false, { "vector_size", 1, 1, false, true, false,
handle_vector_size_attribute, true }, handle_vector_size_attribute, true, NULL },
{ "visibility", 1, 1, false, false, false, { "visibility", 1, 1, false, false, false,
handle_visibility_attribute, false }, handle_visibility_attribute, false, NULL },
{ "tls_model", 1, 1, true, false, false, { "tls_model", 1, 1, true, false, false,
handle_tls_model_attribute, false }, handle_tls_model_attribute, false, NULL },
{ "nonnull", 0, -1, false, true, true, { "nonnull", 0, -1, false, true, true,
handle_nonnull_attribute, false }, handle_nonnull_attribute, false, NULL },
{ "nonstring", 0, 0, true, false, false, { "nonstring", 0, 0, true, false, false,
handle_nonstring_attribute, false }, handle_nonstring_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false, { "nothrow", 0, 0, true, false, false,
handle_nothrow_attribute, false }, handle_nothrow_attribute, false, NULL },
{ "may_alias", 0, 0, false, true, false, NULL, false }, { "may_alias", 0, 0, false, true, false, NULL, false, NULL },
{ "cleanup", 1, 1, true, false, false, { "cleanup", 1, 1, true, false, false,
handle_cleanup_attribute, false }, handle_cleanup_attribute, false, NULL },
{ "warn_unused_result", 0, 0, false, true, true, { "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, { "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 /* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */ to prevent its usage in source code. */
{ "type generic", 0, 0, false, true, true, { "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, { "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, { "cold", 0, 0, true, false, false,
handle_cold_attribute, false }, handle_cold_attribute, false,
attr_cold_hot_exclusions },
{ "hot", 0, 0, true, false, false, { "hot", 0, 0, true, false, false,
handle_hot_attribute, false }, handle_hot_attribute, false,
attr_cold_hot_exclusions },
{ "no_address_safety_analysis", { "no_address_safety_analysis",
0, 0, true, false, false, 0, 0, true, false, false,
handle_no_address_safety_analysis_attribute, handle_no_address_safety_analysis_attribute,
false }, false, NULL },
{ "no_sanitize", 1, 1, true, false, false, { "no_sanitize", 1, 1, true, false, false,
handle_no_sanitize_attribute, handle_no_sanitize_attribute,
false }, false, NULL },
{ "no_sanitize_address", 0, 0, true, false, false, { "no_sanitize_address", 0, 0, true, false, false,
handle_no_sanitize_address_attribute, handle_no_sanitize_address_attribute,
false }, false, NULL },
{ "no_sanitize_thread", 0, 0, true, false, false, { "no_sanitize_thread", 0, 0, true, false, false,
handle_no_sanitize_thread_attribute, handle_no_sanitize_thread_attribute,
false }, false, NULL },
{ "no_sanitize_undefined", 0, 0, true, false, false, { "no_sanitize_undefined", 0, 0, true, false, false,
handle_no_sanitize_undefined_attribute, handle_no_sanitize_undefined_attribute,
false }, false, NULL },
{ "asan odr indicator", 0, 0, true, false, false, { "asan odr indicator", 0, 0, true, false, false,
handle_asan_odr_indicator_attribute, handle_asan_odr_indicator_attribute,
false }, false, NULL },
{ "warning", 1, 1, true, false, false, { "warning", 1, 1, true, false, false,
handle_error_attribute, false }, handle_error_attribute, false, NULL },
{ "error", 1, 1, true, false, false, { "error", 1, 1, true, false, false,
handle_error_attribute, false }, handle_error_attribute, false, NULL },
{ "target", 1, -1, true, false, false, { "target", 1, -1, true, false, false,
handle_target_attribute, false }, handle_target_attribute, false, NULL },
{ "target_clones", 1, -1, true, false, false, { "target_clones", 1, -1, true, false, false,
handle_target_clones_attribute, false }, handle_target_clones_attribute, false, NULL },
{ "optimize", 1, -1, true, false, false, { "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 /* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */ source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true, { "*tm regparm", 0, 0, false, true, true,
ignore_attribute, false }, ignore_attribute, false, NULL },
{ "no_split_stack", 0, 0, true, false, false, { "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. /* For internal use (marking of builtins and runtime functions) only.
The name contains space to prevent its usage in source code. */ The name contains space to prevent its usage in source code. */
{ "fn spec", 1, 1, false, true, true, { "fn spec", 1, 1, false, true, true,
handle_fnspec_attribute, false }, handle_fnspec_attribute, false, NULL },
{ "warn_unused", 0, 0, false, false, false, { "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, { "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, { "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, { "simd", 0, 1, true, false, false,
handle_simd_attribute, false }, handle_simd_attribute, false, NULL },
{ "omp declare target", 0, 0, true, false, false, { "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, { "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, { "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, { "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, { "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, { "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, { "bnd_legacy", 0, 0, true, false, false,
handle_bnd_legacy, false }, handle_bnd_legacy, false, NULL },
{ "bnd_instrument", 0, 0, true, false, false, { "bnd_instrument", 0, 0, true, false, false,
handle_bnd_instrument, false }, handle_bnd_instrument, false, NULL },
{ "fallthrough", 0, 0, false, false, false, { "fallthrough", 0, 0, false, false, false,
handle_fallthrough_attribute, false }, handle_fallthrough_attribute, false, NULL },
{ "patchable_function_entry", 1, 2, true, false, false, { "patchable_function_entry", 1, 2, true, false, false,
handle_patchable_function_entry_attribute, handle_patchable_function_entry_attribute,
false }, false, NULL },
{ "nocf_check", 0, 0, false, true, true, { "nocf_check", 0, 0, false, true, true,
handle_nocf_check_attribute, true }, handle_nocf_check_attribute, true, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Give the specifications for the format attributes, used by C and all /* Give the specifications for the format attributes, used by C and all
@ -383,10 +489,10 @@ const struct attribute_spec c_common_format_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity } */
{ "format", 3, 3, false, true, true, { "format", 3, 3, false, true, true,
handle_format_attribute, false }, handle_format_attribute, false, NULL },
{ "format_arg", 1, 1, false, true, true, { "format_arg", 1, 1, false, true, true,
handle_format_arg_attribute, false }, handle_format_arg_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain
@ -524,14 +630,7 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
if (TREE_CODE (*node) == FUNCTION_DECL if (TREE_CODE (*node) == FUNCTION_DECL
|| TREE_CODE (*node) == LABEL_DECL) || TREE_CODE (*node) == LABEL_DECL)
{ {
if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) /* Attribute hot processing is done later with lookup_attribute. */
{
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. */
} }
else else
{ {
@ -552,14 +651,7 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
if (TREE_CODE (*node) == FUNCTION_DECL if (TREE_CODE (*node) == FUNCTION_DECL
|| TREE_CODE (*node) == LABEL_DECL) || TREE_CODE (*node) == LABEL_DECL)
{ {
if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) /* Attribute cold processing is done later with lookup_attribute. */
{
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. */
} }
else else
{ {
@ -1086,7 +1178,7 @@ handle_no_reorder_attribute (tree *pnode,
static tree static tree
handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), 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); tree type = TREE_TYPE (*node);
@ -1107,6 +1199,14 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
*no_add_attrs = true; *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; return NULL_TREE;
} }
@ -1689,15 +1789,19 @@ check_cxx_fundamental_alignment_constraints (tree node,
handle_aligned_attribute. */ handle_aligned_attribute. */
static tree 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 *no_add_attrs,
bool warn_if_not_aligned_p) bool warn_if_not_aligned_p)
{ {
tree decl = NULL_TREE; tree decl = NULL_TREE;
tree *type = NULL; tree *type = NULL;
int is_type = 0; bool is_type = false;
tree align_expr; 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) if (args)
{ {
@ -1716,10 +1820,21 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
is_type = TREE_CODE (*node) == TYPE_DECL; is_type = TREE_CODE (*node) == TYPE_DECL;
} }
else if (TYPE_P (*node)) else if (TYPE_P (*node))
type = node, is_type = 1; type = node, is_type = true;
if ((i = check_user_alignment (align_expr, true)) == -1 /* Log2 of specified alignment. */
|| !check_cxx_fundamental_alignment_constraints (*node, i, flags)) 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 (pow2align == -1
|| !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags))
*no_add_attrs = true; *no_add_attrs = true;
else if (is_type) else if (is_type)
{ {
@ -1742,12 +1857,12 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
if (warn_if_not_aligned_p) 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; warn_if_not_aligned_p = false;
} }
else else
{ {
SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT); SET_TYPE_ALIGN (*type, bitalign);
TYPE_USER_ALIGN (*type) = 1; TYPE_USER_ALIGN (*type) = 1;
} }
} }
@ -1757,8 +1872,34 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
error ("alignment may not be specified for %q+D", decl); error ("alignment may not be specified for %q+D", decl);
*no_add_attrs = true; *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) else if (DECL_USER_ALIGN (decl)
&& DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) && DECL_ALIGN (decl) > bitalign)
/* C++-11 [dcl.align/4]: /* C++-11 [dcl.align/4]:
When multiple alignment-specifiers are specified for an When multiple alignment-specifiers are specified for an
@ -1770,7 +1911,7 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
*no_add_attrs = true; *no_add_attrs = true;
else if (!warn_if_not_aligned_p else if (!warn_if_not_aligned_p
&& TREE_CODE (decl) == FUNCTION_DECL && 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 /* Don't warn function alignment here if warn_if_not_aligned_p is
true. It will be warned later. */ true. It will be warned later. */
@ -1789,13 +1930,13 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
{ {
if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl)) 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; warn_if_not_aligned_p = false;
} }
} }
else else
{ {
SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT); SET_DECL_ALIGN (decl, bitalign);
DECL_USER_ALIGN (decl) = 1; DECL_USER_ALIGN (decl) = 1;
} }
} }
@ -1814,10 +1955,10 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
struct attribute_spec.handler. */ struct attribute_spec.handler. */
static tree 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) 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); no_add_attrs, false);
} }
@ -1825,11 +1966,11 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args,
struct attribute_spec.handler. */ struct attribute_spec.handler. */
static tree 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, tree args, int flags,
bool *no_add_attrs) 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); no_add_attrs, true);
} }
@ -2538,8 +2679,15 @@ handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
int ARG_UNUSED (flags), bool *no_add_attrs) int ARG_UNUSED (flags), bool *no_add_attrs)
{ {
if (TREE_CODE (*node) == FUNCTION_DECL) 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 else
{ {
warning (OPT_Wattributes, "%qE attribute ignored", name); warning (OPT_Wattributes, "%qE attribute ignored", name);

View File

@ -2230,36 +2230,19 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl)
newdecl); newdecl);
/* Diagnose inline __attribute__ ((noinline)) which is silly. */ /* Diagnose inline __attribute__ ((noinline)) which is silly. */
const char *noinline = "noinline";
if (DECL_DECLARED_INLINE_P (newdecl) if (DECL_DECLARED_INLINE_P (newdecl)
&& DECL_UNINLINABLE (olddecl) && DECL_UNINLINABLE (olddecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) && lookup_attribute (noinline, DECL_ATTRIBUTES (olddecl)))
warned |= warning (OPT_Wattributes, "inline declaration of %qD follows " 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) else if (DECL_DECLARED_INLINE_P (olddecl)
&& DECL_UNINLINABLE (newdecl) && DECL_UNINLINABLE (newdecl)
&& lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
"noinline follows inline declaration ", newdecl); "%qs follows inline declaration ", newdecl, noinline);
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");
return warned; return warned;
} }

View File

@ -1,3 +1,9 @@
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> 2017-12-06 David Malcolm <dmalcolm@redhat.com>
PR c/83236 PR c/83236

View File

@ -4632,7 +4632,16 @@ c_decl_attributes (tree *node, tree attributes, int flags)
attributes = tree_cons (get_identifier ("omp declare target"), attributes = tree_cons (get_identifier ("omp declare target"),
NULL_TREE, attributes); 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);
} }

View File

@ -7506,9 +7506,10 @@ common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED,
static const struct attribute_spec vms_attribute_table[] = static const struct attribute_spec vms_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity, exclusions } */
{ COMMON_OBJECT, 0, 1, true, false, false, common_object_handler, false }, { COMMON_OBJECT, 0, 1, true, false, false, common_object_handler, false,
{ NULL, 0, 0, false, false, false, NULL, false } NULL },
{ NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
void void

View File

@ -219,21 +219,23 @@ const struct attribute_spec arc_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ 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 /* 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 it may lie outside of the 21/25 bit addressing range of a normal function
call. */ 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 /* Whereas these functions are always known to reside within the 25 bit
addressing range of unconditionalized bl. */ 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 /* And these functions are always known to reside within the 21 bit
addressing range of blcc. */ 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 /* Function which are not having the prologue and epilogue generated
by the compiler. */ by the compiler. */
{ "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false }, { "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false,
{ NULL, 0, 0, false, false, false, NULL, false } NULL },
{ NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
static int arc_comp_type_attributes (const_tree, const_tree); static int arc_comp_type_attributes (const_tree, const_tree);
static void arc_file_start (void); static void arc_file_start (void);

View File

@ -323,24 +323,24 @@ static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT);
static const struct attribute_spec arm_attribute_table[] = static const struct attribute_spec arm_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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 /* 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 it may lie outside of the 26 bit addressing range of a normal function
call. */ 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 /* Whereas these functions are always known to reside within the 26 bit
addressing range. */ 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. */ /* Specify the procedure call conventions for a function. */
{ "pcs", 1, 1, false, true, true, arm_handle_pcs_attribute, { "pcs", 1, 1, false, true, true, arm_handle_pcs_attribute,
false }, false, NULL },
/* Interrupt Service Routines have special prologue and epilogue requirements. */ /* Interrupt Service Routines have special prologue and epilogue requirements. */
{ "isr", 0, 1, false, false, false, arm_handle_isr_attribute, { "isr", 0, 1, false, false, false, arm_handle_isr_attribute,
false }, false, NULL },
{ "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute, { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute,
false }, false, NULL },
{ "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute, { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute,
false }, false, NULL },
#ifdef ARM_PE #ifdef ARM_PE
/* ARM/PE has three new attributes: /* ARM/PE has three new attributes:
interfacearm - ? interfacearm - ?
@ -351,22 +351,24 @@ static const struct attribute_spec arm_attribute_table[] =
them with spaces. We do NOT support this. Instead, use __declspec them with spaces. We do NOT support this. Instead, use __declspec
multiple times. multiple times.
*/ */
{ "dllimport", 0, 0, true, false, false, NULL, false }, { "dllimport", 0, 0, true, false, false, NULL, false, NULL },
{ "dllexport", 0, 0, true, false, false, NULL, false }, { "dllexport", 0, 0, true, false, false, NULL, false, NULL },
{ "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute, { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute,
false }, false, NULL },
#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
{ "dllimport", 0, 0, false, false, false, handle_dll_attribute, false }, { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false,
{ "dllexport", 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, { "notshared", 0, 0, false, true, false, arm_handle_notshared_attribute,
false }, false, NULL },
#endif #endif
/* ARMv8-M Security Extensions support. */ /* ARMv8-M Security Extensions support. */
{ "cmse_nonsecure_entry", 0, 0, true, false, false, { "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, { "cmse_nonsecure_call", 0, 0, true, false, false,
arm_handle_cmse_nonsecure_call, true }, arm_handle_cmse_nonsecure_call, true, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Initialize the GCC target structure. */ /* Initialize the GCC target structure. */

View File

@ -9877,28 +9877,28 @@ avr_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity } */
{ "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute, { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute,
false }, false, NULL },
{ "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute, { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute,
false }, false, NULL },
{ "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute, { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute,
false }, false, NULL },
{ "no_gccisr", 0, 0, true, false, false, avr_handle_fndecl_attribute, { "no_gccisr", 0, 0, true, false, false, avr_handle_fndecl_attribute,
false }, false, NULL },
{ "naked", 0, 0, false, true, true, avr_handle_fntype_attribute, { "naked", 0, 0, false, true, true, avr_handle_fntype_attribute,
false }, false, NULL },
{ "OS_task", 0, 0, false, true, true, avr_handle_fntype_attribute, { "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, { "OS_main", 0, 0, false, true, true, avr_handle_fntype_attribute,
false }, false, NULL },
{ "io", 0, 1, true, false, false, avr_handle_addr_attribute, { "io", 0, 1, true, false, false, avr_handle_addr_attribute,
false }, false, NULL },
{ "io_low", 0, 1, true, false, false, avr_handle_addr_attribute, { "io_low", 0, 1, true, false, false, avr_handle_addr_attribute,
false }, false, NULL },
{ "address", 1, 1, true, false, false, avr_handle_addr_attribute, { "address", 1, 1, true, false, false, avr_handle_addr_attribute,
false }, false, NULL },
{ "absdata", 0, 0, true, false, false, avr_handle_absdata_attribute, { "absdata", 0, 0, true, false, false, avr_handle_absdata_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };

View File

@ -4906,29 +4906,30 @@ bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name),
static const struct attribute_spec bfin_attribute_table[] = static const struct attribute_spec bfin_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute,
false }, false, NULL },
{ "exception_handler", 0, 0, false, true, true, handle_int_attribute, { "exception_handler", 0, 0, false, true, true, handle_int_attribute,
false }, false, NULL },
{ "nmi_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 }, NULL },
{ "kspisusp", 0, 0, false, true, true, NULL, false }, { "nesting", 0, 0, false, true, true, NULL, false, NULL },
{ "saveall", 0, 0, false, true, true, NULL, false }, { "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, { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute,
false }, false, NULL },
{ "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute, { "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, { "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, { "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, { "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, { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
false }, false, NULL },
{ "l2", 0, 0, true, false, false, bfin_handle_l2_attribute, false }, { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to

View File

@ -207,9 +207,9 @@ static void cr16_print_operand_address (FILE *, machine_mode, rtx);
static const struct attribute_spec cr16_attribute_table[] = { static const struct attribute_spec cr16_attribute_table[] = {
/* ISRs have special prologue and epilogue requirements. */ /* ISRs have special prologue and epilogue requirements. */
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, NULL, false}, {"interrupt", 0, 0, false, true, true, NULL, false, NULL},
{NULL, 0, 0, false, false, false, NULL, false} {NULL, 0, 0, false, false, false, NULL, false, NULL}
}; };
/* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive /* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive

View File

@ -460,13 +460,14 @@ epiphany_init_reg_tables (void)
static const struct attribute_spec epiphany_attribute_table[] = static const struct attribute_spec epiphany_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
{ "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true }, affects_type_identity, exclusions } */
{ "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false }, { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true, NULL },
{ "long_call", 0, 0, false, true, true, NULL, false }, { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false, NULL },
{ "short_call", 0, 0, false, true, true, NULL, false }, { "long_call", 0, 0, false, true, true, NULL, false, NULL },
{ "disinterrupt", 0, 0, false, true, true, NULL, true }, { "short_call", 0, 0, false, true, true, NULL, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { "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 /* Handle an "interrupt" attribute; arguments as in

View File

@ -5425,22 +5425,22 @@ h8300_insert_attributes (tree node, tree *attributes)
static const struct attribute_spec h8300_attribute_table[] = static const struct attribute_spec h8300_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "interrupt_handler", 0, 0, true, false, false,
h8300_handle_fndecl_attribute, false }, h8300_handle_fndecl_attribute, false, NULL },
{ "saveall", 0, 0, true, false, false, { "saveall", 0, 0, true, false, false,
h8300_handle_fndecl_attribute, false }, h8300_handle_fndecl_attribute, false, NULL },
{ "OS_Task", 0, 0, true, false, false, { "OS_Task", 0, 0, true, false, false,
h8300_handle_fndecl_attribute, false }, h8300_handle_fndecl_attribute, false, NULL },
{ "monitor", 0, 0, true, false, false, { "monitor", 0, 0, true, false, false,
h8300_handle_fndecl_attribute, false }, h8300_handle_fndecl_attribute, false, NULL },
{ "function_vector", 0, 0, true, false, false, { "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, { "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, { "tiny_data", 0, 0, true, false, false,
h8300_handle_tiny_data_attribute, false }, h8300_handle_tiny_data_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };

View File

@ -44693,69 +44693,71 @@ ix86_expand_round_sse4 (rtx op0, rtx op1)
static const struct attribute_spec ix86_attribute_table[] = static const struct attribute_spec ix86_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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 /* Stdcall attribute says callee is responsible for popping arguments
if they are not variable. */ if they are not variable. */
{ "stdcall", 0, 0, false, true, true, ix86_handle_cconv_attribute, { "stdcall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* Fastcall attribute says callee is responsible for popping arguments /* Fastcall attribute says callee is responsible for popping arguments
if they are not variable. */ if they are not variable. */
{ "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute, { "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* Thiscall attribute says callee is responsible for popping arguments /* Thiscall attribute says callee is responsible for popping arguments
if they are not variable. */ if they are not variable. */
{ "thiscall", 0, 0, false, true, true, ix86_handle_cconv_attribute, { "thiscall", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* Cdecl attribute says the callee is a normal C declaration */ /* Cdecl attribute says the callee is a normal C declaration */
{ "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute, { "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* Regparm attribute specifies how many integer arguments are to be /* Regparm attribute specifies how many integer arguments are to be
passed in registers. */ passed in registers. */
{ "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute, { "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* Sseregparm attribute says we are using x86_64 calling conventions /* Sseregparm attribute says we are using x86_64 calling conventions
for FP arguments. */ for FP arguments. */
{ "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute, { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true }, true, NULL },
/* The transactional memory builtins are implicitly regparm or fastcall /* The transactional memory builtins are implicitly regparm or fastcall
depending on the ABI. Override the generic do-nothing attribute that depending on the ABI. Override the generic do-nothing attribute that
these builtins were declared with. */ these builtins were declared with. */
{ "*tm regparm", 0, 0, false, true, true, ix86_handle_tm_regparm_attribute, { "*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. */ /* force_align_arg_pointer says this function realigns the stack at entry. */
{ (const char *)&ix86_force_align_arg_pointer_string, 0, 0, { (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 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
{ "dllimport", 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 }, { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false, NULL },
{ "shared", 0, 0, true, false, false, ix86_handle_shared_attribute, { "shared", 0, 0, true, false, false, ix86_handle_shared_attribute,
false }, false, NULL },
#endif #endif
{ "ms_struct", 0, 0, false, false, false, ix86_handle_struct_attribute, { "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, { "gcc_struct", 0, 0, false, false, false, ix86_handle_struct_attribute,
false }, false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE #ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE, SUBTARGET_ATTRIBUTE_TABLE,
#endif #endif
/* ms_abi and sysv_abi calling convention function attributes. */ /* ms_abi and sysv_abi calling convention function attributes. */
{ "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true }, { "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 }, { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute, true,
{ "ms_abi va_list", 0, 0, false, false, false, NULL, false }, NULL },
{ "sysv_abi va_list", 0, 0, false, false, false, NULL, false }, { "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, { "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute,
false }, false, NULL },
{ "callee_pop_aggregate_return", 1, 1, false, true, true, { "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, { "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, { "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, { "naked", 0, 0, true, false, false,
ix86_handle_fndecl_attribute, false }, ix86_handle_fndecl_attribute, false, NULL },
/* End element. */ /* 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. */ /* Implement targetm.vectorize.builtin_vectorization_cost. */

View File

@ -360,17 +360,17 @@ static bool ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d);
static const struct attribute_spec ia64_attribute_table[] = static const struct attribute_spec ia64_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity, exclusions } */
{ "syscall_linkage", 0, 0, false, true, true, NULL, false }, { "syscall_linkage", 0, 0, false, true, true, NULL, false, NULL },
{ "model", 1, 1, true, false, false, ia64_handle_model_attribute, { "model", 1, 1, true, false, false, ia64_handle_model_attribute,
false }, false, NULL },
#if TARGET_ABI_OPEN_VMS #if TARGET_ABI_OPEN_VMS
{ "common_object", 1, 1, true, false, false, { "common_object", 1, 1, true, false, false,
ia64_vms_common_object_attribute, false }, ia64_vms_common_object_attribute, false, NULL },
#endif #endif
{ "version_id", 1, 1, true, false, false, { "version_id", 1, 1, true, false, false,
ia64_handle_version_id_attribute, false }, ia64_handle_version_id_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Initialize the GCC target structure. */ /* Initialize the GCC target structure. */

View File

@ -3000,12 +3000,14 @@ current_function_special_page_vector (rtx x)
#undef TARGET_ATTRIBUTE_TABLE #undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE m32c_attribute_table #define TARGET_ATTRIBUTE_TABLE m32c_attribute_table
static const struct attribute_spec m32c_attribute_table[] = { static const struct attribute_spec m32c_attribute_table[] = {
{"interrupt", 0, 0, false, false, false, interrupt_handler, false}, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
{"bank_switch", 0, 0, false, false, false, interrupt_handler, false}, affects_type_identity, exclusions } */
{"fast_interrupt", 0, 0, false, false, false, interrupt_handler, false}, {"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, {"function_vector", 1, 1, true, false, false, function_vector_handler,
false}, false, NULL},
{0, 0, 0, 0, 0, 0, 0, false} {0, 0, 0, 0, 0, 0, 0, false, NULL}
}; };
#undef TARGET_COMP_TYPE_ATTRIBUTES #undef TARGET_COMP_TYPE_ATTRIBUTES

View File

@ -111,11 +111,11 @@ static HOST_WIDE_INT m32r_starting_frame_offset (void);
static const struct attribute_spec m32r_attribute_table[] = static const struct attribute_spec m32r_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, NULL, false }, { "interrupt", 0, 0, true, false, false, NULL, false, NULL },
{ "model", 1, 1, true, false, false, m32r_handle_model_attribute, { "model", 1, 1, true, false, false, m32r_handle_model_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Initialize the GCC target structure. */ /* Initialize the GCC target structure. */

View File

@ -348,14 +348,14 @@ static bool m68k_modes_tieable_p (machine_mode, machine_mode);
static const struct attribute_spec m68k_attribute_table[] = static const struct attribute_spec m68k_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "interrupt", 0, 0, true, false, false, m68k_handle_fndecl_attribute,
false }, false },
{ "interrupt_handler", 0, 0, true, false, 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, { "interrupt_thread", 0, 0, true, false, false,
m68k_handle_fndecl_attribute, false }, m68k_handle_fndecl_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
struct gcc_target targetm = TARGET_INITIALIZER; struct gcc_target targetm = TARGET_INITIALIZER;

View File

@ -152,12 +152,12 @@ static bool mcore_modes_tieable_p (machine_mode, machine_mode);
static const struct attribute_spec mcore_attribute_table[] = static const struct attribute_spec mcore_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity, exclusions } */
{ "dllexport", 0, 0, true, false, false, NULL, false }, { "dllexport", 0, 0, true, false, false, NULL, false, NULL },
{ "dllimport", 0, 0, true, false, false, NULL, false }, { "dllimport", 0, 0, true, false, false, NULL, false, NULL },
{ "naked", 0, 0, true, false, false, mcore_handle_naked_attribute, { "naked", 0, 0, true, false, false, mcore_handle_naked_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Initialize the GCC target structure. */ /* Initialize the GCC target structure. */

View File

@ -216,17 +216,17 @@ int save_volatiles;
const struct attribute_spec microblaze_attribute_table[] = { const struct attribute_spec microblaze_attribute_table[] = {
/* name min_len, max_len, decl_req, type_req, fn_type, req_handler, /* 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, {"interrupt_handler", 0, 0, true, false, false, NULL,
false }, false, NULL },
{"break_handler", 0, 0, true, false, false, NULL, {"break_handler", 0, 0, true, false, false, NULL,
false }, false, NULL },
{"fast_interrupt", 0, 0, true, false, false, NULL, {"fast_interrupt", 0, 0, true, false, false, NULL,
false }, false, NULL },
{"save_volatiles" , 0, 0, true, false, false, NULL, {"save_volatiles" , 0, 0, true, false, false, NULL,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, { NULL, 0, 0, false, false, false, NULL,
false } false, NULL }
}; };
static int microblaze_interrupt_function_p (tree); static int microblaze_interrupt_function_p (tree);

View File

@ -597,27 +597,27 @@ static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int,
static const struct attribute_spec mips_attribute_table[] = { static const struct attribute_spec mips_attribute_table[] = {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
om_diagnostic } */ om_diagnostic } */
{ "long_call", 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 }, { "short_call", 0, 0, false, true, true, NULL, false, NULL },
{ "far", 0, 0, false, true, true, NULL, false }, { "far", 0, 0, false, true, true, NULL, false, NULL },
{ "near", 0, 0, false, true, true, NULL, false }, { "near", 0, 0, false, true, true, NULL, false, NULL },
/* We would really like to treat "mips16" and "nomips16" as type /* We would really like to treat "mips16" and "nomips16" as type
attributes, but GCC doesn't provide the hooks we need to support attributes, but GCC doesn't provide the hooks we need to support
the right conversion rules. As declaration attributes, they affect the right conversion rules. As declaration attributes, they affect
code generation but don't carry other semantics. */ code generation but don't carry other semantics. */
{ "mips16", 0, 0, true, false, false, NULL, false }, { "mips16", 0, 0, true, false, false, NULL, false, NULL },
{ "nomips16", 0, 0, true, false, false, NULL, false }, { "nomips16", 0, 0, true, false, false, NULL, false, NULL },
{ "micromips", 0, 0, true, false, false, NULL, false }, { "micromips", 0, 0, true, false, false, NULL, false, NULL },
{ "nomicromips", 0, 0, true, false, false, NULL, false }, { "nomicromips", 0, 0, true, false, false, NULL, false, NULL },
{ "nocompression", 0, 0, true, false, false, NULL, false }, { "nocompression", 0, 0, true, false, false, NULL, false, NULL },
/* Allow functions to be specified as interrupt handlers */ /* Allow functions to be specified as interrupt handlers */
{ "interrupt", 0, 1, false, true, true, mips_handle_interrupt_attr, { "interrupt", 0, 1, false, true, true, mips_handle_interrupt_attr,
false }, false, NULL },
{ "use_shadow_register_set", 0, 1, false, true, true, { "use_shadow_register_set", 0, 1, false, true, true,
mips_handle_use_shadow_register_set_attr, false }, mips_handle_use_shadow_register_set_attr, false, NULL },
{ "keep_interrupts_masked", 0, 0, false, true, true, NULL, false }, { "keep_interrupts_masked", 0, 0, false, true, true, NULL, false, NULL },
{ "use_debug_exception_return", 0, 0, false, true, true, NULL, false }, { "use_debug_exception_return", 0, 0, false, true, true, NULL, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* A table describing all the processors GCC knows about; see /* A table describing all the processors GCC knows about; see

View File

@ -2052,20 +2052,25 @@ const struct attribute_spec msp430_attribute_table[] =
/* Name min_num_args type_req, affects_type_identity /* Name min_num_args type_req, affects_type_identity
max_num_args, fn_type_req max_num_args, fn_type_req
decl_req handler. */ decl_req handler. */
{ ATTR_INTR, 0, 1, true, false, false, msp430_attr, false }, { ATTR_INTR, 0, 1, true, false, false, msp430_attr, false, NULL },
{ ATTR_NAKED, 0, 0, true, false, false, msp430_attr, false }, { ATTR_NAKED, 0, 0, true, false, false, msp430_attr, false, NULL },
{ ATTR_REENT, 0, 0, true, false, false, msp430_attr, false }, { ATTR_REENT, 0, 0, true, false, false, msp430_attr, false, NULL },
{ ATTR_CRIT, 0, 0, true, false, false, msp430_attr, false }, { ATTR_CRIT, 0, 0, true, false, false, msp430_attr, false, NULL },
{ ATTR_WAKEUP, 0, 0, true, false, false, msp430_attr, false }, { ATTR_WAKEUP, 0, 0, true, false, false, msp430_attr, false, NULL },
{ ATTR_LOWER, 0, 0, true, false, false, msp430_section_attr, false }, { ATTR_LOWER, 0, 0, true, false, false, msp430_section_attr, false,
{ ATTR_UPPER, 0, 0, true, false, false, msp430_section_attr, false }, NULL },
{ ATTR_EITHER, 0, 0, true, false, false, msp430_section_attr, false }, { 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 }, { ATTR_NOINIT, 0, 0, true, false, false, msp430_data_attr, false,
{ ATTR_PERSIST, 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, 0, 0, false, false, false, NULL, false, NULL }
}; };
#undef TARGET_ASM_FUNCTION_PROLOGUE #undef TARGET_ASM_FUNCTION_PROLOGUE

View File

@ -86,30 +86,30 @@ static const struct attribute_spec nds32_attribute_table[] =
function_type_required, handler, affects_type_identity } */ function_type_required, handler, affects_type_identity } */
/* The interrupt vid: [0-63]+ (actual vector number starts from 9 to 72). */ /* 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). */ /* 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. */ /* 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. */ /* The attributes describing isr nested type. */
{ "nested", 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 }, { "not_nested", 0, 0, false, false, false, NULL, false, NULL },
{ "nested_ready", 0, 0, false, false, false, NULL, false }, { "nested_ready", 0, 0, false, false, false, NULL, false, NULL },
/* The attributes describing isr register save scheme. */ /* The attributes describing isr register save scheme. */
{ "save_all", 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 }, { "partial_save", 0, 0, false, false, false, NULL, false, NULL },
/* The attributes used by reset attribute. */ /* The attributes used by reset attribute. */
{ "nmi", 1, 1, false, false, false, NULL, false }, { "nmi", 1, 1, false, false, false, NULL, false, NULL },
{ "warm", 1, 1, false, false, false, NULL, false }, { "warm", 1, 1, false, false, false, NULL, false, NULL },
/* The attribute telling no prologue/epilogue. */ /* 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. */ /* 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 }
}; };

View File

@ -4458,10 +4458,12 @@ nvptx_handle_shared_attribute (tree *node, tree name, tree ARG_UNUSED (args),
static const struct attribute_spec nvptx_attribute_table[] = static const struct attribute_spec nvptx_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity, exclusions } */
{ "kernel", 0, 0, true, false, false, nvptx_handle_kernel_attribute, false }, { "kernel", 0, 0, true, false, false, nvptx_handle_kernel_attribute, false,
{ "shared", 0, 0, true, false, false, nvptx_handle_shared_attribute, false }, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { "shared", 0, 0, true, false, false, nvptx_handle_shared_attribute, false,
NULL },
{ NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Limit vector alignments to BIGGEST_ALIGNMENT. */ /* Limit vector alignments to BIGGEST_ALIGNMENT. */

View File

@ -1534,21 +1534,21 @@ static const char alt_reg_names[][8] =
static const struct attribute_spec rs6000_attribute_table[] = static const struct attribute_spec rs6000_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute,
false }, false, NULL },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
false }, false, NULL },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, { "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
false }, false, NULL },
{ "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute, { "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, { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
false }, false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE #ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE, SUBTARGET_ATTRIBUTE_TABLE,
#endif #endif
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
#ifndef TARGET_PROFILE_KERNEL #ifndef TARGET_PROFILE_KERNEL

View File

@ -860,14 +860,14 @@ const struct attribute_spec rl78_attribute_table[] =
/* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity. */ affects_type_identity. */
{ "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
false }, false, NULL },
{ "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute, { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
false }, false, NULL },
{ "naked", 0, 0, true, false, false, rl78_handle_naked_attribute, { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute,
false }, false, NULL },
{ "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute, { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };

View File

@ -1518,21 +1518,21 @@ static const char alt_reg_names[][8] =
static const struct attribute_spec rs6000_attribute_table[] = static const struct attribute_spec rs6000_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute,
false }, false, NULL },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, { "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
false }, false, NULL },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute, { "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute,
false }, false, NULL },
{ "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute, { "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, { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
false }, false, NULL },
#ifdef SUBTARGET_ATTRIBUTE_TABLE #ifdef SUBTARGET_ATTRIBUTE_TABLE
SUBTARGET_ATTRIBUTE_TABLE, SUBTARGET_ATTRIBUTE_TABLE,
#endif #endif
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
#ifndef TARGET_PROFILE_KERNEL #ifndef TARGET_PROFILE_KERNEL

View File

@ -2732,16 +2732,16 @@ rx_handle_vector_attribute (tree * node,
const struct attribute_spec rx_attribute_table[] = const struct attribute_spec rx_attribute_table[] =
{ {
/* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* 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, { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
false }, false, NULL },
{ "interrupt", 0, -1, true, false, false, rx_handle_func_attribute, { "interrupt", 0, -1, true, false, false, rx_handle_func_attribute,
false }, false, NULL },
{ "naked", 0, 0, true, false, false, rx_handle_func_attribute, { "naked", 0, 0, true, false, false, rx_handle_func_attribute,
false }, false, NULL },
{ "vector", 1, -1, true, false, false, rx_handle_vector_attribute, { "vector", 1, -1, true, false, false, rx_handle_vector_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */ /* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */

View File

@ -1178,10 +1178,12 @@ s390_handle_vectorbool_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
} }
static const struct attribute_spec s390_attribute_table[] = { static const struct attribute_spec s390_attribute_table[] = {
{ "hotpatch", 2, 2, true, false, false, s390_handle_hotpatch_attribute, false }, { "hotpatch", 2, 2, true, false, false,
{ "s390_vector_bool", 0, 0, false, true, false, s390_handle_vectorbool_attribute, true }, s390_handle_hotpatch_attribute, false, NULL },
{ "s390_vector_bool", 0, 0, false, true, false,
s390_handle_vectorbool_attribute, true, NULL },
/* End element. */ /* 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 /* Return the alignment for LABEL. We default to the -falign-labels

View File

@ -330,24 +330,24 @@ static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t);
static const struct attribute_spec sh_attribute_table[] = static const struct attribute_spec sh_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "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, { "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, { "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, { "renesas", 0, 0, false, true, false,
sh_handle_renesas_attribute, false }, sh_handle_renesas_attribute, false, NULL },
{ "trapa_handler", 0, 0, true, false, false, { "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, { "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, { "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, { "function_vector", 1, 1, true, false, false,
sh2a_handle_function_vector_handler_attribute, false }, sh2a_handle_function_vector_handler_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Initialize the GCC target structure. */ /* Initialize the GCC target structure. */

View File

@ -691,9 +691,9 @@ static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT);
static const struct attribute_spec sparc_attribute_table[] = static const struct attribute_spec sparc_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
do_diagnostic } */ do_diagnostic, exclusions } */
SUBTARGET_ATTRIBUTE_TABLE, SUBTARGET_ATTRIBUTE_TABLE,
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
#endif #endif

View File

@ -7215,12 +7215,12 @@ spu_constant_alignment (const_tree, HOST_WIDE_INT align)
static const struct attribute_spec spu_attribute_table[] = static const struct attribute_spec spu_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "naked", 0, 0, true, false, false, spu_handle_fndecl_attribute,
false }, false, NULL },
{ "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute, { "spu_vector", 0, 0, false, true, false, spu_handle_vector_attribute,
false }, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* TARGET overrides. */ /* TARGET overrides. */

View File

@ -2190,14 +2190,14 @@ static tree xstormy16_handle_below100_attribute
static const struct attribute_spec xstormy16_attribute_table[] = static const struct attribute_spec xstormy16_attribute_table[] =
{ {
/* name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* 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, { "interrupt", 0, 0, false, true, true,
xstormy16_handle_interrupt_attribute , false }, xstormy16_handle_interrupt_attribute , false, NULL },
{ "BELOW100", 0, 0, false, false, false, { "BELOW100", 0, 0, false, false, false,
xstormy16_handle_below100_attribute, false }, xstormy16_handle_below100_attribute, false, NULL },
{ "below100", 0, 0, false, false, false, { "below100", 0, 0, false, false, false,
xstormy16_handle_below100_attribute, false }, xstormy16_handle_below100_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Handle an "interrupt" attribute; /* Handle an "interrupt" attribute;

View File

@ -3188,18 +3188,18 @@ v850_adjust_insn_length (rtx_insn *insn, int length)
static const struct attribute_spec v850_attribute_table[] = static const struct attribute_spec v850_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "interrupt_handler", 0, 0, true, false, false,
v850_handle_interrupt_attribute, false }, v850_handle_interrupt_attribute, false, NULL },
{ "interrupt", 0, 0, true, false, false, { "interrupt", 0, 0, true, false, false,
v850_handle_interrupt_attribute, false }, v850_handle_interrupt_attribute, false, NULL },
{ "sda", 0, 0, true, false, false, { "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, { "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, { "zda", 0, 0, true, false, false,
v850_handle_data_area_attribute, false }, v850_handle_data_area_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
static void static void

View File

@ -146,9 +146,10 @@ static inline bool current_function_has_lr_slot (void);
static const struct attribute_spec visium_attribute_table[] = static const struct attribute_spec visium_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, visium_handle_interrupt_attr, false}, {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false,
{NULL, 0, 0, false, false, false, NULL, false} NULL},
{NULL, 0, 0, false, false, false, NULL, false, NULL},
}; };
static struct machine_function *visium_init_machine_status (void); static struct machine_function *visium_init_machine_status (void);

View File

@ -1,3 +1,14 @@
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> 2017-12-06 Jakub Jelinek <jakub@redhat.com>
PR c++/80259 PR c++/80259

View File

@ -6116,7 +6116,7 @@ extern void note_break_stmt (void);
extern bool note_iteration_stmt_body_start (void); extern bool note_iteration_stmt_body_start (void);
extern void note_iteration_stmt_body_end (bool); extern void note_iteration_stmt_body_end (bool);
extern tree make_lambda_name (void); 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 bool maybe_version_functions (tree, tree);
extern tree duplicate_decls (tree, tree, bool); extern tree duplicate_decls (tree, tree, bool);
extern tree declare_local_label (tree); extern tree declare_local_label (tree);

View File

@ -992,7 +992,7 @@ push_local_name (tree decl)
`const int&'. */ `const int&'. */
int int
decls_match (tree newdecl, tree olddecl) decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
{ {
int types_match; int types_match;
@ -1087,6 +1087,7 @@ decls_match (tree newdecl, tree olddecl)
if (types_match if (types_match
&& !DECL_EXTERN_C_P (newdecl) && !DECL_EXTERN_C_P (newdecl)
&& !DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (olddecl)
&& record_versions
&& maybe_version_functions (newdecl, olddecl)) && maybe_version_functions (newdecl, olddecl))
return 0; return 0;
} }

View File

@ -1482,7 +1482,31 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
attributes, flags); attributes, flags);
} }
else 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) if (TREE_CODE (*decl) == TYPE_DECL)
SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));

View File

@ -4330,24 +4330,24 @@ handle_nodiscard_attribute (tree *node, tree name, tree /*args*/,
const struct attribute_spec cxx_attribute_table[] = const struct attribute_spec cxx_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "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, { "abi_tag", 1, -1, false, false, false,
handle_abi_tag_attribute, true }, handle_abi_tag_attribute, true, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Table of C++ standard attributes. */ /* Table of C++ standard attributes. */
const struct attribute_spec std_attribute_table[] = const struct attribute_spec std_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "maybe_unused", 0, 0, false, false, false,
handle_unused_attribute, false }, handle_unused_attribute, false, NULL },
{ "nodiscard", 0, 0, false, false, false, { "nodiscard", 0, 0, false, false, false,
handle_nodiscard_attribute, false }, handle_nodiscard_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Handle an "init_priority" attribute; arguments as in /* Handle an "init_priority" attribute; arguments as in

View File

@ -2493,9 +2493,14 @@ are automatically detected and this attribute is ignored.
@cindex @code{const} function attribute @cindex @code{const} function attribute
@cindex functions that have no side effects @cindex functions that have no side effects
Many functions do not examine any values except their arguments, and Many functions do not examine any values except their arguments, and
have no effects except the return value. Basically this is just slightly have no effects except to return a value. Calls to such functions lend
more strict class than the @code{pure} attribute below, since function is not themselves to optimization such as common subexpression elimination.
allowed to read global memory. 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 @cindex pointer arguments
Note that a function that has pointer arguments and examines the data Note that a function that has pointer arguments and examines the data
@ -3190,7 +3195,7 @@ to prevent recursion.
@cindex functions that have no side effects @cindex functions that have no side effects
Many functions have no effects except the return value and their Many functions have no effects except the return value and their
return value depends only on the parameters and/or global variables. 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 to common subexpression elimination and loop optimization just as an
arithmetic operator would be. These functions should be declared arithmetic operator would be. These functions should be declared
with the attribute @code{pure}. For example, with the attribute @code{pure}. For example,
@ -3208,6 +3213,11 @@ Interesting non-pure functions are functions with infinite loops or those
depending on volatile memory or other system resource, that may change between depending on volatile memory or other system resource, that may change between
two consecutive calls (such as @code{feof} in a multithreading environment). 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 @item returns_nonnull
@cindex @code{returns_nonnull} function attribute @cindex @code{returns_nonnull} function attribute
The @code{returns_nonnull} attribute specifies that the function The @code{returns_nonnull} attribute specifies that the function

View File

@ -1,3 +1,9 @@
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> 2017-12-03 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/36313 PR fortran/36313

View File

@ -92,12 +92,12 @@ static const struct attribute_spec gfc_attribute_table[] =
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
affects_type_identity } */ affects_type_identity } */
{ "omp declare target", 0, 0, true, false, false, { "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, { "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, { "oacc function", 0, -1, true, false, false,
gfc_handle_omp_declare_target_attribute, false }, gfc_handle_omp_declare_target_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
#undef LANG_HOOKS_NAME #undef LANG_HOOKS_NAME

View File

@ -1,3 +1,9 @@
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> 2017-11-30 Jakub Jelinek <jakub@redhat.com>
* lto.c (create_subid_section_table): Use ; instead of ;;. * lto.c (create_subid_section_table): Use ; instead of ;;.

View File

@ -57,46 +57,82 @@ static tree handle_format_attribute (tree *, tree, tree, int, bool *);
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); static tree handle_format_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. */ /* Table of machine-independent attributes supported in GIMPLE. */
const struct attribute_spec lto_attribute_table[] = const struct attribute_spec lto_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
do_diagnostic } */ do_diagnostic, exclusions } */
{ "noreturn", 0, 0, true, false, false, { "noreturn", 0, 0, true, false, false,
handle_noreturn_attribute, false }, handle_noreturn_attribute, false,
attr_noreturn_exclusions },
{ "leaf", 0, 0, true, false, false, { "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. */ /* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false, { "const", 0, 0, true, false, false,
handle_const_attribute, false }, handle_const_attribute, false,
attr_const_pure_exclusions },
{ "malloc", 0, 0, true, false, false, { "malloc", 0, 0, true, false, false,
handle_malloc_attribute, false }, handle_malloc_attribute, false, NULL },
{ "pure", 0, 0, true, false, false, { "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, { "no vops", 0, 0, true, false, false,
handle_novops_attribute, false }, handle_novops_attribute, false, NULL },
{ "nonnull", 0, -1, false, true, true, { "nonnull", 0, -1, false, true, true,
handle_nonnull_attribute, false }, handle_nonnull_attribute, false, NULL },
{ "nothrow", 0, 0, true, false, false, { "nothrow", 0, 0, true, false, false,
handle_nothrow_attribute, false }, handle_nothrow_attribute, false, NULL },
{ "patchable_function_entry", 1, 2, true, false, false, { "patchable_function_entry", 1, 2, true, false, false,
handle_patchable_function_entry_attribute, handle_patchable_function_entry_attribute,
false }, false, NULL },
{ "returns_twice", 0, 0, true, false, false, { "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, { "sentinel", 0, 1, false, true, true,
handle_sentinel_attribute, false }, handle_sentinel_attribute, false, NULL },
{ "type generic", 0, 0, false, true, true, { "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, { "fn spec", 1, 1, false, true, true,
handle_fnspec_attribute, false }, handle_fnspec_attribute, false, NULL },
{ "transaction_pure", 0, 0, false, true, true, { "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 /* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */ source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true, { "*tm regparm", 0, 0, false, true, true,
ignore_attribute, false }, ignore_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
/* Give the specifications for the format attributes, used by C and all /* Give the specifications for the format attributes, used by C and all
@ -105,12 +141,12 @@ const struct attribute_spec lto_attribute_table[] =
const struct attribute_spec lto_format_attribute_table[] = const struct attribute_spec lto_format_attribute_table[] =
{ {
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, /* { 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, { "format", 3, 3, false, true, true,
handle_format_attribute, false }, handle_format_attribute, false, NULL },
{ "format_arg", 1, 1, false, true, true, { "format_arg", 1, 1, false, true, true,
handle_format_arg_attribute, false }, handle_format_arg_attribute, false, NULL },
{ NULL, 0, 0, false, false, false, NULL, false } { NULL, 0, 0, false, false, false, NULL, false, NULL }
}; };
enum built_in_attribute enum built_in_attribute
@ -264,6 +300,10 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name),
tree ARG_UNUSED (args), int ARG_UNUSED (flags), tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs)) 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); tree type = TREE_TYPE (*node);
/* See FIXME comment on noreturn in c_common_attribute_table. */ /* See FIXME comment on noreturn in c_common_attribute_table. */

View File

@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
#include "target.h" #include "target.h"
#include "langhooks.h" #include "langhooks.h"
#include "options.h" #include "options.h"
#include "stringpool.h"
#include "attribs.h"
/* This function needed to be split out from selftest.c as it references /* This function needed to be split out from selftest.c as it references
tests from the whole source tree, and so is within tests from the whole source tree, and so is within
@ -85,6 +87,7 @@ selftest::run_tests ()
spellcheck_c_tests (); spellcheck_c_tests ();
spellcheck_tree_c_tests (); spellcheck_tree_c_tests ();
tree_cfg_c_tests (); tree_cfg_c_tests ();
attribute_c_tests ();
/* This one relies on most of the above. */ /* This one relies on most of the above. */
function_tests_c_tests (); function_tests_c_tests ();

View File

@ -170,6 +170,7 @@ extern const char *path_to_selftest_files;
/* Declarations for specific families of tests (by source file), in /* Declarations for specific families of tests (by source file), in
alphabetical order. */ alphabetical order. */
extern void attribute_c_tests ();
extern void bitmap_c_tests (); extern void bitmap_c_tests ();
extern void sbitmap_c_tests (); extern void sbitmap_c_tests ();
extern void diagnostic_c_tests (); extern void diagnostic_c_tests ();

View File

@ -1,3 +1,16 @@
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> 2017-12-07 Tamar Christina <tamar.christina@arm.com>
PR target/82641 PR target/82641

View File

@ -12,16 +12,16 @@ extern __attribute__((noinline)) int fn1 (void); /* { dg-message "previous decla
extern inline int fn1 (void); /* { dg-warning "inline declaration of" } */ extern inline int fn1 (void); /* { dg-warning "inline declaration of" } */
extern inline int fn2 (void); /* { dg-message "previous declaration" } */ 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__((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__((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__((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__((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." } */

View File

@ -17,7 +17,7 @@ static void function_declaration_both_after(void) {t();}
static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */ 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 inline void function_declaration_noinline_after(void) {t();} /* { dg-message "note: previous definition" } */
@ -41,7 +41,7 @@ static void function_declaration_inline_noinline_after(void) __attribute__((__no
static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */ 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();} static void function_declaration_noinline_inline_before(void) {t();}

View File

@ -2,8 +2,9 @@
/* { dg-options "-fkeep-inline-functions -O" } */ /* { dg-options "-fkeep-inline-functions -O" } */
static inline __attribute__ ((const)) static inline __attribute__ ((const))
void baz (int i) int baz (int i)
{ {
return i;
} }
static __attribute__ ((always_inline)) static __attribute__ ((always_inline))

View File

@ -46,16 +46,18 @@ int bizr (void)
return i + 1; return i + 1;
} }
/* This might be regarded as pure and folded, rather than inlined. /* This might be regarded as pure and folded, rather than inlined,
It's pure evil. */ 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)) 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" } */ } /* { dg-warning "does return" } */
static int __attribute__ ((pure, const)) static int __attribute__ ((pure, const))
bark (void) bark (void) { /* { dg-warning "ignoring attribute .const." } */
{
barf (); barf ();
} }

View File

@ -113,17 +113,18 @@ int test9 (int *intarr)
int test99 (int *intarr) int test99 (int *intarr)
{ {
extern int foo9 (int) __attribute__ ((pure)); extern int foo99 (int) __attribute__ ((pure));
int h, v; int h, v;
g9 = 9; g9 = 9;
h = foo9 (g9); h = foo99 (g9);
v = g9; v = g9;
if (v != 9) if (v != 9)
link_error (); link_error ();
return g9; return g9;
} }
extern int foo99 (int); /* foo9 is const because of its declaration in test9. */
extern int foo9 (int);
int test999 (int *arr) int test999 (int *arr)
{ {
@ -134,10 +135,12 @@ int test999 (int *arr)
v1 = g9; v1 = g9;
if (v1 != 9) if (v1 != 9)
link_error (); link_error ();
l = foo99 (l); l = foo9 (l);
return v1 + l; return v1 + l;
} }
/* foo99 is pure because of its declaration in test99. */
extern int foo9 (int);
int test9999 (void) int test9999 (void)
{ {

View File

@ -1938,6 +1938,20 @@ struct attribute_spec {
int flags, bool *no_add_attrs); int flags, bool *no_add_attrs);
/* Specifies if attribute affects type's identity. */ /* Specifies if attribute affects type's identity. */
bool affects_type_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 /* These functions allow a front-end to perform a manual layout of a

View File

@ -1,3 +1,9 @@
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> 2017-12-05 Jason Merrill <jason@redhat.com>
Jonathan Wakely <jwakely@redhat.com> Jonathan Wakely <jwakely@redhat.com>

View File

@ -355,7 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
// XXX GLIBCXX_ABI Deprecated // XXX GLIBCXX_ABI Deprecated
_GLIBCXX_CONST void void
_M_destroy_thread_key(void*) throw (); _M_destroy_thread_key(void*) throw ();
size_t size_t