aboutsummaryrefslogtreecommitdiff
path: root/gcc/attribs.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-11-09 17:32:52 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-11-09 10:32:52 -0700
commit79a2c4281c7dcaa6a138d24fd037c62453a12bde (patch)
treedff179677c863457f73ef49310ef719591c305e7 /gcc/attribs.c
parent900dab1338b45c8fa8d1b315dce53712b857da1d (diff)
downloadgcc-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.c189
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