diff options
author | Martin Sebor <msebor@redhat.com> | 2018-11-09 17:32:52 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2018-11-09 10:32:52 -0700 |
commit | 79a2c4281c7dcaa6a138d24fd037c62453a12bde (patch) | |
tree | dff179677c863457f73ef49310ef719591c305e7 /gcc/attribs.c | |
parent | 900dab1338b45c8fa8d1b315dce53712b857da1d (diff) | |
download | gcc-79a2c4281c7dcaa6a138d24fd037c62453a12bde.zip gcc-79a2c4281c7dcaa6a138d24fd037c62453a12bde.tar.gz gcc-79a2c4281c7dcaa6a138d24fd037c62453a12bde.tar.bz2 |
PR middle-end/81824 - Warn for missing attributes with function aliases
gcc/c-family/ChangeLog:
PR middle-end/81824
* c-attribs.c (handle_copy_attribute): New function.
gcc/cp/ChangeLog:
PR middle-end/81824
* pt.c (warn_spec_missing_attributes): Move code to attribs.c.
Call decls_mismatched_attributes.
gcc/ChangeLog:
PR middle-end/81824
* attribs.c (has_attribute): New helper function.
(decls_mismatched_attributes, maybe_diag_alias_attributes): Same.
* attribs.h (decls_mismatched_attributes): Declare.
* cgraphunit.c (handle_alias_pairs): Call maybe_diag_alias_attributes.
(maybe_diag_incompatible_alias): Use OPT_Wattribute_alias_.
* common.opt (-Wattribute-alias): Take an argument.
(-Wno-attribute-alias): New option.
* doc/extend.texi (Common Function Attributes): Document copy.
(Common Variable Attributes): Same.
* doc/invoke.texi (-Wmissing-attributes): Document enhancement.
(-Wattribute-alias): Document new option argument.
gcc/testsuite/ChangeLog:
PR middle-end/81824
* gcc.dg/Wattribute-alias.c: New test.
* gcc.dg/Wmissing-attributes.c: New test.
* gcc.dg/attr-copy.c: New test.
* gcc.dg/attr-copy-2.c: New test.
* gcc.dg/attr-copy-3.c: New test.
* gcc.dg/attr-copy-4.c: New test.
From-SVN: r265980
Diffstat (limited to 'gcc/attribs.c')
-rw-r--r-- | gcc/attribs.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c index 8b72127..dfe13ad7 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -30,6 +30,9 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "selftest.h" #include "hash-set.h" +#include "diagnostic.h" +#include "pretty-print.h" +#include "intl.h" /* Table of the tables of attributes (common, language, format, machine) searched. */ @@ -1812,6 +1815,192 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) return list; } +/* Return true if the function decl or type NODE has been declared + with attribute ANAME among attributes ATTRS. */ + +static bool +has_attribute (tree node, tree attrs, const char *aname) +{ + if (!strcmp (aname, "const")) + { + if (DECL_P (node) && TREE_READONLY (node)) + return true; + } + else if (!strcmp (aname, "malloc")) + { + if (DECL_P (node) && DECL_IS_MALLOC (node)) + return true; + } + else if (!strcmp (aname, "noreturn")) + { + if (DECL_P (node) && TREE_THIS_VOLATILE (node)) + return true; + } + else if (!strcmp (aname, "nothrow")) + { + if (TREE_NOTHROW (node)) + return true; + } + else if (!strcmp (aname, "pure")) + { + if (DECL_P (node) && DECL_PURE_P (node)) + return true; + } + + return lookup_attribute (aname, attrs); +} + +/* Return the number of mismatched function or type attributes between + the "template" function declaration TMPL and DECL. The word "template" + doesn't necessarily refer to a C++ template but rather a declaration + whose attributes should be matched by those on DECL. For a non-zero + return value set *ATTRSTR to a string representation of the list of + mismatched attributes with quoted names. + ATTRLIST is a list of additional attributes that SPEC should be + taken to ultimately be declared with. */ + +unsigned +decls_mismatched_attributes (tree tmpl, tree decl, tree attrlist, + const char* const blacklist[], + pretty_printer *attrstr) +{ + if (TREE_CODE (tmpl) != FUNCTION_DECL) + return 0; + + /* Avoid warning if either declaration or its type is deprecated. */ + if (TREE_DEPRECATED (tmpl) + || TREE_DEPRECATED (decl)) + return 0; + + const tree tmpls[] = { tmpl, TREE_TYPE (tmpl) }; + const tree decls[] = { decl, TREE_TYPE (decl) }; + + if (TREE_DEPRECATED (tmpls[1]) + || TREE_DEPRECATED (decls[1]) + || TREE_DEPRECATED (TREE_TYPE (tmpls[1])) + || TREE_DEPRECATED (TREE_TYPE (decls[1]))) + return 0; + + tree tmpl_attrs[] = { DECL_ATTRIBUTES (tmpl), TYPE_ATTRIBUTES (tmpls[1]) }; + tree decl_attrs[] = { DECL_ATTRIBUTES (decl), TYPE_ATTRIBUTES (decls[1]) }; + + if (!decl_attrs[0]) + decl_attrs[0] = attrlist; + else if (!decl_attrs[1]) + decl_attrs[1] = attrlist; + + /* Avoid warning if the template has no attributes. */ + if (!tmpl_attrs[0] && !tmpl_attrs[1]) + return 0; + + /* Avoid warning if either declaration contains an attribute on + the white list below. */ + const char* const whitelist[] = { + "error", "warning" + }; + + for (unsigned i = 0; i != 2; ++i) + for (unsigned j = 0; j != sizeof whitelist / sizeof *whitelist; ++j) + if (lookup_attribute (whitelist[j], tmpl_attrs[i]) + || lookup_attribute (whitelist[j], decl_attrs[i])) + return 0; + + /* Put together a list of the black-listed attributes that the template + is declared with and the declaration is not, in case it's not apparent + from the most recent declaration of the template. */ + unsigned nattrs = 0; + + for (unsigned i = 0; blacklist[i]; ++i) + { + for (unsigned j = 0; j != 2; ++j) + { + if (!has_attribute (tmpls[j], tmpl_attrs[j], blacklist[i])) + continue; + + unsigned kmax = 1 + !!decl_attrs[1]; + for (unsigned k = 0; k != kmax; ++k) + { + if (has_attribute (decls[k], decl_attrs[k], blacklist[i])) + break; + + if (!k && kmax > 1) + continue; + + if (nattrs) + pp_string (attrstr, ", "); + pp_begin_quote (attrstr, pp_show_color (global_dc->printer)); + pp_string (attrstr, blacklist[i]); + pp_end_quote (attrstr, pp_show_color (global_dc->printer)); + ++nattrs; + } + } + } + + return nattrs; +} + +/* Issue a warning for the declaration ALIAS for TARGET where ALIAS + specifies either attributes that are incompatible with those of + TARGET, or attributes that are missing and that declaring ALIAS + with would benefit. */ + +void +maybe_diag_alias_attributes (tree alias, tree target) +{ + /* Do not expect attributes to match between aliases and ifunc + resolvers. There is no obvious correspondence between them. */ + if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias))) + return; + + const char* const blacklist[] = { + "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", + "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", + "returns_twice", NULL + }; + + pretty_printer attrnames; + if (warn_attribute_alias > 1) + { + /* With -Wattribute-alias=2 detect alias declarations that are more + restrictive than their targets first. Those indicate potential + codegen bugs. */ + if (unsigned n = decls_mismatched_attributes (alias, target, NULL_TREE, + blacklist, &attrnames)) + { + auto_diagnostic_group d; + if (warning_n (DECL_SOURCE_LOCATION (alias), + OPT_Wattribute_alias_, n, + "%qD specifies more restrictive attribute than " + "its target %qD: %s", + "%qD specifies more restrictive attributes than " + "its target %qD: %s", + alias, target, pp_formatted_text (&attrnames))) + inform (DECL_SOURCE_LOCATION (target), + "%qD target declared here", alias); + return; + } + } + + /* Detect alias declarations that are less restrictive than their + targets. Those suggest potential optimization opportunities + (solved by adding the missing attribute(s) to the alias). */ + if (unsigned n = decls_mismatched_attributes (target, alias, NULL_TREE, + blacklist, &attrnames)) + { + auto_diagnostic_group d; + if (warning_n (DECL_SOURCE_LOCATION (alias), + OPT_Wmissing_attributes, n, + "%qD specifies less restrictive attribute than " + "its target %qD: %s", + "%qD specifies less restrictive attributes than " + "its target %qD: %s", + alias, target, pp_formatted_text (&attrnames))) + inform (DECL_SOURCE_LOCATION (target), + "%qD target declared here", alias); + } +} + + #if CHECKING_P namespace selftest |