Commit 487a92fe by Joseph Myers Committed by Joseph Myers

c-tree.h (struct c_expr): Define.

	* c-tree.h (struct c_expr): Define.
	(C_SET_EXP_ORIGINAL_CODE): Remove.
	(parser_build_binary_op, build_compound_expr): Update prototypes.
	* c-parse.in (%union): Add exprtype.
	(FUNC_NAME): Mark as ttype.
	(expr, expr_no_commas, cast_expr, unary_expr, primary): Change to
	exprtype.
	(expr): Update.  Define directly in terms of expr_no_commas
	instead of using nonnull_exprlist.
	(nonnull_exprlist, unary_expr, cast_expr, expr_no_commas, primary,
	offsetof_member_designator, typespec_nonreserved_nonattr, init,
	initval, designator, component_declarator,
	component_notype_declarator, enumerator, array_declarator,
	condition, exexpr, switch_statement, stmt_nocomp, stmt,
	nonnull_asm_operands, ivar_declarator, receiver): Update.  Don't
	set C_EXP_ORIGINAL_CODE.  Use TREE_NO_WARNING for assignments
	where appropriate.
	* c-common.h (C_EXP_ORIGINAL_CODE): Remove.
	* c-common.c (c_common_truthvalue_conversion): Don't check
	C_EXP_ORIGINAL_CODE.
	* c-typeck.c (parser_build_binary_op): Use c_expr structures.
	Don't use C_EXP_ORIGINAL_CODE.
	(default_conversion, default_function_array_conversion): Don't use
	C_EXP_ORIGINAL_CODE.  Preserve TREE_NO_WARNING.
	(internal_build_compound_expr): Merge into build_compound_expr.
	(build_compound_expr): Take two operands instead of a TREE_LIST.
	* objc/objc-act.c (get_super_receiver): Update calls to
	build_compound_expr.

cp:
	* typeck.c (build_modify_expr, build_x_modify_expr): Set
	TREE_NO_WARNING on assignments with an operator other than '='.

testsuite:
	* g++.dg/warn/Wparentheses-1.C, g++.dg/warn/Wparentheses-2.C,
	gcc.dg/Wparentheses-10.c: New tests.
	* gcc.dg/Wparentheses-5.c: Remove XFAILs.

