PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument

PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
PR c++/87542 - bogus error on attribute format with a named constant argument

gcc/ChangeLog:

	PR c++/87541
	PR c++/87542
	* tree.c (type_argument_type): New function.
	* tree.h (type_argument_type): Declare it.
	* gcc/doc/extend.texi (alloc_align): Update and clarify.
	(alloc_size, nonnull, sentinel): Same.

gcc/c-family/ChangeLog:

	PR c++/87541
	PR c++/87542
	* c-attribs.c (positional_argument): New function.
	(handle_alloc_size_attribute): Use it and simplify.
	(handle_alloc_align_attribute): Same.
	(handle_assume_aligned_attribute): Same.
	(handle_nonnull_attribute): Same.
	* c-common.c (check_function_arguments): Pass fntype to
	check_function_format.
	* c-common.h (check_function_format): Add an argument.
	(PosArgFlags, positional_argument): Declare new type and function.
	* c-format.c (decode_format_attr): Add arguments.
	(check_format_string, get_constant): Same.
	(convert_format_name_to_system_name): Adjust.

gcc/testsuite/ChangeLog:

	PR c++/87541
	PR c++/87542
	* g++.dg/ext/attr-alloc_size.C: New test.
	* c-c++-common/pr71574.c: Adjust diagnostics.
	* c-c++-common/attributes-1.c: Same.
	* gcc.dg/attr-alloc_align-2.c: Same.
	* gcc.dg/attr-alloc_align-4.c: New test.
	* gcc.dg/attr-alloc_size-2.c: Adjust diagnostics.
	* gcc.dg/attr-alloc_size.c: Same.
	* gcc.dg/attr-assume_aligned-4.c: New test.
	* gcc.dg/format/attr-3.c: Adjust diagnostics.
	* gcc.dg/nonnull-2.c: Same.
	* gcc.dg/torture/pr80612.c: Same.
	* obj-c++.dg/attributes/method-format-1.mm: Same.
	* obj-c++.dg/attributes/method-nonnull-1.mm: Same.
	* objc.dg/attributes/method-format-1.m: same.
	* objc.dg/attributes/method-nonnull-1.m: Same.

From-SVN: r266195
This commit is contained in:
Martin Sebor 2018-11-15 22:53:57 +00:00 committed by Martin Sebor
parent cd5da9837b
commit 1d24950977
26 changed files with 734 additions and 213 deletions

View File

@ -1,3 +1,12 @@
2018-11-15 Martin Sebor <msebor@redhat.com>
PR c++/87541
PR c++/87542
* tree.c (type_argument_type): New function.
* tree.h (type_argument_type): Declare it.
* gcc/doc/extend.texi (alloc_align): Update and clarify.
(alloc_size, nonnull, sentinel): Same.
2018-11-15 Andrew Stubbs <ams@codesourcery.com>
Kwok Cheung Yeung <kcy@codesourcery.com>

View File

@ -1,3 +1,20 @@
2018-11-15 Martin Sebor <msebor@redhat.com>
PR c++/87541
PR c++/87542
* c-attribs.c (positional_argument): New function.
(handle_alloc_size_attribute): Use it and simplify.
(handle_alloc_align_attribute): Same.
(handle_assume_aligned_attribute): Same.
(handle_nonnull_attribute): Same.
* c-common.c (check_function_arguments): Pass fntype to
check_function_format.
* c-common.h (check_function_format): Add an argument.
(PosArgFlags, positional_argument): Declare new type and function.
* c-format.c (decode_format_attr): Add arguments.
(check_format_string, get_constant): Same.
(convert_format_name_to_system_name): Adjust.
2018-11-15 David Malcolm <dmalcolm@redhat.com>
PR other/19165

View File

