gcc: Backport fixes for -W parentheses in C++

This fixes GCC 19564:
  http://gcc.gnu.org/ml/gcc-patches/2006-12/msg00868.html
  http://gcc.gnu.org/ml/gcc-patches/2006-12/msg01772.html
  http://gcc.gnu.org/ml/gcc-patches/2007-01/msg00545.html

The patch and its fixes are used by Google in their enhanced gcc-4.2.1
port and predates the license switch in GCC so they are still under
GPLv2.

MFC after:	3 weeks
This commit is contained in:
Pedro F. Giffuni 2013-11-13 04:31:27 +00:00
parent e2838b315a
commit 3b5bdcdf37
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=258081
10 changed files with 256 additions and 113 deletions

View File

@ -232,6 +232,17 @@
* config.gcc: Support core2 processor.
2006-12-13 Ian Lance Taylor <iant@google.com> (r119855)
PR c++/19564
PR c++/19756
* c-typeck.c (parser_build_binary_op): Move parentheses warnings
to warn_about_parentheses in c-common.c.
* c-common.c (warn_about_parentheses): New function.
* c-common.h (warn_about_parentheses): Declare.
* doc/invoke.texi (Warning Options): Update -Wparentheses
description.
2006-12-02 H.J. Lu <hongjiu.lu@intel.com> (r119454 - partial)
PR target/30040

View File