From-SVN: r84911
parent 2de7ffa7
2004-07-19 Joseph S. Myers <jsm@polyomino.org.uk>
* c-tree.h (struct c_expr): Define.
(C_SET_EXP_ORIGINAL_CODE): Remove.
(parser_build_binary_op, build_compound_expr): Update prototypes.
* c-parse.in (%union): Add exprtype.
(FUNC_NAME): Mark as ttype.
(expr, expr_no_commas, cast_expr, unary_expr, primary): Change to
exprtype.
(expr): Update. Define directly in terms of expr_no_commas
instead of using nonnull_exprlist.
(nonnull_exprlist, unary_expr, cast_expr, expr_no_commas, primary,
offsetof_member_designator, typespec_nonreserved_nonattr, init,
initval, designator, component_declarator,
component_notype_declarator, enumerator, array_declarator,
condition, exexpr, switch_statement, stmt_nocomp, stmt,
nonnull_asm_operands, ivar_declarator, receiver): Update. Don't
set C_EXP_ORIGINAL_CODE. Use TREE_NO_WARNING for assignments
where appropriate.
* c-common.h (C_EXP_ORIGINAL_CODE): Remove.
* c-common.c (c_common_truthvalue_conversion): Don't check
C_EXP_ORIGINAL_CODE.
* c-typeck.c (parser_build_binary_op): Use c_expr structures.
Don't use C_EXP_ORIGINAL_CODE.
(default_conversion, default_function_array_conversion): Don't use
C_EXP_ORIGINAL_CODE. Preserve TREE_NO_WARNING.
(internal_build_compound_expr): Merge into build_compound_expr.
(build_compound_expr): Take two operands instead of a TREE_LIST.
* objc/objc-act.c (get_super_receiver): Update calls to
build_compound_expr.
2004-07-12 Paolo Bonzini <bonzini@gnu.org>
* config/sh/sh.c (sh_use_dfa_interface): Remove.
......
......@@ -2365,9 +2365,7 @@ c_common_truthvalue_conversion (tree expr)
break;
case MODIFY_EXPR:
if (warn_parentheses
&& C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR
&& !TREE_NO_WARNING (expr))
if (warn_parentheses && !TREE_NO_WARNING (expr))
warning ("suggest parentheses around assignment used as truth value");
break;
......
......@@ -598,10 +598,6 @@ extern int skip_evaluation;
#define C_TYPE_OBJECT_OR_INCOMPLETE_P(type) \
(!C_TYPE_FUNCTION_P (type))
/* Record in each node resulting from a binary operator
what operator was specified for it. */
#define C_EXP_ORIGINAL_CODE(exp) ((enum tree_code) TREE_COMPLEXITY (exp))
/* Attribute table common to the C front ends. */
extern const struct attribute_spec c_common_attribute_table[];
extern const struct attribute_spec c_common_format_attribute_table[];
......
......@@ -80,10 +80,6 @@ struct lang_type GTY(())
#define C_TYPE_VARIABLE_SIZE(TYPE) TYPE_LANG_FLAG_1 (TYPE)
#define C_DECL_VARIABLE_SIZE(TYPE) DECL_LANG_FLAG_0 (TYPE)
/* Store a value in that field. */
#define C_SET_EXP_ORIGINAL_CODE(EXP, CODE) \
(TREE_COMPLEXITY (EXP) = (int) (CODE))
/* Record whether a typedef for type `int' was actually `signed int'. */
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
......@@ -116,6 +112,18 @@ struct lang_type GTY(())
without prototypes. */
#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_LANG_SLOT_1 (NODE)
/* Record parser information about an expression that is irrelevant
for code generation alongside a tree representing its value. */
struct c_expr
{
/* The value of the expression. */
tree value;
/* Record the original binary operator of an expression, which may
have been changed by fold, or ERROR_MARK for other expressions
(including parenthesized expressions). */
enum tree_code original_code;
};
/* Save and restore the variables in this file and elsewhere
that keep track of the progress of compilation of the current function.
Used for nested functions. */
......@@ -225,10 +233,11 @@ extern tree build_component_ref (tree, tree);
extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree build_external_ref (tree, int);
extern tree parser_build_binary_op (enum tree_code, tree, tree);
extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr,
struct c_expr);
extern void readonly_error (tree, const char *);
extern tree build_conditional_expr (tree, tree, tree);
extern tree build_compound_expr (tree);
extern tree build_compound_expr (tree, tree);
extern tree c_cast_expr (tree, tree);
extern tree build_c_cast (tree, tree);
extern tree build_modify_expr (tree, enum tree_code, tree);
......
......@@ -62,7 +62,6 @@ static tree default_function_array_conversion (tree);
static tree lookup_field (tree, tree);
static tree convert_arguments (tree, tree, tree, tree);
static tree pointer_diff (tree, tree);
static tree internal_build_compound_expr (tree, int);
static tree convert_for_assignment (tree, tree, const char *, tree, tree,
int);
static void warn_for_assignment (const char *, const char *, tree, int);
......@@ -1182,9 +1181,8 @@ default_function_array_conversion (tree exp)
exp = TREE_OPERAND (exp, 0);
}
/* Preserve the original expression code. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
if (code == FUNCTION_TYPE)
{
......@@ -1294,9 +1292,8 @@ default_conversion (tree exp)
&& TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
exp = TREE_OPERAND (exp, 0);
/* Preserve the original expression code. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
if (TREE_NO_WARNING (orig_exp))
TREE_NO_WARNING (exp) = 1;
/* Normally convert enums to int,
but convert wide enums to something wider. */
......@@ -2099,28 +2096,23 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
we check for operands that were written with other binary operators
in a way that is likely to confuse the user. */
tree
parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
struct c_expr
parser_build_binary_op (enum tree_code code, struct c_expr arg1,
struct c_expr arg2)
{
tree result = build_binary_op (code, arg1, arg2, 1);
struct c_expr result;
char class;
char class1 = TREE_CODE_CLASS (TREE_CODE (arg1));
char class2 = TREE_CODE_CLASS (TREE_CODE (arg2));
enum tree_code code1 = ERROR_MARK;
enum tree_code code2 = ERROR_MARK;
enum tree_code code1 = arg1.original_code;
enum tree_code code2 = arg2.original_code;
if (TREE_CODE (result) == ERROR_MARK)
return error_mark_node;
result.value = build_binary_op (code, arg1.value, arg2.value, 1);
result.original_code = code;
if (IS_EXPR_CODE_CLASS (class1))
code1 = C_EXP_ORIGINAL_CODE (arg1);
if (IS_EXPR_CODE_CLASS (class2))
code2 = C_EXP_ORIGINAL_CODE (arg2);
if (TREE_CODE (result.value) == ERROR_MARK)
return result;
/* Check for cases such as x+y<<z which users are likely
to misinterpret. If parens are used, C_EXP_ORIGINAL_CODE
is cleared to prevent these warnings. */
to misinterpret. */
if (warn_parentheses)
{
if (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
......@@ -2178,25 +2170,9 @@ parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
}
unsigned_conversion_warning (result, arg1);
unsigned_conversion_warning (result, arg2);
overflow_warning (result);
class = TREE_CODE_CLASS (TREE_CODE (result));
/* Record the code that was specified in the source,
for the sake of warnings about confusing nesting. */
if (IS_EXPR_CODE_CLASS (class))
C_SET_EXP_ORIGINAL_CODE (result, code);
else
{
/* We used to use NOP_EXPR rather than NON_LVALUE_EXPR
so that convert_for_assignment wouldn't strip it.
That way, we got warnings for things like p = (1 - 1).
But it turns out we should not get those warnings. */
result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result);
C_SET_EXP_ORIGINAL_CODE (result, code);
}
unsigned_conversion_warning (result.value, arg1.value);
unsigned_conversion_warning (result.value, arg2.value);
overflow_warning (result.value);
return result;
}
......@@ -2894,44 +2870,27 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
}
/* Given a list of expressions, return a compound expression
that performs them all and returns the value of the last of them. */
/* Return a compound expression that performs two expressions and
returns the value of the second of them. */
tree
build_compound_expr (tree list)
build_compound_expr (tree expr1, tree expr2)
{
return internal_build_compound_expr (list, TRUE);
}
static tree
internal_build_compound_expr (tree list, int first_p)
{
tree rest;
if (TREE_CHAIN (list) == 0)
{
/* Convert arrays and functions to pointers when there
really is a comma operator. */
if (!first_p)
TREE_VALUE (list)
= default_function_array_conversion (TREE_VALUE (list));
/* Don't let (0, 0) be null pointer constant. */
if (!first_p && integer_zerop (TREE_VALUE (list)))
return non_lvalue (TREE_VALUE (list));
return TREE_VALUE (list);
}
/* Convert arrays and functions to pointers. */
expr2 = default_function_array_conversion (expr2);
rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
/* Don't let (0, 0) be null pointer constant. */
if (integer_zerop (expr2))
expr2 = non_lvalue (expr2);
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
if (! TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
statement: with -Wextra or -Wunused, we should warn if it doesn't have
any side-effects, unless it was explicitly cast to (void). */
if (warn_unused_value
&& ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
&& ! (TREE_CODE (expr1) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (expr1))))
warning ("left-hand operand of comma expression has no effect");
}
......@@ -2940,9 +2899,9 @@ internal_build_compound_expr (tree list, int first_p)
`foo() + bar(), baz()' the result of the `+' operator is not used,
so we should issue a warning. */
else if (warn_unused_value)
warn_if_unused_value (TREE_VALUE (list), input_location);
warn_if_unused_value (expr1, input_location);
return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
return build (COMPOUND_EXPR, TREE_TYPE (expr2), expr1, expr2);
}
/* Build an expression representing a cast to type TYPE of expression EXPR. */
......
2004-07-19 Joseph S. Myers <jsm@polyomino.org.uk>
* typeck.c (build_modify_expr, build_x_modify_expr): Set
TREE_NO_WARNING on assignments with an operator other than '='.
2004-07-10 Steven Bosscher <stevenb@suse.de>
Joseph S. Myers <jsm@polyomino.org.uk>
......
......@@ -4995,6 +4995,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
tree olhs = NULL_TREE;
bool plain_assign = (modifycode == NOP_EXPR);
/* Avoid duplicate error messages from operands that had errors. */
if (lhs == error_mark_node || rhs == error_mark_node)
......@@ -5254,6 +5255,8 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
if (!plain_assign)
TREE_NO_WARNING (result) = 1;
/* If we got the LHS in a different type for storing in,
convert the result back to the nominal type of LHS
......@@ -5285,7 +5288,10 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
make_node (modifycode),
/*overloaded_p=*/NULL);
if (rval)
return rval;
{
TREE_NO_WARNING (rval) = 1;
return rval;
}
}
return build_modify_expr (lhs, modifycode, rhs);
}
......
......@@ -7870,7 +7870,7 @@ get_super_receiver (void)
/* Set receiver to self. */
super_expr = build_component_ref (UOBJC_SUPER_decl, self_id);
super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl);
super_expr_list = build_tree_list (NULL_TREE, super_expr);
super_expr_list = super_expr;
/* Set class to begin searching. */
#ifdef OBJCPLUS
......@@ -7941,12 +7941,12 @@ get_super_receiver (void)
super_class));
}
chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
super_expr_list = build_compound_expr (super_expr_list, super_expr);
super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0);
chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
super_expr_list = build_compound_expr (super_expr_list, super_expr);
return build_compound_expr (super_expr_list);
return super_expr_list;
}
else
{
......
2004-07-19 Joseph S. Myers <jsm@polyomino.org.uk>
* g++.dg/warn/Wparentheses-1.C, g++.dg/warn/Wparentheses-2.C,
gcc.dg/Wparentheses-10.c: New tests.
* gcc.dg/Wparentheses-5.c: Remove XFAILs.
2004-07-18 Tobias Schlueter <tobias.schlueter@physik.uni-muenchen.de>
PR fortran/16465
......
// Test operation of -Wparentheses. Warnings for assignments used as
// truth-values. Essentially the same as gcc.dg/Wparentheses-3.c.
// Origin: Joseph Myers <jsm@polyomino.org.uk>
// { dg-do compile }
// { dg-options "-Wparentheses" }
int foo (int);
int a, b, c;
bool d;
void
bar (void)
{
if (a = b) // { dg-warning "assignment" "correct warning" }
foo (0);
if ((a = b))
foo (1);
if (a = a) // { dg-warning "assignment" "correct warning" }
foo (2);
if ((a = a))
foo (3);
if (b = c) // { dg-warning "assignment" "correct warning" }
foo (4);
else
foo (5);
if ((b = c))
foo (6);
else
foo (7);
if (b = b) // { dg-warning "assignment" "correct warning" }
foo (8);
else
foo (9);
if ((b = b))
foo (10);
else
foo (11);
while (c = b) // { dg-warning "assignment" "correct warning" }
foo (12);
while ((c = b))
foo (13);
while (c = c) // { dg-warning "assignment" "correct warning" }
foo (14);
while ((c = c))
foo (15);
do foo (16); while (a = b); // { dg-warning "assignment" "correct warning" }
do foo (17); while ((a = b));
do foo (18); while (a = a); // { dg-warning "assignment" "correct warning" }
do foo (19); while ((a = a));
for (;c = b;) // { dg-warning "assignment" "correct warning" }
foo (20);
for (;(c = b);)
foo (21);
for (;c = c;) // { dg-warning "assignment" "correct warning" }
foo (22);
for (;(c = c);)
foo (23);
d = a = b; // { dg-warning "assignment" "correct warning" }
foo (24);
d = (a = b);
foo (25);
d = a = a; // { dg-warning "assignment" "correct warning" }
foo (26);
d = (a = a);
foo (27);
}
// Test operation of -Wparentheses. Warnings for assignments used as
// truth-values shouldn't apply other than for plain assignment.
// Essentially the same as gcc.dg/Wparentheses-10.c.
// Origin: Joseph Myers <jsm@polyomino.org.uk>
// { dg-do compile }
// { dg-options "-Wparentheses" }
int foo (int);
int a, b, c;
bool d;
void
bar (void)
{
if (a += b)
foo (0);
if (a -= a)
foo (1);
if (b *= c)
foo (2);
else
foo (3);
if (b /= b)
foo (4);
else
foo (5);
while (c %= b)
foo (6);
while (c <<= c)
foo (7);
do foo (8); while (a >>= b);
do foo (9); while (a &= a);
for (;c ^= b;)
foo (10);
for (;c |= c;)
foo (11);
d = a += b;
foo (12);
d = a -= a;
foo (13);
}
/* Test operation of -Wparentheses. Warnings for assignments used as
truth-values shouldn't apply other than for plain assignment. */
/* Origin: Joseph Myers <jsm@polyomino.org.uk> */
/* { dg-do compile } */
/* { dg-options "-Wparentheses -std=gnu99" } */
int foo (int);
int a, b, c;
_Bool d;
void
bar (void)
{
if (a += b)
foo (0);
if (a -= a)
foo (1);
if (b *= c)
foo (2);
else
foo (3);
if (b /= b)
foo (4);
else
foo (5);
while (c %= b)
foo (6);
while (c <<= c)
foo (7);
do foo (8); while (a >>= b);
do foo (9); while (a &= a);
for (;c ^= b;)
foo (10);
for (;c |= c;)
foo (11);
d = a += b;
foo (12);
d = a -= a;
foo (13);
}
......@@ -13,10 +13,10 @@ bar (int a, int b, int c)
foo (a && b || c); /* { dg-warning "parentheses" "correct warning" } */
foo ((a && b) || c);
foo (a && (b || c));
foo (1 && 2 || c); /* { dg-warning "parentheses" "correct warning" { xfail *-*-* } } */
foo (1 && 2 || c); /* { dg-warning "parentheses" "correct warning" } */
foo ((1 && 2) || c);
foo (1 && (2 || c));
foo (1 && 2 || 3); /* { dg-warning "parentheses" "correct warning" { xfail *-*-* } } */
foo (1 && 2 || 3); /* { dg-warning "parentheses" "correct warning" } */
foo ((1 && 2) || 3);
foo (1 && (2 || 3));
foo (a || b && c); /* { dg-warning "parentheses" "correct warning" } */
......
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