@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-iterator.h"
#include "opts.h"
#include "gimplify.h"
#include "tree-pretty-print.h"
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@ -495,6 +496,188 @@ attribute_takes_identifier_p (const_tree attr_id)
return targetm.attribute_takes_identifier_p (attr_id);
}
/* Verify that argument value POS at position ARGNO to attribute NAME
applied to function TYPE refers to a function parameter at position
POS and the expected type CODE. If so, return POS after default
conversions, if any. Otherwise, issue appropriate warnings and
return null. A non-zero 1-based ARGNO should be passed ib by
callers only for attributes with more than one argument. */
tree
positional_argument (const_tree fntype, const_tree atname, tree pos,
tree_code code, int argno /* = 0 */,
int flags /* = posargflags () */)
{
if (pos && TREE_CODE (pos) != IDENTIFIER_NODE
&& TREE_CODE (pos) != FUNCTION_DECL)
pos = default_conversion (pos);
tree postype = TREE_TYPE (pos);
if (pos == error_mark_node || !postype)
{
/* Only mention the positional argument number when it's non-zero. */
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument is invalid", atname);
else
warning (OPT_Wattributes,
"%qE attribute argument %i is invalid", atname, argno);
return NULL_TREE;
}
if (!INTEGRAL_TYPE_P (postype))
{
/* Handle this case specially to avoid mentioning the value
of pointer constants in diagnostics. Only mention
the positional argument number when it's non-zero. */
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument has type %qT",
atname, postype);
else
warning (OPT_Wattributes,
"%qE attribute argument %i has type %qT",
atname, argno, postype);
return NULL_TREE;
}
if (TREE_CODE (pos) != INTEGER_CST)
{
/* Only mention the argument number when it's non-zero. */
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument value %qE is not an integer "
"constant",
atname, pos);
else
warning (OPT_Wattributes,
"%qE attribute argument %i value %qE is not an integer "
"constant",
atname, argno, pos);
return NULL_TREE;
}
/* Argument positions are 1-based. */
if (integer_zerop (pos))
{
if (flags & POSARG_ZERO)
/* Zero is explicitly allowed. */
return pos;
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument value %qE does not refer to "
"a function parameter",
atname, pos);
else
warning (OPT_Wattributes,
"%qE attribute argument %i value %qE does not refer to "
"a function parameter",
atname, argno, pos);
return NULL_TREE;
}
if (!prototype_p (fntype))
return pos;
/* Verify that the argument position does not exceed the number
of formal arguments to the function. When POSARG_ELLIPSIS
is set, ARGNO may be beyond the last argument of a vararg
function. */
unsigned nargs = type_num_arguments (fntype);
if (!nargs
|| !tree_fits_uhwi_p (pos)
|| ((flags & POSARG_ELLIPSIS) == 0
&& !IN_RANGE (tree_to_uhwi (pos), 1, nargs)))
{
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument value %qE exceeds the number "
"of function parameters %u",
atname, pos, nargs);
else
warning (OPT_Wattributes,
"%qE attribute argument %i value %qE exceeds the number "
"of function parameters %u",
atname, argno, pos, nargs);
return NULL_TREE;
}
/* Verify that the type of the referenced formal argument matches
the expected type. */
unsigned HOST_WIDE_INT ipos = tree_to_uhwi (pos);
/* Zero was handled above. */
gcc_assert (ipos != 0);
if (tree argtype = type_argument_type (fntype, ipos))
{
if (flags & POSARG_ELLIPSIS)
{
if (argno < 1)
error ("%qE attribute argument value %qE does not refer to "
"a variable argument list",
atname, pos);
else
error ("%qE attribute argument %i value %qE does not refer to "
"a variable argument list",
atname, argno, pos);
return NULL_TREE;
}
/* Where the expected code is STRING_CST accept any pointer
to a narrow character type, qualified or otherwise. */
bool type_match;
if (code == STRING_CST && POINTER_TYPE_P (argtype))
{
tree type = TREE_TYPE (argtype);
type = TYPE_MAIN_VARIANT (type);
type_match = (type == char_type_node
|| type == signed_char_type_node
|| type == unsigned_char_type_node);
}
else
type_match = TREE_CODE (argtype) == code;
if (!type_match)
{
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument value %qE refers to "
"parameter type %qT",
atname, pos, argtype);
else
warning (OPT_Wattributes,
"%qE attribute argument %i value %qE refers to "
"parameter type %qT",
atname, argno, pos, argtype);
return NULL_TREE;
}
}
else if (!(flags & POSARG_ELLIPSIS))
{
if (argno < 1)
warning (OPT_Wattributes,
"%qE attribute argument value %qE refers to "
"a variadic function parameter of unknown type",
atname, pos);
else
warning (OPT_Wattributes,
"%qE attribute argument %i value %qE refers to "
"a variadic function parameter of unknown type",
atname, argno, pos);
return NULL_TREE;
}
return pos;
}
/* Attribute handlers common to C front ends. */
/* Handle a "packed" attribute; arguments as in
@ -2563,27 +2746,40 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
struct attribute_spec.handler. */
static tree
handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
handle_alloc_size_attribute (tree *node, tree name, tree args,
int ARG_UNUSED (flags), bool *no_add_attrs)
{
unsigned arg_count = type_num_arguments (*node);
for (; args; args = TREE_CHAIN (args))
tree decl = *node;
tree rettype = TREE_TYPE (decl);
if (!POINTER_TYPE_P (rettype))
{
tree position = TREE_VALUE (args);
if (position && TREE_CODE (position) != IDENTIFIER_NODE
&& TREE_CODE (position) != FUNCTION_DECL)
position = default_conversion (position);
if (!tree_fits_uhwi_p (position)
|| !arg_count
|| !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
{
warning (OPT_Wattributes,
"alloc_size parameter outside range");
*no_add_attrs = true;
return NULL_TREE;
}
warning (OPT_Wattributes,
"%qE attribute ignored on a function returning %qT",
name, rettype);
*no_add_attrs = true;
return NULL_TREE;
}
for (int i = 1; args; ++i)
{
tree pos = TREE_VALUE (args);
/* NEXT is null when the attribute includes just one argument.
That's used to tell positional_argument to avoid mentioning
the argument number in diagnostics (since there's just one
mentioning it is unnecessary and coule be confusing). */
tree next = TREE_CHAIN (args);
if (tree val = positional_argument (decl, name, pos, INTEGER_TYPE,
next || i > 1 ? i : 0))
TREE_VALUE (args) = val;
else
{
*no_add_attrs = true;
break;
}
args = next;
}
return NULL_TREE;
}
@ -2591,24 +2787,23 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
struct attribute_spec.handler. */
static tree
handle_alloc_align_attribute (tree *node, tree, tree args, int,
handle_alloc_align_attribute (tree *node, tree name, tree args, int,
bool *no_add_attrs)
{
unsigned arg_count = type_num_arguments (*node);
tree position = TREE_VALUE (args);
if (position && TREE_CODE (position) != IDENTIFIER_NODE
&& TREE_CODE (position) != FUNCTION_DECL)
position = default_conversion (position);
if (!tree_fits_uhwi_p (position)
|| !arg_count
|| !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
tree decl = *node;
tree rettype = TREE_TYPE (decl);
if (!POINTER_TYPE_P (rettype))
{
warning (OPT_Wattributes,
"alloc_align parameter outside range");
"%qE attribute ignored on a function returning %qT",
name, rettype);
*no_add_attrs = true;
return NULL_TREE;
}
if (!positional_argument (*node, name, TREE_VALUE (args), INTEGER_TYPE))
*no_add_attrs = true;
return NULL_TREE;
}
@ -2616,20 +2811,60 @@ handle_alloc_align_attribute (tree *node, tree, tree args, int,
struct attribute_spec.handler. */
static tree
handle_assume_aligned_attribute (tree *, tree, tree args, int,
handle_assume_aligned_attribute (tree *node, tree name, tree args, int,
bool *no_add_attrs)
{
tree decl = *node;
tree rettype = TREE_TYPE (decl);
if (TREE_CODE (rettype) != POINTER_TYPE)
{
warning (OPT_Wattributes,
"%qE attribute ignored on a function returning %qT",
name, rettype);
*no_add_attrs = true;
return NULL_TREE;
}
/* The alignment specified by the first argument. */
tree align = NULL_TREE;
for (; args; args = TREE_CHAIN (args))
{
tree position = TREE_VALUE (args);
if (position && TREE_CODE (position) != IDENTIFIER_NODE
&& TREE_CODE (position) != FUNCTION_DECL)
position = default_conversion (position);
tree val = TREE_VALUE (args);
if (val && TREE_CODE (val) != IDENTIFIER_NODE
&& TREE_CODE (val) != FUNCTION_DECL)
val = default_conversion (val);
if (TREE_CODE (position) != INTEGER_CST)
if (!tree_fits_shwi_p (val))
{
warning (OPT_Wattributes,
"assume_aligned parameter not integer constant");
"%qE attribute %E is not an integer constant",
name, val);
*no_add_attrs = true;
return NULL_TREE;
}
if (!align)
{
/* Validate and save the alignment. */
if (!integer_pow2p (val))
{
warning (OPT_Wattributes,
"%qE attribute argument %E is not a power of 2",
name, val);
*no_add_attrs = true;
return NULL_TREE;
}
align = val;
}
else if (tree_int_cst_sgn (val) < 0 || tree_int_cst_le (align, val))
{
/* The misalignment specified by the second argument
must be non-negative and less than the alignment. */
warning (OPT_Wattributes,
"%qE attribute argument %E is not in the range [0, %E)",
name, val, align);
*no_add_attrs = true;
return NULL_TREE;
}
@ -3262,12 +3497,11 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
/* Handle the "nonnull" attribute. */
static tree
handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
handle_nonnull_attribute (tree *node, tree name,
tree args, int ARG_UNUSED (flags),
bool *no_add_attrs)
{
tree type = *node;
unsigned HOST_WIDE_INT attr_arg_num;
/* If no arguments are specified, all pointer arguments should be
non-null. Verify a full prototype is given so that the arguments
@ -3286,57 +3520,23 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
return NULL_TREE;
}
/* Argument list specified. Verify that each argument number references
a pointer argument. */
for (attr_arg_num = 1; args; attr_arg_num++, args = TREE_CHAIN (args))
for (int i = 1; args; ++i)
{
unsigned HOST_WIDE_INT arg_num = 0, ck_num;
tree arg = TREE_VALUE (args);
if (arg && TREE_CODE (arg) != IDENTIFIER_NODE
&& TREE_CODE (arg) != FUNCTION_DECL)
TREE_VALUE (args) = arg = default_conversion (arg);
if (!get_nonnull_operand (arg, &arg_num))
tree pos = TREE_VALUE (args);
/* NEXT is null when the attribute includes just one argument.
That's used to tell positional_argument to avoid mentioning
the argument number in diagnostics (since there's just one
mentioning it is unnecessary and coule be confusing). */
tree next = TREE_CHAIN (args);
if (tree val = positional_argument (type, name, pos, POINTER_TYPE,
next || i > 1 ? i : 0))
TREE_VALUE (args) = val;
else
{
error ("nonnull argument has invalid operand number (argument %lu)",
(unsigned long) attr_arg_num);
*no_add_attrs = true;
return NULL_TREE;
}
if (prototype_p (type))
{
function_args_iterator iter;
tree argument;
function_args_iter_init (&iter, type);
for (ck_num = 1; ; ck_num++, function_args_iter_next (&iter))
{
argument = function_args_iter_cond (&iter);
if (argument == NULL_TREE || ck_num == arg_num)
break;
}
if (!argument
|| TREE_CODE (argument) == VOID_TYPE)
{
error ("nonnull argument with out-of-range operand number "
"(argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
}
if (TREE_CODE (argument) != POINTER_TYPE)
{
error ("nonnull argument references non-pointer operand "
"(argument %lu, operand %lu)",
(unsigned long) attr_arg_num, (unsigned long) arg_num);
*no_add_attrs = true;
return NULL_TREE;
}
break;
}
args = next;
}
return NULL_TREE;

View File

@ -5658,7 +5658,8 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
/* Check for errors in format strings. */
if (warn_format || warn_suggest_attribute_format)
check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray, arglocs);
check_function_format (fntype, TYPE_ATTRIBUTES (fntype), nargs, argarray,
arglocs);
if (warn_format)
check_function_sentinel (fntype, nargs, argarray);

View File

@ -808,7 +808,8 @@ extern void check_function_arguments_recurse (void (*)
unsigned HOST_WIDE_INT);
extern bool check_builtin_function_arguments (location_t, vec<location_t>,
tree, int, tree *);
extern void check_function_format (tree, int, tree *, vec<location_t> *);
extern void check_function_format (const_tree, tree, int, tree *,
vec<location_t> *);
extern bool attribute_fallthrough_p (tree);
extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
@ -1330,6 +1331,18 @@ extern int tm_attr_to_mask (tree);
extern tree tm_mask_to_attr (int);
extern tree find_tm_attribute (tree);
/* A bitmap of flags to positional_argument. */
enum posargflags {
/* Consider positional attribute argument value zero valid. */
POSARG_ZERO = 1,
/* Consider positional attribute argument value valid if it refers
to the ellipsis (i.e., beyond the last typed argument). */
POSARG_ELLIPSIS = 2
};
extern tree positional_argument (const_tree, const_tree, tree, tree_code,
int = 0, int = posargflags ());
extern enum flt_eval_method
excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);

View File

@ -63,15 +63,17 @@ static GTY(()) tree local_gimple_ptr_node;
static GTY(()) tree local_cgraph_node_ptr_node;
static GTY(()) tree locus;
static bool decode_format_attr (tree, function_format_info *, int);
static bool decode_format_attr (const_tree, tree, tree, function_format_info *,
bool);
static int decode_format_type (const char *);
static bool check_format_string (tree argument,
static bool check_format_string (const_tree argument,
unsigned HOST_WIDE_INT format_num,
int flags, bool *no_add_attrs,
int expected_format_type);
static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
int validated_p);
static tree get_constant (const_tree fntype, const_tree atname, tree expr,
int argno, unsigned HOST_WIDE_INT *value,
int flags, bool validated_p);
static const char *convert_format_name_to_system_name (const char *attr_name);
static int first_target_format_type;
@ -133,16 +135,19 @@ valid_stringptr_type_p (tree strref)
/* Handle a "format_arg" attribute; arguments as in
struct attribute_spec.handler. */
tree
handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
handle_format_arg_attribute (tree *node, tree atname,
tree args, int flags, bool *no_add_attrs)
{
tree type = *node;
tree format_num_expr = TREE_VALUE (args);
/* Note that TREE_VALUE (args) is changed in place below. */
tree *format_num_expr = &TREE_VALUE (args);
unsigned HOST_WIDE_INT format_num = 0;
if (!get_constant (format_num_expr, &format_num, 0))
if (tree val = get_constant (type, atname, *format_num_expr, 0, &format_num,
0, false))
*format_num_expr = val;
else
{
error ("format string has invalid operand number");
*no_add_attrs = true;
return NULL_TREE;
}
@ -171,7 +176,7 @@ handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
error). When we know the specific reference type expected, this is also
checked. */
static bool
check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
int flags, bool *no_add_attrs, int expected_format_type)
{
unsigned HOST_WIDE_INT i;
@ -264,19 +269,20 @@ check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
/* Verify EXPR is a constant, and store its value.
If validated_p is true there should be no errors.
Returns true on success, false otherwise. */
static bool
get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
Returns the converted constant value on success, null otherwise. */
static tree
get_constant (const_tree fntype, const_tree atname, tree expr, int argno,
unsigned HOST_WIDE_INT *value, int flags, bool validated_p)
{
if (!tree_fits_uhwi_p (expr))
if (tree val = positional_argument (fntype, atname, expr, STRING_CST,
argno, flags))
{
gcc_assert (!validated_p);
return false;
*value = TREE_INT_CST_LOW (val);
return val;
}
*value = TREE_INT_CST_LOW (expr);
return true;
gcc_assert (!validated_p);
return NULL_TREE;
}
/* Decode the arguments to a "format" attribute into a
@ -287,12 +293,14 @@ get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
attributes are successfully decoded, false otherwise. */
static bool
decode_format_attr (tree args, function_format_info *info, int validated_p)
decode_format_attr (const_tree fntype, tree atname, tree args,
function_format_info *info, bool validated_p)
{
tree format_type_id = TREE_VALUE (args);
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
tree first_arg_num_expr
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
/* Note that TREE_VALUE (args) is changed in place below. Ditto
for the value of the next element on the list. */
tree *format_num_expr = &TREE_VALUE (TREE_CHAIN (args));
tree *first_arg_num_expr = &TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
@ -327,17 +335,18 @@ decode_format_attr (tree args, function_format_info *info, int validated_p)
}
}
if (!get_constant (format_num_expr, &info->format_num, validated_p))
{
error ("format string has invalid operand number");
return false;
}
if (tree val = get_constant (fntype, atname, *format_num_expr,
2, &info->format_num, 0, validated_p))
*format_num_expr = val;
else
return false;
if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p))
{
error ("%<...%> has invalid operand number");
return false;
}
if (tree val = get_constant (fntype, atname, *first_arg_num_expr,
3, &info->first_arg_num,
(POSARG_ZERO | POSARG_ELLIPSIS), validated_p))
*first_arg_num_expr = val;
else
return false;
if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
{
@ -1083,11 +1092,13 @@ decode_format_type (const char *s)
attribute themselves. */
void
check_function_format (tree attrs, int nargs, tree *argarray,
vec<location_t> *arglocs)
check_function_format (const_tree fntype, tree attrs, int nargs,
tree *argarray, vec<location_t> *arglocs)
{
tree a;
tree atname = get_identifier ("format");
/* See if this function has any format attributes. */
for (a = attrs; a; a = TREE_CHAIN (a))
{
@ -1095,7 +1106,8 @@ check_function_format (tree attrs, int nargs, tree *argarray,
{
/* Yup; check it. */
function_format_info info;
decode_format_attr (TREE_VALUE (a), &info, /*validated=*/true);
decode_format_attr (fntype, atname, TREE_VALUE (a), &info,
/*validated=*/true);
if (warn_format)
{
/* FIXME: Rewrite all the internal functions in this file
@ -4124,10 +4136,10 @@ convert_format_name_to_system_name (const char *attr_name)
/* Handle a "format" attribute; arguments as in
struct attribute_spec.handler. */
tree
handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
handle_format_attribute (tree *node, tree atname, tree args,
int flags, bool *no_add_attrs)
{
tree type = *node;
const_tree type = *node;
function_format_info info;
#ifdef TARGET_FORMAT_TYPES
@ -4153,7 +4165,7 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
if (!decode_format_attr (args, &info, 0))
if (!decode_format_attr (type, atname, args, &info, /* validated_p = */false))
{
*no_add_attrs = true;
return NULL_TREE;

View File

@ -2406,33 +2406,39 @@ further information.
The @code{aligned} attribute can also be used for variables and fields
(@pxref{Variable Attributes}.)
@item alloc_align
@item alloc_align (@var{position})
@cindex @code{alloc_align} function attribute
The @code{alloc_align} attribute is used to tell the compiler that the
function return value points to memory, where the returned pointer minimum
alignment is given by one of the functions parameters. GCC uses this
information to improve pointer alignment analysis.
The @code{alloc_align} attribute may be applied to a function that
returns a pointer and takes at least one argument of an integer type.
It indicates that the returned pointer is aligned on a boundary given
by the function argument at @var{position}. Meaningful alignments are
powers of 2 greater than one. GCC uses this information to improve
pointer alignment analysis.
The function parameter denoting the allocated alignment is specified by
one integer argument, whose number is the argument of the attribute.
one constant integer argument whose number is the argument of the attribute.
Argument numbering starts at one.
For instance,
@smallexample
void* my_memalign(size_t, size_t) __attribute__((alloc_align(1)))
void* my_memalign (size_t, size_t) __attribute__ ((alloc_align (1)));
@end smallexample
@noindent
declares that @code{my_memalign} returns memory with minimum alignment
given by parameter 1.
@item alloc_size
@item alloc_size (@var{position})
@itemx alloc_size (@var{position-1}, @var{position-2})
@cindex @code{alloc_size} function attribute
The @code{alloc_size} attribute is used to tell the compiler that the
function return value points to memory, where the size is given by
one or two of the functions parameters. GCC uses this
information to improve the correctness of @code{__builtin_object_size}.
The @code{alloc_size} attribute may be applied to a function that
returns a pointer and takes at least one argument of an integer type.
It indicates that the returned pointer points to memory whose size is
given by the function argument at @var{position-1}, or by the product
of the arguments at @var{position-1} and @var{position-2}. Meaningful
sizes are positive values less than @code{PTRDIFF_MAX}. GCC uses this
information to improve the results of @code{__builtin_object_size}.
The function parameter(s) denoting the allocated size are specified by
one or two integer arguments supplied to the attribute. The allocated size
@ -2443,8 +2449,8 @@ one.
For instance,
@smallexample
void* my_calloc(size_t, size_t) __attribute__((alloc_size(1,2)))
void* my_realloc(void*, size_t) __attribute__((alloc_size(2)))
void* my_calloc (size_t, size_t) __attribute__ ((alloc_size (1, 2)));
void* my_realloc (void*, size_t) __attribute__ ((alloc_size (2)));
@end smallexample
@noindent
@ -2470,22 +2476,25 @@ info format it either means marking the function as artificial
or using the caller location for all instructions within the inlined
body.
@item assume_aligned
@item assume_aligned (@var{alignment})
@itemx assume_aligned (@var{alignment}, @var{offset})
@cindex @code{assume_aligned} function attribute
The @code{assume_aligned} attribute is used to tell the compiler that the
function return value points to memory, where the returned pointer minimum
alignment is given by the first argument.
If the attribute has two arguments, the second argument is misalignment offset.
The @code{assume_aligned} attribute may be applied to a function that
returns a pointer. It indicates that the returned pointer is aligned
on a boundary given by @var{alignment}. If the attribute has two
arguments, the second argument is misalignment @var{offset}. Meaningful
values of @var{alignment} are powers of 2 greater than one. Meaningful
values of @var{offset} are greater than zero and less than @var{alignment}.
For instance
@smallexample
void* my_alloc1(size_t) __attribute__((assume_aligned(16)))
void* my_alloc2(size_t) __attribute__((assume_aligned(32, 8)))
void* my_alloc1 (size_t) __attribute__((assume_aligned (16)));
void* my_alloc2 (size_t) __attribute__((assume_aligned (32, 8)));
@end smallexample
@noindent
declares that @code{my_alloc1} returns 16-byte aligned pointer and
declares that @code{my_alloc1} returns 16-byte aligned pointers and
that @code{my_alloc2} returns a pointer whose value modulo 32 is equal
to 8.
@ -3118,8 +3127,9 @@ of testing the compiler.
@itemx nonnull (@var{arg-index}, @dots{})
@cindex @code{nonnull} function attribute
@cindex functions with non-null pointer arguments
The @code{nonnull} attribute specifies that some function parameters should
be non-null pointers. For instance, the declaration:
The @code{nonnull} attribute may be applied to a function that takes at
least one argument of a pointer type. It indicates that the referenced
arguments must be non-null pointers. For instance, the declaration:
@smallexample
extern void *
@ -3354,13 +3364,14 @@ If you need to map the entire contents of a module to a particular
section, consider using the facilities of the linker instead.
@item sentinel
@itemx sentinel (@var{position})
@cindex @code{sentinel} function attribute
This function attribute ensures that a parameter in a function call is
an explicit @code{NULL}. The attribute is only valid on variadic
functions. By default, the sentinel is located at position zero, the
last parameter of the function call. If an optional integer position
argument P is supplied to the attribute, the sentinel must be located at
position P counting backwards from the end of the argument list.
This function attribute indicates that an argument in a call to the function
is expected to be an explicit @code{NULL}. The attribute is only valid on
variadic functions. By default, the sentinel is expected to be the last
argument of the function call. If the optional @var{position} argument
is specified to the attribute, the sentinel must be located at
@var{position} counting backwards from the end of the argument list.
@smallexample
__attribute__ ((sentinel))
@ -3372,10 +3383,11 @@ The attribute is automatically set with a position of 0 for the built-in
functions @code{execl} and @code{execlp}. The built-in function
@code{execle} has the attribute set with a position of 1.
A valid @code{NULL} in this context is defined as zero with any pointer
type. If your system defines the @code{NULL} macro with an integer type
then you need to add an explicit cast. GCC replaces @code{stddef.h}
with a copy that redefines NULL appropriately.
A valid @code{NULL} in this context is defined as zero with any object
pointer type. If your system defines the @code{NULL} macro with
an integer type then you need to add an explicit cast. During
installation GCC replaces the system @code{<stddef.h>} header with
a copy that redefines NULL appropriately.
The warnings for missing or incorrect sentinels are enabled with
@option{-Wformat}.

View File

@ -1,3 +1,23 @@
2018-11-15 Martin Sebor <msebor@redhat.com>
PR c++/87541
PR c++/87542
* g++.dg/ext/attr-alloc_size.C: New test.
* c-c++-common/pr71574.c: Adjust diagnostics.
* c-c++-common/attributes-1.c: Same.
* gcc.dg/attr-alloc_align-2.c: Same.
* gcc.dg/attr-alloc_align-4.c: New test.
* gcc.dg/attr-alloc_size-2.c: Adjust diagnostics.
* gcc.dg/attr-alloc_size.c: Same.
* gcc.dg/attr-assume_aligned-4.c: New test.
* gcc.dg/format/attr-3.c: Adjust diagnostics.
* gcc.dg/nonnull-2.c: Same.
* gcc.dg/torture/pr80612.c: Same.
* obj-c++.dg/attributes/method-format-1.mm: Same.
* obj-c++.dg/attributes/method-nonnull-1.mm: Same.
* objc.dg/attributes/method-format-1.m: same.
* objc.dg/attributes/method-nonnull-1.m: Same.
2018-11-15 Martin Sebor <msebor@redhat.com>
PR c/83656

View File

@ -1,21 +1,22 @@
/* { dg-do compile } */
/* { dg-prune-output "undeclared here \\(not in a function\\)|\[^\n\r\]* was not declared in this scope" } */
void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning "outside range" } */
void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning "outside range" } */
void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,bar))); /* { dg-warning ".alloc_size. attribute argument 2 is invalid" } */
void* my_realloc(void*, unsigned) __attribute__((alloc_size(bar))); /* { dg-warning ".alloc_size. attribute argument is invalid" } */
typedef char vec __attribute__((vector_size(bar))); /* { dg-warning "ignored" } */
void f1(char*) __attribute__((nonnull(bar))); /* { dg-error "invalid operand" } */
void f2(char*) __attribute__((nonnull(1,bar))); /* { dg-error "invalid operand" } */
void f1(char*) __attribute__((nonnull(bar))); /* { dg-warning ".nonnull. attribute argument is invalid" } */
void foo(void);
void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning "outside range" } */
void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning "outside range" } */
void f2(char*) __attribute__((nonnull(1,bar))); /* { dg-warning ".nonnull. attribute argument 2 is invalid" } */
void foo(int);
void* my_calloc(unsigned, unsigned) __attribute__((alloc_size(1,foo))); /* { dg-warning ".alloc_size. attribute argument 2 has type .void\\\(int\\\)." } */
void* my_realloc(void*, unsigned) __attribute__((alloc_size(foo))); /* { dg-warning ".alloc_size. attribute argument has type .void ?\\\(int\\\)" } */
typedef char vec __attribute__((vector_size(foo))); /* { dg-warning "ignored" } */
void f1(char*) __attribute__((nonnull(foo))); /* { dg-error "invalid operand" } */
void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-error "invalid operand" } */
void f1(char*) __attribute__((nonnull(foo))); /* { dg-warning ".nonnull. attribute argument has type .void ?\\\(int\\\)." } */
void f2(char*) __attribute__((nonnull(1,foo))); /* { dg-warning ".nonnull. attribute argument 2 has type .void ?\\\(int\\\)." } */
void g() __attribute__((aligned(foo))); /* { dg-error "invalid value|not an integer" } */

View File

@ -1,12 +1,15 @@
/* PR c/71574 */
/* PR c/71574 - ICE on code with alloc_align attribute */
/* { dg-do compile } */
int fn1 (void);
int fn2 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning "parameter outside range" } */
int fn3 (void) __attribute__ ((alloc_size (fn1))); /* { dg-warning "parameter outside range" } */
int fn4 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning "not integer constant" } */
int fn5 (char *, char *) __attribute__((nonnull (fn1))); /* { dg-error "nonnull argument has invalid operand" } */
int fn1 (int);
int fn2 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning ".alloc_align. attribute ignored on a function returning .int." } */
int fn3 (void) __attribute__ ((alloc_size (fn1))); /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
int fn4 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning ".assume_aligned. attribute ignored on a function returning .int." } */
int fn5 (char *, char *) __attribute__((nonnull (fn1))); /* { dg-warning ".nonnull. attribute argument has type .int\\\(int\\\)." } */
int fn6 (const char *, ...) __attribute__ ((sentinel (fn1))); /* { dg-warning "not an integer constant" } */
void* fn7 (void) __attribute__ ((alloc_align (fn1))); /* { dg-warning ".alloc_align. attribute argument has type .int\\\(int\\\)." } */
void* fn8 (void) __attribute__ ((assume_aligned (fn1))); /* { dg-warning "not an integer constant" } */
typedef int __attribute__((vector_size (fn1))) v4si; /* { dg-warning "attribute ignored" } */
typedef int T __attribute__((aligned (fn1))); /* { dg-error "requested alignment is not" } */

