Enhance -Waddress to detect more suspicious expressions [PR102103].
Resolves: PR c/102103 - missing warning comparing array address to null gcc/ChangeLog: PR c/102103 * doc/invoke.texi (-Waddress): Update. * gengtype.c (write_types): Avoid -Waddress. * poly-int.h (POLY_SET_COEFF): Avoid using null. gcc/c-family/ChangeLog: PR c/102103 * c-common.c (decl_with_nonnull_addr_p): Handle members. Check and perform warning suppression. (c_common_truthvalue_conversion): Enhance warning suppression. gcc/c/ChangeLog: PR c/102103 * c-typeck.c (maybe_warn_for_null_address): New function. (build_binary_op): Call it. gcc/cp/ChangeLog: PR c/102103 * typeck.c (warn_for_null_address): Enhance. (cp_build_binary_op): Call it also for member pointers. gcc/fortran/ChangeLog: PR c/102103 * array.c: Remove an unnecessary test. * trans-array.c: Same. gcc/testsuite/ChangeLog: PR c/102103 * g++.dg/cpp0x/constexpr-array-ptr10.C: Suppress a valid warning. * g++.dg/warn/Wreturn-local-addr-6.C: Correct a cast. * gcc.dg/Waddress.c: Expect a warning. * c-c++-common/Waddress-3.c: New test. * c-c++-common/Waddress-4.c: New test. * g++.dg/warn/Waddress-5.C: New test. * g++.dg/warn/Waddress-6.C: New test. * g++.dg/warn/pr101219.C: Expect a warning. * gcc.dg/Waddress-3.c: New test.
This commit is contained in:
parent
f171091008
commit
4dc7ce6fb3
@ -3393,14 +3393,16 @@ c_wrap_maybe_const (tree expr, bool non_const)
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Return whether EXPR is a declaration whose address can never be
|
||||
NULL. */
|
||||
/* Return whether EXPR is a declaration whose address can never be NULL.
|
||||
The address of the first struct member could be NULL only if it were
|
||||
accessed through a NULL pointer, and such an access would be invalid. */
|
||||
|
||||
bool
|
||||
decl_with_nonnull_addr_p (const_tree expr)
|
||||
{
|
||||
return (DECL_P (expr)
|
||||
&& (TREE_CODE (expr) == PARM_DECL
|
||||
&& (TREE_CODE (expr) == FIELD_DECL
|
||||
|| TREE_CODE (expr) == PARM_DECL
|
||||
|| TREE_CODE (expr) == LABEL_DECL
|
||||
|| !DECL_WEAK (expr)));
|
||||
}
|
||||
@ -3488,13 +3490,17 @@ c_common_truthvalue_conversion (location_t location, tree expr)
|
||||
case ADDR_EXPR:
|
||||
{
|
||||
tree inner = TREE_OPERAND (expr, 0);
|
||||
if (decl_with_nonnull_addr_p (inner))
|
||||
if (decl_with_nonnull_addr_p (inner)
|
||||
/* Check both EXPR and INNER for suppression. */
|
||||
&& !warning_suppressed_p (expr, OPT_Waddress)
|
||||
&& !warning_suppressed_p (inner, OPT_Waddress))
|
||||
{
|
||||
/* Common Ada programmer's mistake. */
|
||||
/* Common Ada programmer's mistake. */
|
||||
warning_at (location,
|
||||
OPT_Waddress,
|
||||
"the address of %qD will always evaluate as %<true%>",
|
||||
inner);
|
||||
suppress_warning (inner, OPT_Waddress);
|
||||
return truthvalue_true_node;
|
||||
}
|
||||
break;
|
||||
@ -3627,8 +3633,17 @@ c_common_truthvalue_conversion (location_t location, tree expr)
|
||||
break;
|
||||
/* If this isn't narrowing the argument, we can ignore it. */
|
||||
if (TYPE_PRECISION (totype) >= TYPE_PRECISION (fromtype))
|
||||
return c_common_truthvalue_conversion (location,
|
||||
TREE_OPERAND (expr, 0));
|
||||
{
|
||||
tree op0 = TREE_OPERAND (expr, 0);
|
||||
if ((TREE_CODE (fromtype) == POINTER_TYPE
|
||||
&& TREE_CODE (totype) == INTEGER_TYPE)
|
||||
|| warning_suppressed_p (expr, OPT_Waddress))
|
||||
/* Suppress -Waddress for casts to intptr_t, propagating
|
||||
any suppression from the enclosing expression to its
|
||||
operand. */
|
||||
suppress_warning (op0, OPT_Waddress);
|
||||
return c_common_truthvalue_conversion (location, op0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
140
gcc/c/c-typeck.c
140
gcc/c/c-typeck.c
@ -11554,6 +11554,110 @@ build_vec_cmp (tree_code code, tree type,
|
||||
return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
|
||||
}
|
||||
|
||||
/* Possibly warn about an address of OP never being NULL in a comparison
|
||||
operation CODE involving null. */
|
||||
|
||||
static void
|
||||
maybe_warn_for_null_address (location_t loc, tree op, tree_code code)
|
||||
{
|
||||
if (!warn_address || warning_suppressed_p (op, OPT_Waddress))
|
||||
return;
|
||||
|
||||
if (TREE_CODE (op) == NOP_EXPR)
|
||||
{
|
||||
/* Allow casts to intptr_t to suppress the warning. */
|
||||
tree type = TREE_TYPE (op);
|
||||
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
return;
|
||||
op = TREE_OPERAND (op, 0);
|
||||
}
|
||||
|
||||
if (TREE_CODE (op) == POINTER_PLUS_EXPR)
|
||||
{
|
||||
/* Allow a cast to void* to suppress the warning. */
|
||||
tree type = TREE_TYPE (TREE_TYPE (op));
|
||||
if (VOID_TYPE_P (type))
|
||||
return;
|
||||
|
||||
/* Adding any value to a null pointer, including zero, is undefined
|
||||
in C. This includes the expression &p[0] where p is the null
|
||||
pointer, although &p[0] will have been folded to p by this point
|
||||
and so not diagnosed. */
|
||||
if (code == EQ_EXPR)
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<false%> "
|
||||
"for the pointer operand in %qE must not be NULL",
|
||||
op);
|
||||
else
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<true%> "
|
||||
"for the pointer operand in %qE must not be NULL",
|
||||
op);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (TREE_CODE (op) != ADDR_EXPR)
|
||||
return;
|
||||
|
||||
op = TREE_OPERAND (op, 0);
|
||||
|
||||
if (TREE_CODE (op) == IMAGPART_EXPR
|
||||
|| TREE_CODE (op) == REALPART_EXPR)
|
||||
{
|
||||
/* The address of either complex part may not be null. */
|
||||
if (code == EQ_EXPR)
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<false%> "
|
||||
"for the address of %qE will never be NULL",
|
||||
op);
|
||||
else
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<true%> "
|
||||
"for the address of %qE will never be NULL",
|
||||
op);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set to true in the loop below if OP dereferences is operand.
|
||||
In such a case the ultimate target need not be a decl for
|
||||
the null [in]equality test to be constant. */
|
||||
bool deref = false;
|
||||
|
||||
/* Get the outermost array or object, or member. */
|
||||
while (handled_component_p (op))
|
||||
{
|
||||
if (TREE_CODE (op) == COMPONENT_REF)
|
||||
{
|
||||
/* Get the member (its address is never null). */
|
||||
op = TREE_OPERAND (op, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the outer array/object to refer to in the warning. */
|
||||
op = TREE_OPERAND (op, 0);
|
||||
deref = true;
|
||||
}
|
||||
|
||||
if ((!deref && !decl_with_nonnull_addr_p (op))
|
||||
|| from_macro_expansion_at (loc))
|
||||
return;
|
||||
|
||||
if (code == EQ_EXPR)
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<false%> "
|
||||
"for the address of %qE will never be NULL",
|
||||
op);
|
||||
else
|
||||
warning_at (loc, OPT_Waddress,
|
||||
"the comparison will always evaluate as %<true%> "
|
||||
"for the address of %qE will never be NULL",
|
||||
op);
|
||||
|
||||
if (DECL_P (op))
|
||||
inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op);
|
||||
}
|
||||
|
||||
/* Build a binary-operation expression without default conversions.
|
||||
CODE is the kind of expression to build.
|
||||
LOCATION is the operator's location.
|
||||
@ -12189,44 +12293,12 @@ build_binary_op (location_t location, enum tree_code code,
|
||||
short_compare = 1;
|
||||
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
|
||||
{
|
||||
if (TREE_CODE (op0) == ADDR_EXPR
|
||||
&& decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))
|
||||
&& !from_macro_expansion_at (location))
|
||||
{
|
||||
if (code == EQ_EXPR)
|
||||
warning_at (location,
|
||||
OPT_Waddress,
|
||||
"the comparison will always evaluate as %<false%> "
|
||||
"for the address of %qD will never be NULL",
|
||||
TREE_OPERAND (op0, 0));
|
||||
else
|
||||
warning_at (location,
|
||||
OPT_Waddress,
|
||||
"the comparison will always evaluate as %<true%> "
|
||||
"for the address of %qD will never be NULL",
|
||||
TREE_OPERAND (op0, 0));
|
||||
}
|
||||
maybe_warn_for_null_address (location, op0, code);
|
||||
result_type = type0;
|
||||
}
|
||||
else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
|
||||
{
|
||||
if (TREE_CODE (op1) == ADDR_EXPR
|
||||
&& decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))
|
||||
&& !from_macro_expansion_at (location))
|
||||
{
|
||||
if (code == EQ_EXPR)
|
||||
warning_at (location,
|
||||
OPT_Waddress,
|
||||
"the comparison will always evaluate as %<false%> "
|
||||
"for the address of %qD will never be NULL",
|
||||
TREE_OPERAND (op1, 0));
|
||||
else
|
||||
warning_at (location,
|
||||
OPT_Waddress,
|
||||
"the comparison will always evaluate as %<true%> "
|
||||
"for the address of %qD will never be NULL",
|
||||
TREE_OPERAND (op1, 0));
|
||||
}
|
||||
maybe_warn_for_null_address (location, op1, code);
|
||||
result_type = type1;
|
||||
}
|
||||
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
|
||||
|
@ -4603,25 +4603,93 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
|
||||
|| warning_suppressed_p (op, OPT_Waddress))
|
||||
return;
|
||||
|
||||
if (TREE_CODE (op) == NON_DEPENDENT_EXPR)
|
||||
op = TREE_OPERAND (op, 0);
|
||||
|
||||
tree cop = fold_for_warn (op);
|
||||
|
||||
if (TREE_CODE (cop) == ADDR_EXPR
|
||||
&& decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
|
||||
&& !warning_suppressed_p (cop, OPT_Waddress))
|
||||
warning_at (location, OPT_Waddress, "the address of %qD will never "
|
||||
"be NULL", TREE_OPERAND (cop, 0));
|
||||
if (TREE_CODE (cop) == NON_LVALUE_EXPR)
|
||||
/* Unwrap the expression for C++ 98. */
|
||||
cop = TREE_OPERAND (cop, 0);
|
||||
|
||||
if (CONVERT_EXPR_P (op)
|
||||
if (TREE_CODE (cop) == PTRMEM_CST)
|
||||
{
|
||||
/* The address of a nonstatic data member is never null. */
|
||||
warning_at (location, OPT_Waddress,
|
||||
"the address %qE will never be NULL",
|
||||
cop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TREE_CODE (cop) == NOP_EXPR)
|
||||
{
|
||||
/* Allow casts to intptr_t to suppress the warning. */
|
||||
tree type = TREE_TYPE (cop);
|
||||
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
return;
|
||||
|
||||
STRIP_NOPS (cop);
|
||||
}
|
||||
|
||||
bool warned = false;
|
||||
if (TREE_CODE (cop) == ADDR_EXPR)
|
||||
{
|
||||
cop = TREE_OPERAND (cop, 0);
|
||||
|
||||
/* Set to true in the loop below if OP dereferences its operand.
|
||||
In such a case the ultimate target need not be a decl for
|
||||
the null [in]equality test to be necessarily constant. */
|
||||
bool deref = false;
|
||||
|
||||
/* Get the outermost array or object, or member. */
|
||||
while (handled_component_p (cop))
|
||||
{
|
||||
if (TREE_CODE (cop) == COMPONENT_REF)
|
||||
{
|
||||
/* Get the member (its address is never null). */
|
||||
cop = TREE_OPERAND (cop, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the outer array/object to refer to in the warning. */
|
||||
cop = TREE_OPERAND (cop, 0);
|
||||
deref = true;
|
||||
}
|
||||
|
||||
if ((!deref && !decl_with_nonnull_addr_p (cop))
|
||||
|| from_macro_expansion_at (location)
|
||||
|| warning_suppressed_p (cop, OPT_Waddress))
|
||||
return;
|
||||
|
||||
warned = warning_at (location, OPT_Waddress,
|
||||
"the address of %qD will never be NULL", cop);
|
||||
op = cop;
|
||||
}
|
||||
else if (TREE_CODE (cop) == POINTER_PLUS_EXPR)
|
||||
{
|
||||
/* Adding zero to the null pointer is well-defined in C++. When
|
||||
the offset is unknown (i.e., not a constant) warn anyway since
|
||||
it's less likely that the pointer operand is null than not. */
|
||||
tree off = TREE_OPERAND (cop, 1);
|
||||
if (!integer_zerop (off)
|
||||
&& !warning_suppressed_p (cop, OPT_Waddress))
|
||||
warning_at (location, OPT_Waddress, "comparing the result of pointer "
|
||||
"addition %qE and NULL", cop);
|
||||
return;
|
||||
}
|
||||
else if (CONVERT_EXPR_P (op)
|
||||
&& TYPE_REF_P (TREE_TYPE (TREE_OPERAND (op, 0))))
|
||||
{
|
||||
tree inner_op = op;
|
||||
STRIP_NOPS (inner_op);
|
||||
STRIP_NOPS (op);
|
||||
|
||||
if (DECL_P (inner_op))
|
||||
warning_at (location, OPT_Waddress,
|
||||
"the compiler can assume that the address of "
|
||||
"%qD will never be NULL", inner_op);
|
||||
if (DECL_P (op))
|
||||
warned = warning_at (location, OPT_Waddress,
|
||||
"the compiler can assume that the address of "
|
||||
"%qD will never be NULL", op);
|
||||
}
|
||||
|
||||
if (warned && DECL_P (op))
|
||||
inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op);
|
||||
}
|
||||
|
||||
/* Warn about [expr.arith.conv]/2: If one operand is of enumeration type and
|
||||
@ -5411,6 +5479,8 @@ cp_build_binary_op (const op_location_t &location,
|
||||
op1 = cp_convert (TREE_TYPE (op0), op1, complain);
|
||||
}
|
||||
result_type = TREE_TYPE (op0);
|
||||
|
||||
warn_for_null_address (location, orig_op0, complain);
|
||||
}
|
||||
else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0))
|
||||
return cp_build_binary_op (location, code, op1, op0, complain);
|
||||
|
@ -8551,17 +8551,43 @@ by @option{-Wall}.
|
||||
@item -Waddress
|
||||
@opindex Waddress
|
||||
@opindex Wno-address
|
||||
Warn about suspicious uses of memory addresses. These include using
|
||||
the address of a function in a conditional expression, such as
|
||||
@code{void func(void); if (func)}, and comparisons against the memory
|
||||
address of a string literal, such as @code{if (x == "abc")}. Such
|
||||
uses typically indicate a programmer error: the address of a function
|
||||
always evaluates to true, so their use in a conditional usually
|
||||
indicate that the programmer forgot the parentheses in a function
|
||||
call; and comparisons against string literals result in unspecified
|
||||
behavior and are not portable in C, so they usually indicate that the
|
||||
programmer intended to use @code{strcmp}. This warning is enabled by
|
||||
@option{-Wall}.
|
||||
Warn about suspicious uses of address expressions. These include comparing
|
||||
the address of a function or a declared object to the null pointer constant
|
||||
such as in
|
||||
@smallexample
|
||||
void f (void);
|
||||
void g (void)
|
||||
@{
|
||||
if (!func) // warning: expression evaluates to false
|
||||
abort ();
|
||||
@}
|
||||
@end smallexample
|
||||
comparisons of a pointer to a string literal, such as in
|
||||
@smallexample
|
||||
void f (const char *x)
|
||||
@{
|
||||
if (x == "abc") // warning: expression evaluates to false
|
||||
puts ("equal");
|
||||
@}
|
||||
@end smallexample
|
||||
and tests of the results of pointer addition or subtraction for equality
|
||||
to null, such as in
|
||||
@smallexample
|
||||
void f (const int *p, int i)
|
||||
@{
|
||||
return p + i == NULL;
|
||||
@}
|
||||
@end smallexample
|
||||
Such uses typically indicate a programmer error: the address of most
|
||||
functions and objects necessarily evaluates to true (the exception are
|
||||
weak symbols), so their use in a conditional might indicate missing
|
||||
parentheses in a function call or a missing dereference in an array
|
||||
expression. The subset of the warning for object pointers can be
|
||||
suppressed by casting the pointer operand to an integer type such
|
||||
as @code{inptr_t} or @code{uinptr_t}.
|
||||
Comparisons against string literals result in unspecified behavior
|
||||
and are not portable, and suggest the intent was to call @code{strcmp}.
|
||||
@option{-Waddress} warning is enabled by @option{-Wall}.
|
||||
|
||||
@item -Wno-address-of-packed-member
|
||||
@opindex Waddress-of-packed-member
|
||||
|
@ -2581,7 +2581,7 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
|
||||
}
|
||||
}
|
||||
|
||||
if (array->shape && array->shape[dimen])
|
||||
if (array->shape)
|
||||
{
|
||||
mpz_init_set (*result, array->shape[dimen]);
|
||||
return true;
|
||||
|
@ -5104,7 +5104,6 @@ set_loop_bounds (gfc_loopinfo *loop)
|
||||
|
||||
if (info->shape)
|
||||
{
|
||||
gcc_assert (info->shape[dim]);
|
||||
/* The frontend has worked out the size for us. */
|
||||
if (!loopspec[n]
|
||||
|| !specinfo->shape
|
||||
|
@ -3685,8 +3685,8 @@ write_types (outf_p output_header, type_p structures,
|
||||
output_mangled_typename (output_header, s);
|
||||
oprintf (output_header, "(X) do { \\\n");
|
||||
oprintf (output_header,
|
||||
" if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix,
|
||||
s_id_for_tag);
|
||||
" if ((intptr_t)(X) != 0) gt_%sx_%s (X);\\\n",
|
||||
wtd->prefix, s_id_for_tag);
|
||||
oprintf (output_header, " } while (0)\n");
|
||||
|
||||
for (opt = s->u.s.opt; opt; opt = opt->next)
|
||||
|
@ -324,10 +324,10 @@ struct poly_result<T1, T2, 2>
|
||||
routine can take the address of RES rather than the address of
|
||||
a temporary.
|
||||
|
||||
The dummy comparison against a null C * is just a way of checking
|
||||
The dummy self-comparison against C * is just a way of checking
|
||||
that C gives the right type. */
|
||||
#define POLY_SET_COEFF(C, RES, I, VALUE) \
|
||||
((void) (&(RES).coeffs[0] == (C *) 0), \
|
||||
((void) (&(RES).coeffs[0] == (C *) (void *) &(RES).coeffs[0]), \
|
||||
wi::int_traits<C>::precision_type == wi::FLEXIBLE_PRECISION \
|
||||
? (void) ((RES).coeffs[I] = VALUE) \
|
||||
: (void) ((RES).coeffs[I].~C (), new (&(RES).coeffs[I]) C (VALUE)))
|
||||
|
125
gcc/testsuite/c-c++-common/Waddress-3.c
Normal file
125
gcc/testsuite/c-c++-common/Waddress-3.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* PR c/102103 - missing warning comparing array address to null
|
||||
{ dg-do compile }
|
||||
{ dg-options "-Wall" } */
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
#ifndef __cplusplus
|
||||
# define bool _Bool
|
||||
#endif
|
||||
|
||||
struct S { void *p, *a1[2], *a2[2][2]; } s, *p;
|
||||
|
||||
extern const void *a1[2];
|
||||
extern void *a2[2][2], *ax[];
|
||||
|
||||
void T (bool);
|
||||
|
||||
void test_array_eq_0 (int i)
|
||||
{
|
||||
// Verify that casts intptr_t suppress the warning.
|
||||
T ((intptr_t)a1 == 0);
|
||||
T ((uintptr_t)a1 == 0);
|
||||
T (a1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a1); // { dg-warning "-Waddress" }
|
||||
// Verify that casts to other pointer types don't suppress it.
|
||||
T ((void *)a1 == 0); // { dg-warning "-Waddress" }
|
||||
T ((char *)a1 == 0); // { dg-warning "-Waddress" }
|
||||
T (a1[0] == 0);
|
||||
T (0 == (intptr_t)&a1[0]);
|
||||
T (0 == &a1[0]); // { dg-warning "-Waddress" }
|
||||
T (a1[i] == 0);
|
||||
T (0 == (uintptr_t)&a1[i]);
|
||||
T (0 == &a1[i]); // { dg-warning "-Waddress" }
|
||||
|
||||
T ((intptr_t)a2 == 0);
|
||||
T (a2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2); // { dg-warning "-Waddress" }
|
||||
T (a2[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a1[0]); // { dg-warning "-Waddress" }
|
||||
T (a2[i] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2[i]); // { dg-warning "-Waddress" }
|
||||
T (a2[0][0] == 0);
|
||||
T (0 == &a2[0][0]); // { dg-warning "-Waddress" }
|
||||
T (&ax == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &ax); // { dg-warning "-Waddress" }
|
||||
T (&ax[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == ax[0]);
|
||||
}
|
||||
|
||||
|
||||
void test_array_neq_0 (int i)
|
||||
{
|
||||
// Verify that casts to intptr_t suppress the warning.
|
||||
T ((uintptr_t)a1);
|
||||
|
||||
T (a1); // { dg-warning "-Waddress" }
|
||||
T ((void *)a1); // { dg-warning "-Waddress" }
|
||||
T (&a1 != 0); // { dg-warning "-Waddress" }
|
||||
T (a1[0]);
|
||||
T (&a1[0] != 0); // { dg-warning "-Waddress" }
|
||||
T (a1[i]);
|
||||
T (&a1[i] != 0); // { dg-warning "-Waddress" }
|
||||
|
||||
T ((intptr_t)a2);
|
||||
T (a2); // { dg-warning "-Waddress" }
|
||||
T ((void *)a2); // { dg-warning "-Waddress" }
|
||||
T ((char *)a2); // { dg-warning "-Waddress" }
|
||||
T (&a2 != 0); // { dg-warning "-Waddress" }
|
||||
T (a2[0]); // { dg-warning "-Waddress" }
|
||||
T (&a1[0] != 0); // { dg-warning "-Waddress" }
|
||||
T (a2[i]); // { dg-warning "-Waddress" }
|
||||
T (&a2[i] != 0); // { dg-warning "-Waddress" }
|
||||
T (a2[0][0]);
|
||||
T (&a2[0][0] != 0); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
|
||||
void test_member_array_eq_0 (int i)
|
||||
{
|
||||
// Verify that casts to intptr_t suppress the warning.
|
||||
T ((intptr_t)s.a1 == 0);
|
||||
T (s.a1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a1); // { dg-warning "-Waddress" }
|
||||
T (s.a1[0] == 0);
|
||||
T ((void*)s.a1); // { dg-warning "-Waddress" }
|
||||
T (0 == &a1[0]); // { dg-warning "-Waddress" }
|
||||
T (s.a1[i] == 0);
|
||||
T (0 == &a1[i]); // { dg-warning "-Waddress" }
|
||||
|
||||
T ((uintptr_t)s.a2 == 0);
|
||||
T (s.a2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2); // { dg-warning "-Waddress" }
|
||||
T ((void *)s.a2 == 0);// { dg-warning "-Waddress" }
|
||||
T (s.a2[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a1[0]); // { dg-warning "-Waddress" }
|
||||
T (s.a2[i] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2[i]); // { dg-warning "-Waddress" }
|
||||
T (s.a2[0][0] == 0);
|
||||
T (0 == &a2[0][0]); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
|
||||
void test_member_array_neq_0 (int i)
|
||||
{
|
||||
// Verify that casts to intptr_t suppress the warning.
|
||||
T ((uintptr_t)s.a1);
|
||||
T (s.a1); // { dg-warning "-Waddress" }
|
||||
T (&s.a1 != 0); // { dg-warning "-Waddress" }
|
||||
T ((void *)&s.a1[0]); // { dg-warning "-Waddress" }
|
||||
T (s.a1[0]);
|
||||
T (&s.a1[0] != 0); // { dg-warning "-Waddress" }
|
||||
T (s.a1[i]);
|
||||
T (&s.a1[i] != 0); // { dg-warning "-Waddress" }
|
||||
|
||||
T ((intptr_t)s.a2);
|
||||
T (s.a2); // { dg-warning "-Waddress" }
|
||||
T (&s.a2 != 0); // { dg-warning "-Waddress" }
|
||||
T (s.a2[0]); // { dg-warning "-Waddress" }
|
||||
T (&s.a1[0] != 0); // { dg-warning "-Waddress" }
|
||||
T (s.a2[i]); // { dg-warning "-Waddress" }
|
||||
T (&s.a2[i] != 0); // { dg-warning "-Waddress" }
|
||||
T (s.a2[0][0]);
|
||||
T (&s.a2[0][0] != 0); // { dg-warning "-Waddress" }
|
||||
}
|
106
gcc/testsuite/c-c++-common/Waddress-4.c
Normal file
106
gcc/testsuite/c-c++-common/Waddress-4.c
Normal file
@ -0,0 +1,106 @@
|
||||
/* PR c/102103 - missing warning comparing array address to null
|
||||
{ dg-do compile }
|
||||
{ dg-options "-Wall" } */
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __INTPTR_TYPE__ uintptr_t;
|
||||
|
||||
extern char *ax[], *a2[][2];
|
||||
|
||||
void T (int);
|
||||
|
||||
void test_ax_plus_eq_0 (int i)
|
||||
{
|
||||
// Verify that casts to intptr_t suppress the warning.
|
||||
T ((intptr_t)(ax + 0) == 0);
|
||||
T ((uintptr_t)(ax + 1) == 0);
|
||||
|
||||
T (ax + 0 == 0); // { dg-warning "-Waddress" }
|
||||
T (&ax[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (ax - 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &ax[-1]); // { dg-warning "-Waddress" }
|
||||
T ((void *)(&ax[0] + 2) == 0); // { dg-warning "-Waddress" }
|
||||
T (&ax[0] + 2 == 0); // { dg-warning "-Waddress" }
|
||||
T (ax + 3 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &ax[-4]); // { dg-warning "-Waddress" }
|
||||
T (ax - i == 0); // { dg-warning "-Waddress" }
|
||||
T (&ax[i] == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &ax[1] + i); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
void test_a2_plus_eq_0 (int i)
|
||||
{
|
||||
// Verify that casts to intptr_t suppress the warning.
|
||||
T ((intptr_t)(a2 + 0) == 0);
|
||||
T ((uintptr_t)(a2 + 1) == 0);
|
||||
|
||||
T (a2 + 0 == 0); // { dg-warning "-Waddress" }
|
||||
// Verify that a cast to another pointer type doesn't suppress it.
|
||||
T ((void*)(a2 + 0) == 0); // { dg-warning "-Waddress" }
|
||||
T ((char*)a2 + 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (&a2[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (a2 - 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2[-1]); // { dg-warning "-Waddress" }
|
||||
T (a2 + 2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &a2[-2]); // { dg-warning "-Waddress" }
|
||||
T (a2 - i == 0); // { dg-warning "-Waddress" }
|
||||
T (&a2[i] == 0); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
// Exercise a pointer.
|
||||
void test_p_plus_eq_0 (int *p, int i)
|
||||
{
|
||||
/* P + 0 and equivalently &P[0] are invalid for a null P but they're
|
||||
folded to p before the warning has a chance to trigger. */
|
||||
T (p + 0 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
T (&p[0] == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
|
||||
T (p - 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &p[-1]); // { dg-warning "-Waddress" }
|
||||
T (p + 2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &p[-2]); // { dg-warning "-Waddress" }
|
||||
T (p - i == 0); // { dg-warning "-Waddress" }
|
||||
T (&p[i] == 0); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
// Exercise pointer to array.
|
||||
void test_pa_plus_eq_0 (int (*p)[], int (*p2)[][2], int i)
|
||||
{
|
||||
// The array pointer may be null.
|
||||
T (*p == 0);
|
||||
/* &**P is equivalent to *P and might be the result od macro expansion.
|
||||
Verify it doesn't cause a warning. */
|
||||
T (&**p == 0);
|
||||
|
||||
/* *P + 0 is invalid but folded to *P before the warning has a chance
|
||||
to trigger. */
|
||||
T (*p + 0 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
|
||||
T (&(*p)[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (*p - 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &(*p)[-1]); // { dg-warning "-Waddress" }
|
||||
T (*p + 2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &(*p)[-2]); // { dg-warning "-Waddress" }
|
||||
T (*p - i == 0); // { dg-warning "-Waddress" }
|
||||
T (&(*p)[i] == 0); // { dg-warning "-Waddress" }
|
||||
|
||||
|
||||
/* Similar to the above but for a pointer to a two-dimensional array,
|
||||
referring to the higher-level element (i.e., an array itself). */
|
||||
T (*p2 == 0);
|
||||
T (**p2 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
T (&**p2 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
T (&***p2 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
T (&**p2 == 0);
|
||||
|
||||
T (*p2 + 0 == 0); // { dg-warning "-Waddress" "pr102555" { xfail *-*-* } }
|
||||
T (&(*p2)[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (&(*p2)[0][1] == 0); // { dg-warning "-Waddress" }
|
||||
T (*p2 - 1 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &(*p2)[-1]); // { dg-warning "-Waddress" }
|
||||
T (0 == &(*p2)[1][2]); // { dg-warning "-Waddress" }
|
||||
T (*p2 + 2 == 0); // { dg-warning "-Waddress" }
|
||||
T (0 == &(*p2)[-2]); // { dg-warning "-Waddress" }
|
||||
T (*p2 - i == 0); // { dg-warning "-Waddress" }
|
||||
T (&(*p2)[i] == 0); // { dg-warning "-Waddress" }
|
||||
}
|
@ -85,8 +85,11 @@ extern __attribute__ ((weak)) int i;
|
||||
constexpr int *p1 = &i + 1;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
// Suppress warning: ordered comparison of pointer with integer zero.
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
// Suppress warning: ordered comparison of pointer with integer zero
|
||||
// Also suppress -Waddress for comparisons of constant addresses to
|
||||
// to null.
|
||||
#pragma GCC diagnostic ignored "-Waddress"
|
||||
|
||||
constexpr bool b0 = p1; // { dg-error "not a constant expression" }
|
||||
constexpr bool b1 = p1 == 0; // { dg-error "not a constant expression" }
|
||||
|
115
gcc/testsuite/g++.dg/warn/Waddress-5.C
Normal file
115
gcc/testsuite/g++.dg/warn/Waddress-5.C
Normal file
@ -0,0 +1,115 @@
|
||||
/* PR c/102103 - missing warning comparing array address to null
|
||||
{ dg-do compile }
|
||||
{ dg-options "-Wall" } */
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
# define nullptr __null
|
||||
#endif
|
||||
|
||||
struct A
|
||||
{
|
||||
void f ();
|
||||
virtual void vf ();
|
||||
virtual void pvf () = 0;
|
||||
|
||||
void sf ();
|
||||
|
||||
int *p;
|
||||
int a[2];
|
||||
};
|
||||
|
||||
void T (bool);
|
||||
|
||||
void warn_memptr_if ()
|
||||
{
|
||||
// Exercise warnings for addresses of nonstatic member functions.
|
||||
if (&A::f == 0) // { dg-warning "the address '&A::f'" }
|
||||
T (0);
|
||||
|
||||
if (&A::vf) // { dg-warning "-Waddress" }
|
||||
T (0);
|
||||
|
||||
if (&A::pvf != 0) // { dg-warning "-Waddress" }
|
||||
T (0);
|
||||
|
||||
// Exercise warnings for addresses of static member functions.
|
||||
if (&A::sf == 0) // { dg-warning "-Waddress" }
|
||||
T (0);
|
||||
|
||||
if (&A::sf) // { dg-warning "-Waddress" }
|
||||
T (0);
|
||||
|
||||
// Exercise warnings for addresses of nonstatic data members.
|
||||
if (&A::p == 0) // { dg-warning "the address '&A::p'" }
|
||||
T (0);
|
||||
|
||||
if (&A::a == nullptr) // { dg-warning "-Waddress" }
|
||||
T (0);
|
||||
}
|
||||
|
||||
void warn_memptr_bool ()
|
||||
{
|
||||
// Exercise warnings for addresses of nonstatic member functions.
|
||||
T (&A::f == 0); // { dg-warning "-Waddress" }
|
||||
T (&A::vf); // { dg-warning "-Waddress" }
|
||||
T (&A::pvf != 0); // { dg-warning "-Waddress" }
|
||||
|
||||
// Exercise warnings for addresses of static member functions.
|
||||
T (&A::sf == 0); // { dg-warning "-Waddress" }
|
||||
T (&A::sf); // { dg-warning "-Waddress" }
|
||||
|
||||
// Exercise warnings for addresses of nonstatic data members.
|
||||
T (&A::p == 0); // { dg-warning "-Waddress" }
|
||||
T (&A::a == nullptr); // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
||||
|
||||
/* Verify that no warnings are issued for a dependent expression in
|
||||
a template. */
|
||||
|
||||
template <int>
|
||||
struct B
|
||||
{
|
||||
// This is why.
|
||||
struct F { void* operator& () const { return 0; } } f;
|
||||
};
|
||||
|
||||
template <class Type, int N>
|
||||
void nowarn_dependent (Type targ)
|
||||
{
|
||||
T (&Type::x == 0);
|
||||
T (&targ == 0);
|
||||
|
||||
Type tarr[1];
|
||||
T (&tarr[0] == nullptr);
|
||||
|
||||
T (&B<N>::f == 0);
|
||||
|
||||
/* Like in the case above, the address-of operator could be a member
|
||||
of B<N>::vf that returns zero. */
|
||||
T (&B<N>::vf);
|
||||
T (&B<N>::pvf != 0);
|
||||
T (&B<N>::p == 0);
|
||||
T (&B<N>::a == 0);
|
||||
}
|
||||
|
||||
|
||||
/* Verify that in an uninstantiated template warnings are not issued
|
||||
for dependent expressions but are issued otherwise. */
|
||||
|
||||
template <class Type>
|
||||
void warn_non_dependent (Type targ, Type *tptr, int i)
|
||||
{
|
||||
/* The address of a pointer to a dependent type cannot be null but
|
||||
the warning doesn't have a chance to see it. */
|
||||
T (&tptr == 0); // { dg-warning "-Waddress" "pr102378" { xfail *-*-* } }
|
||||
T (&i == 0); // { dg-warning "-Waddress" }
|
||||
|
||||
int iarr[1];
|
||||
T (&iarr == 0); // { dg-warning "-Waddress" }
|
||||
T (&*iarr != 0); // { dg-warning "-Waddress" "pr102378" { xfail *-*-* } }
|
||||
T (&iarr[0] == 0); // { dg-warning "-Waddress" }
|
||||
|
||||
Type tarr[1];
|
||||
T (&tarr == nullptr); // { dg-warning "-Waddress" "pr102378" { xfail *-*-* } }
|
||||
}
|
79
gcc/testsuite/g++.dg/warn/Waddress-6.C
Normal file
79
gcc/testsuite/g++.dg/warn/Waddress-6.C
Normal file
@ -0,0 +1,79 @@
|
||||
/* PR c/102103 - missing warning comparing array address to null
|
||||
{ dg-do compile }
|
||||
Verify -Waddress for member arrays of structs and notes.
|
||||
{ dg-options "-Wall" } */
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
# define nullptr __null
|
||||
#endif
|
||||
|
||||
void T (bool);
|
||||
|
||||
struct A
|
||||
{
|
||||
int n;
|
||||
int ia[]; // { dg-message "'A::ia' declared here" }
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
A a[3]; // { dg-message "'B::a' declared here" }
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
B b[3]; // { dg-message "'C::b' declared here" }
|
||||
};
|
||||
|
||||
struct D
|
||||
{
|
||||
C c[3]; // { dg-message "'D::c' declared here" }
|
||||
};
|
||||
|
||||
|
||||
void test_waddress_1d ()
|
||||
{
|
||||
D d[2]; // { dg-message "'d' declared here" }
|
||||
|
||||
T (d); // { dg-warning "address of 'd'" }
|
||||
T (d == nullptr); // { dg-warning "address of 'd'" }
|
||||
T (&d); // { dg-warning "address of 'd'" }
|
||||
T (d->c); // { dg-warning "address of 'D::c'" }
|
||||
T (d->c != nullptr); // { dg-warning "address of 'D::c'" }
|
||||
T (d->c->b); // { dg-warning "address of 'C::b'" }
|
||||
T (d->c[1].b->a); // { dg-warning "address of 'B::a'" }
|
||||
T (d->c->b[2].a->ia); // { dg-warning "address of 'A::ia'" }
|
||||
|
||||
if (d->c->b[2].a[1].ia) // { dg-warning "address of 'A::ia'" }
|
||||
T (0);
|
||||
|
||||
if (bool b = d->c->b[1].a) // { dg-warning "address of 'B::a'" }
|
||||
T (b);
|
||||
|
||||
/* The following is represented as a declaration of P followed
|
||||
by an if statement and so it isn't diagnosed. It's not clear
|
||||
that it should be since the pointer is then used.
|
||||
void *p = d->c->b[2].a;
|
||||
if (p) ...
|
||||
*/
|
||||
if (void *p = d->c->b[2].a) // { dg-warning "address of 'A::ia'" "" { xfail *-*-* } }
|
||||
T (p);
|
||||
}
|
||||
|
||||
|
||||
void test_waddress_2d (int i)
|
||||
{
|
||||
D d[2][3]; // { dg-message "'d' declared here" }
|
||||
|
||||
T (d); // { dg-warning "address of 'd'" }
|
||||
T (d == nullptr); // { dg-warning "address of 'd'" }
|
||||
T (&d); // { dg-warning "address of 'd'" }
|
||||
T (*d); // { dg-warning "address of 'd'" }
|
||||
T (d[1] != nullptr); // { dg-warning "address of 'd'" }
|
||||
T (&d[1]->c); // { dg-warning "address of 'D::c'" }
|
||||
T (d[1]->c); // { dg-warning "address of 'D::c'" }
|
||||
T (d[1]->c == nullptr); // { dg-warning "address of 'D::c'" }
|
||||
T (d[i]->c[1].b); // { dg-warning "address of 'C::b'" }
|
||||
T ((*(d + i))->c->b->a); // { dg-warning "address of 'B::a'" }
|
||||
T (d[1][2].c->b->a->ia); // { dg-warning "address of 'A::ia'" }
|
||||
}
|
@ -9,7 +9,7 @@ const intptr_t&
|
||||
return_addr_label_as_intref (void)
|
||||
{
|
||||
label:
|
||||
if ((const intptr_t*)&&label == 0)
|
||||
if ((const intptr_t)&&label == 0)
|
||||
__builtin_exit (1);
|
||||
|
||||
return *(const intptr_t*)&&label; // { dg-warning "\\\[-Wreturn-local-addr]" } */
|
||||
@ -19,7 +19,7 @@ const intptr_t&
|
||||
return_addr_local_as_intref (void)
|
||||
{
|
||||
int a[1];
|
||||
if ((const intptr_t*)a == 0)
|
||||
if ((const intptr_t)a == 0)
|
||||
__builtin_exit (1);
|
||||
|
||||
return (const intptr_t&)a; // { dg-warning "\\\[-Wreturn-local-addr]" } */
|
||||
|
@ -7,5 +7,7 @@ struct S { void m(); };
|
||||
template <int> bool f() {
|
||||
void (S::*mp)();
|
||||
|
||||
return &S::m == mp; // no warning emitted here (no instantiation)
|
||||
/* The expression below isn't type-dependent so also verify
|
||||
it's diagnosed even though the template isn't instantiated. */
|
||||
return &S::m == mp; // { dg-warning "\\\[-Waddress" }
|
||||
}
|
||||
|
35
gcc/testsuite/gcc.dg/Waddress-3.c
Normal file
35
gcc/testsuite/gcc.dg/Waddress-3.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* PR c/102103 - missing warning comparing array address to null
|
||||
{ dg-do compile }
|
||||
{ dg-options "-Wall" } */
|
||||
|
||||
typedef _Complex float Cflt;
|
||||
|
||||
extern Cflt cf, cfa[], cfa2[][2];
|
||||
|
||||
Cflt *pcf (void);
|
||||
|
||||
void T (int);
|
||||
|
||||
void test_complex (Cflt *p, int i)
|
||||
{
|
||||
T (&__real__ cf == 0); // { dg-warning "address of '__real__ cf'" }
|
||||
T (&__imag__ cf == 0); // { dg-warning "address of '__imag__ cf'" }
|
||||
|
||||
T (0 != &__real__ cf); // { dg-warning "-Waddress" }
|
||||
T (0 != &__imag__ cf); // { dg-warning "-Waddress" }
|
||||
|
||||
T (&__real__ cfa[0] == 0); // { dg-warning "-Waddress" }
|
||||
T (&__imag__ cfa[1] == 0); // { dg-warning "-Waddress" }
|
||||
|
||||
T (0 != &__real__ cfa2[i][i]); // { dg-warning "-Waddress" }
|
||||
T (0 != &__imag__ cfa2[i][i]); // { dg-warning "-Waddress" }
|
||||
|
||||
T (0 == &__real__ *p); // { dg-warning "-Waddress" }
|
||||
T (0 == &__imag__ *p); // { dg-warning "-Waddress" }
|
||||
|
||||
T (0 == &__real__ p[i]); // { dg-warning "-Waddress" }
|
||||
T (0 == &__imag__ p[i]); // { dg-warning "-Waddress" }
|
||||
|
||||
T (&__real__ *pcf () == 0); // { dg-warning "-Waddress" }
|
||||
T (0 != &__imag__ *pcf ()); // { dg-warning "-Waddress" }
|
||||
}
|
@ -6,5 +6,5 @@ int
|
||||
foo(void)
|
||||
{
|
||||
char a[1];
|
||||
return a == 0;
|
||||
return a == 0; // { dg-warning "-Waddress" }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user