diff options
author | Martin Sebor <msebor@redhat.com> | 2017-12-07 16:32:03 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2017-12-07 09:32:03 -0700 |
commit | 5d9ae53d70c72991e26648d915e7fb8e00b8e811 (patch) | |
tree | a586e44e1f5c41fd8ae4cb8fd80446c763cc595d /gcc/c-family | |
parent | 1d8b0222b15f2188b659de4a731d8fd5ea23bed0 (diff) | |
download | gcc-5d9ae53d70c72991e26648d915e7fb8e00b8e811.zip gcc-5d9ae53d70c72991e26648d915e7fb8e00b8e811.tar.gz gcc-5d9ae53d70c72991e26648d915e7fb8e00b8e811.tar.bz2 |
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
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.c | 410 | ||||
-rw-r--r-- | gcc/c-family/c-warn.c | 29 |
3 files changed, 302 insertions, 154 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a845fbf..4ad83f3 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -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> PR c/83236 diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index cff5b44..186df05 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -150,6 +150,93 @@ static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); +/* Helper to define attribute exclusions. */ +#define ATTR_EXCL(name, function, type, variable) \ + { name, function, type, variable } + +/* Define attributes that are mutually exclusive with one another. */ +static const struct attribute_spec::exclusions attr_aligned_exclusions[] = +{ + /* Attribute name exclusion applies to: + function, type, variable */ + ATTR_EXCL ("aligned", true, false, false), + ATTR_EXCL ("packed", true, false, false), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = +{ + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_common_exclusions[] = +{ + ATTR_EXCL ("common", true, true, true), + ATTR_EXCL ("nocommon", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_inline_exclusions[] = +{ + ATTR_EXCL ("noinline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_noinline_exclusions[] = +{ + ATTR_EXCL ("always_inline", true, true, true), + ATTR_EXCL ("gnu_inline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = +{ + ATTR_EXCL ("alloc_align", true, true, true), + ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("malloc", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL ("returns_twice", true, true, true), + ATTR_EXCL ("warn_unused_result", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions +attr_warn_unused_result_exclusions[] = +{ + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("warn_unused_result", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = +{ + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc. */ +static const struct attribute_spec::exclusions attr_alloc_exclusions[] = +{ + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = +{ + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("alloc_align", true, true, true), + ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("malloc", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + /* Table of machine-independent attributes common to all C-like languages. All attributes referencing arguments should be additionally processed @@ -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, affects_type_identity } */ { "packed", 0, 0, false, false, false, - handle_packed_attribute , false}, + handle_packed_attribute, false, + attr_aligned_exclusions }, { "nocommon", 0, 0, true, false, false, - handle_nocommon_attribute, false}, + handle_nocommon_attribute, false, + attr_common_exclusions }, { "common", 0, 0, true, false, false, - handle_common_attribute, false }, + handle_common_attribute, false, + attr_common_exclusions }, /* FIXME: logically, noreturn attributes should be listed as "false, true, true" and apply to function types. But implementing this would require all the places in the compiler that use TREE_THIS_VOLATILE on a decl to identify non-returning functions to be located and fixed to check the function type instead. */ { "noreturn", 0, 0, true, false, false, - handle_noreturn_attribute, false }, + handle_noreturn_attribute, false, + attr_noreturn_exclusions }, { "volatile", 0, 0, true, false, false, - handle_noreturn_attribute, false }, + handle_noreturn_attribute, false, NULL }, { "stack_protect", 0, 0, true, false, false, - handle_stack_protect_attribute, false }, + handle_stack_protect_attribute, false, NULL }, { "noinline", 0, 0, true, false, false, - handle_noinline_attribute, false }, + handle_noinline_attribute, false, + attr_noinline_exclusions }, { "noclone", 0, 0, true, false, false, - handle_noclone_attribute, false }, + handle_noclone_attribute, false, NULL }, { "no_icf", 0, 0, true, false, false, - handle_noicf_attribute, false }, + handle_noicf_attribute, false, NULL }, { "noipa", 0, 0, true, false, false, - handle_noipa_attribute, false }, + handle_noipa_attribute, false, NULL }, { "leaf", 0, 0, true, false, false, - handle_leaf_attribute, false }, + handle_leaf_attribute, false, NULL }, { "always_inline", 0, 0, true, false, false, - handle_always_inline_attribute, false }, + handle_always_inline_attribute, false, + attr_inline_exclusions }, { "gnu_inline", 0, 0, true, false, false, - handle_gnu_inline_attribute, false }, + handle_gnu_inline_attribute, false, + attr_inline_exclusions }, { "artificial", 0, 0, true, false, false, - handle_artificial_attribute, false }, + handle_artificial_attribute, false, NULL }, { "flatten", 0, 0, true, false, false, - handle_flatten_attribute, false }, + handle_flatten_attribute, false, NULL }, { "used", 0, 0, true, false, false, - handle_used_attribute, false }, + handle_used_attribute, false, NULL }, { "unused", 0, 0, false, false, false, - handle_unused_attribute, false }, + handle_unused_attribute, false, NULL }, { "externally_visible", 0, 0, true, false, false, - handle_externally_visible_attribute, false }, + handle_externally_visible_attribute, false, NULL }, { "no_reorder", 0, 0, true, false, false, - handle_no_reorder_attribute, false }, + handle_no_reorder_attribute, false, NULL }, /* The same comments as for noreturn attributes apply to const ones. */ { "const", 0, 0, true, false, false, - handle_const_attribute, false }, + handle_const_attribute, false, + attr_const_pure_exclusions }, { "scalar_storage_order", 1, 1, false, false, false, - handle_scalar_storage_order_attribute, false }, + handle_scalar_storage_order_attribute, false, NULL }, { "transparent_union", 0, 0, false, false, false, - handle_transparent_union_attribute, false }, + handle_transparent_union_attribute, false, NULL }, { "constructor", 0, 1, true, false, false, - handle_constructor_attribute, false }, + handle_constructor_attribute, false, NULL }, { "destructor", 0, 1, true, false, false, - handle_destructor_attribute, false }, + handle_destructor_attribute, false, NULL }, { "mode", 1, 1, false, true, false, - handle_mode_attribute, false }, + handle_mode_attribute, false, NULL }, { "section", 1, 1, true, false, false, - handle_section_attribute, false }, + handle_section_attribute, false, NULL }, { "aligned", 0, 1, false, false, false, - handle_aligned_attribute, false }, + handle_aligned_attribute, false, + attr_aligned_exclusions }, { "warn_if_not_aligned", 0, 1, false, false, false, handle_warn_if_not_aligned_attribute, - false }, + false, NULL }, { "weak", 0, 0, true, false, false, - handle_weak_attribute, false }, + handle_weak_attribute, false, NULL }, { "noplt", 0, 0, true, false, false, - handle_noplt_attribute, false }, + handle_noplt_attribute, false, NULL }, { "ifunc", 1, 1, true, false, false, - handle_ifunc_attribute, false }, + handle_ifunc_attribute, false, NULL }, { "alias", 1, 1, true, false, false, - handle_alias_attribute, false }, + handle_alias_attribute, false, NULL }, { "weakref", 0, 1, true, false, false, - handle_weakref_attribute, false }, + handle_weakref_attribute, false, NULL }, { "no_instrument_function", 0, 0, true, false, false, handle_no_instrument_function_attribute, - false }, + false, NULL }, { "no_profile_instrument_function", 0, 0, true, false, false, handle_no_profile_instrument_function_attribute, - false }, + false, NULL }, { "malloc", 0, 0, true, false, false, - handle_malloc_attribute, false }, + handle_malloc_attribute, false, + attr_alloc_exclusions }, { "returns_twice", 0, 0, true, false, false, - handle_returns_twice_attribute, false }, + handle_returns_twice_attribute, false, + attr_returns_twice_exclusions }, { "no_stack_limit", 0, 0, true, false, false, - handle_no_limit_stack_attribute, false }, + handle_no_limit_stack_attribute, false, NULL }, { "pure", 0, 0, true, false, false, - handle_pure_attribute, false }, + handle_pure_attribute, false, + attr_const_pure_exclusions }, { "transaction_callable", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_unsafe", 0, 0, false, true, false, - handle_tm_attribute, true }, + handle_tm_attribute, true, NULL }, { "transaction_safe", 0, 0, false, true, false, - handle_tm_attribute, true }, + handle_tm_attribute, true, NULL }, { "transaction_safe_dynamic", 0, 0, true, false, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_may_cancel_outer", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, /* ??? These two attributes didn't make the transition from the Intel language document to the multi-vendor language document. */ { "transaction_pure", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_wrap", 1, 1, true, false, false, - handle_tm_wrap_attribute, false }, + handle_tm_wrap_attribute, false, NULL }, /* For internal use (marking of builtins) only. The name contains space to prevent its usage in source code. */ { "no vops", 0, 0, true, false, false, - handle_novops_attribute, false }, + handle_novops_attribute, false, NULL }, { "deprecated", 0, 1, false, false, false, - handle_deprecated_attribute, false }, + handle_deprecated_attribute, false, NULL }, { "vector_size", 1, 1, false, true, false, - handle_vector_size_attribute, true }, + handle_vector_size_attribute, true, NULL }, { "visibility", 1, 1, false, false, false, - handle_visibility_attribute, false }, + handle_visibility_attribute, false, NULL }, { "tls_model", 1, 1, true, false, false, - handle_tls_model_attribute, false }, + handle_tls_model_attribute, false, NULL }, { "nonnull", 0, -1, false, true, true, - handle_nonnull_attribute, false }, + handle_nonnull_attribute, false, NULL }, { "nonstring", 0, 0, true, false, false, - handle_nonstring_attribute, false }, + handle_nonstring_attribute, false, NULL }, { "nothrow", 0, 0, true, false, false, - handle_nothrow_attribute, false }, - { "may_alias", 0, 0, false, true, false, NULL, false }, + handle_nothrow_attribute, false, NULL }, + { "may_alias", 0, 0, false, true, false, NULL, false, NULL }, { "cleanup", 1, 1, true, false, false, - handle_cleanup_attribute, false }, + handle_cleanup_attribute, false, NULL }, { "warn_unused_result", 0, 0, false, true, true, - handle_warn_unused_result_attribute, false }, + handle_warn_unused_result_attribute, false, + attr_warn_unused_result_exclusions }, { "sentinel", 0, 1, false, true, true, - handle_sentinel_attribute, false }, + handle_sentinel_attribute, false, NULL }, /* For internal use (marking of builtins) only. The name contains space to prevent its usage in source code. */ { "type generic", 0, 0, false, true, true, - handle_type_generic_attribute, false }, + handle_type_generic_attribute, false, NULL }, { "alloc_size", 1, 2, false, true, true, - handle_alloc_size_attribute, false }, + handle_alloc_size_attribute, false, + attr_alloc_exclusions }, { "cold", 0, 0, true, false, false, - handle_cold_attribute, false }, + handle_cold_attribute, false, + attr_cold_hot_exclusions }, { "hot", 0, 0, true, false, false, - handle_hot_attribute, false }, + handle_hot_attribute, false, + attr_cold_hot_exclusions }, { "no_address_safety_analysis", 0, 0, true, false, false, handle_no_address_safety_analysis_attribute, - false }, + false, NULL }, { "no_sanitize", 1, 1, true, false, false, handle_no_sanitize_attribute, - false }, + false, NULL }, { "no_sanitize_address", 0, 0, true, false, false, handle_no_sanitize_address_attribute, - false }, + false, NULL }, { "no_sanitize_thread", 0, 0, true, false, false, handle_no_sanitize_thread_attribute, - false }, + false, NULL }, { "no_sanitize_undefined", 0, 0, true, false, false, handle_no_sanitize_undefined_attribute, - false }, + false, NULL }, { "asan odr indicator", 0, 0, true, false, false, handle_asan_odr_indicator_attribute, - false }, + false, NULL }, { "warning", 1, 1, true, false, false, - handle_error_attribute, false }, + handle_error_attribute, false, NULL }, { "error", 1, 1, true, false, false, - handle_error_attribute, false }, + handle_error_attribute, false, NULL }, { "target", 1, -1, true, false, false, - handle_target_attribute, false }, + handle_target_attribute, false, NULL }, { "target_clones", 1, -1, true, false, false, - handle_target_clones_attribute, false }, + handle_target_clones_attribute, false, NULL }, { "optimize", 1, -1, true, false, false, - handle_optimize_attribute, false }, + handle_optimize_attribute, false, NULL }, /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, - ignore_attribute, false }, + ignore_attribute, false, NULL }, { "no_split_stack", 0, 0, true, false, false, - handle_no_split_stack_attribute, false }, + handle_no_split_stack_attribute, false, NULL }, /* For internal use (marking of builtins and runtime functions) only. The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, - handle_fnspec_attribute, false }, + handle_fnspec_attribute, false, NULL }, { "warn_unused", 0, 0, false, false, false, - handle_warn_unused_attribute, false }, + handle_warn_unused_attribute, false, NULL }, { "returns_nonnull", 0, 0, false, true, true, - handle_returns_nonnull_attribute, false }, + handle_returns_nonnull_attribute, false, NULL }, { "omp declare simd", 0, -1, true, false, false, - handle_omp_declare_simd_attribute, false }, + handle_omp_declare_simd_attribute, false, NULL }, + { "cilk simd function", 0, -1, true, false, false, + handle_omp_declare_simd_attribute, false, NULL }, { "simd", 0, 1, true, false, false, - handle_simd_attribute, false }, + handle_simd_attribute, false, NULL }, { "omp declare target", 0, 0, true, false, false, - handle_omp_declare_target_attribute, false }, + handle_omp_declare_target_attribute, false, NULL }, { "omp declare target link", 0, 0, true, false, false, - handle_omp_declare_target_attribute, false }, + handle_omp_declare_target_attribute, false, NULL }, { "alloc_align", 1, 1, false, true, true, - handle_alloc_align_attribute, false }, + handle_alloc_align_attribute, false, + attr_alloc_exclusions }, { "assume_aligned", 1, 2, false, true, true, - handle_assume_aligned_attribute, false }, + handle_assume_aligned_attribute, false, NULL }, { "designated_init", 0, 0, false, true, false, - handle_designated_init_attribute, false }, + handle_designated_init_attribute, false, NULL }, { "bnd_variable_size", 0, 0, true, false, false, - handle_bnd_variable_size_attribute, false }, + handle_bnd_variable_size_attribute, false, NULL }, { "bnd_legacy", 0, 0, true, false, false, - handle_bnd_legacy, false }, + handle_bnd_legacy, false, NULL }, { "bnd_instrument", 0, 0, true, false, false, - handle_bnd_instrument, false }, + handle_bnd_instrument, false, NULL }, { "fallthrough", 0, 0, false, false, false, - handle_fallthrough_attribute, false }, + handle_fallthrough_attribute, false, NULL }, { "patchable_function_entry", 1, 2, true, false, false, handle_patchable_function_entry_attribute, - false }, - { "nocf_check", 0, 0, false, true, true, - handle_nocf_check_attribute, true }, - { NULL, 0, 0, false, false, false, NULL, false } + false, NULL }, + { "nocf_check", 0, 0, false, true, true, + handle_nocf_check_attribute, true, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Give the specifications for the format attributes, used by C and all @@ -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, affects_type_identity } */ { "format", 3, 3, false, true, true, - handle_format_attribute, false }, + handle_format_attribute, false, NULL }, { "format_arg", 1, 1, false, true, true, - handle_format_arg_attribute, false }, - { NULL, 0, 0, false, false, false, NULL, false } + handle_format_arg_attribute, false, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain @@ -524,14 +630,7 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (*node) == FUNCTION_DECL || TREE_CODE (*node) == LABEL_DECL) { - if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute ignored due to conflict " - "with attribute %qs", name, "cold"); - *no_add_attrs = true; - } - /* Most of the rest of the hot processing is done later with - lookup_attribute. */ + /* Attribute hot processing is done later with lookup_attribute. */ } else { @@ -552,14 +651,7 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (*node) == FUNCTION_DECL || TREE_CODE (*node) == LABEL_DECL) { - if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute ignored due to conflict " - "with attribute %qs", name, "hot"); - *no_add_attrs = true; - } - /* Most of the rest of the cold processing is done later with - lookup_attribute. */ + /* Attribute cold processing is done later with lookup_attribute. */ } else { @@ -1086,7 +1178,7 @@ handle_no_reorder_attribute (tree *pnode, static tree handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) + int flags, bool *no_add_attrs) { tree type = TREE_TYPE (*node); @@ -1107,6 +1199,14 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), *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; } @@ -1689,15 +1789,19 @@ check_cxx_fundamental_alignment_constraints (tree node, handle_aligned_attribute. */ static tree -common_handle_aligned_attribute (tree *node, tree args, int flags, +common_handle_aligned_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs, bool warn_if_not_aligned_p) { tree decl = NULL_TREE; tree *type = NULL; - int is_type = 0; + bool is_type = false; tree align_expr; - int i; + + /* The last (already pushed) declaration with all validated attributes + merged in or the current about-to-be-pushed one if one hasn't been + yet. */ + tree last_decl = node[1] ? node[1] : *node; if (args) { @@ -1716,10 +1820,21 @@ common_handle_aligned_attribute (tree *node, tree args, int flags, is_type = TREE_CODE (*node) == TYPE_DECL; } else if (TYPE_P (*node)) - type = node, is_type = 1; + type = node, is_type = true; + + /* Log2 of specified alignment. */ + int pow2align = check_user_alignment (align_expr, true); + + /* The alignment in bits corresponding to the specified alignment. */ + unsigned bitalign = (1U << pow2align) * BITS_PER_UNIT; + + /* The alignment of the current declaration and that of the last + pushed declaration, determined on demand below. */ + unsigned curalign = 0; + unsigned lastalign = 0; - if ((i = check_user_alignment (align_expr, true)) == -1 - || !check_cxx_fundamental_alignment_constraints (*node, i, flags)) + if (pow2align == -1 + || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags)) *no_add_attrs = true; else if (is_type) { @@ -1742,12 +1857,12 @@ common_handle_aligned_attribute (tree *node, tree args, int flags, if (warn_if_not_aligned_p) { - SET_TYPE_WARN_IF_NOT_ALIGN (*type, (1U << i) * BITS_PER_UNIT); + SET_TYPE_WARN_IF_NOT_ALIGN (*type, bitalign); warn_if_not_aligned_p = false; } else { - SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT); + SET_TYPE_ALIGN (*type, bitalign); TYPE_USER_ALIGN (*type) = 1; } } @@ -1757,8 +1872,34 @@ common_handle_aligned_attribute (tree *node, tree args, int flags, error ("alignment may not be specified for %q+D", decl); *no_add_attrs = true; } + else if (TREE_CODE (decl) == FUNCTION_DECL + && ((curalign = DECL_ALIGN (decl)) > bitalign + || ((lastalign = DECL_ALIGN (last_decl)) > bitalign))) + { + /* Either a prior attribute on the same declaration or one + on a prior declaration of the same function specifies + stricter alignment than this attribute. */ + bool note = lastalign != 0; + if (lastalign) + curalign = lastalign; + + curalign /= BITS_PER_UNIT; + bitalign /= BITS_PER_UNIT; + + if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl)) + warning (OPT_Wattributes, + "ignoring attribute %<%E (%u)%> because it conflicts with " + "attribute %<%E (%u)%>", name, bitalign, name, curalign); + else + error ("alignment for %q+D must be at least %d", decl, curalign); + + if (note) + inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here"); + + *no_add_attrs = true; + } else if (DECL_USER_ALIGN (decl) - && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + && DECL_ALIGN (decl) > bitalign) /* C++-11 [dcl.align/4]: When multiple alignment-specifiers are specified for an @@ -1770,7 +1911,7 @@ common_handle_aligned_attribute (tree *node, tree args, int flags, *no_add_attrs = true; else if (!warn_if_not_aligned_p && TREE_CODE (decl) == FUNCTION_DECL - && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + && DECL_ALIGN (decl) > bitalign) { /* Don't warn function alignment here if warn_if_not_aligned_p is true. It will be warned later. */ @@ -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)) { - SET_DECL_WARN_IF_NOT_ALIGN (decl, (1U << i) * BITS_PER_UNIT); + SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign); warn_if_not_aligned_p = false; } } else { - SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT); + SET_DECL_ALIGN (decl, bitalign); DECL_USER_ALIGN (decl) = 1; } } @@ -1814,10 +1955,10 @@ common_handle_aligned_attribute (tree *node, tree args, int flags, struct attribute_spec.handler. */ static tree -handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, +handle_aligned_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) { - return common_handle_aligned_attribute (node, args, flags, + return common_handle_aligned_attribute (node, name, args, flags, no_add_attrs, false); } @@ -1825,11 +1966,11 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, struct attribute_spec.handler. */ static tree -handle_warn_if_not_aligned_attribute (tree *node, tree ARG_UNUSED (name), +handle_warn_if_not_aligned_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) { - return common_handle_aligned_attribute (node, args, flags, + return common_handle_aligned_attribute (node, name, args, flags, no_add_attrs, true); } @@ -2538,8 +2679,15 @@ handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_PURE_P (*node) = 1; - /* ??? TODO: Support types. */ + { + tree type = TREE_TYPE (*node); + if (VOID_TYPE_P (TREE_TYPE (type))) + warning (OPT_Wattributes, "%qE attribute on function " + "returning %<void%>", name); + + DECL_PURE_P (*node) = 1; + /* ??? TODO: Support types. */ + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index 6cfded9..6045d6e 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -2230,36 +2230,19 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl) newdecl); /* Diagnose inline __attribute__ ((noinline)) which is silly. */ + const char *noinline = "noinline"; + if (DECL_DECLARED_INLINE_P (newdecl) && DECL_UNINLINABLE (olddecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) + && lookup_attribute (noinline, DECL_ATTRIBUTES (olddecl))) warned |= warning (OPT_Wattributes, "inline declaration of %qD follows " - "declaration with attribute noinline", newdecl); + "declaration with attribute %qs", newdecl, noinline); else if (DECL_DECLARED_INLINE_P (olddecl) && DECL_UNINLINABLE (newdecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "noinline follows inline declaration ", newdecl); - else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "noinline", "always_inline"); - else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "always_inline", "noinline"); - else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "cold", "hot"); - else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "hot", "cold"); + "%qs follows inline declaration ", newdecl, noinline); + return warned; } |