C++ PATCH: Avoid warnings on comparision of PMF with NULL
Mark Mitchell
mitchell@codesourcery.com
Thu Jul 2 17:57:00 GMT 2009
On ARM, comparing a pointer to function member with NULL resulted in a
bogus warning about use of NULL in arithmetic. This bug was specific
to targets that store the virtual bit for PMFs in the delta field. In
that case, cp_build_binary_op changes the operands around, and the
test we ran late in cp_build_binary_op to check for uses of NULL then
got confused because it was looking at the modified operands instead
of the original one.
I moved the test earlier, and added a bunch more test cases to the
null4.C test that checks for these sorts of warnings as well as their
absence.
Tested on arm-eabi, applied to mainline.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
2009-07-02 Mark Mitchell <mark@codesourcery.com>
* typeck.c (cp_build_binary_op): Move warnings about use of NULL
in arithmetic earlier and allow comparisions of NULL with
pointers-to-members.
2009-07-02 Mark Mitchell <mark@codesourcery.com>
* g++.dg/warn/null4.C: Extend.
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 149189)
+++ gcc/cp/typeck.c (working copy)
@@ -3419,7 +3419,6 @@ cp_build_binary_op (location_t location,
/* If an error was already reported for one of the arguments,
avoid reporting another error. */
-
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
@@ -3430,6 +3429,25 @@ cp_build_binary_op (location_t location,
return error_mark_node;
}
+ /* Issue warnings about peculiar, but valid, uses of NULL. */
+ if ((orig_op0 == null_node || orig_op1 == null_node)
+ /* It's reasonable to use pointer values as operands of &&
+ and ||, so NULL is no exception. */
+ && code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR
+ && ( /* Both are NULL (or 0) and the operation was not a
+ comparison or a pointer subtraction. */
+ (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1)
+ && code != EQ_EXPR && code != NE_EXPR && code != MINUS_EXPR)
+ /* Or if one of OP0 or OP1 is neither a pointer nor NULL. */
+ || (!null_ptr_cst_p (orig_op0)
+ && !TYPE_PTR_P (type0) && !TYPE_PTR_TO_MEMBER_P (type0))
+ || (!null_ptr_cst_p (orig_op1)
+ && !TYPE_PTR_P (type1) && !TYPE_PTR_TO_MEMBER_P (type1)))
+ && (complain & tf_warning))
+ /* Some sort of arithmetic operation involving NULL was
+ performed. */
+ warning (OPT_Wpointer_arith, "NULL used in arithmetic");
+
switch (code)
{
case MINUS_EXPR:
@@ -4031,25 +4049,6 @@ cp_build_binary_op (location_t location,
}
}
- /* Issue warnings about peculiar, but valid, uses of NULL. */
- if ((orig_op0 == null_node || orig_op1 == null_node)
- /* It's reasonable to use pointer values as operands of &&
- and ||, so NULL is no exception. */
- && code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR
- && ( /* Both are NULL (or 0) and the operation was not a comparison. */
- (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1)
- && code != EQ_EXPR && code != NE_EXPR)
- /* Or if one of OP0 or OP1 is neither a pointer nor NULL. */
- || (!null_ptr_cst_p (orig_op0) && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
- || (!null_ptr_cst_p (orig_op1) && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE))
- && (complain & tf_warning))
- /* Some sort of arithmetic operation involving NULL was
- performed. Note that pointer-difference and pointer-addition
- have already been handled above, and so we don't end up here in
- that case. */
- warning (OPT_Wpointer_arith, "NULL used in arithmetic");
-
-
/* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
Then the expression will be built.
It will be given type FINAL_TYPE if that is nonzero;
Index: gcc/testsuite/g++.dg/warn/null4.C
===================================================================
--- gcc/testsuite/g++.dg/warn/null4.C (revision 149189)
+++ gcc/testsuite/g++.dg/warn/null4.C (working copy)
@@ -11,9 +11,22 @@ int foo (void)
if (NULL < NULL) return -1; // { dg-warning "NULL used in arithmetic" }
if (NULL >= 0) return -1; // { dg-warning "NULL used in arithmetic" }
if (NULL <= 0) return -1; // { dg-warning "NULL used in arithmetic" }
+ // Adding to the NULL pointer, which has no specific type, should
+ // result in a warning; the type of the resulting expression is
+ // actually "int", not a pointer type.
+ if (NULL + 1) return -1; // { dg-warning "NULL used in arithmetic" }
+ if (1 + NULL) return -1; // { dg-warning "NULL used in arithmetic" }
return 0;
}
+int *ip;
+
+struct S {};
+typedef int S::*SPD;
+typedef void (S::*SPF)(void);
+SPD spd;
+SPF spf;
+
int bar (void)
{
if (NULL) return -1;
@@ -25,5 +38,18 @@ int bar (void)
if (NULL != NULL) return -1;
if (NULL == 0) return -1;
if (NULL != 0) return -1;
+ // Subtraction of pointers is vaild, so using NULL is OK.
+ if (ip - NULL) return -1;
+ if (NULL - NULL) return -1;
+ // Comparing NULL with a pointer-to-member is OK.
+ if (NULL == spd) return -1;
+ if (spd == NULL) return -1;
+ if (NULL != spd) return -1;
+ if (spd != NULL) return -1;
+ if (NULL == spf) return -1;
+ if (spf == NULL) return -1;
+ if (NULL != spf) return -1;
+ if (spf != NULL) return -1;
+
return 0;
}
More information about the Gcc-patches
mailing list