View File

@ -0,0 +1,53 @@
/* PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ALLOC_SIZE(N) __attribute__ ((alloc_size (N)))
const int i1 = 1;
ALLOC_SIZE (i1) void* fcst (int);
void* call_fcst (void)
{
void *p = fcst (1);
__builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1)); // { dg-warning "\\\[-Wstringop-overflow=" }
return p;
}
enum { e1 = 1 };
ALLOC_SIZE (e1) void* fenum (int);
void* call_fenum (void)
{
void *p = fenum (1);
__builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1)); // { dg-warning "\\\[-Wstringop-overflow=" }
return p;
}
template <class T>
struct A
{
ALLOC_SIZE (T::N1) static void* ftemplarg_1 (int);
ALLOC_SIZE (T::N2) static void*
ftemplarg_2 (int); // { dg-warning "attribute argument value .2. exceeds the number of function parameters 1" }
};
struct B { static const int N1 = 1; static const int N2 = 1; };
void* call_ftemplarg_1 (A<B> *pa)
{
void *p = pa->ftemplarg_1 (1);
__builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1)); // { dg-warning "\\\[-Wstringop-overflow=" }
return p;
}
struct C { static const int N1 = 1; static const int N2 = 2; };
void* call_ftemplarg_2 (A<C> *pa)
{
void *p = pa->ftemplarg_2 (1);
__builtin___memset_chk (p, 0, 2, __builtin_object_size (p, 1));
return p;
}

View File

@ -5,6 +5,6 @@ void *f1 (int) __attribute__((alloc_align (1)));
void *f2 (int, int, int) __attribute__((alloc_align (3)));
void *f3 (void) __attribute__((alloc_align)); /* { dg-error "wrong number of arguments specified" } */
void *f4 (int, int) __attribute__((alloc_align (1, 2))); /* { dg-error "wrong number of arguments specified" } */
void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning "outside range" } */
void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning "outside range" } */
void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning "outside range" } */
void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning ".alloc_align. attribute argument value .i. is not an integer constant" } */
void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning ".alloc_align. attribute argument value .0. does not refer to a function parameter" } */
void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning ".alloc_align. attribute argument value .2. exceeds the number of function parameters 1" } */

