aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-10-01 11:50:25 -0600
committerMartin Sebor <msebor@redhat.com>2021-10-01 11:57:05 -0600
commit4dc7ce6fb3917958d1a6036d8acf2953b9c1b868 (patch)
treedbf4c85270f34d710113d1bdeb3883cd32d6ff01 /gcc/c
parentf1710910087fb1f4a7706e9ce838163ffcbc50b4 (diff)
downloadgcc-4dc7ce6fb3917958d1a6036d8acf2953b9c1b868.zip
gcc-4dc7ce6fb3917958d1a6036d8acf2953b9c1b868.tar.gz
gcc-4dc7ce6fb3917958d1a6036d8acf2953b9c1b868.tar.bz2
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.
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/c-typeck.c140
1 files changed, 106 insertions, 34 deletions
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index c74f876..33963d7 100644
--- a/gcc/c/c-typeck.c
+++ b/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)