diff options
author | Martin Sebor <msebor@redhat.com> | 2021-10-01 11:50:25 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-10-01 11:57:05 -0600 |
commit | 4dc7ce6fb3917958d1a6036d8acf2953b9c1b868 (patch) | |
tree | dbf4c85270f34d710113d1bdeb3883cd32d6ff01 /gcc/c | |
parent | f1710910087fb1f4a7706e9ce838163ffcbc50b4 (diff) | |
download | gcc-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.c | 140 |
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) |