View File

@ -0,0 +1,43 @@
/* PR middle-end/81871 - bogus attribute alloc_align accepted
{ dg-do compile }
{ dg-options "-Wall" } */
#define ALIGN(N) __attribute__ ((alloc_align (N)))
#define SIZE_MAX __SIZE_MAX__
ALIGN (1) void fvv_m1 (void); /* { dg-warning ".alloc_align. attribute ignored on a function returning .void." } */
ALIGN (1) int fiv_1 (void); /* { dg-warning ".alloc_align. attribute ignored on a function returning .int." } */
ALIGN (0) void* fpvv_0 (void); /* { dg-warning ".alloc_align. attribute argument value .0. does not refer to a function parameter" } */
ALIGN (1) void* fpvv_1 (void); /* { dg-warning ".alloc_align. attribute argument value .1. exceeds the number of function parameters 0" } */
ALIGN (2) void* fii_2 (int); /* { dg-warning ".alloc_align. attribute argument value .2. exceeds the number of function parameters 1" } */
ALIGN (1) void fvi_1 (int); /* { dg-warning ".alloc_align. attribute ignored on a function returning .void." } */
/* Using alloc_align with a function returning a pointer to a function
should perhaps trigger a warning. */
typedef void (F)(void);
ALIGN (1) F* fpF_i_1 (int);
ALIGN (SIZE_MAX) void*
fpvi_szmax (int); /* { dg-warning ".alloc_align. attribute argument value .\[0-9\]+. exceeds the number of function parameters 1" } */
ALIGN ("1") void*
fpvi_str_1 (int); /* { dg-warning ".alloc_align. attribute argument has type .char\\\[2]" } */
ALIGN ((void*)0) void*
fpvi_pv0 (int); /* { dg-warning ".alloc_align. attribute argument has type .void \\\*." } */
ALIGN ((double*)1) void*
fpvi_pd1 (int); /* { dg-warning ".alloc_align. attribute argument has type .double \\\*." } */
ALIGN (1) void*
fpvi_pv_1 (void*); /* { dg-warning ".alloc_align. attribute argument value .1. refers to parameter type .void \\\*." } */
struct S { int i; };
ALIGN (2) void*
fpvi_S_2 (int, struct S); /* { dg-warning ".alloc_align. attribute argument value .2. refers to parameter type .struct S." } */

