Implementation is pretty straightforward. The only catch is that the middle-end doesn't actually assume that REFERENCE_TYPEs are non-NULL so code like
int &a = *(int *)0; if (&a != 0) will warn that &a will never be NULL yet the middle-end will fold the conditional to false instead of true anyway. But I guess that's not a big deal. Does this look OK after testing? gcc/c-family/ChangeLog: * c-common.c (c_common_truthvalue_conversion): Warn when converting an address of a reference to a truth value. gcc/cp/ChangeLog: * typeck.c (cp_build_binary_op): Warn when comparing an address of a reference against NULL. gcc/testsuite/ChangeLog: g++.dg/warn/Walways-true-3.C: New test. --- gcc/c-family/c-common.c | 12 ++++++++++++ gcc/cp/typeck.c | 10 ++++++++-- gcc/testsuite/g++.dg/warn/Walways-true-3.C | 30 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Walways-true-3.C diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 7fe7fa6..89bbdc9 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -4784,6 +4784,18 @@ c_common_truthvalue_conversion (location_t location, tree expr) tree totype = TREE_TYPE (expr); tree fromtype = TREE_TYPE (TREE_OPERAND (expr, 0)); + if (POINTER_TYPE_P (totype) + && TREE_CODE (fromtype) == REFERENCE_TYPE) + { + tree inner = TREE_OPERAND (expr, 0); + if (decl_with_nonnull_addr_p (inner)) + warning_at (location, + OPT_Waddress, + "the address of reference %qD may be assumed to " + "always evaluate to %<true%>", + inner); + } + /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, since that affects how `default_conversion' will behave. */ if (TREE_CODE (totype) == REFERENCE_TYPE diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 250b5d6..0d177b7 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4415,7 +4415,10 @@ cp_build_binary_op (location_t location, else result_type = type0; - if (TREE_CODE (op0) == ADDR_EXPR + if ((TREE_CODE (op0) == ADDR_EXPR + || (CONVERT_EXPR_P (op0) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0))) + == REFERENCE_TYPE)) && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))) { if ((complain & tf_warning) @@ -4437,7 +4440,10 @@ cp_build_binary_op (location_t location, else result_type = type1; - if (TREE_CODE (op1) == ADDR_EXPR + if ((TREE_CODE (op1) == ADDR_EXPR + || (CONVERT_EXPR_P (op1) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (op1, 0))) + == REFERENCE_TYPE)) && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))) { if ((complain & tf_warning) diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-3.C b/gcc/testsuite/g++.dg/warn/Walways-true-3.C new file mode 100644 index 0000000..a145932 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Walways-true-3.C @@ -0,0 +1,30 @@ +// { dg-options "-Waddress" } + +void foo (void); + +int d; +int &c = d; + +void +bar (int &a) +{ + int &b = a; + + if (&a) // { dg-warning "address of reference" } + foo (); + + if (&b) // { dg-warning "address of reference" } + foo (); + + if (&c) // { dg-warning "address of reference" } + foo (); + + if (&a == 0) // { dg-warning "never be NULL" } + foo (); + + if (&b != 0) // { dg-warning "never be NULL" } + foo (); + + if (0 == &c) // { dg-warning "never be NULL" } + foo (); +} -- 2.4.0.rc2.31.g7c597ef