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
This commit is contained in:
Martin Sebor 2018-11-09 17:32:52 +00:00 committed by Martin Sebor
parent 900dab1338
commit 79a2c4281c
19 changed files with 1451 additions and 114 deletions

View File

@ -1,3 +1,18 @@
2018-11-09 Martin Sebor <msebor@redhat.com>
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.
2018-11-09 Richard Earnshaw <rearnsha@arm.com>
* config/arm/parsecpu.awk (/alias/): Tighten invisible alias

View File

@ -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

View File

@ -105,6 +105,12 @@ extern int attribute_list_contained (const_tree, const_tree);
extern tree private_lookup_attribute (const char *attr_name, size_t attr_len,
tree list);
extern unsigned decls_mismatched_attributes (tree, tree, tree,
const char* const[],
pretty_printer*);
extern void maybe_diag_alias_attributes (tree, tree);
/* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
so that we have a canonical form of attribute names. */

View File

@ -1,3 +1,8 @@
2018-11-09 Martin Sebor <msebor@redhat.com>
PR middle-end/81824
* c-attribs.c (handle_copy_attribute): New function.
2018-11-09 Martin Sebor <msebor@redhat.com>
PR c/87795

View File

@ -146,6 +146,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
int, bool *);
static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
@ -455,6 +456,8 @@ const struct attribute_spec c_common_attribute_table[] =
NULL },
{ "nocf_check", 0, 0, false, true, true, true,
handle_nocf_check_attribute, NULL },
{ "copy", 1, 1, false, false, false, false,
handle_copy_attribute, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
@ -2137,6 +2140,151 @@ handle_alias_attribute (tree *node, tree name, tree args,
return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
}
/* Handle the "copy" attribute NAME by copying the set of attributes
from the symbol referenced by ARGS to the declaration of *NODE. */
static tree
handle_copy_attribute (tree *node, tree name, tree args,
int flags, bool *no_add_attrs)
{
/* Do not apply the copy attribute itself. It serves no purpose
other than to copy other attributes. */
*no_add_attrs = true;
tree decl = *node;
tree ref = TREE_VALUE (args);
if (ref == error_mark_node)
return NULL_TREE;
if (TREE_CODE (ref) == STRING_CST)
{
/* Explicitly handle this case since using a string literal
as an argument is a likely mistake. */
error_at (DECL_SOURCE_LOCATION (decl),
"%qE attribute argument cannot be a string",
name);
return NULL_TREE;
}
if (CONSTANT_CLASS_P (ref)
&& (INTEGRAL_TYPE_P (TREE_TYPE (ref))
|| FLOAT_TYPE_P (TREE_TYPE (ref))))
{
/* Similar to the string case, since some function attributes
accept literal numbers as arguments (e.g., alloc_size or
nonnull) using one here is a likely mistake. */
error_at (DECL_SOURCE_LOCATION (decl),
"%qE attribute argument cannot be a constant arithmetic "
"expression",
name);
return NULL_TREE;
}
if (ref == node[1])
{
/* Another possible mistake (but indirect self-references aren't
and diagnosed and shouldn't be). */
if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
"%qE attribute ignored on a redeclaration "
"of the referenced symbol",
name))
inform (DECL_SOURCE_LOCATION (node[1]),
"previous declaration here");
return NULL_TREE;
}
/* Consider address-of expressions in the attribute argument
as requests to copy from the referenced entity. For constant
expressions, consider those to be requests to copy from their
type, such as in:
struct __attribute__ (copy ((struct T *)0)) U { ... };
which copies type attributes from struct T to the declaration
of struct U. */
if (TREE_CODE (ref) == ADDR_EXPR)
ref = TREE_OPERAND (ref, 0);
else if (CONSTANT_CLASS_P (ref))
ref = TREE_TYPE (ref);
if (DECL_P (decl))
{
if ((VAR_P (decl)
&& (TREE_CODE (ref) == FUNCTION_DECL
|| (EXPR_P (ref)
&& POINTER_TYPE_P (TREE_TYPE (ref))
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (TREE_TYPE (ref))))))
|| (TREE_CODE (decl) == FUNCTION_DECL
&& (VAR_P (ref)
|| (EXPR_P (ref)
&& !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (ref))))))
{
/* It makes no sense to try to copy function attributes
to a variable, or variable attributes to a function. */
if (warning (OPT_Wattributes,
"%qE attribute ignored on a declaration of "
"a different kind than referenced symbol",
name)
&& DECL_P (ref))
inform (DECL_SOURCE_LOCATION (ref),
"symbol %qD referenced by %qD declared here", ref, decl);
return NULL_TREE;
}
tree attrs = NULL_TREE;
if (DECL_P (ref))
attrs = DECL_ATTRIBUTES (ref);
else if (TYPE_P (ref))
attrs = TYPE_ATTRIBUTES (ref);
/* Copy decl attributes from REF to DECL. */
for (tree at = attrs; at; at = TREE_CHAIN (at))
{
/* Avoid copying attributes that affect a symbol linkage or
visibility since those in all likelihood only apply to
the target.
FIXME: make it possible to specify which attributes to
copy or not to copy in the copy attribute itself. */
tree atname = get_attribute_name (at);
if (is_attribute_p ("alias", atname)
|| is_attribute_p ("ifunc", atname)
|| is_attribute_p ("visibility", atname)
|| is_attribute_p ("weak", atname)
|| is_attribute_p ("weakref", atname))
continue;
tree atargs = TREE_VALUE (at);
/* Create a copy of just the one attribute ar AT, including
its argumentsm and add it to DECL. */
tree attr = tree_cons (atname, copy_list (atargs), NULL_TREE);
decl_attributes (node, attr, flags, ref);
}
/* Proceed to copy type attributes below. */
}
else if (!TYPE_P (decl))
{
error_at (DECL_SOURCE_LOCATION (decl),
"%qE attribute must apply to a declaration",
name);
return NULL_TREE;
}
tree reftype = ref;
if (DECL_P (ref) || EXPR_P (ref))
reftype = TREE_TYPE (ref);
if (POINTER_TYPE_P (reftype))
reftype = TREE_TYPE (reftype);
tree attrs = TYPE_ATTRIBUTES (reftype);
/* Copy type attributes from REF to DECL. */
for (tree at = attrs; at; at = TREE_CHAIN (at))
decl_attributes (node, at, flags, ref);
return NULL_TREE;
}
/* Handle a "weakref" attribute; arguments as in struct
attribute_spec.handler. */
@ -2962,34 +3110,11 @@ handle_deprecated_attribute (tree *node, tree name,
return NULL_TREE;
}
/* Handle a "vector_size" attribute; arguments as in
struct attribute_spec.handler. */
/* Return the "base" type from TYPE that is suitable to apply attribute
vector_size to by stripping arrays, function types, etc. */
static tree
handle_vector_size_attribute (tree *node, tree name, tree args,
int ARG_UNUSED (flags),
bool *no_add_attrs)
type_for_vector_size (tree type)
{
unsigned HOST_WIDE_INT vecsize, nunits;
machine_mode orig_mode;
tree type = *node, new_type, size;
*no_add_attrs = true;
size = TREE_VALUE (args);
if (size && TREE_CODE (size) != IDENTIFIER_NODE
&& TREE_CODE (size) != FUNCTION_DECL)
size = default_conversion (size);
if (!tree_fits_uhwi_p (size))
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
return NULL_TREE;
}
/* Get the vector size (in bytes). */
vecsize = tree_to_uhwi (size);
/* We need to provide for vector pointers, vector arrays, and
functions returning vectors. For example:
@ -3005,8 +3130,25 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
|| TREE_CODE (type) == OFFSET_TYPE)
type = TREE_TYPE (type);
return type;
}
/* Given TYPE, return the base type to which the vector_size attribute
ATNAME with ARGS, when non-null, can be applied, if one exists.
On success and when both ARGS and PTRNUNITS are non-null, set
*PTRNUNINTS to the number of vector units. When PTRNUNITS is not
null, issue a warning when the attribute argument is not constant
and an error if there is no such type. Otherwise issue a warning
in the latter case and return null. */
static tree
type_valid_for_vector_size (tree type, tree atname, tree args,
unsigned HOST_WIDE_INT *ptrnunits)
{
bool error_p = ptrnunits != NULL;
/* Get the mode of the type being modified. */
orig_mode = TYPE_MODE (type);
machine_mode orig_mode = TYPE_MODE (type);
if ((!INTEGRAL_TYPE_P (type)
&& !SCALAR_FLOAT_TYPE_P (type)
@ -3017,14 +3159,38 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
|| !tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
|| TREE_CODE (type) == BOOLEAN_TYPE)
{
error ("invalid vector type for attribute %qE", name);
if (error_p)
error ("invalid vector type for attribute %qE", atname);
else
warning (OPT_Wattributes, "invalid vector type for attribute %qE",
atname);
return NULL_TREE;
}
/* When no argument has been provided this is just a request to validate
the type above. Return TYPE to indicate success. */
if (!args)
return type;
tree size = TREE_VALUE (args);
if (size && TREE_CODE (size) != IDENTIFIER_NODE
&& TREE_CODE (size) != FUNCTION_DECL)
size = default_conversion (size);
if (!tree_fits_uhwi_p (size))
{
/* FIXME: make the error message more informative. */
if (error_p)
warning (OPT_Wattributes, "%qE attribute ignored", atname);
return NULL_TREE;
}
unsigned HOST_WIDE_INT vecsize = tree_to_uhwi (size);
if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type)))
{
error ("vector size not an integral multiple of component size");
return NULL;
if (error_p)
error ("vector size not an integral multiple of component size");
return NULL_TREE;
}
if (vecsize == 0)
@ -3034,14 +3200,44 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
}
/* Calculate how many units fit in the vector. */
nunits = vecsize / tree_to_uhwi (TYPE_SIZE_UNIT (type));
unsigned HOST_WIDE_INT nunits = vecsize / tree_to_uhwi (TYPE_SIZE_UNIT (type));
if (nunits & (nunits - 1))
{
error ("number of components of the vector not a power of two");
if (error_p)
error ("number of components of the vector not a power of two");
else
warning (OPT_Wattributes,
"number of components of the vector not a power of two");
return NULL_TREE;
}
new_type = build_vector_type (type, nunits);
if (ptrnunits)
*ptrnunits = nunits;
return type;
}
/* Handle a "vector_size" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_vector_size_attribute (tree *node, tree name, tree args,
int ARG_UNUSED (flags),
bool *no_add_attrs)
{
*no_add_attrs = true;
/* Determine the "base" type to apply the attribute to. */
tree type = type_for_vector_size (*node);
/* Get the vector size (in bytes) and let the function compute
the number of vector units. */
unsigned HOST_WIDE_INT nunits;
type = type_valid_for_vector_size (type, name, args, &nunits);
if (!type)
return NULL_TREE;
tree new_type = build_vector_type (type, nunits);
/* Build back pointers if needed. */
*node = lang_hooks.types.reconstruct_complex_type (*node, new_type);
@ -3512,3 +3708,324 @@ handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *)
/* Nothing to be done here. */
return NULL_TREE;
}
/* Attempt to partially validate a single attribute ATTR as if
it were to be applied to an entity OPER. */
static bool
validate_attribute (location_t atloc, tree oper, tree attr)
{
/* Determine whether the name of the attribute is valid
and fail with an error if not. */
tree atname = get_attribute_name (attr);
if (!lookup_attribute_spec (atname))
{
if (atloc != UNKNOWN_LOCATION)
error_at (atloc, "unknown attribute %qE", atname);
return false;
}
tree args = TREE_VALUE (attr);
if (!args)
return true;
/* FIXME: Do some validation. */
const char *atstr = IDENTIFIER_POINTER (atname);
if (!strcmp (atstr, "format"))
return true;
/* Only when attribute arguments have been provided try to validate
the whole thing. decl_attributes doesn't return an indication of
success or failure so proceed regardless. */
const char tmpname[] = "__builtin_has_attribute_tmp.";
tree tmpid = get_identifier (tmpname);
tree tmpdecl;
if (!strcmp (atstr, "vector_size"))
{
tree type = TYPE_P (oper) ? oper : TREE_TYPE (oper);
/* Check for function type here since type_for_vector_size
strips it while looking for a function's return type. */
if (FUNC_OR_METHOD_TYPE_P (type))
{
warning_at (atloc, OPT_Wattributes,
"invalid operand type %qT for %qs", type, atstr);
return false;
}
type = type_for_vector_size (type);
if (VECTOR_TYPE_P (type))
type = TREE_TYPE (type);
/* Avoid trying to apply attribute vector_size to OPER since
it's overly restrictive. Simply make sure it has the right
type. */
return type_valid_for_vector_size (type, atname, args, NULL);
}
if (TYPE_P (oper))
tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, oper);
else
tmpdecl = build_decl (atloc, TREE_CODE (oper), tmpid, TREE_TYPE (oper));
/* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes
believe the DECL declared above is at file scope. (See bug 87526.) */
tree save_curfunc = current_function_decl;
current_function_decl = NULL_TREE;
if (DECL_P (tmpdecl))
{
if (DECL_P (oper))
/* An alias cannot be a defintion so declare the symbol extern. */
DECL_EXTERNAL (tmpdecl) = true;
/* Attribute visibility only applies to symbols visible from other
translation units so make it "public." */
TREE_PUBLIC (tmpdecl) = TREE_PUBLIC (oper);
}
decl_attributes (&tmpdecl, attr, 0);
current_function_decl = save_curfunc;
/* FIXME: Change decl_attributes to indicate success or failure (and
parameterize it to avoid failing with errors). */
return true;
}
/* Return true if the DECL, EXPR, or TYPE t has been declared with
attribute ATTR. For DECL, consider also its type. For EXPR,
consider just its type. */
bool
has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
{
if (!attr || !t || t == error_mark_node)
return false;
if (!validate_attribute (atloc, t, attr))
return false;
tree type = NULL_TREE;
tree expr = NULL_TREE;
if (TYPE_P (t))
type = t;
else
{
do
{
/* Determine the array element/member declaration from
an ARRAY/COMPONENT_REF. */
STRIP_NOPS (t);
tree_code code = TREE_CODE (t);
if (code == ARRAY_REF)
t = TREE_OPERAND (t, 0);
else if (code == COMPONENT_REF)
t = TREE_OPERAND (t, 1);
else
break;
} while (true);
expr = t;
}
/* Set to true when an attribute is found in the referenced entity
that matches the specified attribute. */
bool found_match = false;
tree atname = get_attribute_name (attr);
const char *namestr = IDENTIFIER_POINTER (atname);
/* Iterate once for a type and twice for a function or variable
declaration: once for the DECL and the second time for its
TYPE. */
for (bool done = false; !found_match && !done; )
{
tree atlist;
if (type)
{
if (type == error_mark_node)
{
/* This could be a label. FIXME: add support for labels. */
warning_at (atloc, OPT_Wattributes,
(TYPE_P (t)
? G_("%qs attribute not supported for %qT "
"in %<__builtin_has_attribute%>")
: G_("%qs attribute not supported for %qE "
"in %<__builtin_has_attribute%>")),
namestr, t);
return false;
}
/* Clear EXPR to prevent considering it again below. */
atlist = TYPE_ATTRIBUTES (type);
expr = NULL_TREE;
done = true;
}
else if (DECL_P (expr))
{
/* Set TYPE to the DECL's type to process it on the next
iteration. */
atlist = DECL_ATTRIBUTES (expr);
type = TREE_TYPE (expr);
}
else
{
atlist = TYPE_ATTRIBUTES (TREE_TYPE (expr));
done = true;
}
/* True when an attribute with the sought name (though not necessarily
with the sought attributes) has been found on the attribute chain. */
bool found_attr = false;
/* For attribute aligned ignore the attribute list and consider
the tree node itself instead. */
if (type && !strcmp ("aligned", namestr))
atlist = NULL_TREE;
/* When clear, the first mismatched attribute argument results
in failure. Otherwise, the first matched attribute argument
results in success. */
bool attr_nonnull = !strcmp ("nonnull", namestr);
bool ignore_mismatches = attr_nonnull;
/* Iterate over the instances of the sought attribute on the DECL or
TYPE (there may be multiple instances with different arguments). */
for (; (atlist = lookup_attribute (namestr, atlist));
found_attr = true, atlist = TREE_CHAIN (atlist))
{
/* If there are no arguments to match the result is true except
for nonnull where the attribute with no arguments must match. */
if (!TREE_VALUE (attr))
return attr_nonnull ? !TREE_VALUE (atlist) : true;
/* Attribute nonnull with no arguments subsumes all values of
the attribute. FIXME: This is overly broad since it only
applies to pointer arguments, but querying non-pointer
arguments is diagnosed. */
if (!TREE_VALUE (atlist) && attr_nonnull)
return true;
/* Iterate over the DECL or TYPE attribute argument's values. */
for (tree val = TREE_VALUE (atlist); val; val = TREE_CHAIN (val))
{
/* Iterate over the arguments in the sought attribute comparing
their values to those specified for the DECL or TYPE. */
for (tree arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg))
{
tree v1 = TREE_VALUE (val);
tree v2 = TREE_VALUE (arg);
if (v1 == v2)
return true;
if (!v1 || !v2)
break;
if (TREE_CODE (v1) == IDENTIFIER_NODE
|| TREE_CODE (v2) == IDENTIFIER_NODE)
/* Two identifiers are the same if their values are
equal (that's handled above). Otherwise ther are
either not the same or oneis not an identifier. */
return false;
/* Convert to make them equality-comparable. */
v1 = convert (v1);
v2 = convert (v2);
/* A positive value indicates equality, negative means
"don't know." */
if (simple_cst_equal (v1, v2) == 1)
return true;
if (!ignore_mismatches)
break;
}
}
}
if (!found_attr)
{
/* Some attributes are encoded directly in the tree node. */
if (!strcmp ("aligned", namestr))
{
if (tree arg = TREE_VALUE (attr))
{
arg = convert (TREE_VALUE (arg));
if (expr && DECL_P (expr)
&& DECL_USER_ALIGN (expr)
&& tree_fits_uhwi_p (arg))
found_match = DECL_ALIGN_UNIT (expr) == tree_to_uhwi (arg);
else if (type && TYPE_USER_ALIGN (type))
found_match = TYPE_ALIGN_UNIT (type) == tree_to_uhwi (arg);
}
else if (expr && DECL_P (expr))
found_match = DECL_USER_ALIGN (expr);
else if (type)
found_match = TYPE_USER_ALIGN (type);
}
else if (!strcmp ("const", namestr))
{
if (expr && DECL_P (expr))
found_match = TREE_READONLY (expr);
}
else if (!strcmp ("const", namestr))
{
if (expr && DECL_P (expr))
found_match = DECL_PURE_P (expr);
}
else if (!strcmp ("deprecated", namestr))
{
found_match = TREE_DEPRECATED (expr ? expr : type);
if (found_match)
return true;
}
else if (!strcmp ("vector_size", namestr))
{
if (!type)
continue;
/* Determine the base type from arrays, pointers, and such.
Fail if the base type is not a vector. */
type = type_for_vector_size (type);
if (!VECTOR_TYPE_P (type))
return false;
if (tree arg = TREE_VALUE (attr))
{
/* Compare the vector size argument for equality. */
arg = convert (TREE_VALUE (arg));
return tree_int_cst_equal (arg, TYPE_SIZE_UNIT (type)) == 1;
}
else
return true;
}
else if (!strcmp ("warn_if_not_aligned", namestr))
{
if (tree arg = TREE_VALUE (attr))
{
arg = convert (TREE_VALUE (arg));
if (expr && DECL_P (expr))
found_match = (DECL_WARN_IF_NOT_ALIGN (expr)
== tree_to_uhwi (arg) * BITS_PER_UNIT);
else if (type)
found_match = (TYPE_WARN_IF_NOT_ALIGN (type)
== tree_to_uhwi (arg) * BITS_PER_UNIT);
}
else if (expr && DECL_P (expr))
found_match = DECL_WARN_IF_NOT_ALIGN (expr);
else if (type)
found_match = TYPE_WARN_IF_NOT_ALIGN (type);
}
else if (!strcmp ("transparent_union", namestr))
{
if (type)
found_match = TYPE_TRANSPARENT_AGGR (type) != 0;
}
else if (!strcmp ("mode", namestr))
{
/* Finally issue a warning for attributes that cannot
be supported in this context. Attribute mode is not
added to a symbol and cannot be determined from it. */
warning_at (atloc, OPT_Wattributes,
"%qs attribute not supported in "
"%<__builtin_has_attribute%>", namestr);
break;
}
}
}
return found_match;
}