View File

@ -0,0 +1,60 @@
/* PR middle-end/81871 - bogus attribute alloc_align accepted
Test exercising the problem with attribute alloc_size.
{ dg-do compile }
{ dg-options "-Wall" } */
#define ASIZE(...) __attribute__ ((alloc_size (__VA_ARGS__)))
#define SIZE_MAX __SIZE_MAX__
ASIZE (-1) void fvv_m1 (void); /* { dg-warning ".alloc_size. attribute ignored on a function returning .void." } */
ASIZE (1) int fiv_1 (void); /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
ASIZE (1, 2) int fiv_1_2 (void); /* { dg-warning ".alloc_size. attribute ignored on a function returning .int." } */
ASIZE (0) void* fpvv_0 (void); /* { dg-warning ".alloc_size. attribute argument value .0. does not refer to a function parameter" } */
ASIZE (1, 0) void*
fpvv_1_0 (int); /* { dg-warning ".alloc_size. attribute argument 2 value .0. does not refer to a function parameter" } */
ASIZE (1) void* fpvv_1 (void); /* { dg-warning ".alloc_size. attribute argument value .1. exceeds the number of function parameters 0" } */
ASIZE (1, 9) void*
fpvv_1_9 (int); /* { dg-warning ".alloc_size. attribute argument 2 value .9. exceeds the number of function parameters 1" } */
ASIZE (2) void* fii_2 (int); /* { dg-warning ".alloc_size. attribute argument value .2. exceeds the number of function parameters 1" } */
ASIZE (1) void fvi_1 (int); /* { dg-warning ".alloc_size. attribute ignored on a function returning .void." } */
/* Using alloc_size with a function returning a pointer to a function
should perhaps trigger a warning. */
typedef void (F)(void);
ASIZE (1) F* fpF_i_1 (int);
ASIZE (SIZE_MAX) void*
fpvi_szmax (int); /* { dg-warning ".alloc_size. attribute argument value .\[0-9\]+. exceeds the number of function parameters 1" } */
ASIZE ("12") void*
fpvi_str_1 (int); /* { dg-warning ".alloc_size. attribute argument has type .char\\\[3]." } */
ASIZE (1, "123") void*
fpvi_str_2 (int, int); /* { dg-warning ".alloc_size. attribute argument 2 has type .char\\\[4]." } */
ASIZE ((void*)0) void*
fpvi_pv0 (int); /* { dg-warning ".alloc_size. attribute argument has type .void \\\*." } */
ASIZE ((double*)sizeof (double)) void*
fpvi_pd1 (int); /* { dg-warning ".alloc_size. attribute argument has type .double \\\*." } */
ASIZE (1) void*
fpvi_pv_1 (void*); /* { dg-warning ".alloc_size. attribute argument value .1. refers to parameter type .void \\\*." } */
struct S { int i; };
ASIZE (2) void*
fpvi_S_2 (int, struct S); /* { dg-warning ".alloc_size. attribute argument value .2. refers to parameter type .struct S." } */
ASIZE ((struct S){ 1 }) void*
fpvi_S (int); /* { dg-warning ".alloc_size. attribute argument has type .struct S." } */
ASIZE (1, (struct S){ 1 }) void*
fpvi_1_S (int); /* { dg-warning ".alloc_size. attribute argument 2 has type .struct S." } */

