mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-11 08:50:46 +08:00
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:
parent
cd5da9837b
commit
1d24950977
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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}.
|
||||
|
@ -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
|
||||
|
@ -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" } */
|
||||
|
@ -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" } */
|
||||
|
53
gcc/testsuite/g++.dg/ext/attr-alloc_size.C
Normal file
53
gcc/testsuite/g++.dg/ext/attr-alloc_size.C
Normal 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;
|
||||
}
|
@ -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" } */
|
||||
|
43
gcc/testsuite/gcc.dg/attr-alloc_align-4.c
Normal file
43
gcc/testsuite/gcc.dg/attr-alloc_align-4.c
Normal 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." } */
|
||||
|
60
gcc/testsuite/gcc.dg/attr-alloc_size-12.c
Normal file
60
gcc/testsuite/gcc.dg/attr-alloc_size-12.c
Normal 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." } */
|
@ -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)));
|
||||
|
@ -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)
|
||||
|
36
gcc/testsuite/gcc.dg/attr-assume_aligned-4.c
Normal file
36
gcc/testsuite/gcc.dg/attr-assume_aligned-4.c
Normal 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);
|
@ -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" } */
|
||||
|
@ -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)
|
||||
|
@ -13,3 +13,5 @@ struct obstack {
|
||||
}
|
||||
void fn2(int) __attribute__((__alloc_size__(1)));
|
||||
void fn3() { fn1(fn2); }
|
||||
|
||||
/* { dg-prune-output "attribute ignored" } */
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
42
gcc/tree.c
42
gcc/tree.c
@ -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. */
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user