View File

@ -1364,7 +1364,7 @@ maybe_diag_incompatible_alias (tree alias, tree target)
auto_diagnostic_group d;
if (warning_at (DECL_SOURCE_LOCATION (target),
OPT_Wattribute_alias,
OPT_Wattribute_alias_,
"%<ifunc%> resolver for %qD should return %qT",
alias, funcptr))
inform (DECL_SOURCE_LOCATION (alias),
@ -1374,11 +1374,11 @@ maybe_diag_incompatible_alias (tree alias, tree target)
{
auto_diagnostic_group d;
if (warning_at (DECL_SOURCE_LOCATION (alias),
OPT_Wattribute_alias,
OPT_Wattribute_alias_,
"%qD alias between functions of incompatible "
"types %qT and %qT", alias, altype, targtype))
inform (DECL_SOURCE_LOCATION (target),
"aliased declaration here");
"aliased declaration here");
}
}
}
@ -1441,6 +1441,8 @@ handle_alias_pairs (void)
{
maybe_diag_incompatible_alias (p->decl, target_node->decl);
maybe_diag_alias_attributes (p->decl, target_node->decl);
cgraph_node *src_node = cgraph_node::get (p->decl);
if (src_node && src_node->definition)
src_node->reset ();

View File

@ -550,9 +550,13 @@ Wattributes
Common Var(warn_attributes) Init(1) Warning
Warn about inappropriate attribute usage.
Wattribute-alias
Common Var(warn_attributes) Init(1) Warning
Warn about type safety and similar errors in attribute alias and related.
Wattribute-alias=
Common Joined RejectNegative UInteger Var(warn_attribute_alias) Init(1) Warning IntegerRange(0, 2)
Warn about type safety and similar errors and mismatches in attribute alias and related.
Wno-attribute-alias
Common Alias(Wattribute_alias=, 0, 0) Warning
Disable -Wattribute-alias.
Wcannot-profile
Common Var(warn_cannot_profile) Init(1) Warning

View File

@ -1,3 +1,9 @@
2018-11-09 Martin Sebor <msebor@redhat.com>
PR middle-end/81824
* pt.c (warn_spec_missing_attributes): Move code to attribs.c.
Call decls_mismatched_attributes.
2018-11-08 Jakub Jelinek <jakub@redhat.com>
* constexpr.c (potential_constant_expression_1): Handle OMP_DEPOBJ.

View File

@ -2647,81 +2647,19 @@ warn_spec_missing_attributes (tree tmpl, tree spec, tree attrlist)
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
tmpl = DECL_TEMPLATE_RESULT (tmpl);
if (TREE_CODE (tmpl) != FUNCTION_DECL)
return;
/* Avoid warning if either declaration or its type is deprecated. */
if (TREE_DEPRECATED (tmpl)
|| TREE_DEPRECATED (spec))
return;
tree tmpl_type = TREE_TYPE (tmpl);
tree spec_type = TREE_TYPE (spec);
if (TREE_DEPRECATED (tmpl_type)
|| TREE_DEPRECATED (spec_type)
|| TREE_DEPRECATED (TREE_TYPE (tmpl_type))
|| TREE_DEPRECATED (TREE_TYPE (spec_type)))
return;
tree tmpl_attrs[] = { DECL_ATTRIBUTES (tmpl), TYPE_ATTRIBUTES (tmpl_type) };
tree spec_attrs[] = { DECL_ATTRIBUTES (spec), TYPE_ATTRIBUTES (spec_type) };
if (!spec_attrs[0])
spec_attrs[0] = attrlist;
else if (!spec_attrs[1])
spec_attrs[1] = attrlist;
/* Avoid warning if the primary has no attributes. */
if (!tmpl_attrs[0] && !tmpl_attrs[1])
return;
/* 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], spec_attrs[i]))
return;
/* Avoid warning if the difference between the primary and
the specialization is not in one of the attributes below. */
const char* const blacklist[] = {
"alloc_align", "alloc_size", "assume_aligned", "format",
"format_arg", "malloc", "nonnull"
"format_arg", "malloc", "nonnull", NULL
};
/* Put together a list of the black listed attributes that the primary
template is declared with that the specialization is not, in case
it's not apparent from the most recent declaration of the primary. */
unsigned nattrs = 0;
pretty_printer str;
for (unsigned i = 0; i != sizeof blacklist / sizeof *blacklist; ++i)
{
for (unsigned j = 0; j != 2; ++j)
{
if (!lookup_attribute (blacklist[i], tmpl_attrs[j]))
continue;
for (unsigned k = 0; k != 1 + !!spec_attrs[1]; ++k)
{
if (lookup_attribute (blacklist[i], spec_attrs[k]))
break;
if (nattrs)
pp_string (&str, ", ");
pp_begin_quote (&str, pp_show_color (global_dc->printer));
pp_string (&str, blacklist[i]);
pp_end_quote (&str, pp_show_color (global_dc->printer));
++nattrs;
}
}
}
unsigned nattrs = decls_mismatched_attributes (tmpl, spec, attrlist,
blacklist, &str);
if (!nattrs)
return;

View File

@ -2552,6 +2552,40 @@ decorated with attribute @code{constructor} are invoked is unspecified.
In mixed declarations, attribute @code{init_priority} can be used to
impose a specific ordering.
@item copy
@itemx copy (@var{function})
@cindex @code{copy} function attribute
The @code{copy} attribute applies the set of attributes with which
@var{function} has been declared to the declaration of the function
to which the attribute is applied. The attribute is designed for
libraries that define aliases or function resolvers that are expected
to specify the same set of attributes as their targets. The @code{copy}
attribute can be used with functions, variables, or types. However,
the kind of symbol to which the attribute is applied (either function
or variable) must match the kind of symbol to which the argument refers.
The @code{copy} attribute copies only syntaxtic and semantic attributes
but attributes that affect a symbol's linkage or visibility such as
@code{alias}, @code{visibility}, or @code{weak}. The @code{deprecated}
attribute is also not copied. @xref{Common Type Attributes}.
@xref{Common Variable Attributes}.
For example, the @var{StrongAlias} macro below makes use of the @code{alias}
and @code{copy} attributes to define an alias named @var{alloc} for function
@var{allocate} declated with attributes @var{alloc_size}, @var{malloc}, and
@var{nothrow}. Thanks to the @code{__typeof__} operator the alias has
the same type as the target function. As a result of the @code{copy}
attribute the alias also shares the same attributes as the target.
@smallexample
#define StrongAlias(TagetFunc, AliasDecl) \
extern __typeof__ (TargetFunc) AliasDecl \
__attribute__ ((alias (#TargetFunc), copy (TargetFunc)));
extern __attribute__ ((alloc_size (1), malloc, nothrow))
void* allocate (size_t);
StrongAlias (allocate, alloc);
@end smallexample
@item deprecated
@itemx deprecated (@var{msg})
@cindex @code{deprecated} function attribute
@ -6174,6 +6208,23 @@ opposite---to allocate space for it directly.
These attributes override the default chosen by the
@option{-fno-common} and @option{-fcommon} flags respectively.
@item copy
@itemx copy (@var{variable})
@cindex @code{copy} variable attribute
The @code{copy} attribute applies the set of attributes with which
@var{variable} has been declared to the declaration of the variable
to which the attribute is applied. The attribute is designed for
libraries that define aliases that are expected to specify the same
set of attributes as the aliased symbols. The @code{copy} attribute
can be used with variables, functions or types. However, the kind
of symbol to which the attribute is applied (either varible or
function) must match the kind of symbol to which the argument refers.
The @code{copy} attribute copies only syntaxtic and semantic attributes
but attributes that affect a symbol's linkage or visibility such as
@code{alias}, @code{visibility}, or @code{weak}. The @code{deprecated}
attribute is also not copied. @xref{Common Function Attributes}.
@xref{Common Type Attributes}.
@item deprecated
@itemx deprecated (@var{msg})
@cindex @code{deprecated} variable attribute
@ -7105,6 +7156,38 @@ struct foo
This warning can be disabled by @option{-Wno-if-not-aligned}.
@item copy
@itemx copy (@var{expression})
@cindex @code{copy} type attribute
The @code{copy} attribute applies the set of attributes with which
the type of the @var{expression} has been declared to the declaration
of the type to which the attribute is applied. The attribute is
designed for libraries that define aliases that are expected to
specify the same set of attributes as the aliased symbols.
The @code{copy} attribute can be used with types, variables, or
functions. However, the kind of symbol to which the attribute is
applied (either varible or function) must match the kind of symbol
to which the argument refers.
The @code{copy} attribute copies only syntaxtic and semantic attributes
but attributes that affect a symbol's linkage or visibility such as
@code{alias}, @code{visibility}, or @code{weak}. The @code{deprecated}
attribute is also not copied. @xref{Common Function Attributes}.
@xref{Common Variable Attributes}.
For example, suppose @code{struct A} below is defined in some third
partly library header to have the alignment requirement @code{N} and
to force a warning whenever a variable of the type is not so aligned
due to attribute @code{packed}. Specifying the @code{copy} attribute
on the definition on the unrelated @code{struct B} has the effect of
copying all relevant attributes from the type referenced by the pointer
expression to @code{struct B}.
@smallexample
struct __attribute__ ((aligned (N), warn_if_not_aligned (N)))
A @{ /* @r{@dots{}} */ @};
struct __attribute__ ((copy ( (struct A *)0)) B @{ /* @r{@dots{}} */ @};
@end smallexample
@item deprecated
@itemx deprecated (@var{msg})
@cindex @code{deprecated} type attribute

View File

@ -283,7 +283,8 @@ Objective-C and Objective-C++ Dialects}.
-Walloc-zero -Walloc-size-larger-than=@var{byte-size}
-Walloca -Walloca-larger-than=@var{byte-size} @gol
-Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
-Wno-attributes -Wbool-compare -Wbool-operation @gol
-Wno-attributes -Wno-attribute-alias @gol
-Wbool-compare -Wbool-operation @gol
-Wno-builtin-declaration-mismatch @gol
-Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol
-Wc++-compat -Wc++11-compat -Wc++14-compat -Wc++17-compat @gol
@ -316,7 +317,7 @@ Objective-C and Objective-C++ Dialects}.
-Winvalid-pch -Wlarger-than=@var{byte-size} @gol
-Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
-Wmain -Wmaybe-uninitialized -Wmemset-elt-size -Wmemset-transposed-args @gol
-Wmisleading-indentation -Wmissing-attributes -Wmissing-braces @gol
-Wmisleading-indentation -Wno-missing-attributes -Wmissing-braces @gol
-Wmissing-field-initializers -Wmissing-include-dirs -Wmissing-profile @gol
-Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare @gol
-Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
@ -4805,13 +4806,24 @@ about the layout of the file that the directive references.
This warning is enabled by @option{-Wall} in C and C++.
@item -Wmissing-attributes
@item -Wno-missing-attributes
@opindex Wmissing-attributes
@opindex Wno-missing-attributes
Warn when a declaration of a function is missing one or more attributes
that a related function is declared with and whose absence may adversely
affect the correctness or efficiency of generated code. For example, in
C++, the warning is issued when an explicit specialization of a primary
affect the correctness or efficiency of generated code. For example,
the warning is issued for declarations of aliases that use attributes
to specify less restrictive requirements than those of their targets.
This typically represents a potential optimization oportunity rather
than a hidden bug. The @option{-Wattribute-alias} option controls warnings
issued for mismatches between declarations of aliases and their targets
that might be indicative of code generation bugs.
Attributes considered include @code{alloc_align}, @code{alloc_size},
@code{cold}, @code{const}, @code{hot}, @code{leaf}, @code{malloc},
@code{nonnull}, @code{noreturn}, @code{nothrow}, @code{pure},
@code{returns_nonnull}, and @code{returns_twice}.
In C++, the warning is issued when an explicit specialization of a primary
template declared with attribute @code{alloc_align}, @code{alloc_size},
@code{assume_aligned}, @code{format}, @code{format_arg}, @code{malloc},
or @code{nonnull} is declared without it. Attributes @code{deprecated},
@ -5831,10 +5843,28 @@ pointers. This warning level may give a larger number of
false positives and is deactivated by default.
@end table
@item -Wattribute-alias
@item -Wattribute-alias=@var{n}
@itemx -Wno-attribute-alias
@opindex -Wattribute-alias
@opindex -Wno-attribute-alias
Warn about declarations using the @code{alias} and similar attributes whose
target is incompatible with the type of the alias. @xref{Function Attributes,
,Declaring Attributes of Functions}.
target is incompatible with the type of the alias.
@xref{Function Attributes,,Declaring Attributes of Functions}.
The @option{-Wattribute-alias=1} is enabled by @option{-Wall}.
@table @gcctabopt
@item -Wattribute-alias=1
The default warning level of the @option{-Wattribute-alias} option diagnoses
incompatibilities between the type of the alias declaration and that of its
target. Such incompatibilities are typically indicative of bugs.
@item -Wattribute-alias=2
At this level @option{-Wattribute-alias} also diagnoses mismatches between
the set of attributes of the alias declaration and the attributes applied
to its target. Although in some cases such mismatches may indicate bugs,
in other cases they may be benign and could be resolved simply by adding
the missing attribute to the target.
@end table
@item -Wbool-compare
@opindex Wno-bool-compare

View File

@ -1,3 +1,13 @@
2018-11-09 Martin Sebor <msebor@redhat.com>
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.
2018-11-09 Martin Sebor <msebor@redhat.com>
PR c/87795

View File

@ -0,0 +1,49 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
{ dg-do compile }
{ dg-options "-Wall -Wattribute-alias=2" } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
void
target_no_nothrow (void) /* { dg-message ".alias_nothrow. target declared here" } */
{ }
ATTR (alias ("target_no_nothrow"), nothrow) void
alias_nothrow (void); /* { dg-warning ".alias_nothrow. specifies more restrictive attribute than its target .target_no_nothrow.: .nothrow." } */
ATTR (pure) int
alias_pure (void);
int
target_no_pure (void) /* { dg-message ".alias_pure. target declared here" } */
{ return 0; }
ATTR (alias ("target_no_pure")) int
alias_pure (void); /* { dg-warning ".alias_pure. specifies more restrictive attribute than its target .target_no_pure.: .pure." } */
ATTR (const) int
alias_const (void);
int
target_pure (void) /* { dg-message ".alias_const. target declared here" } */
{ return 0; }
ATTR (alias ("target_pure")) int
alias_const (void); /* { dg-warning ".alias_const. specifies more restrictive attribute than its target .target_pure.: .const." } */
/* There is no obvious relationship between the attributes on an ifunc
resolver and those on its aliases. Verify that mismatches between
aliases and ifunc resolvers do not trigger warnings. */
typedef int F (void);
ATTR (pure, leaf) F* resolve_to_const (void)
{ return alias_const; }
ATTR (ifunc ("resolve_to_const")) F alias_no_const_ifunc;
ATTR (const, ifunc ("resolve_to_const")) F alias_const_ifunc;
ATTR (ifunc ("resolve_to_const")) int alias_no_leaf_ifunc (void);

View File

@ -0,0 +1,95 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
{ dg-do compile }
{ dg-options "-Wall" } */
#define ATTR(list) __attribute__ (list)
int alias_no_const (void);
ATTR ((const)) int
target_const (void) /* { dg-message ".alias_no_const. target declared here" } */
{ return 0; }
ATTR ((alias ("target_const"))) int
alias_no_const (void); /* { dg-warning ".alias_no_const. specifies less restrictive attribute than its target .target_const.: .const." } */
ATTR ((alloc_size (1), malloc)) void*
target_malloc (int n) /* { dg-message ".alias_no_malloc. target declared here" } */
{ return __builtin_malloc (n); }
ATTR ((alias ("target_malloc"))) void*
alias_no_malloc (int); /* { dg-warning ".alias_no_malloc. specifies less restrictive attributes than its target .target_malloc.: .alloc_size., .malloc." } */
ATTR ((leaf)) int
target_leaf (void) /* { dg-message ".alias_no_leaf. target declared here" } */
{ return 0; }
ATTR ((alias ("target_leaf"))) int
alias_no_leaf (void); /* { dg-warning ".alias_no_leaf. specifies less restrictive attribute than its target .target_leaf.: .leaf." } */
/* Verify that attributes noclone, noinline, and noipa on the target
don't cause a warning for aliases without the attribute. */
ATTR ((noclone)) int
target_noclone (void)
{ return 0; }
ATTR ((alias ("target_noclone"))) int
alias_no_noclone (void);
ATTR ((noipa)) int
target_noipa (void)
{ return 0; }
ATTR ((alias ("target_noipa"))) int
alias_no_noipa (void);
ATTR ((noinline)) int
target_noinline (void)
{ return 0; }
ATTR ((alias ("target_noinline"))) int
alias_no_noinline (void);
ATTR ((nothrow)) int
target_nothrow (void) /* { dg-message ".alias_no_nothrow. target declared here" } */
{ return 0; }
ATTR ((alias ("target_nothrow"))) int
alias_no_nothrow (void); /* { dg-warning ".alias_no_nothrow. specifies less restrictive attribute than its target .target_nothrow.: .nothrow." } */
/* Verify that attribute weak on the target doesn't cause and isn't
mentioned in a warning for aliases without the attribute. */
ATTR ((weak)) int
target_weak (void)
{ return 0; }
ATTR ((alias ("target_weak"))) int
alias_no_weak (void);
ATTR ((nothrow, weak)) int
target_nothrow_weak (void) /* { dg-message ".alias_nothrow_no_weak. target declared here" } */
{ return 0; }
ATTR ((alias ("target_nothrow_weak"))) int
alias_nothrow_no_weak (void); /* { dg-warning ".alias_nothrow_no_weak. specifies less restrictive attribute than its target .target_nothrow_weak.: .nothrow." } */
/* Verify that __typeof__ doesn't include attributes. */
ATTR ((cold)) int
target_cold (void)
{ return 0; }
__typeof__ (target_cold) ATTR ((alias ("target_cold")))
alias_cold; /* { dg-warning ".alias_cold. specifies less restrictive attribute than its target .target_cold.: .cold." } */

View File

@ -0,0 +1,209 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
Exercise attribute copy for functions.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define Assert(expr) typedef char AssertExpr[2 * !!(expr) - 1]
#define ATTR(list) __attribute__ (list)
/* Verify that referencing a symbol with no attributes is accepted
with no diagnostics. */
void ref0 (void);
ATTR ((copy (ref0))) void
f0 (void);
/* Verify that referencing a symbol using the address-of and dereferencing
operators is also accepted with no diagnostics. */
ATTR ((copy (&ref0))) void f1 (void);
ATTR ((copy (*ref0))) void f2 (void);
/* Verify that referencing a symbol of a different kind than that
of the one the attribute is applied to is diagnosed. */
int v0; /* { dg-message "symbol .v0. referenced by .f3. declared here" } */
ATTR ((copy (v0))) void
f3 (void); /* { dg-warning ".copy. attribute ignored on a declaration of a different kind than referenced symbol" } */
void f4 (void); /* { dg-message "symbol .f4. referenced by .v1. declared here" } */
ATTR ((copy (f4))) int
v1; /* { dg-warning ".copy. attribute ignored on a declaration of a different kind than referenced symbol" } */
ATTR ((copy (v0 + 1)))
void f5 (void); /* { dg-warning ".copy. attribute ignored on a declaration of a different kind than referenced symbol" } */
void f6 (void);
ATTR ((copy (f6 - 1)))
int v1; /* { dg-warning ".copy. attribute ignored on a declaration of a different kind than referenced symbol" } */
/* Verify that circular references of the copy function attribute
are handled gracefully (i.e., not by getting into an infinite
recursion) by issuing a diagnostic. */
void xref1 (void); /* { dg-message "previous declaration here" } */
ATTR ((copy (xref1))) void
xref1 (void); /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
ATTR ((copy (xref1))) void
xref1 (void); /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
ATTR ((copy (xref1), copy (xref1))) void
xref1 (void); /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
/* Use attribute noreturn to verify that circular references propagate
atttibutes as expected, and unlike in the self-referential instances
above, without a warning. Also use the address-of operator to make
sure it doesn't change anything. */
ATTR ((noreturn)) void xref2 (void);
ATTR ((copy (xref2))) void xref3 (void);
ATTR ((copy (&xref3))) void xref4 (void);
ATTR ((copy (xref4))) void xref5 (void);
ATTR ((copy (&xref5))) void xref6 (void);
ATTR ((copy (xref6))) void xref7 (void);
ATTR ((copy (&xref7))) void xref8 (void);
ATTR ((copy (xref8))) void xref9 (void);
ATTR ((copy (&xref9))) void xref2 (void);
int call_ref2 (void) { xref2 (); }
int call_ref3 (void) { xref3 (); }
int call_ref4 (void) { xref4 (); }
int call_ref5 (void) { xref5 (); }
int call_ref6 (void) { xref6 (); }
int call_ref7 (void) { xref7 (); }
int call_ref8 (void) { xref8 (); }
int call_ref9 (void) { xref9 (); }
/* Verify that copying attributes from multiple symbols into one works
as expected. */
ATTR ((malloc)) void*
xref10 (void);
ATTR ((alloc_size (1)))
void* xref11 (int);
ATTR ((copy (xref10), copy (xref11)))
void* xref12 (int);
void* call_xref12 (void)
{
void *p = xref12 (3);
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Wstringop-overflow=]" } */
return p;
}
/* Verify that attribute exclusions apply. */
ATTR ((const)) int
fconst (void);
ATTR ((pure)) int
fpure (void); /* { dg-message "previous declaration here" } */
ATTR ((copy (fconst), copy (fpure))) int
fconst_pure (void); /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .const." } */
/* Also verify that the note in the exclusion warning points to
the declaration from which the conflicting attribute is copied.
The wording in the note could be improved but it's the same as
in ordinary exclusions so making it different between the two
would take some API changes. */
ATTR ((const)) int
gconst (void); /* { dg-message "previous declaration here" } */
ATTR ((pure, copy (gconst))) int
gpure_const (void); /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .pure." } */
/* Verify that attribute deprecated isn't copied (but referencing
the deprecated declaration still triggers a warning). */
ATTR ((deprecated)) void
fdeprecated (void); /* { dg-message "declared here" } */
/* Unlike in most other instance the warning below is on the line
with the copy attribute that references the deprecated function. */
ATTR ((copy (fdeprecated))) /* { dg-warning "\\\[-Wdeprecated-declarations]" } */
int fcurrent (void);
ATTR ((copy (fcurrent))) int
fcurrent2 (void);
int call_fcurrent (void) { return fcurrent () + fcurrent2 (); }
/* Verify that attributes are copied on a declaration using __typeof__
and that -Wmissing-attributes is not issued. */
ATTR ((cold)) int
target_cold (void)
{ return 0; }
__typeof__ (target_cold) ATTR ((copy (target_cold), alias ("target_cold")))
alias_cold; /* { dg-bogus "\\\[-Wmissing-attributes]." } */
/* Verify that attribute alias is not copied. This also indirectly
verifies that attribute copy itself isn't copied. */
ATTR ((noreturn)) void fnoret (void) { __builtin_abort (); }
ATTR ((alias ("fnoret"), copy (fnoret))) void fnoret_alias (void);
ATTR ((copy (fnoret_alias))) void fnoret2 (void) { __builtin_exit (1); }
/* Expect no warning below. */
int call_noret (void) { fnoret2 (); }
/* Verify that attribute nonnull (which is part of a function type,
even when it's specified on a function declaration) is copied to
the alias from its target. Expect no warning about the alias
specifying less restrictive attributes than its target, but do
verify that passing a null to the alias triggers -Wnonnull. */
ATTR ((nonnull))
void* ftarget_nonnull (void *p) { return p; }
ATTR ((alias ("ftarget_nonnull"), copy (ftarget_nonnull)))
void* falias_nonnull (void*);
void call_falias_nonnull (void)
{
falias_nonnull (0); /* { dg-warning "-Wnonnull" } */
}
/* Same as above but for malloc. Also verify that the attribute
on the alias is used by -Wstringop-overflow. */
ATTR ((malloc))
void* ftarget_malloc (void) { return __builtin_malloc (1); }
ATTR ((alias ("ftarget_malloc"), copy (ftarget_malloc)))
void* falias_malloc (void);
void* call_falias_malloc (void)
{
char *p = falias_malloc ();
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Wstringop-overflow=]" } */
return p;
}
/* Same as above but for nothrow. */
ATTR ((nothrow))
void ftarget_nothrow (void) { }
ATTR ((alias ("ftarget_nothrow"), copy (ftarget_nothrow)))
void falias_nothrow (void);

View File

@ -0,0 +1,75 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
Exercise attribute copy for variables.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ATTR(list) __attribute__ (list)
/* Verify that referencing a symbol with no attributes is accepted
with no diagnostics. */
int ref0;
ATTR ((copy (ref0))) long
var0;
/* Verify that referencing a symbol using the address-of and dereferencing
operators is also accepted with no diagnostics. */
ATTR ((copy (&ref0))) void* ptr0;
ATTR ((copy (*&ref0))) int arr[1];
/* Verify that referencing a symbol of a different kind than that
of the one the attribute is applied to is diagnosed. */
int ref1; /* { dg-message "previous declaration here" } */
ATTR ((copy (ref1))) int
ref1; /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol " } */
/* Verify that circular references of the copy variable attribute
are handled gracefully (i.e., not by getting into an infinite
recursion) by issuing a diagnostic. */
char xref1;
ATTR ((copy (xref1))) char
xref1; /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
ATTR ((copy (xref1))) char
xref1; /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
ATTR ((copy (xref1), copy (xref1))) char
xref1; /* { dg-warning ".copy. attribute ignored on a redeclaration of the referenced symbol" } */
/* Use attribute unused to verify that circular references propagate
atttibutes as expected (expect no warnings the circular reference
or for any of the unused symbols). Also use the address-of operator
to make sure it doesn't change anything. */
static ATTR ((unused)) int xref2;
static ATTR ((copy (xref2))) int xref3;
static ATTR ((copy (&xref3))) int xref4;
static ATTR ((copy (xref4))) int xref5;
static ATTR ((copy (&xref5))) int xref6;
static ATTR ((copy (xref6))) int xref7;
static ATTR ((copy (&xref7))) int xref8;
static ATTR ((copy (xref8))) int xref9;
static ATTR ((copy (&xref9))) int xref2;
/* Verify that attribute exclusions apply. */
ATTR ((common)) int common_var;
ATTR ((nocommon)) double nocommon_var;
ATTR ((copy (common_var), copy (nocommon_var))) long
common_copy; /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */
/* Verify that attribute deprecated isn't copied. */
ATTR ((deprecated)) char deprecated_var;
ATTR ((copy (deprecated_var))) int current_var; /* { dg-warning "\\\[-Wdeprecated-declarations]" } */
ATTR ((copy (current_var))) int current_var_2;
int return_current_vars (void) { return current_var + current_var_2; }

View File

@ -0,0 +1,61 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
Exercise attribute copy for types.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define Assert(expr) typedef char AssertExpr[2 * !!(expr) - 1]
#define ATTR(list) __attribute__ (list)
/* Use attribute packed to verify that type attributes are copied
from one type to another. */
struct ATTR ((packed)) PackedA { int i; char c; };
Assert (__alignof (struct PackedA) == 1);
struct ATTR ((copy ((struct PackedA*)0))) PackedB { long i; char c; };
Assert (__alignof (struct PackedA) == __alignof (struct PackedB));
struct PackedMember
{
char c;
ATTR ((copy ((struct PackedB*)0))) double packed_mem;
};
Assert (__alignof (struct PackedMember) == 1);
extern const struct PackedA packed;
struct Unpacked { int i; char c; };
Assert (__alignof (struct Unpacked) > 1);
/* Verify that copying the packed attribute to the declaration
of an object is ignored with a warning. (There should be
a way to copy just the subset of attributes from a type that
aren't ignored and won't cause a warning, maybe via attribute
copy_except or something like that.) */
extern ATTR ((copy ((struct PackedA*)0))) const struct Unpacked
unpacked; /* { dg-warning ".packed. attribute ignored" } */
Assert (__alignof (packed) == 1);
Assert (__alignof (unpacked) == __alignof (struct Unpacked));
/* Verify that attribute deprecated isn't copied (but referencing
the deprecated type in the copy attribute still triggers a warning). */
struct ATTR ((aligned (8), deprecated))
AlignedDeprecated { char c; };
struct ATTR ((copy ((struct AlignedDeprecated *)0))) /* { dg-warning "\\\[-Wdeprecated-declarations]" } */
AlignedCopy { short s; };
Assert (__alignof (struct AlignedCopy) == 8);
struct AlignedCopy aligned_copy;
Assert (__alignof (aligned_copy) == 8);

View File

@ -0,0 +1,33 @@
/* PR middle-end/81824 - Warn for missing attributes with function aliases
Exercise error handling for attribute copy.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ATTR(list) __attribute__ (list)
/* Verify incorrect numbers of arguments. */
ATTR ((copy)) void
fno_args (void); /* { dg-error "wrong number of arguments specified for .copy. attribute" } */
ATTR ((copy ())) void
fno_args2 (void); /* { dg-error "wrong number of arguments specified for .copy. attribute" } */
ATTR ((copy (fno_args, fno_args))) void
fmlti_args (void); /* { dg-error "wrong number of arguments specified for .copy. attribute" } */
/* Verify that referencing an undeclared symbol is rejected with an error. */
ATTR ((copy (foobar))) /* { dg-error ".foobar. undeclared" } */
void fundeclared (void);
/* Verify that using a string argument triggers a descriptive error
(given attributes like alias and weakref using a string is a likely
mistake). */
ATTR ((copy ("foobar")))
void fstring (void); /* { dg-error ".copy. attribute argument cannot be a string" } */
/* Ditto for an integer. */
ATTR ((copy (123)))
void fnumber (void); /* { dg-error ".copy. attribute argument cannot be a constant arithmetic expression" } */

View File

@ -1149,16 +1149,26 @@ extern int gomp_test_nest_lock_25 (omp_nest_lock_25_t *) __GOMP_NOTHROW;
# define attribute_hidden
#endif
#if __GNUC__ >= 9
# define HAVE_ATTRIBUTE_COPY
#endif
#ifdef HAVE_ATTRIBUTE_COPY
# define attribute_copy(arg) __attribute__ ((copy (arg)))
#else
# define attribute_copy(arg)
#endif
#ifdef HAVE_ATTRIBUTE_ALIAS
# define strong_alias(fn, al) \
extern __typeof (fn) al __attribute__ ((alias (#fn)));
extern __typeof (fn) al __attribute__ ((alias (#fn))) attribute_copy (fn);
# define ialias_ulp ialias_str1(__USER_LABEL_PREFIX__)
# define ialias_str1(x) ialias_str2(x)
# define ialias_str2(x) #x
# define ialias(fn) \
extern __typeof (fn) gomp_ialias_##fn \
__attribute__ ((alias (#fn))) attribute_hidden;
__attribute__ ((alias (#fn))) attribute_hidden attribute_copy (fn);
# define ialias_redirect(fn) \
extern __typeof (fn) fn __asm__ (ialias_ulp "gomp_ialias_" #fn) attribute_hidden;
# define ialias_call(fn) gomp_ialias_ ## fn