View File

@ -1,4 +1,5 @@
/* { dg-do compile } */
char *foo() __attribute__((alloc_size(1))); /* { dg-warning "outside range" } */
/* PR c/36021 - __attribute__((alloc_size(n))) with function of no
arguments causes gcc to segfault
{ dg-do compile } */
char *foo() __attribute__((alloc_size(1)));

View File

@ -5,13 +5,13 @@ extern void abort (void);
#include "../gcc.c-torture/execute/builtins/chk.h"
extern char *mallocminus1(int size) __attribute__((alloc_size(-1))); /* { dg-warning "parameter outside range" } */
extern char *malloc0(int size) __attribute__((alloc_size(0))); /* { dg-warning "parameter outside range" } */
extern char *mallocminus1(int size) __attribute__((alloc_size(-1))); /* { dg-warning ".alloc_size. attribute argument value .-1. exceeds the number of function parameters 1" } */
extern char *malloc0(int size) __attribute__((alloc_size(0))); /* { dg-warning ".alloc_size. attribute argument value .0. does not refer to a function parameter" } */
extern char *malloc1(int size) __attribute__((alloc_size(1)));
extern char *malloc2(int empty, int size) __attribute__((alloc_size(2)));
extern char *calloc1(int size, int elements) __attribute__((alloc_size(1,2)));
extern char *calloc2(int size, int empty, int elements) __attribute__((alloc_size(1,3)));
extern char *balloc1(void *size) __attribute__((alloc_size(1)));
extern char *balloc1(void *size) __attribute__((alloc_size(1))); /* { dg-warning ".alloc_size. attribute argument value .1. refers to parameter type .void *." } */
void
test (void)