@ -2585,9 +2585,13 @@ c_common_truthvalue_conversion (tree expr)
break;
case MODIFY_EXPR:
if (!TREE_NO_WARNING (expr))
warning (OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
if (!TREE_NO_WARNING (expr)
&& warn_parentheses)
{
warning (OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
TREE_NO_WARNING (expr) = 1;
}
break;
default:
@ -6471,5 +6475,87 @@ warn_array_subscript_with_type_char (tree index)
warning (OPT_Wchar_subscripts, "array subscript has type %<char%>");
}
/* Implement -Wparentheses for the unexpected C precedence rules, to
cover cases like x + y << z which readers are likely to
misinterpret. We have seen an expression in which CODE is a binary
operator used to combine expressions headed by CODE_LEFT and
CODE_RIGHT. CODE_LEFT and CODE_RIGHT may be ERROR_MARK, which
means that that side of the expression was not formed using a
binary operator, or it was enclosed in parentheses. */
void
warn_about_parentheses (enum tree_code code, enum tree_code code_left,
enum tree_code code_right)
{
if (!warn_parentheses)
return;
if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
{
if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code_left == TRUTH_ANDIF_EXPR
|| code_right == TRUTH_ANDIF_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
{
if (code_left == BIT_AND_EXPR || code_left == BIT_XOR_EXPR
|| code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == BIT_AND_EXPR || code_right == BIT_XOR_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
if (TREE_CODE_CLASS (code_left) == tcc_comparison
|| TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
{
if (code_left == BIT_AND_EXPR
|| code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == BIT_AND_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
if (TREE_CODE_CLASS (code_left) == tcc_comparison
|| TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of ^");
}
if (code == BIT_AND_EXPR)
{
if (code_left == PLUS_EXPR || code_left == MINUS_EXPR
|| code_right == PLUS_EXPR || code_right == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
if (TREE_CODE_CLASS (code_left) == tcc_comparison
|| TREE_CODE_CLASS (code_right) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
if (TREE_CODE_CLASS (code) == tcc_comparison
&& (TREE_CODE_CLASS (code_left) == tcc_comparison
|| TREE_CODE_CLASS (code_right) == tcc_comparison))
warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
"have their mathematical meaning");
}
#include "gt-c-common.h"

View File

@ -850,6 +850,9 @@ extern int complete_array_type (tree *, tree, bool);
extern tree builtin_type_for_size (int, bool);
extern void warn_array_subscript_with_type_char (tree);
extern void warn_about_parentheses (enum tree_code, enum tree_code,
enum tree_code);
/* In c-gimplify.c */
extern void c_genericize (tree);

View File

@ -2631,73 +2631,7 @@ parser_build_binary_op (enum tree_code code, struct c_expr arg1,
/* Check for cases such as x+y<<z which users are likely
to misinterpret. */
if (warn_parentheses)
{
if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around + or - inside shift");
}
if (code == TRUTH_ORIF_EXPR)
{
if (code1 == TRUTH_ANDIF_EXPR
|| code2 == TRUTH_ANDIF_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around && within ||");
}
if (code == BIT_IOR_EXPR)
{
if (code1 == BIT_AND_EXPR || code1 == BIT_XOR_EXPR
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around arithmetic in operand of |");
/* Check cases like x|y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of |");
}
if (code == BIT_XOR_EXPR)
{
if (code1 == BIT_AND_EXPR
|| code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == BIT_AND_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around arithmetic in operand of ^");
/* Check cases like x^y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of ^");
}
if (code == BIT_AND_EXPR)
{
if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
|| code2 == PLUS_EXPR || code2 == MINUS_EXPR)
warning (OPT_Wparentheses,
"suggest parentheses around + or - in operand of &");
/* Check cases like x&y==z */
if (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison)
warning (OPT_Wparentheses,
"suggest parentheses around comparison in operand of &");
}
/* Similarly, check for cases like 1<=i<=10 that are probably errors. */
if (TREE_CODE_CLASS (code) == tcc_comparison
&& (TREE_CODE_CLASS (code1) == tcc_comparison
|| TREE_CODE_CLASS (code2) == tcc_comparison))
warning (OPT_Wparentheses, "comparisons like X<=Y<=Z do not "
"have their mathematical meaning");
}
warn_about_parentheses (code, code1, code2);
/* Warn about comparisons against string literals, with the exception
of testing for equality or inequality of a string literal with NULL. */

View File

@ -4460,8 +4460,9 @@ extern tree build_x_indirect_ref (tree, const char *);
extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree get_member_function_from_ptrfunc (tree *, tree);
extern tree build_x_binary_op (enum tree_code, tree, tree,
bool *);
extern tree build_x_binary_op (enum tree_code, tree,
enum tree_code, tree,
enum tree_code, bool *);
extern tree build_x_unary_op (enum tree_code, tree);
extern tree unary_complex_lvalue (enum tree_code, tree);
extern tree build_x_conditional_expr (tree, tree, tree);

View File

@ -1177,8 +1177,15 @@ typedef enum cp_parser_status_kind
typedef struct cp_parser_expression_stack_entry
{
/* Left hand side of the binary operation we are currently
parsing. */
tree lhs;
/* Original tree code for left hand side, if it was a binary
expression itself (used for -Wparentheses). */
enum tree_code lhs_type;
/* Tree code for the binary operation we are parsing. */
enum tree_code tree_type;
/* Precedence of the binary operation we are parsing. */
int prec;
} cp_parser_expression_stack_entry;
@ -1536,7 +1543,7 @@ static tree cp_parser_builtin_offsetof
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
(cp_parser *, tree, bool);
(cp_parser *, tree, bool, bool *);
static void cp_parser_label_for_labeled_statement
(cp_parser *);
static tree cp_parser_expression_statement
@ -1546,7 +1553,7 @@ static tree cp_parser_compound_statement
static void cp_parser_statement_seq_opt
(cp_parser *, tree);
static tree cp_parser_selection_statement
(cp_parser *);
(cp_parser *, bool *);
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
@ -1559,7 +1566,7 @@ static void cp_parser_declaration_statement
(cp_parser *);
static tree cp_parser_implicitly_scoped_statement
(cp_parser *);
(cp_parser *, bool *);
static void cp_parser_already_scoped_statement
(cp_parser *);
@ -5730,12 +5737,13 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p)
cp_parser_expression_stack_entry *sp = &stack[0];
tree lhs, rhs;
cp_token *token;
enum tree_code tree_type;
enum tree_code tree_type, lhs_type, rhs_type;
enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec;
bool overloaded_p;
/* Parse the first expression. */
lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p);
lhs_type = ERROR_MARK;
for (;;)
{
@ -5768,6 +5776,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p)
/* Extract another operand. It may be the RHS of this expression
or the LHS of a new, higher priority expression. */
rhs = cp_parser_simple_cast_expression (parser);
rhs_type = ERROR_MARK;
/* Get another operator token. Look up its precedence to avoid
building a useless (immediately popped) stack entry for common
@ -5783,8 +5792,10 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p)
sp->prec = prec;
sp->tree_type = tree_type;
sp->lhs = lhs;
sp->lhs_type = lhs_type;
sp++;
lhs = rhs;
lhs_type = rhs_type;
prec = new_prec;
new_prec = lookahead_prec;
goto get_rhs;
@ -5801,11 +5812,15 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p)
prec = sp->prec;
tree_type = sp->tree_type;
rhs = lhs;
rhs_type = lhs_type;
lhs = sp->lhs;
lhs_type = sp->lhs_type;
}
overloaded_p = false;
lhs = build_x_binary_op (tree_type, lhs, rhs, &overloaded_p);
lhs = build_x_binary_op (tree_type, lhs, lhs_type, rhs, rhs_type,
&overloaded_p);
lhs_type = tree_type;
/* If the binary operator required the use of an overloaded operator,
then this expression cannot be an integral constant-expression.
@ -6222,17 +6237,23 @@ cp_parser_builtin_offsetof (cp_parser *parser)
try-block
IN_COMPOUND is true when the statement is nested inside a
cp_parser_compound_statement; this matters for certain pragmas. */
cp_parser_compound_statement; this matters for certain pragmas.
If IF_P is not NULL, *IF_P is set to indicate whether the statement
is a (possibly labeled) if statement which is not enclosed in braces
and has an else clause. This is used to implement -Wparentheses. */
static void
cp_parser_statement (cp_parser* parser, tree in_statement_expr,
bool in_compound)
bool in_compound, bool *if_p)
{
tree statement;
cp_token *token;
location_t statement_location;
restart:
if (if_p != NULL)
*if_p = false;
/* There is no statement yet. */
statement = NULL_TREE;
/* Peek at the next token. */
@ -6257,7 +6278,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
case RID_IF:
case RID_SWITCH:
statement = cp_parser_selection_statement (parser);
statement = cp_parser_selection_statement (parser, if_p);
break;
case RID_WHILE:
@ -6522,7 +6543,7 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
break;
/* Parse the statement. */
cp_parser_statement (parser, in_statement_expr, true);
cp_parser_statement (parser, in_statement_expr, true, NULL);
}
}
@ -6533,14 +6554,22 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
if ( condition ) statement else statement
switch ( condition ) statement
Returns the new IF_STMT or SWITCH_STMT. */
Returns the new IF_STMT or SWITCH_STMT.
If IF_P is not NULL, *IF_P is set to indicate whether the statement
is a (possibly labeled) if statement which is not enclosed in
braces and has an else clause. This is used to implement
-Wparentheses. */
static tree
cp_parser_selection_statement (cp_parser* parser)
cp_parser_selection_statement (cp_parser* parser, bool *if_p)
{
cp_token *token;
enum rid keyword;
if (if_p != NULL)
*if_p = false;
/* Peek at the next token. */
token = cp_parser_require (parser, CPP_KEYWORD, "selection-statement");
@ -6576,11 +6605,13 @@ cp_parser_selection_statement (cp_parser* parser)
if (keyword == RID_IF)
{
bool nested_if;
/* Add the condition. */
finish_if_stmt_cond (condition, statement);
/* Parse the then-clause. */
cp_parser_implicitly_scoped_statement (parser);
cp_parser_implicitly_scoped_statement (parser, &nested_if);
finish_then_clause (statement);
/* If the next token is `else', parse the else-clause. */
@ -6591,8 +6622,28 @@ cp_parser_selection_statement (cp_parser* parser)
cp_lexer_consume_token (parser->lexer);
begin_else_clause (statement);
/* Parse the else-clause. */
cp_parser_implicitly_scoped_statement (parser);
cp_parser_implicitly_scoped_statement (parser, NULL);
finish_else_clause (statement);
/* If we are currently parsing a then-clause, then
IF_P will not be NULL. We set it to true to
indicate that this if statement has an else clause.
This may trigger the Wparentheses warning below
when we get back up to the parent if statement. */
if (if_p != NULL)
*if_p = true;
}
else
{
/* This if statement does not have an else clause. If
NESTED_IF is true, then the then-clause is an if
statement which does have an else clause. We warn
about the potential ambiguity. */
if (nested_if)
warning (OPT_Wparentheses,
("%Hsuggest explicit braces "
"to avoid ambiguous %<else%>"),
EXPR_LOCUS (statement));
}
/* Now we're all done with the if-statement. */
@ -6611,7 +6662,7 @@ cp_parser_selection_statement (cp_parser* parser)
in_statement = parser->in_statement;
parser->in_switch_statement_p = true;
parser->in_statement |= IN_SWITCH_STMT;
cp_parser_implicitly_scoped_statement (parser);
cp_parser_implicitly_scoped_statement (parser, NULL);
parser->in_switch_statement_p = in_switch_statement_p;
parser->in_statement = in_statement;
@ -6789,7 +6840,7 @@ cp_parser_iteration_statement (cp_parser* parser)
statement = begin_do_stmt ();
/* Parse the body of the do-statement. */
parser->in_statement = IN_ITERATION_STMT;
cp_parser_implicitly_scoped_statement (parser);
cp_parser_implicitly_scoped_statement (parser, NULL);
parser->in_statement = in_statement;
finish_do_body (statement);
/* Look for the `while' keyword. */
@ -7031,13 +7082,21 @@ cp_parser_declaration_statement (cp_parser* parser)
but ensures that is in its own scope, even if it is not a
compound-statement.
If IF_P is not NULL, *IF_P is set to indicate whether the statement
is a (possibly labeled) if statement which is not enclosed in
braces and has an else clause. This is used to implement
-Wparentheses.
Returns the new statement. */
static tree
cp_parser_implicitly_scoped_statement (cp_parser* parser)
cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p)
{
tree statement;
if (if_p != NULL)
*if_p = false;
/* Mark if () ; with a special NOP_EXPR. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
@ -7053,7 +7112,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
/* Create a compound-statement. */
statement = begin_compound_stmt (0);
/* Parse the dependent-statement. */
cp_parser_statement (parser, NULL_TREE, false);
cp_parser_statement (parser, NULL_TREE, false, if_p);
/* Finish the dummy compound-statement. */
finish_compound_stmt (statement);
}
@ -7072,7 +7131,7 @@ cp_parser_already_scoped_statement (cp_parser* parser)
{
/* If the token is a `{', then we must take special action. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
cp_parser_statement (parser, NULL_TREE, false);
cp_parser_statement (parser, NULL_TREE, false, NULL);
else
{
/* Avoid calling cp_parser_compound_statement, so that we
@ -18645,7 +18704,7 @@ cp_parser_omp_structured_block (cp_parser *parser)
tree stmt = begin_omp_structured_block ();
unsigned int save = cp_parser_begin_omp_structured_block (parser);
cp_parser_statement (parser, NULL_TREE, false);
cp_parser_statement (parser, NULL_TREE, false, NULL);
cp_parser_end_omp_structured_block (parser, save);
return finish_omp_structured_block (stmt);
@ -18890,7 +18949,7 @@ cp_parser_omp_for_loop (cp_parser *parser)
/* Note that the grammar doesn't call for a structured block here,
though the loop as a whole is a structured block. */
body = push_stmt_list ();
cp_parser_statement (parser, NULL_TREE, false);
cp_parser_statement (parser, NULL_TREE, false, NULL);
body = pop_stmt_list (body);
return finish_omp_for (loc, decl, init, cond, incr, body, pre_body);
@ -18983,7 +19042,7 @@ cp_parser_omp_sections_scope (cp_parser *parser)
while (1)
{
cp_parser_statement (parser, NULL_TREE, false);
cp_parser_statement (parser, NULL_TREE, false, NULL);
tok = cp_lexer_peek_token (parser->lexer);
if (tok->pragma_kind == PRAGMA_OMP_SECTION)

View File

@ -9078,7 +9078,13 @@ tsubst_copy_and_build (tree t,
return build_x_binary_op
(TREE_CODE (t),
RECUR (TREE_OPERAND (t, 0)),
(TREE_NO_WARNING (TREE_OPERAND (t, 0))
? ERROR_MARK
: TREE_CODE (TREE_OPERAND (t, 0))),
RECUR (TREE_OPERAND (t, 1)),
(TREE_NO_WARNING (TREE_OPERAND (t, 1))
? ERROR_MARK
: TREE_CODE (TREE_OPERAND (t, 1))),
/*overloaded_p=*/NULL);
case SCOPE_REF:
@ -9087,7 +9093,14 @@ tsubst_copy_and_build (tree t,
case ARRAY_REF:
op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
args, complain, in_decl);
return build_x_binary_op (ARRAY_REF, op1, RECUR (TREE_OPERAND (t, 1)),
return build_x_binary_op (ARRAY_REF, op1,
(TREE_NO_WARNING (TREE_OPERAND (t, 0))
? ERROR_MARK
: TREE_CODE (TREE_OPERAND (t, 0))),
RECUR (TREE_OPERAND (t, 1)),
(TREE_NO_WARNING (TREE_OPERAND (t, 1))
? ERROR_MARK
: TREE_CODE (TREE_OPERAND (t, 1))),
/*overloaded_p=*/NULL);
case SIZEOF_EXPR:

View File

@ -587,6 +587,16 @@ maybe_convert_cond (tree cond)
/* Do the conversion. */
cond = convert_from_reference (cond);
if (TREE_CODE (cond) == MODIFY_EXPR
&& !TREE_NO_WARNING (cond)
&& warn_parentheses)
{
warning (OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
TREE_NO_WARNING (cond) = 1;
}
return condition_conversion (cond);
}

View File

@ -1690,17 +1690,20 @@ rationalize_conditional_expr (enum tree_code code, tree t)
are equal, so we know what conditional expression this used to be. */
if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
tree op0 = TREE_OPERAND (t, 0);
tree op1 = TREE_OPERAND (t, 1);
/* The following code is incorrect if either operand side-effects. */
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
&& !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
gcc_assert (!TREE_SIDE_EFFECTS (op0)
&& !TREE_SIDE_EFFECTS (op1));
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1),
op0, TREE_CODE (op0),
op1, TREE_CODE (op1),
/*overloaded_p=*/NULL),
build_unary_op (code, TREE_OPERAND (t, 0), 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0));
build_unary_op (code, op0, 0),
build_unary_op (code, op1, 0));
}
return
@ -2908,8 +2911,8 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
conversions on the operands. CODE is the kind of expression to build. */
tree
build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
bool *overloaded_p)
build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
tree arg2, enum tree_code arg2_code, bool *overloaded_p)
{
tree orig_arg1;
tree orig_arg2;
@ -2933,6 +2936,17 @@ build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
overloaded_p);
/* Check for cases such as x+y<<z which users are likely to
misinterpret. But don't warn about obj << x + y, since that is a
common idiom for I/O. */
if (warn_parentheses
&& !processing_template_decl
&& !error_operand_p (arg1)
&& !error_operand_p (arg2)
&& (code != LSHIFT_EXPR
|| !IS_AGGR_TYPE (TREE_TYPE (arg1))))
warn_about_parentheses (code, arg1_code, arg2_code);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
@ -6280,6 +6294,19 @@ convert_for_assignment (tree type, tree rhs,
errtype);
}
/* If -Wparentheses, warn about a = b = c when a has type bool and b
does not. */
if (warn_parentheses
&& type == boolean_type_node
&& TREE_CODE (rhs) == MODIFY_EXPR
&& !TREE_NO_WARNING (rhs)
&& TREE_TYPE (rhs) != boolean_type_node)
{
warning (OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
TREE_NO_WARNING (rhs) = 1;
}
return perform_implicit_conversion (strip_top_quals (type), rhs);
}

View File

@ -2212,9 +2212,7 @@ Warn if a user-supplied include directory does not exist.
Warn if parentheses are omitted in certain contexts, such
as when there is an assignment in a context where a truth value
is expected, or when operators are nested whose precedence people
often get confused about. Only the warning for an assignment used as
a truth value is supported when compiling C++; the other warnings are
only supported when compiling C@.
often get confused about.
Also warn if a comparison like @samp{x<=y<=z} appears; this is
equivalent to @samp{(x<=y ? 1 : 0) <= z}, which is a different
@ -2236,14 +2234,15 @@ such a case:
@end group
@end smallexample
In C, every @code{else} branch belongs to the innermost possible @code{if}
statement, which in this example is @code{if (b)}. This is often not
what the programmer expected, as illustrated in the above example by
indentation the programmer chose. When there is the potential for this
confusion, GCC will issue a warning when this flag is specified.
To eliminate the warning, add explicit braces around the innermost
@code{if} statement so there is no way the @code{else} could belong to
the enclosing @code{if}. The resulting code would look like this:
In C/C++, every @code{else} branch belongs to the innermost possible
@code{if} statement, which in this example is @code{if (b)}. This is
often not what the programmer expected, as illustrated in the above
example by indentation the programmer chose. When there is the
potential for this confusion, GCC will issue a warning when this flag
is specified. To eliminate the warning, add explicit braces around
the innermost @code{if} statement so there is no way the @code{else}
could belong to the enclosing @code{if}. The resulting code would
look like this:
@smallexample
@group