diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c894c7229fc..92925123a4a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2007-01-05 Ian Lance Taylor + + * c-common.c (decl_with_nonnull_addr_p): New function. + (c_common_truthvalue_conversion): Call it. + * c-typeck.c (build_binary_op): Likewise. + * c-common.h (decl_with_nonnull_addr_p): Declare. + 2007-01-05 Jakub Jelinek PR c/30360 diff --git a/gcc/c-common.c b/gcc/c-common.c index 2fd2a81b924..1794bd8642e 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -2591,6 +2591,18 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) return fold_build2 (resultcode, result_type, ptrop, intop); } +/* Return whether EXPR is a declaration whose address can never be + NULL. */ + +bool +decl_with_nonnull_addr_p (tree expr) +{ + return (DECL_P (expr) + && (TREE_CODE (expr) == PARM_DECL + || TREE_CODE (expr) == LABEL_DECL + || !DECL_WEAK (expr))); +} + /* Prepare expr to be an argument of a TRUTH_NOT_EXPR, or for an `if' or `while' statement or ?..: exp. It should already have been validated to be of suitable type; otherwise, a bad @@ -2656,23 +2668,22 @@ c_common_truthvalue_conversion (tree expr) case ADDR_EXPR: { tree inner = TREE_OPERAND (expr, 0); - if (DECL_P (inner) - && (TREE_CODE (inner) == PARM_DECL - || TREE_CODE (inner) == LABEL_DECL - || !DECL_WEAK (inner))) + if (decl_with_nonnull_addr_p (inner)) { - /* Common Ada/Pascal programmer's mistake. We always warn - about this since it is so bad. */ - warning (OPT_Walways_true, "the address of %qD will always evaluate as %", + /* Common Ada/Pascal programmer's mistake. */ + warning (OPT_Walways_true, + "the address of %qD will always evaluate as %", inner); return truthvalue_true_node; } - /* If we are taking the address of an external decl, it might be - zero if it is weak, so we cannot optimize. */ - if (DECL_P (inner) - && DECL_EXTERNAL (inner)) - break; + /* If we still have a decl, it is possible for its address to + be NULL, so we cannot optimize. */ + if (DECL_P (inner)) + { + gcc_assert (DECL_WEAK (inner)); + break; + } if (TREE_SIDE_EFFECTS (inner)) return build2 (COMPOUND_EXPR, truthvalue_type_node, diff --git a/gcc/c-common.h b/gcc/c-common.h index b2b10bd2d7b..86b44870a57 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -652,6 +652,7 @@ extern tree c_common_unsigned_type (tree); extern tree c_common_signed_type (tree); extern tree c_common_signed_or_unsigned_type (int, tree); extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); +extern bool decl_with_nonnull_addr_p (tree); extern tree c_common_truthvalue_conversion (tree); extern void c_apply_type_quals_to_decl (int, tree); extern tree c_sizeof_or_alignof_type (tree, bool, int); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 955bfd959f8..28d023de552 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -8013,10 +8013,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) { if (TREE_CODE (op0) == ADDR_EXPR - && DECL_P (TREE_OPERAND (op0, 0)) - && (TREE_CODE (TREE_OPERAND (op0, 0)) == PARM_DECL - || TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL - || !DECL_WEAK (TREE_OPERAND (op0, 0)))) + && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))) warning (OPT_Walways_true, "the address of %qD will never be NULL", TREE_OPERAND (op0, 0)); result_type = type0; @@ -8024,10 +8021,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0)) { if (TREE_CODE (op1) == ADDR_EXPR - && DECL_P (TREE_OPERAND (op1, 0)) - && (TREE_CODE (TREE_OPERAND (op1, 0)) == PARM_DECL - || TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL - || !DECL_WEAK (TREE_OPERAND (op1, 0)))) + && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))) warning (OPT_Walways_true, "the address of %qD will never be NULL", TREE_OPERAND (op1, 0)); result_type = type1; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 79dce7482ac..1f7945d9b1f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2007-01-05 Ian Lance Taylor + + * typeck.c (build_binary_op): Warn about comparing a non-weak + address to NULL. + 2007-01-05 Douglas Gregor * pt.c (tsubst): Propagate the need for structural equality checks diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6c05b9fe1f1..061241dbf52 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3334,10 +3334,22 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, "comparison"); else if ((code0 == POINTER_TYPE || TYPE_PTRMEM_P (type0)) && null_ptr_cst_p (op1)) - result_type = type0; + { + if (TREE_CODE (op0) == ADDR_EXPR + && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0))) + warning (OPT_Walways_true, "the address of %qD will never be NULL", + TREE_OPERAND (op0, 0)); + result_type = type0; + } else if ((code1 == POINTER_TYPE || TYPE_PTRMEM_P (type1)) && null_ptr_cst_p (op0)) - result_type = type1; + { + if (TREE_CODE (op1) == ADDR_EXPR + && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0))) + warning (OPT_Walways_true, "the address of %qD will never be NULL", + TREE_OPERAND (op1, 0)); + result_type = type1; + } else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) { result_type = type0; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4636099980a..8856b7e2ff6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-01-05 Ian Lance Taylor + + * gcc.dg/Walways-true-1.c: New test. + * gcc.dg/Walways-true-2.c: New test. + * g++.dg/warn/Walways-true-1.C: New test. + * g++.dg/warn/Walways-true-2.C: New test. + 2007-01-05 Jakub Jelinek PR c/30360 diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-1.C b/gcc/testsuite/g++.dg/warn/Walways-true-1.C new file mode 100644 index 00000000000..5102ca1a377 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Walways-true-1.C @@ -0,0 +1,57 @@ +// Test -Walways-true for testing an address against NULL. +// Origin: Ian Lance Taylor + +// { dg-do compile} +// { dg-options "-Walways-true" } + +extern int foo (int); + +int i; + +void +bar (int a) +{ + lab: + if (foo) // { dg-warning "always evaluate as" "correct warning" } + foo (0); + if (foo (1)) + ; + if (&i) // { dg-warning "always evaluate as" "correct warning" } + foo (2); + if (i) + foo (3); + if (&a) // { dg-warning "always evaluate as" "correct warning" } + foo (4); + if (a) + foo (5); + if (&&lab) // { dg-warning "always evaluate as" "correct warning" } + foo (6); + if (foo == 0) // { dg-warning "never be NULL" "correct warning" } + foo (7); + if (foo (1) == 0) + foo (8); + if (&i == 0) // { dg-warning "never be NULL" "correct warning" } + foo (9); + if (i == 0) + foo (10); + if (&a == 0) // { dg-warning "never be NULL" "correct warning" } + foo (11); + if (a == 0) + foo (12); + if (&&lab == 0) // { dg-warning "never be NULL" "correct warning" } + foo (13); + if (0 == foo) // { dg-warning "never be NULL" "correct warning" } + foo (14); + if (0 == foo (1)) + foo (15); + if (0 == &i) // { dg-warning "never be NULL" "correct warning" } + foo (16); + if (0 == i) + foo (17); + if (0 == &a) // { dg-warning "never be NULL" "correct warning" } + foo (18); + if (0 == a) + foo (19); + if (0 == &&lab) // { dg-warning "never be NULL" "correct warning" } + foo (20); +} diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-2.C b/gcc/testsuite/g++.dg/warn/Walways-true-2.C new file mode 100644 index 00000000000..540856650e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Walways-true-2.C @@ -0,0 +1,60 @@ +// Make sure we don't assume that a weak symbol is always non-NULL. +// This is just like Walways-true-1.C, except that it uses a weak +// symbol. +// Origin: Ian Lance Taylor + +// { dg-do compile} +// { dg-options "-Walways-true" } +// { dg-require-weak "" } + +extern int foo (int) __attribute__ ((weak)); + +int i __attribute__ ((weak)); + +void +bar (int a) +{ + lab: + if (foo) + foo (0); + if (foo (1)) + ; + if (&i) + foo (2); + if (i) + foo (3); + if (&a) // { dg-warning "always evaluate as" "correct warning" } + foo (4); + if (a) + foo (5); + if (&&lab) // { dg-warning "always evaluate as" "correct warning" } + foo (6); + if (foo == 0) + foo (7); + if (foo (1) == 0) + foo (8); + if (&i == 0) + foo (9); + if (i == 0) + foo (10); + if (&a == 0) // { dg-warning "never be NULL" "correct warning" } + foo (11); + if (a == 0) + foo (12); + if (&&lab == 0) // { dg-warning "never be NULL" "correct warning" } + foo (13); + if (0 == foo) + foo (14); + if (0 == foo (1)) + foo (15); + if (0 == &i) + foo (16); + if (0 == i) + foo (17); + if (0 == &a) // { dg-warning "never be NULL" "correct warning" } + foo (18); + if (0 == a) + foo (19); + if (0 == &&lab) // { dg-warning "never be NULL" "correct warning" } + foo (20); +} diff --git a/gcc/testsuite/gcc.dg/Walways-true-1.c b/gcc/testsuite/gcc.dg/Walways-true-1.c new file mode 100644 index 00000000000..f531e8f4b79 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Walways-true-1.c @@ -0,0 +1,57 @@ +/* Test -Walways-true for testing an address against NULL. + Origin: Ian Lance Taylor . */ + +/* { dg-do compile} */ +/* { dg-options "-Walways-true" } */ + +extern int foo (int); + +int i; + +void +bar (int a) +{ + lab: + if (foo) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (0); + if (foo (1)) + ; + if (&i) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (2); + if (i) + foo (3); + if (&a) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (4); + if (a) + foo (5); + if (&&lab) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (6); + if (foo == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (7); + if (foo (1) == 0) + foo (8); + if (&i == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (9); + if (i == 0) + foo (10); + if (&a == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (11); + if (a == 0) + foo (12); + if (&&lab == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (13); + if (0 == foo) /* { dg-warning "never be NULL" "correct warning" } */ + foo (14); + if (0 == foo (1)) + foo (15); + if (0 == &i) /* { dg-warning "never be NULL" "correct warning" } */ + foo (16); + if (0 == i) + foo (17); + if (0 == &a) /* { dg-warning "never be NULL" "correct warning" } */ + foo (18); + if (0 == a) + foo (19); + if (0 == &&lab) /* { dg-warning "never be NULL" "correct warning" } */ + foo (20); +} diff --git a/gcc/testsuite/gcc.dg/Walways-true-2.c b/gcc/testsuite/gcc.dg/Walways-true-2.c new file mode 100644 index 00000000000..cab897b4e3d --- /dev/null +++ b/gcc/testsuite/gcc.dg/Walways-true-2.c @@ -0,0 +1,60 @@ +/* Make sure we don't assume that a weak symbol is always non-NULL. + This is just like Walways-true-1.C, except that it uses a weak + symbol. + Origin: Ian Lance Taylor . */ + +/* { dg-do compile} */ +/* { dg-options "-Walways-true" } */ +/* { dg-require-weak "" } */ + +extern int foo (int) __attribute__ ((weak)); + +int i __attribute__ ((weak)); + +void +bar (int a) +{ + lab: + if (foo) + foo (0); + if (foo (1)) + ; + if (&i) + foo (2); + if (i) + foo (3); + if (&a) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (4); + if (a) + foo (5); + if (&&lab) /* { dg-warning "always evaluate as" "correct warning" } */ + foo (6); + if (foo == 0) + foo (7); + if (foo (1) == 0) + foo (8); + if (&i == 0) + foo (9); + if (i == 0) + foo (10); + if (&a == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (11); + if (a == 0) + foo (12); + if (&&lab == 0) /* { dg-warning "never be NULL" "correct warning" } */ + foo (13); + if (0 == foo) + foo (14); + if (0 == foo (1)) + foo (15); + if (0 == &i) + foo (16); + if (0 == i) + foo (17); + if (0 == &a) /* { dg-warning "never be NULL" "correct warning" } */ + foo (18); + if (0 == a) + foo (19); + if (0 == &&lab) /* { dg-warning "never be NULL" "correct warning" } */ + foo (20); +}