View File

@ -0,0 +1,36 @@
/* PR middle-end/87533 - bogus assume_aligned attribute silently accepted
{ dg-do compile }
{ dg-options "-Wall" } */
#define A(...) __attribute__ ((assume_aligned (__VA_ARGS__)))
A (1) void fv_1 (void); /* { dg-warning ".assume_aligned. attribute ignored on a function returning .void." } */
A (1) int fi_1 (void); /* { dg-warning ".assume_aligned. attribute ignored on a function returning .int." } */
A (-1) void* fpv_m1 (void); /* { dg-warning ".assume_aligned. attribute argument -1 is not a power of 2" } */
A (0) void* fpv_0 (void); /* { dg-warning ".assume_aligned. attribute argument 0 is not a power of 2" } */
/* Alignment of 1 is fine, it just doesn't offer any benefits. */
A (1) void* fpv_1 (void);
A (3) void* fpv_3 (void); /* { dg-warning ".assume_aligned. attribute argument 3 is not a power of 2" } */
A (16383) void* fpv_16km1 (void); /* { dg-warning ".assume_aligned. attribute argument 16383 is not a power of 2" } */
A (16384) void* fpv_16k (void);
A (16385) void* fpv_16kp1 (void); /* { dg-warning ".assume_aligned. attribute argument 16385 is not a power of 2" } */
A (32767) void* fpv_32km1 (void); /* { dg-warning ".assume_aligned. attribute argument 32767 is not a power of 2" } */
A (4, -1) void* fpv_4_m1 (void); /* { dg-warning ".assume_aligned. attribute argument -1 is not in the range \\\[0, 4\\\)" } */
A (4, 0) void* fpv_4_0 (void);
A (4, 1) void* fpv_4_1 (void);
A (4, 2) void* fpv_4_2 (void);
A (4, 3) void* fpv_4_3 (void);
A (4, 4) void* fpv_4_3 (void); /* { dg-warning ".assume_aligned. attribute argument 4 is not in the range \\\[0, 4\\\)" } */
A (4) void* gpv_4_3 (void);
A (2) void* gpv_4_3 (void);

View File

