re PR c/32061 ((Wlogical-op) wording of warning of constant logicials need improvement)

2009-04-19  Manuel López-Ibáñez  <manu@gcc.gnu.org>

	PR c/32061
	PR c++/36954
	* doc/invoke.texi: Add -Wlogical-op to -Wextra.
	* common.opt (Wlogical-op): Move from here...
	* c.opt (Wlogical-op): ... to here.
	* c-typeck.c (parser_build_binary_op): Update call to
	warn_logical_operator.
	* c-opts.c (c_common_post_options): Enable warn_logical_op with
	extra_warnings.
	* c-common.c (warn_logical_op): Update.
	* c-common.h (warn_logical_op): Update declaration.
cp/
	* call.c (build_new_op): Save the original codes of operands
	before folding.
	
testsuite/
	* gcc.dg/pr32061.c: New.
	* gcc.dg/Wlogical-op-1.c: Update.
	* g++.dg/warn/Wlogical-op-1.C: Update.
	* g++.dg/warn/pr36954.C: New.

From-SVN: r146344
parent c93c8cf4
2009-04-19 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/32061
PR c++/36954
* doc/invoke.texi: Add -Wlogical-op to -Wextra.
* common.opt (Wlogical-op): Move from here...
* c.opt (Wlogical-op): ... to here.
* c-typeck.c (parser_build_binary_op): Update call to
warn_logical_operator.
* c-opts.c (c_common_post_options): Enable warn_logical_op with
extra_warnings.
* c-common.c (warn_logical_op): Update.
* c-common.h (warn_logical_op): Update declaration.
2009-04-19 Eric Botcazou <ebotcazou@adacore.com> 2009-04-19 Eric Botcazou <ebotcazou@adacore.com>
* tree.c (protected_set_expr_location): Fix formatting. * tree.c (protected_set_expr_location): Fix formatting.
......
...@@ -1712,38 +1712,43 @@ overflow_warning (tree value) ...@@ -1712,38 +1712,43 @@ overflow_warning (tree value)
} }
} }
/* Warn about uses of logical || / && operator in a context where it
/* Warn about use of a logical || / && operator being used in a is likely that the bitwise equivalent was intended by the
context where it is likely that the bitwise equivalent was intended programmer. We have seen an expression in which CODE is a binary
by the programmer. CODE is the TREE_CODE of the operator, ARG1 operator used to combine expressions OP_LEFT and OP_RIGHT, which
and ARG2 the arguments. */ before folding had CODE_LEFT and CODE_RIGHT. */
void void
warn_logical_operator (enum tree_code code, tree arg1, tree warn_logical_operator (location_t location, enum tree_code code,
arg2) enum tree_code code_left, tree op_left,
{ enum tree_code ARG_UNUSED (code_right), tree op_right)
switch (code) {
{ if (code != TRUTH_ANDIF_EXPR
case TRUTH_ANDIF_EXPR: && code != TRUTH_AND_EXPR
case TRUTH_ORIF_EXPR: && code != TRUTH_ORIF_EXPR
case TRUTH_OR_EXPR: && code != TRUTH_OR_EXPR)
case TRUTH_AND_EXPR: return;
if (!TREE_NO_WARNING (arg1)
&& INTEGRAL_TYPE_P (TREE_TYPE (arg1)) /* Warn if &&/|| are being used in a context where it is
&& !CONSTANT_CLASS_P (arg1) likely that the bitwise equivalent was intended by the
&& TREE_CODE (arg2) == INTEGER_CST programmer. That is, an expression such as op && MASK
&& !integer_zerop (arg2)) where op should not be any boolean expression, nor a
{ constant, and mask seems to be a non-boolean integer constant. */
warning (OPT_Wlogical_op, if (!truth_value_p (code_left)
"logical %<%s%> with non-zero constant " && INTEGRAL_TYPE_P (TREE_TYPE (op_left))
"will always evaluate as true", && !CONSTANT_CLASS_P (op_left)
((code == TRUTH_ANDIF_EXPR) && !TREE_NO_WARNING (op_left)
|| (code == TRUTH_AND_EXPR)) ? "&&" : "||"); && TREE_CODE (op_right) == INTEGER_CST
TREE_NO_WARNING (arg1) = true; && !integer_zerop (op_right)
} && !integer_onep (op_right))
break; {
default: if (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR)
break; warning_at (location, OPT_Wlogical_op, "logical %<or%>"
" applied to non-boolean constant");
else
warning_at (location, OPT_Wlogical_op, "logical %<and%>"
" applied to non-boolean constant");
TREE_NO_WARNING (op_left) = true;
} }
} }
......
...@@ -801,7 +801,8 @@ extern bool strict_aliasing_warning (tree, tree, tree); ...@@ -801,7 +801,8 @@ extern bool strict_aliasing_warning (tree, tree, tree);
extern void warnings_for_convert_and_check (tree, tree, tree); extern void warnings_for_convert_and_check (tree, tree, tree);
extern tree convert_and_check (tree, tree); extern tree convert_and_check (tree, tree);
extern void overflow_warning (tree); extern void overflow_warning (tree);
extern void warn_logical_operator (enum tree_code, tree, tree); extern void warn_logical_operator (location_t, enum tree_code,
enum tree_code, tree, enum tree_code, tree);
extern void check_main_parameter_types (tree decl); extern void check_main_parameter_types (tree decl);
extern bool c_determine_visibility (tree); extern bool c_determine_visibility (tree);
extern bool same_scalar_type_ignoring_signedness (tree, tree); extern bool same_scalar_type_ignoring_signedness (tree, tree);
......
...@@ -1080,6 +1080,8 @@ c_common_post_options (const char **pfilename) ...@@ -1080,6 +1080,8 @@ c_common_post_options (const char **pfilename)
warn_override_init = extra_warnings; warn_override_init = extra_warnings;
if (warn_ignored_qualifiers == -1) if (warn_ignored_qualifiers == -1)
warn_ignored_qualifiers = extra_warnings; warn_ignored_qualifiers = extra_warnings;
if (warn_logical_op == -1)
warn_logical_op = extra_warnings;
/* -Wpointer-sign is disabled by default, but it is enabled if any /* -Wpointer-sign is disabled by default, but it is enabled if any
of -Wall or -pedantic are given. */ of -Wall or -pedantic are given. */
......
...@@ -2925,8 +2925,9 @@ parser_build_binary_op (location_t location, enum tree_code code, ...@@ -2925,8 +2925,9 @@ parser_build_binary_op (location_t location, enum tree_code code,
if (warn_parentheses) if (warn_parentheses)
warn_about_parentheses (code, code1, arg1.value, code2, arg2.value); warn_about_parentheses (code, code1, arg1.value, code2, arg2.value);
if (TREE_CODE_CLASS (code1) != tcc_comparison) if (warn_logical_op)
warn_logical_operator (code, arg1.value, arg2.value); warn_logical_operator (input_location, code,
code1, arg1.value, code2, arg2.value);
/* Warn about comparisons against string literals, with the exception /* Warn about comparisons against string literals, with the exception
of testing for equality or inequality of a string literal with NULL. */ of testing for equality or inequality of a string literal with NULL. */
......
...@@ -284,6 +284,10 @@ Winvalid-pch ...@@ -284,6 +284,10 @@ Winvalid-pch
C ObjC C++ ObjC++ Warning C ObjC C++ ObjC++ Warning
Warn about PCH files that are found but not used Warn about PCH files that are found but not used
Wlogical-op
C ObjC C++ ObjC++ Var(warn_logical_op) Init(-1) Warning
Warn when a logical operator is suspiciously always evaluating to true or false
Wlong-long Wlong-long
C ObjC C++ ObjC++ Var(warn_long_long) Init(1) Warning C ObjC C++ ObjC++ Var(warn_long_long) Init(1) Warning
Do not warn about using \"long long\" when -pedantic Do not warn about using \"long long\" when -pedantic
......
...@@ -128,10 +128,6 @@ Wlarger-than= ...@@ -128,10 +128,6 @@ Wlarger-than=
Common RejectNegative Joined UInteger Warning Common RejectNegative Joined UInteger Warning
-Wlarger-than=<number> Warn if an object is larger than <number> bytes -Wlarger-than=<number> Warn if an object is larger than <number> bytes
Wlogical-op
Common Warning Var(warn_logical_op)
Warn when a logical operator is suspicously always evaluating to true or false
Wunsafe-loop-optimizations Wunsafe-loop-optimizations
Common Var(warn_unsafe_loop_optimizations) Warning Common Var(warn_unsafe_loop_optimizations) Warning
Warn if the loop cannot be optimized due to nontrivial assumptions. Warn if the loop cannot be optimized due to nontrivial assumptions.
......
2009-04-19 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/32061
PR c++/36954
* call.c (build_new_op): Save the original codes of operands
before folding.
2009-04-18 Kazu Hirata <kazu@codesourcery.com> 2009-04-18 Kazu Hirata <kazu@codesourcery.com>
* cp-tree.h: Remove the prototype for insert_block. * cp-tree.h: Remove the prototype for insert_block.
......
...@@ -3897,11 +3897,12 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -3897,11 +3897,12 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
tree result = NULL_TREE; tree result = NULL_TREE;
bool result_valid_p = false; bool result_valid_p = false;
enum tree_code code2 = NOP_EXPR; enum tree_code code2 = NOP_EXPR;
enum tree_code code_orig_arg1 = ERROR_MARK;
enum tree_code code_orig_arg2 = ERROR_MARK;
conversion *conv; conversion *conv;
void *p; void *p;
bool strict_p; bool strict_p;
bool any_viable_p; bool any_viable_p;
bool expl_eq_arg1 = false;
if (error_operand_p (arg1) if (error_operand_p (arg1)
|| error_operand_p (arg2) || error_operand_p (arg2)
...@@ -3935,8 +3936,10 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -3935,8 +3936,10 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
case TRUTH_ANDIF_EXPR: case TRUTH_ANDIF_EXPR:
case TRUTH_AND_EXPR: case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR: case TRUTH_OR_EXPR:
if (COMPARISON_CLASS_P (arg1)) /* These are saved for the sake of warn_logical_operator. */
expl_eq_arg1 = true; code_orig_arg1 = TREE_CODE (arg1);
code_orig_arg2 = TREE_CODE (arg2);
default: default:
break; break;
} }
...@@ -4140,8 +4143,16 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -4140,8 +4143,16 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
if (conv->kind == ck_ref_bind) if (conv->kind == ck_ref_bind)
conv = conv->u.next; conv = conv->u.next;
arg1 = convert_like (conv, arg1, complain); arg1 = convert_like (conv, arg1, complain);
if (arg2) if (arg2)
{ {
/* We need to call warn_logical_operator before
converting arg2 to a boolean_type. */
if (complain & tf_warning)
warn_logical_operator (input_location, code,
code_orig_arg1, arg1,
code_orig_arg2, arg2);
conv = cand->convs[1]; conv = cand->convs[1];
if (conv->kind == ck_ref_bind) if (conv->kind == ck_ref_bind)
conv = conv->u.next; conv = conv->u.next;
...@@ -4155,12 +4166,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -4155,12 +4166,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
arg3 = convert_like (conv, arg3, complain); arg3 = convert_like (conv, arg3, complain);
} }
if (!expl_eq_arg1)
{
if (complain & tf_warning)
warn_logical_operator (code, arg1, arg2);
expl_eq_arg1 = true;
}
} }
} }
...@@ -4185,8 +4190,9 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -4185,8 +4190,9 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
case TRUTH_ORIF_EXPR: case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR: case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR: case TRUTH_OR_EXPR:
if (!expl_eq_arg1) warn_logical_operator (input_location, code,
warn_logical_operator (code, arg1, arg2); code_orig_arg1, arg1, code_orig_arg2, arg2);
/* Fall through. */
case PLUS_EXPR: case PLUS_EXPR:
case MINUS_EXPR: case MINUS_EXPR:
case MULT_EXPR: case MULT_EXPR:
......
...@@ -2804,6 +2804,7 @@ name is still supported, but the newer name is more descriptive.) ...@@ -2804,6 +2804,7 @@ name is still supported, but the newer name is more descriptive.)
@gccoptlist{-Wclobbered @gol @gccoptlist{-Wclobbered @gol
-Wempty-body @gol -Wempty-body @gol
-Wignored-qualifiers @gol -Wignored-qualifiers @gol
-Wlogical-op @gol
-Wmissing-field-initializers @gol -Wmissing-field-initializers @gol
-Wmissing-parameter-type @r{(C only)} @gol -Wmissing-parameter-type @r{(C only)} @gol
-Wold-style-declaration @r{(C only)} @gol -Wold-style-declaration @r{(C only)} @gol
...@@ -3790,7 +3791,8 @@ programmer intended to use @code{strcmp}. This warning is enabled by ...@@ -3790,7 +3791,8 @@ programmer intended to use @code{strcmp}. This warning is enabled by
@opindex Wno-logical-op @opindex Wno-logical-op
Warn about suspicious uses of logical operators in expressions. Warn about suspicious uses of logical operators in expressions.
This includes using logical operators in contexts where a This includes using logical operators in contexts where a
bit-wise operator is likely to be expected. bit-wise operator is likely to be expected. This warning is enabled by
@option{-Wextra}.
@item -Waggregate-return @item -Waggregate-return
@opindex Waggregate-return @opindex Waggregate-return
......
2009-04-19 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR c/32061
PR c++/36954
* gcc.dg/pr32061.c: New.
* gcc.dg/Wlogical-op-1.c: Update.
* g++.dg/warn/Wlogical-op-1.C: Update.
* g++.dg/warn/pr36954.C: New.
2009-04-18 Joseph Myers <joseph@codesourcery.com> 2009-04-18 Joseph Myers <joseph@codesourcery.com>
PR c/27676 PR c/27676
......
...@@ -28,20 +28,39 @@ extern testenum testa(); ...@@ -28,20 +28,39 @@ extern testenum testa();
void foo() void foo()
{ {
if ( f && b2 ) // { dg-warning "always evaluate as" } if ( f && b2 ) // { dg-warning "logical" }
do_something(1); do_something(1);
if ( c && b2 ) // { dg-warning "always evaluate as" } if ( c && b2 ) // { dg-warning "logical" }
do_something(2); do_something(2);
if ( b2 && c == a ) // { dg-bogus "always evaluate as" } if ( b2 && c == a ) // { dg-bogus "logical" }
do_something(101); do_something(101);
if ( 1 && c ) if ( 1 && c )
do_something(102); // { dg-bogus "always evaluate as" } do_something(102); // { dg-bogus "logical" }
if ( t2 && b2 ) // { dg-bogus "always evaluate as" } if ( t2 && b2 ) // { dg-bogus "logical" }
do_something(103); do_something(103);
if ( true && c == a ) // { dg-bogus "always evaluate as" } if ( true && c == a ) // { dg-bogus "logical" }
do_something(104); do_something(104);
if ( b2 && true ) // { dg-bogus "always evaluate as" } if ( b2 && true ) // { dg-bogus "logical" }
do_something(105); do_something(105);
} }
void bar()
{
if ( f || b2 ) // { dg-warning "logical" }
do_something(1);
if ( c || b2 ) // { dg-warning "logical" }
do_something(2);
if ( b2 || c == a ) // { dg-bogus "logical" }
do_something(101);
if ( 1 || c )
do_something(102); // { dg-bogus "logical" }
if ( t2 || b2 ) // { dg-bogus "logical" }
do_something(103);
if ( true || c == a ) // { dg-bogus "logical" }
do_something(104);
if ( b2 || true ) // { dg-bogus "logical" }
do_something(105);
}
// PR c++/36954
// { dg-do compile }
// { dg-options "-Wlogical-op -Wextra -Wall" }
template<class C> void Test()
{
if ((1 == 2) || (true)) {
}
if ((1 == 2) || (!false)) {
}
if (false || true) {
}
}
int main() {
if ((1 == 2) || (true)) {
}
}
...@@ -14,34 +14,64 @@ extern int testa(); ...@@ -14,34 +14,64 @@ extern int testa();
void foo() void foo()
{ {
if ( testa() && b ) /* { dg-warning "always evaluate as" } */ if ( testa() && b ) /* { dg-warning "logical" } */
(void)testa(); (void)testa();
if ( c && b ) /* { dg-warning "always evaluate as" } */ if ( c && b ) /* { dg-warning "logical" } */
(void)testa(); (void)testa();
if ( c && 0x42 ) /* { dg-warning "always evaluate as" } */ if ( c && 0x42 ) /* { dg-warning "logical" } */
(void)testa(); (void)testa();
if ( c && 0x42 ) /* { dg-warning "always evaluate as" } */ if ( c && 0x80 >>6) /* { dg-warning "logical" } */
(void)testa();
if ( b && c == a ) /* { dg-bogus "logical" } */
(void)testa();
if ( 1 && c ) /* { dg-bogus "logical" } */
(void)testa();
if ( t2 && b ) /* { dg-bogus "logical" } */
(void)testa();
if ( 0 && c == a ) /* { dg-bogus "logical" } */
(void)testa();
if ( b && 1 ) /* { dg-bogus "logical" } */
(void)testa();
}
void bar()
{
if ( testa() || b ) /* { dg-warning "logical" } */
(void)testa();
if ( c || b ) /* { dg-warning "logical" } */
(void)testa();
if ( c || 0x42 ) /* { dg-warning "logical" } */
(void) testa(); (void) testa();
if ( c && 0x80 >>6) /* { dg-warning "always evaluate as" } */ if ( c || 0x80 >>6) /* { dg-warning "logical" } */
(void)testa(); (void)testa();
if ( b && c == a ) /* { dg-bogus "always evaluate as" } */ if ( b || c == a ) /* { dg-bogus "logical" } */
(void)testa(); (void)testa();
if ( 1 && c ) /* { dg-bogus "always evaluate as" } */ if ( 1 || c ) /* { dg-bogus "logical" } */
(void)testa(); (void)testa();
if ( t2 && b ) /* { dg-bogus "always evaluate as" } */ if ( t2 || b ) /* { dg-bogus "logical" } */
(void)testa(); (void)testa();
if ( 0 && c == a ) /* { dg-bogus "always evaluate as" } */ if ( 0 || c == a ) /* { dg-bogus "logical" } */
(void)testa(); (void)testa();
if ( b && 1 ) /* { dg-bogus "always evaluate as" } */ if ( b || 1 ) /* { dg-bogus "logical" } */
(void)testa(); (void)testa();
} }
/* PR c/32061
{ dg-do compile }
{ dg-options "-Wlogical-op -Wall -Wextra" }
*/
#define FORCE 1
#define FLAG 1
int func (int resp, int flags)
{
return (resp && (FORCE || (FLAG & flags)));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment