re PR c/16302 (gcc fails to warn about some common logic errors)

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

	PR 16302
	* fold-const.c (make_range,build_range_check,merge_ranges): Move
	declaration to...
	(merge_ranges): Returns bool. 
	* tree.h (make_range): .. to here.
	(build_range_check): Likewise.
	(merge_ranges): Likewise. Renamed from merge_ranges.
	* c-typeck.c (parser_build_binary_op): Update calls to
	warn_logical_operator.
	* c-common.c (warn_logical_operator): Add new warning.
	* c-common.h (warn_logical_operator): Update declaration.
cp/
	* call.c (build_new_op): Update calls to warn_logical_operator.
	
testsuite/
	* gcc.dg/pr16302.c: New.
	* g++.dg/warn/pr16302.C: New.

From-SVN: r147596
parent 1b53c5f3
2009-05-15 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 16302
* fold-const.c (make_range,build_range_check,merge_ranges): Move
declaration to...
(merge_ranges): Returns bool.
* tree.h (make_range): .. to here.
(build_range_check): Likewise.
(merge_ranges): Likewise. Renamed from merge_ranges.
* c-typeck.c (parser_build_binary_op): Update calls to
warn_logical_operator.
* c-common.c (warn_logical_operator): Add new warning.
* c-common.h (warn_logical_operator): Update declaration.
2009-05-15 Manuel López-Ibáñez <manu@gcc.gnu.org>
* ira-conflicts.c (add_insn_allocno_copies): Fix wrong
conditional.
......
......@@ -1716,14 +1716,18 @@ overflow_warning (tree value)
/* Warn about uses of logical || / && operator in a context where it
is likely that the bitwise equivalent was intended by the
programmer. We have seen an expression in which CODE is a binary
operator used to combine expressions OP_LEFT and OP_RIGHT, which
before folding had CODE_LEFT and CODE_RIGHT. */
operator used to combine expressions OP_LEFT and OP_RIGHT, which before folding
had CODE_LEFT and CODE_RIGHT, into an expression of type TYPE. */
void
warn_logical_operator (location_t location, enum tree_code code,
warn_logical_operator (location_t location, enum tree_code code, tree type,
enum tree_code code_left, tree op_left,
enum tree_code ARG_UNUSED (code_right), tree op_right)
{
int or_op = (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR);
int in0_p, in1_p, in_p;
tree low0, low1, low, high0, high1, high, lhs, rhs, tem;
bool strict_overflow_p = false;
if (code != TRUTH_ANDIF_EXPR
&& code != TRUTH_AND_EXPR
&& code != TRUTH_ORIF_EXPR
......@@ -1743,13 +1747,65 @@ warn_logical_operator (location_t location, enum tree_code code,
&& !integer_zerop (op_right)
&& !integer_onep (op_right))
{
if (code == TRUTH_ORIF_EXPR || code == TRUTH_OR_EXPR)
if (or_op)
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;
return;
}
/* We do not warn for constants because they are typical of macro
expansions that test for features. */
if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right))
return;
/* This warning only makes sense with logical operands. */
if (!(truth_value_p (TREE_CODE (op_left))
|| INTEGRAL_TYPE_P (TREE_TYPE (op_left)))
|| !(truth_value_p (TREE_CODE (op_right))
|| INTEGRAL_TYPE_P (TREE_TYPE (op_right))))
return;
lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p);
rhs = make_range (op_right, &in1_p, &low1, &high1, &strict_overflow_p);
if (lhs && TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
lhs = C_MAYBE_CONST_EXPR_EXPR (lhs);
if (rhs && TREE_CODE (rhs) == C_MAYBE_CONST_EXPR)
rhs = C_MAYBE_CONST_EXPR_EXPR (rhs);
/* If this is an OR operation, invert both sides; we will invert
again at the end. */
if (or_op)
in0_p = !in0_p, in1_p = !in1_p;
/* If both expressions are the same, if we can merge the ranges, and we
can build the range test, return it or it inverted. If one of the
ranges is always true or always false, consider it to be the same
expression as the other. */
if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0))
&& merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
in1_p, low1, high1)
&& 0 != (tem = build_range_check (type,
lhs != 0 ? lhs
: rhs != 0 ? rhs : integer_zero_node,
in_p, low, high)))
{
if (TREE_CODE (tem) != INTEGER_CST)
return;
if (or_op)
warning_at (location, OPT_Wlogical_op,
"logical %<or%> "
"of collectively exhaustive tests is always true");
else
warning_at (location, OPT_Wlogical_op,
"logical %<and%> "
"of mutually exclusive tests is always false");
}
}
......
......@@ -804,7 +804,7 @@ extern bool strict_aliasing_warning (tree, tree, tree);
extern void warnings_for_convert_and_check (tree, tree, tree);
extern tree convert_and_check (tree, tree);
extern void overflow_warning (tree);
extern void warn_logical_operator (location_t, enum tree_code,
extern void warn_logical_operator (location_t, enum tree_code, tree,
enum tree_code, tree, enum tree_code, tree);
extern void check_main_parameter_types (tree decl);
extern bool c_determine_visibility (tree);
......
......@@ -2961,7 +2961,7 @@ parser_build_binary_op (location_t location, enum tree_code code,
warn_about_parentheses (code, code1, arg1.value, code2, arg2.value);
if (warn_logical_op)
warn_logical_operator (input_location, code,
warn_logical_operator (input_location, code, TREE_TYPE (result.value),
code1, arg1.value, code2, arg2.value);
/* Warn about comparisons against string literals, with the exception
......
2009-05-15 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 16302
* call.c (build_new_op): Update calls to warn_logical_operator.
2009-05-14 Ian Lance Taylor <iant@google.com>
* class.c (layout_class_type): Change itk to unsigned int.
......
......@@ -4161,7 +4161,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
/* We need to call warn_logical_operator before
converting arg2 to a boolean_type. */
if (complain & tf_warning)
warn_logical_operator (input_location, code,
warn_logical_operator (input_location, code, boolean_type_node,
code_orig_arg1, arg1,
code_orig_arg2, arg2);
......@@ -4202,7 +4202,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
warn_logical_operator (input_location, code,
warn_logical_operator (input_location, code, boolean_type_node,
code_orig_arg1, arg1, code_orig_arg2, arg2);
/* Fall through. */
case PLUS_EXPR:
......
......@@ -119,10 +119,10 @@ static int simple_operand_p (const_tree);
static tree range_binop (enum tree_code, tree, tree, int, tree, int);
static tree range_predecessor (tree);
static tree range_successor (tree);
static tree make_range (tree, int *, tree *, tree *, bool *);
static tree build_range_check (tree, tree, int, tree, tree);
static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
tree);
extern tree make_range (tree, int *, tree *, tree *, bool *);
extern tree build_range_check (tree, tree, int, tree, tree);
extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
tree, tree);
static tree fold_range_test (enum tree_code, tree, tree, tree);
static tree fold_cond_expr_with_comparison (tree, tree, tree, tree);
static tree unextend (tree, int, int, tree);
......@@ -4414,7 +4414,7 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
because signed overflow is undefined; otherwise, do not change
*STRICT_OVERFLOW_P. */
static tree
tree
make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
bool *strict_overflow_p)
{
......@@ -4706,7 +4706,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
type, TYPE, return an expression to test if EXP is in (or out of, depending
on IN_P) the range. Return 0 if the test couldn't be created. */
static tree
tree
build_range_check (tree type, tree exp, int in_p, tree low, tree high)
{
tree etype = TREE_TYPE (exp), value;
......@@ -4877,7 +4877,7 @@ range_successor (tree val)
/* Given two ranges, see if we can merge them into one. Return 1 if we
can, 0 if we can't. Set the output range into the specified parameters. */
static int
bool
merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
tree high0, int in1_p, tree low1, tree high1)
{
......
2009-05-15 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 16302
* gcc.dg/pr16302.c: New.
* g++.dg/warn/pr16302.C: New.
2009-05-15 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/torture/builtin-math-5.c: New.
......
// PR 16302
/* { dg-do compile } */
/* { dg-options "-Wlogical-op" } */
void bar (int);
int
foo (int argc, char *argv[])
{
if (argc != 1 || argc != 2) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc || !argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc && !argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc != 1 || argc != 2); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc || !argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc && !argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc != 1 || argc != 2) ? 1 : 0 ; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc || !argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc && !argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc == 2 && argc == 1) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc || !argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc && !argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc == 2 && argc == 1); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc || !argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc && !argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc == 2 && argc == 1) ? 1 : 0 ; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc || !argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc && !argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc == 2 && argc == 1) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (!argc || argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (!argc && argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc == 2 && argc == 1); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (!argc || argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (!argc && argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc == 2 && argc == 1) ? 1 : 0 ; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (!argc || argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (!argc && argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return 0;
}
int
foo2 (int argc)
{
if (5 != 1 || 5 != 2) return 1;
if (5 < 0 && 5 > 10) return 1;
if (1 || 0) return 1;
if (0 && 1) return 1;
if (2 || !2) return 1;
if (2 && !2) return 1;
if (!(!2) || !(2)) return 1;
if (!(!2) && !(2)) return 1;
bar (5 != 1 || 5 != 2);
bar (5 < 0 && 5 > 10);
bar (1 || 0);
bar (0 && 1);
bar (2 || !2);
bar (2 && !2);
return (5 != 1 || 5 != 2) ? 1 : 0 ;
return (5 < 0 && 5 > 10) ? 1 : 0;
return (1 || 0) ? 1 : 0 ;
return (0 && 1) ? 1 : 0;
return (2 || !2) ? 1 : 0;
return (2 && !2) ? 1 : 0;
return 0;
}
/* PR 16302 */
/* { dg-do compile } */
/* { dg-options "-Wlogical-op" } */
void bar (int);
int
foo (int argc, char *argv[])
{
if (argc != 1 || argc != 2) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc || !argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc && !argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc != 1 || argc != 2); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc || !argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc && !argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc != 1 || argc != 2) ? 1 : 0 ; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc || !argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc && !argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc == 2 && argc == 1) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc || !argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (argc && !argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc == 2 && argc == 1); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc || !argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (argc && !argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc == 2 && argc == 1) ? 1 : 0 ; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc || !argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (argc && !argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc == 2 && argc == 1) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (argc < 0 && argc > 10) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
if (!argc || argc) return 1; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
if (!argc && argc) return 1; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc == 2 && argc == 1); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (argc < 0 && argc > 10); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
bar (!argc || argc); /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
bar (!argc && argc); /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc == 2 && argc == 1) ? 1 : 0 ; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (argc < 0 && argc > 10) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return (!argc || argc) ? 1 : 0; /* { dg-warning "'or' of collectively exhaustive tests is always true" } */
return (!argc && argc) ? 1 : 0; /* { dg-warning "'and' of mutually exclusive tests is always false" } */
return 0;
}
int
foo2 (int argc)
{
if (5 != 1 || 5 != 2) return 1;
if (5 < 0 && 5 > 10) return 1;
if (1 || 0) return 1;
if (0 && 1) return 1;
if (2 || !2) return 1;
if (2 && !2) return 1;
if (!(!2) || !(2)) return 1;
if (!(!2) && !(2)) return 1;
bar (5 != 1 || 5 != 2);
bar (5 < 0 && 5 > 10);
bar (1 || 0);
bar (0 && 1);
bar (2 || !2);
bar (2 && !2);
return (5 != 1 || 5 != 2) ? 1 : 0 ;
return (5 < 0 && 5 > 10) ? 1 : 0;
return (1 || 0) ? 1 : 0 ;
return (0 && 1) ? 1 : 0;
return (2 || !2) ? 1 : 0;
return (2 && !2) ? 1 : 0;
return 0;
}
......@@ -4820,6 +4820,10 @@ extern bool is_builtin_name (const char*);
extern int get_object_alignment (tree, unsigned int, unsigned int);
extern tree fold_call_stmt (gimple, bool);
extern tree gimple_fold_builtin_snprintf_chk (gimple, tree, enum built_in_function);
extern tree make_range (tree, int *, tree *, tree *, bool *);
extern tree build_range_check (tree, tree, int, tree, tree);
extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
tree, tree);
/* In convert.c */
extern tree strip_float_extensions (tree);
......
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