@ -41,10 +41,10 @@ extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* {
/* Both the numbers must be integer constant expressions. */
extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
int foo;
extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-warning ".format. attribute argument 2 value .foo. is not an integer constant" "bad number" } */
extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-warning ".format. attribute argument 3 value .foo. is not an integer constant" "bad number" } */
extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-warning ".format_arg. attribute argument value .foo. is not an integer constant" "bad format_arg number" } */
/* The format string argument must precede the arguments to be formatted.
This includes if no parameter types are specified (which is not valid ISO
@ -56,14 +56,14 @@ extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error
/* The format string argument must be a string type, and the arguments to
be formatted must be the "...". */
extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-warning ".format. attribute argument 2 value .1. refers to parameter type .int." "format int string" } */
extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error ".format. attribute argument 3 value .2. does not refer to a variable argument list" "not ..." } */
/* format_arg formats must take and return a string. */
extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-warning ".format_arg. attribute argument value .1. refers to parameter type .int." } */
extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */

View File

@ -4,11 +4,12 @@
extern void func1 () __attribute__((nonnull)); /* { dg-error "without arguments" } */
extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-error "out-of-range operand" } */
extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-warning ".nonnull. attribute argument value .2. exceeds the number of function parameters 1" } */
extern void func3 (char *) __attribute__((nonnull(foo))); /* { dg-error "invalid operand number|undeclared" } */
extern void func3 (char *) __attribute__((nonnull (foo))); /* { dg-warning ".nonnull. attribute argument is invalid" } */
/* { dg-error ".foo. undeclared" "undeclared argument" { target *-*-* } .-1 } */
extern void func4 (int) __attribute__((nonnull(1))); /* { dg-error "references non-pointer" } */
extern void func4 (int) __attribute__((nonnull(1))); /* { dg-warning ".nonnull. attribute argument value .1. refers to parameter type .int." } */
void
foo (void)

View File

@ -13,3 +13,5 @@ struct obstack {
}
void fn2(int) __attribute__((__alloc_size__(1)));
void fn3() { fn1(fn2); }
/* { dg-prune-output "attribute ignored" } */

View File

@ -19,8 +19,8 @@
- (void) log2: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2))); /* { dg-error "wrong" } */
+ (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */
- (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */
+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
@end
void test (LogObject *object)

View File

@ -19,17 +19,19 @@
- (void) insertObject: (id)object atIndex: (size_t)index andObject: (id)anotherObject atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
/* Test the behavior with invalid code. */
+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
/* { dg-warning "attribute argument is invalid" "" { target *-*-* } .-1 } */
- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "" } */
/* { dg-warning "attribute argument is invalid" "" { target *-*-* } .-1 } */
@end
void test (MyArray *object)

View File

@ -19,8 +19,8 @@
- (void) log2: (int)level message: (const char *) my_format, ... __attribute__ ((format (printf, 2))); /* { dg-error "wrong" } */
+ (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */
- (void) debug2: (const char *) my_format, ... __attribute__ ((format (printf))); /* { dg-error "wrong" } */
+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "args to be formatted is not ..." } */
+ (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
- (void) alert: (const char *) my_format __attribute__ ((format (printf, 1, 2))); /* { dg-error "does not refer to a variable argument list" } */
@end
void test (LogObject *object)

View File

@ -19,17 +19,17 @@
- (void) insertObject: (id)object atIndex: (size_t)index andObject: (id)anotherObject atIndex: (size_t)anotherIndex __attribute__ ((nonnull (1, 3)));
/* Test the behavior with invalid code. */
+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-error "out-of-range" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (0))); /* { dg-warning "does not refer to a function parameter" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-error "out-of-range" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (2))); /* { dg-warning "exceeds the number of function parameters 3" } */
+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-error "non-pointer operand" } */
+ (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
- (void) removeObjectAtIndex: (size_t)object __attribute__ ((nonnull (1))); /* { dg-warning "refers to parameter type .size_t." } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-error "invalid operand" } */
+ (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-warning "is invalid" } */
- (void) removeObject: (id)object __attribute__ ((nonnull (MyArray))); /* { dg-warning "is invalid" } */
@end
void test (MyArray *object)

View File

@ -4955,7 +4955,8 @@ build_nt_call_vec (tree fn, vec<tree, va_gc> *args)
return ret;
}
/* Create a DECL_... node of code CODE, name NAME and data type TYPE.
/* Create a DECL_... node of code CODE, name NAME (if non-null)
and data type TYPE.
We do NOT enter this node in any sort of symbol table.
LOC is the location of the decl.
@ -6944,12 +6945,11 @@ type_list_equal (const_tree l1, const_tree l2)
then this function counts only the ordinary arguments. */
int
type_num_arguments (const_tree type)
type_num_arguments (const_tree fntype)
{
int i = 0;
tree t;
for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
/* If the function does not take a variable number of arguments,
the last element in the list will have type `void'. */
if (VOID_TYPE_P (TREE_VALUE (t)))
@ -6960,6 +6960,40 @@ type_num_arguments (const_tree type)
return i;
}
/* Return the type of the function TYPE's argument ARGNO if known.
For vararg function's where ARGNO refers to one of the variadic
arguments return null. Otherwise, return a void_type_node for
out-of-bounds ARGNO. */
tree
type_argument_type (const_tree fntype, unsigned argno)
{
/* Treat zero the same as an out-of-bounds argument number. */
if (!argno)
return void_type_node;
function_args_iterator iter;
tree argtype;
unsigned i = 1;
FOREACH_FUNCTION_ARGS (fntype, argtype, iter)
{
/* A vararg function's argument list ends in a null. Otherwise,
an ordinary function's argument list ends with void. Return
null if ARGNO refers to a vararg argument, void_type_node if
it's out of bounds, and the formal argument type otherwise. */
if (!argtype)
break;
if (i == argno || VOID_TYPE_P (argtype))
return argtype;
++i;
}
return NULL_TREE;
}
/* Nonzero if integer constants T1 and T2
represent the same constant value. */

View File

@ -4834,6 +4834,7 @@ extern tree get_file_function_name (const char *);
extern tree get_callee_fndecl (const_tree);
extern combined_fn get_call_combined_fn (const_tree);
extern int type_num_arguments (const_tree);
extern tree type_argument_type (const_tree, unsigned) ATTRIBUTE_NONNULL (1);
extern bool associative_tree_code (enum tree_code);
extern bool commutative_tree_code (enum tree_code);
extern bool commutative_ternary_tree_code (enum tree_code);