Patches to remove TREE_COMPLEXITY for C and C++

Joseph S. Myers jsm@polyomino.org.uk
Mon Jul 19 12:15:00 GMT 2004


This pair of patches removes the use of TREE_COMPLEXITY for C and C++.
It doesn't get rid of TREE_COMPLEXITY altogether, since I hadn't
realised that Java was still using it but using the complexity field
directly rather than through the TREE_COMPLEXITY accessor.  Thus, Java
and Ada are left as the only users of this field.

The first patch is Steven Bosscher's patch
<http://gcc.gnu.org/ml/gcc-patches/2004-06/msg00863.html> for uses in
C++, updated to apply to current mainline.

The second patch removes TREE_COMPLEXITY from the C front end and
makes the necessary associated changes to the C++ front end to bring
-Wparentheses back to an approximately working state (it having been
broken by the new C++ parser).  This is the one for which the log is
below.

The approach used for most of the C front end -Wparentheses warnings
is that I previously proposed (references in
<http://gcc.gnu.org/ml/gcc-patches/2004-06/msg01219.html> in the
discussion of the first patch).  The parser structures are intended
incrementally to move further into the front end.  In particular
implementation of proper constant expression rules will follow once
I've written down the necessary four formal models for what should be
implemented for C90, C99 and the GNU extended versions thereof.  The
approach for warnings for assignments used as truth-values is
TREE_NO_WARNING as in the first patch.  For C++ this is clearly
imperfect as assignments can yield many sorts of tree other than
MODIFY_EXPR and so not trigger the warning.  At present a proper
implementation for C++ would require moving the warning out of
c_common_truthvalue_conversion into language-specific code for each
front end, called at the syntactically appropriate points.

This pair of patches together has been bootstrapped with no
regressions on i686-pc-linux-gnu.  There is a 0.6% compile-time
improvement for building a set of .i files of cc1 at -O0 (note this
timing is with --enable-checking compilers), probably because
parenthesised expressions and expression statements no longer all get
encapsulated in garbage TREE_LISTs.  I don't know what further
improvement getting rid of the complexity field from tree_exp will
bring.

Accordingly I request review of (a) patch 1, so Steven Bosscher can
apply that; (b) the C++ and Objective-C parts of patch 2.  If there
are objections to the C++ changes, I'll rework things so that
c-common.c doesn't attempt to give the warning for assignments used as
truth-values for C++ (the status quo being that C_EXP_ORIGINAL_CODE is
never set to MODIFY_EXPR by the current C++ parser, so this warning
never happens for C++) so the C++ front end doesn't need changes
beyond removing all references to TREE_COMPLEXITY /
C_EXP_ORIGINAL_CODE, and file a bug report for the regression in
-Wparentheses support in C++ to record the issue.  (I should probably
file such a bug report anyway for the regression in 3.4.)

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
    jsm@polyomino.org.uk (personal mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

2004-07-18  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.

cp:
2004-07-18  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 '='.

testsuite:
2004-07-18  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.
-------------- next part --------------
diff -rupN GCC.orig/gcc/c-common.c GCC.bosscher/gcc/c-common.c
--- GCC.orig/gcc/c-common.c	2004-07-17 21:13:02.000000000 +0000
+++ GCC.bosscher/gcc/c-common.c	2004-07-17 21:23:27.000000000 +0000
@@ -2365,7 +2365,9 @@ c_common_truthvalue_conversion (tree exp
       break;
 
     case MODIFY_EXPR:
-      if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
+      if (warn_parentheses
+	  && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR
+	  && !TREE_NO_WARNING (expr))
 	warning ("suggest parentheses around assignment used as truth value");
       break;
 
diff -rupN GCC.orig/gcc/cp/cp-tree.h GCC.bosscher/gcc/cp/cp-tree.h
--- GCC.orig/gcc/cp/cp-tree.h	2004-07-17 21:13:02.000000000 +0000
+++ GCC.bosscher/gcc/cp/cp-tree.h	2004-07-17 21:23:27.000000000 +0000
@@ -370,10 +370,6 @@ typedef enum cp_id_kind
 #define C_TYPE_FIELDS_READONLY(TYPE) \
   (LANG_TYPE_CLASS_CHECK (TYPE)->fields_readonly)
 
-/* Store a value in that field.  */
-#define C_SET_EXP_ORIGINAL_CODE(EXP, CODE) \
-  (TREE_COMPLEXITY (EXP) = (int)(CODE))
-
 /* The tokens stored in the default argument.  */
 
 #define DEFARG_TOKENS(NODE) \
diff -rupN GCC.orig/gcc/cp/decl2.c GCC.bosscher/gcc/cp/decl2.c
--- GCC.orig/gcc/cp/decl2.c	2004-07-17 21:13:02.000000000 +0000
+++ GCC.bosscher/gcc/cp/decl2.c	2004-07-17 21:24:55.000000000 +0000
@@ -816,15 +816,8 @@ grokfield (const cp_declarator *declarat
       && TREE_CODE (declarator->u.id.name) == SCOPE_REF
       && (TREE_CODE (TREE_OPERAND (declarator->u.id.name, 1)) 
 	  == IDENTIFIER_NODE))
-    {
-      /* Access declaration */
-      if (! IS_AGGR_TYPE_CODE (TREE_CODE 
-			       (TREE_OPERAND (declarator->u.id.name, 0))))
-	;
-      else if (TREE_COMPLEXITY (declarator->u.id.name) == current_class_depth)
-	pop_nested_class ();
-      return do_class_using_decl (declarator->u.id.name);
-    }
+    /* Access declaration */
+    return do_class_using_decl (declarator->u.id.name);
 
   if (init
       && TREE_CODE (init) == TREE_LIST
diff -rupN GCC.orig/gcc/cp/semantics.c GCC.bosscher/gcc/cp/semantics.c
--- GCC.orig/gcc/cp/semantics.c	2004-07-17 21:13:02.000000000 +0000
+++ GCC.bosscher/gcc/cp/semantics.c	2004-07-17 21:23:46.000000000 +0000
@@ -1231,7 +1231,7 @@ finish_parenthesized_expr (tree expr)
 {
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
     /* This inhibits warnings in c_common_truthvalue_conversion.  */
-    C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK); 
+    TREE_NO_WARNING (expr) = 1;
 
   if (TREE_CODE (expr) == OFFSET_REF)
     /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
-------------- next part --------------
diff -rupN GCC.bosscher/gcc/c-common.c GCC.cexp/gcc/c-common.c
--- GCC.bosscher/gcc/c-common.c	2004-07-17 21:23:27.000000000 +0000
+++ GCC.cexp/gcc/c-common.c	2004-07-17 23:49:07.000000000 +0000
@@ -2365,9 +2365,7 @@ c_common_truthvalue_conversion (tree exp
       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;
 
diff -rupN GCC.bosscher/gcc/c-common.h GCC.cexp/gcc/c-common.h
--- GCC.bosscher/gcc/c-common.h	2004-07-10 07:51:38.000000000 +0000
+++ GCC.cexp/gcc/c-common.h	2004-07-17 21:29:32.000000000 +0000
@@ -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[];
diff -rupN GCC.bosscher/gcc/c-parse.in GCC.cexp/gcc/c-parse.in
--- GCC.bosscher/gcc/c-parse.in	2004-06-30 22:18:29.000000000 +0000
+++ GCC.cexp/gcc/c-parse.in	2004-07-18 14:15:29.000000000 +0000
@@ -102,7 +102,7 @@ do {									\
 
 %start program
 
-%union {long itype; tree ttype; enum tree_code code;
+%union {long itype; tree ttype; struct c_expr exprtype; enum tree_code code;
 	location_t location; }
 
 /* All identifiers that are not reserved words
@@ -184,8 +184,9 @@ do {									\
 %type <ttype> ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
 %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
 
-%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
-%type <ttype> expr_no_commas cast_expr unary_expr primary STRING
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT STRING FUNC_NAME
+%type <ttype> nonnull_exprlist exprlist
+%type <exprtype> expr expr_no_commas cast_expr unary_expr primary
 %type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
 %type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
 %type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
@@ -462,8 +463,10 @@ unop:     '&'
 		{ $$ = TRUTH_NOT_EXPR; }
 	;
 
-expr:	nonnull_exprlist
-		{ $$ = build_compound_expr ($1); }
+expr:	expr_no_commas
+	| expr ',' expr_no_commas
+		{ $$.value = build_compound_expr ($1.value, $3.value);
+		  $$.original_code = COMPOUND_EXPR; }
 	;
 
 exprlist:
@@ -474,44 +477,53 @@ exprlist:
 
 nonnull_exprlist:
 	expr_no_commas
-		{ $$ = build_tree_list (NULL_TREE, $1); }
+		{ $$ = build_tree_list (NULL_TREE, $1.value); }
 	| nonnull_exprlist ',' expr_no_commas
-		{ chainon ($1, build_tree_list (NULL_TREE, $3)); }
+		{ chainon ($1, build_tree_list (NULL_TREE, $3.value)); }
 	;
 
 unary_expr:
 	primary
 	| '*' cast_expr   %prec UNARY
-		{ $$ = build_indirect_ref ($2, "unary *"); }
+		{ $$.value = build_indirect_ref ($2.value, "unary *");
+		  $$.original_code = ERROR_MARK; }
 	/* __extension__ turns off -pedantic for following primary.  */
 	| extension cast_expr	  %prec UNARY
 		{ $$ = $2;
 		  RESTORE_EXT_FLAGS ($1); }
 	| unop cast_expr  %prec UNARY
-		{ $$ = build_unary_op ($1, $2, 0);
-		  overflow_warning ($$); }
+		{ $$.value = build_unary_op ($1, $2.value, 0);
+		  overflow_warning ($$.value);
+		  $$.original_code = ERROR_MARK; }
 	/* Refer to the address of a label as a pointer.  */
 	| ANDAND identifier
-		{ $$ = finish_label_address_expr ($2); }
+		{ $$.value = finish_label_address_expr ($2);
+		  $$.original_code = ERROR_MARK; }
 	| sizeof unary_expr  %prec UNARY
 		{ skip_evaluation--;
-		  if (TREE_CODE ($2) == COMPONENT_REF
-		      && DECL_C_BIT_FIELD (TREE_OPERAND ($2, 1)))
+		  if (TREE_CODE ($2.value) == COMPONENT_REF
+		      && DECL_C_BIT_FIELD (TREE_OPERAND ($2.value, 1)))
 		    error ("`sizeof' applied to a bit-field");
-		  $$ = c_sizeof (TREE_TYPE ($2)); }
+		  $$.value = c_sizeof (TREE_TYPE ($2.value));
+		  $$.original_code = ERROR_MARK; }
 	| sizeof '(' typename ')'  %prec HYPERUNARY
 		{ skip_evaluation--;
-		  $$ = c_sizeof (groktypename ($3)); }
+		  $$.value = c_sizeof (groktypename ($3));
+		  $$.original_code = ERROR_MARK; }
 	| alignof unary_expr  %prec UNARY
 		{ skip_evaluation--;
-		  $$ = c_alignof_expr ($2); }
+		  $$.value = c_alignof_expr ($2.value);
+		  $$.original_code = ERROR_MARK; }
 	| alignof '(' typename ')'  %prec HYPERUNARY
 		{ skip_evaluation--;
-		  $$ = c_alignof (groktypename ($3)); }
+		  $$.value = c_alignof (groktypename ($3));
+		  $$.original_code = ERROR_MARK; }
 	| REALPART cast_expr %prec UNARY
-		{ $$ = build_unary_op (REALPART_EXPR, $2, 0); }
+		{ $$.value = build_unary_op (REALPART_EXPR, $2.value, 0);
+		  $$.original_code = ERROR_MARK; }
 	| IMAGPART cast_expr %prec UNARY
-		{ $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
+		{ $$.value = build_unary_op (IMAGPART_EXPR, $2.value, 0);
+		  $$.original_code = ERROR_MARK; }
 	;
 
 sizeof:
@@ -529,7 +541,8 @@ typeof:
 cast_expr:
 	unary_expr
 	| '(' typename ')' cast_expr  %prec UNARY
-		{ $$ = c_cast_expr ($2, $4); }
+		{ $$.value = c_cast_expr ($2, $4.value);
+		  $$.original_code = ERROR_MARK; }
 	;
 
 expr_no_commas:
@@ -559,54 +572,51 @@ expr_no_commas:
 	| expr_no_commas '^' expr_no_commas
 		{ $$ = parser_build_binary_op ($2, $1, $3); }
 	| expr_no_commas ANDAND
-		{ $1 = lang_hooks.truthvalue_conversion
-		    (default_conversion ($1));
-		  skip_evaluation += $1 == truthvalue_false_node; }
+		{ $1.value = lang_hooks.truthvalue_conversion
+		    (default_conversion ($1.value));
+		  skip_evaluation += $1.value == truthvalue_false_node; }
 	  expr_no_commas
-		{ skip_evaluation -= $1 == truthvalue_false_node;
+		{ skip_evaluation -= $1.value == truthvalue_false_node;
 		  $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
 	| expr_no_commas OROR
-		{ $1 = lang_hooks.truthvalue_conversion
-		    (default_conversion ($1));
-		  skip_evaluation += $1 == truthvalue_true_node; }
+		{ $1.value = lang_hooks.truthvalue_conversion
+		    (default_conversion ($1.value));
+		  skip_evaluation += $1.value == truthvalue_true_node; }
 	  expr_no_commas
-		{ skip_evaluation -= $1 == truthvalue_true_node;
+		{ skip_evaluation -= $1.value == truthvalue_true_node;
 		  $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); }
 	| expr_no_commas '?'
-		{ $1 = lang_hooks.truthvalue_conversion
-		    (default_conversion ($1));
-		  skip_evaluation += $1 == truthvalue_false_node; }
+		{ $1.value = lang_hooks.truthvalue_conversion
+		    (default_conversion ($1.value));
+		  skip_evaluation += $1.value == truthvalue_false_node; }
           expr ':'
-		{ skip_evaluation += (($1 == truthvalue_true_node)
-				      - ($1 == truthvalue_false_node)); }
+		{ skip_evaluation += (($1.value == truthvalue_true_node)
+				      - ($1.value == truthvalue_false_node)); }
 	  expr_no_commas
-		{ skip_evaluation -= $1 == truthvalue_true_node;
-		  $$ = build_conditional_expr ($1, $4, $7); }
+		{ skip_evaluation -= $1.value == truthvalue_true_node;
+		  $$.value = build_conditional_expr ($1.value, $4.value,
+						     $7.value);
+		  $$.original_code = ERROR_MARK; }
 	| expr_no_commas '?'
 		{ if (pedantic)
 		    pedwarn ("ISO C forbids omitting the middle term of a ?: expression");
 		  /* Make sure first operand is calculated only once.  */
-		  $<ttype>2 = save_expr (default_conversion ($1));
-		  $1 = lang_hooks.truthvalue_conversion ($<ttype>2);
-		  skip_evaluation += $1 == truthvalue_true_node; }
+		  $<ttype>2 = save_expr (default_conversion ($1.value));
+		  $1.value = lang_hooks.truthvalue_conversion ($<ttype>2);
+		  skip_evaluation += $1.value == truthvalue_true_node; }
 	  ':' expr_no_commas
-		{ skip_evaluation -= $1 == truthvalue_true_node;
-		  $$ = build_conditional_expr ($1, $<ttype>2, $5); }
+		{ skip_evaluation -= $1.value == truthvalue_true_node;
+		  $$.value = build_conditional_expr ($1.value, $<ttype>2,
+						     $5.value);
+		  $$.original_code = ERROR_MARK; }
 	| expr_no_commas '=' expr_no_commas
-		{ char class;
-		  $$ = build_modify_expr ($1, NOP_EXPR, $3);
-		  class = TREE_CODE_CLASS (TREE_CODE ($$));
-		  if (IS_EXPR_CODE_CLASS (class))
-		    C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR);
+		{ $$.value = build_modify_expr ($1.value, NOP_EXPR, $3.value);
+		  $$.original_code = MODIFY_EXPR;
 		}
 	| expr_no_commas ASSIGN expr_no_commas
-		{ char class;
-		  $$ = build_modify_expr ($1, $2, $3);
-		  /* This inhibits warnings in
-		     c_common_truthvalue_conversion.  */
-		  class = TREE_CODE_CLASS (TREE_CODE ($$));
-		  if (IS_EXPR_CODE_CLASS (class))
-		    C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK);
+		{ $$.value = build_modify_expr ($1.value, $2, $3.value);
+		  TREE_NO_WARNING ($$.value) = 1;
+		  $$.original_code = ERROR_MARK;
 		}
 	;
 
@@ -615,12 +625,16 @@ primary:
 		{
 		  if (yychar == YYEMPTY)
 		    yychar = YYLEX;
-		  $$ = build_external_ref ($1, yychar == '(');
+		  $$.value = build_external_ref ($1, yychar == '(');
+		  $$.original_code = ERROR_MARK;
 		}
 	| CONSTANT
+		{ $$.value = $1; $$.original_code = ERROR_MARK; }
 	| STRING
+		{ $$.value = $1; $$.original_code = ERROR_MARK; }
 	| FUNC_NAME
-		{ $$ = fname_decl (C_RID_CODE ($$), $$); }
+		{ $$.value = fname_decl (C_RID_CODE ($1), $1);
+		  $$.original_code = ERROR_MARK; }
 	| '(' typename ')' '{'
 		{ start_init (NULL_TREE, NULL, 0);
 		  $2 = groktypename ($2);
@@ -632,39 +646,45 @@ primary:
 
 		  if (pedantic && ! flag_isoc99)
 		    pedwarn ("ISO C90 forbids compound literals");
-		  $$ = build_compound_literal (type, constructor);
+		  $$.value = build_compound_literal (type, constructor);
+		  $$.original_code = ERROR_MARK;
 		}
 	| '(' expr ')'
-		{ char class = TREE_CODE_CLASS (TREE_CODE ($2));
-		  if (IS_EXPR_CODE_CLASS (class))
-		    C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
-		  $$ = $2; }
+		{ $$.value = $2.value;
+		  if (TREE_CODE ($$.value) == MODIFY_EXPR)
+		    TREE_NO_WARNING ($$.value) = 1;
+		  $$.original_code = ERROR_MARK; }
 	| '(' error ')'
-		{ $$ = error_mark_node; }
+		{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
 	| compstmt_primary_start compstmt_nostart ')'
                 { if (pedantic)
 		    pedwarn ("ISO C forbids braced-groups within expressions");
-		  $$ = c_finish_stmt_expr ($1);
+		  $$.value = c_finish_stmt_expr ($1);
+		  $$.original_code = ERROR_MARK;
 		}
 	| compstmt_primary_start error ')'
 		{ c_finish_stmt_expr ($1);
-		  $$ = error_mark_node;
+		  $$.value = error_mark_node;
+		  $$.original_code = ERROR_MARK;
 		}
 	| primary '(' exprlist ')'   %prec '.'
-		{ $$ = build_function_call ($1, $3); }
+		{ $$.value = build_function_call ($1.value, $3);
+		  $$.original_code = ERROR_MARK; }
 	| VA_ARG '(' expr_no_commas ',' typename ')'
-		{ $$ = build_va_arg ($3, groktypename ($5)); }
+		{ $$.value = build_va_arg ($3.value, groktypename ($5));
+		  $$.original_code = ERROR_MARK; }
 
 	| OFFSETOF '(' typename ',' offsetof_member_designator ')'
-		{ $$ = build_offsetof (groktypename ($3), $5); }
+		{ $$.value = build_offsetof (groktypename ($3), $5);
+		  $$.original_code = ERROR_MARK; }
 	| OFFSETOF '(' error ')'
-		{ $$ = error_mark_node; }
+		{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
 	| CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ','
 			  expr_no_commas ')'
 		{
                   tree c;
 
-                  c = fold ($3);
+                  c = fold ($3.value);
                   STRIP_NOPS (c);
                   if (TREE_CODE (c) != INTEGER_CST)
                     error ("first argument to __builtin_choose_expr not"
@@ -672,7 +692,7 @@ primary:
                   $$ = integer_zerop (c) ? $7 : $5;
 		}
 	| CHOOSE_EXPR '(' error ')'
-		{ $$ = error_mark_node; }
+		{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
 	| TYPES_COMPATIBLE_P '(' typename ',' typename ')'
 		{
 		  tree e1, e2;
@@ -680,35 +700,46 @@ primary:
 		  e1 = TYPE_MAIN_VARIANT (groktypename ($3));
 		  e2 = TYPE_MAIN_VARIANT (groktypename ($5));
 
-		  $$ = comptypes (e1, e2)
+		  $$.value = comptypes (e1, e2)
 		    ? build_int_2 (1, 0) : build_int_2 (0, 0);
+		  $$.original_code = ERROR_MARK;
 		}
 	| TYPES_COMPATIBLE_P '(' error ')'
-		{ $$ = error_mark_node; }
+		{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
 	| primary '[' expr ']'   %prec '.'
-		{ $$ = build_array_ref ($1, $3); }
+		{ $$.value = build_array_ref ($1.value, $3.value);
+		  $$.original_code = ERROR_MARK; }
 	| primary '.' identifier
-		{ $$ = build_component_ref ($1, $3); }
+		{ $$.value = build_component_ref ($1.value, $3);
+		  $$.original_code = ERROR_MARK; }
 	| primary POINTSAT identifier
 		{
-                  tree expr = build_indirect_ref ($1, "->");
-		  $$ = build_component_ref (expr, $3);
+                  tree expr = build_indirect_ref ($1.value, "->");
+		  $$.value = build_component_ref (expr, $3);
+		  $$.original_code = ERROR_MARK;
 		}
 	| primary PLUSPLUS
-		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
+		{ $$.value = build_unary_op (POSTINCREMENT_EXPR, $1.value, 0);
+		  $$.original_code = ERROR_MARK; }
 	| primary MINUSMINUS
-		{ $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
+		{ $$.value = build_unary_op (POSTDECREMENT_EXPR, $1.value, 0);
+		  $$.original_code = ERROR_MARK; }
 @@ifobjc
 	| objcmessageexpr
-		{ $$ = build_message_expr ($1); }
+		{ $$.value = build_message_expr ($1);
+		  $$.original_code = ERROR_MARK; }
 	| objcselectorexpr
-		{ $$ = build_selector_expr ($1); }
+		{ $$.value = build_selector_expr ($1);
+		  $$.original_code = ERROR_MARK; }
 	| objcprotocolexpr
-		{ $$ = build_protocol_expr ($1); }
+		{ $$.value = build_protocol_expr ($1);
+		  $$.original_code = ERROR_MARK; }
 	| objcencodeexpr
-		{ $$ = build_encode_expr ($1); }
+		{ $$.value = build_encode_expr ($1);
+		  $$.original_code = ERROR_MARK; }
 	| OBJC_STRING
-		{ $$ = build_objc_string_object ($1); }
+		{ $$.value = build_objc_string_object ($1);
+		  $$.original_code = ERROR_MARK; }
 @@end_ifobjc
 	;
 
@@ -724,7 +755,7 @@ offsetof_member_designator:
 	| offsetof_member_designator '.' identifier
 		{ $$ = tree_cons ($3, NULL_TREE, $1); }
 	| offsetof_member_designator '[' expr ']'
-		{ $$ = tree_cons (NULL_TREE, $3, $1); }
+		{ $$ = tree_cons (NULL_TREE, $3.value, $1); }
 	;
 
 old_style_parm_decls:
@@ -1332,10 +1363,10 @@ typespec_nonreserved_nonattr:
 @@end_ifobjc
 	| typeof '(' expr ')'
 		{ skip_evaluation--;
-		  if (TREE_CODE ($3) == COMPONENT_REF
-		      && DECL_C_BIT_FIELD (TREE_OPERAND ($3, 1)))
+		  if (TREE_CODE ($3.value) == COMPONENT_REF
+		      && DECL_C_BIT_FIELD (TREE_OPERAND ($3.value, 1)))
 		    error ("`typeof' applied to a bit-field");
-		  $$ = TREE_TYPE ($3); }
+		  $$ = TREE_TYPE ($3.value); }
 	| typeof '(' typename ')'
 		{ skip_evaluation--; $$ = groktypename ($3); }
 	;
@@ -1445,6 +1476,7 @@ scspec:
 
 init:
 	expr_no_commas
+		{ $$ = $1.value; }
 	| '{'
 		{ really_start_incremental_init (NULL_TREE); }
 	  initlist_maybe_comma '}'
@@ -1490,7 +1522,7 @@ initval:
 	  initlist_maybe_comma '}'
 		{ process_init_element (pop_init_level (0)); }
 	| expr_no_commas
-		{ process_init_element ($1); }
+		{ process_init_element ($1.value); }
 	| error
 	;
 
@@ -1503,11 +1535,11 @@ designator:
 	  '.' identifier
 		{ set_init_label ($2); }
 	| '[' expr_no_commas ELLIPSIS expr_no_commas ']'
-		{ set_init_index ($2, $4);
+		{ set_init_index ($2.value, $4.value);
 		  if (pedantic)
 		    pedwarn ("ISO C forbids specifying range of elements to initialize"); }
 	| '[' expr_no_commas ']'
-		{ set_init_index ($2, NULL_TREE); }
+		{ set_init_index ($2.value, NULL_TREE); }
 	;
 
 nested_function:
@@ -1809,11 +1841,11 @@ component_declarator:
 		  decl_attributes (&$$,
 				   chainon ($2, all_prefix_attributes), 0); }
 	| declarator ':' expr_no_commas maybe_attribute
-		{ $$ = grokfield ($1, current_declspecs, $3);
+		{ $$ = grokfield ($1, current_declspecs, $3.value);
 		  decl_attributes (&$$,
 				   chainon ($4, all_prefix_attributes), 0); }
 	| ':' expr_no_commas maybe_attribute
-		{ $$ = grokfield (NULL_TREE, current_declspecs, $2);
+		{ $$ = grokfield (NULL_TREE, current_declspecs, $2.value);
 		  decl_attributes (&$$,
 				   chainon ($3, all_prefix_attributes), 0); }
 	;
@@ -1824,11 +1856,11 @@ component_notype_declarator:
 		  decl_attributes (&$$,
 				   chainon ($2, all_prefix_attributes), 0); }
 	| notype_declarator ':' expr_no_commas maybe_attribute
-		{ $$ = grokfield ($1, current_declspecs, $3);
+		{ $$ = grokfield ($1, current_declspecs, $3.value);
 		  decl_attributes (&$$,
 				   chainon ($4, all_prefix_attributes), 0); }
 	| ':' expr_no_commas maybe_attribute
-		{ $$ = grokfield (NULL_TREE, current_declspecs, $2);
+		{ $$ = grokfield (NULL_TREE, current_declspecs, $2.value);
 		  decl_attributes (&$$,
 				   chainon ($3, all_prefix_attributes), 0); }
 	;
@@ -1852,7 +1884,7 @@ enumerator:
 	  identifier
 		{ $$ = build_enumerator ($1, NULL_TREE); }
 	| identifier '=' expr_no_commas
-		{ $$ = build_enumerator ($1, $3); }
+		{ $$ = build_enumerator ($1, $3.value); }
 	;
 
 typename:
@@ -1919,16 +1951,16 @@ direct_absdcl1:
 
 array_declarator:
 	'[' maybe_type_quals_attrs expr_no_commas ']'
-		{ $$ = build_array_declarator ($3, $2, 0, 0); }
+		{ $$ = build_array_declarator ($3.value, $2, 0, 0); }
 	| '[' maybe_type_quals_attrs ']'
 		{ $$ = build_array_declarator (NULL_TREE, $2, 0, 0); }
 	| '[' maybe_type_quals_attrs '*' ']'
 		{ $$ = build_array_declarator (NULL_TREE, $2, 0, 1); }
 	| '[' STATIC maybe_type_quals_attrs expr_no_commas ']'
-		{ $$ = build_array_declarator ($4, $3, 1, 0); }
+		{ $$ = build_array_declarator ($4.value, $3, 1, 0); }
 	/* declspecs_nosc_nots is a synonym for type_quals_attrs.  */
 	| '[' declspecs_nosc_nots STATIC expr_no_commas ']'
-		{ $$ = build_array_declarator ($4, $2, 1, 0); }
+		{ $$ = build_array_declarator ($4.value, $2, 1, 0); }
 	;
 
 /* A nonempty series of declarations and statements (possibly followed by
@@ -2102,7 +2134,7 @@ lineno_label:
 	;
 
 condition: save_location expr
-		{ $$ = lang_hooks.truthvalue_conversion ($2);
+		{ $$ = lang_hooks.truthvalue_conversion ($2.value);
 		  if (EXPR_P ($$))
 		    SET_EXPR_LOCATION ($$, $1); }
 	;
@@ -2177,6 +2209,7 @@ xexpr:
 	/* empty */
 		{ $$ = NULL_TREE; }
 	| expr
+		{ $$ = $1.value; }
 	;
 
 for_init_stmt:
@@ -2214,7 +2247,7 @@ for_statement:
 
 switch_statement:
 	SWITCH c99_block_start '(' expr ')'
-		{ $<ttype>$ = c_start_case ($4); }
+		{ $<ttype>$ = c_start_case ($4.value); }
 	start_break c99_block_lineno_labeled_stmt
                 { c_finish_case ($8);
 		  if (c_break_label)
@@ -2227,7 +2260,7 @@ switch_statement:
 /* Parse a single real statement, not including any labels or compounds.  */
 stmt_nocomp:
 	  expr ';'
-		{ $$ = c_finish_expr_stmt ($1); }
+		{ $$ = c_finish_expr_stmt ($1.value); }
 	| if_statement
 		{ $$ = NULL_TREE; }
 	| while_statement
@@ -2245,23 +2278,23 @@ stmt_nocomp:
 	| RETURN ';'
                 { $$ = c_finish_return (NULL_TREE); }
 	| RETURN expr ';'
-                { $$ = c_finish_return ($2); }
+                { $$ = c_finish_return ($2.value); }
 	| asm_stmt
 	| GOTO identifier ';'
 		{ $$ = c_finish_goto_label ($2); }
 	| GOTO '*' expr ';'
-		{ $$ = c_finish_goto_ptr ($3); }
+		{ $$ = c_finish_goto_ptr ($3.value); }
 	| ';'
 		{ $$ = NULL_TREE; }
 @@ifobjc
 	| AT_THROW expr ';'
-		{ $$ = objc_build_throw_stmt ($2); }
+		{ $$ = objc_build_throw_stmt ($2.value); }
 	| AT_THROW ';'
 		{ $$ = objc_build_throw_stmt (NULL_TREE); }
 	| objc_try_catch_stmt
 		{ $$ = NULL_TREE; }
 	| AT_SYNCHRONIZED save_location '(' expr ')' compstmt
-		{ objc_build_synchronized ($2, $4, $6); $$ = NULL_TREE; }
+		{ objc_build_synchronized ($2, $4.value, $6); $$ = NULL_TREE; }
 	;
 
 objc_catch_prefix:
@@ -2312,9 +2345,9 @@ stmt:
    also at the end of a compound statement.  */
 
 label:	  CASE expr_no_commas ':'
-                { $$ = do_case ($2, NULL_TREE); }
+                { $$ = do_case ($2.value, NULL_TREE); }
 	| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
-                { $$ = do_case ($2, $4); }
+                { $$ = do_case ($2.value, $4.value); }
 	| DEFAULT ':'
                 { $$ = do_case (NULL_TREE, NULL_TREE); }
 	| identifier save_location ':' maybe_attribute
@@ -2408,12 +2441,13 @@ nonnull_asm_operands:
 
 asm_operand:
 	  STRING start_string_translation '(' expr ')' stop_string_translation
-		{ $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $4); }
+		{ $$ = build_tree_list (build_tree_list (NULL_TREE, $1),
+					$4.value); }
 	| '[' identifier ']' STRING start_string_translation
 	  '(' expr ')' stop_string_translation
 		{ $2 = build_string (IDENTIFIER_LENGTH ($2),
 				     IDENTIFIER_POINTER ($2));
-		  $$ = build_tree_list (build_tree_list ($2, $4), $7); }
+		  $$ = build_tree_list (build_tree_list ($2, $4), $7.value); }
 	;
 
 asm_clobbers:
@@ -2805,14 +2839,14 @@ ivar_declarator:
 		{
 		  $$ = add_instance_variable (objc_ivar_context,
 					      objc_public_flag,
-					      $1, current_declspecs, $3);
+					      $1, current_declspecs, $3.value);
                 }
 	| ':' expr_no_commas
 		{
 		  $$ = add_instance_variable (objc_ivar_context,
 					      objc_public_flag,
 					      NULL_TREE,
-					      current_declspecs, $2);
+					      current_declspecs, $2.value);
                 }
 	;
 
@@ -3068,6 +3102,7 @@ keywordarg:
 
 receiver:
 	  expr
+		{ $$ = $1.value; }
 	| CLASSNAME
 		{
 		  $$ = get_class_reference ($1);
diff -rupN GCC.bosscher/gcc/c-tree.h GCC.cexp/gcc/c-tree.h
--- GCC.bosscher/gcc/c-tree.h	2004-07-17 19:25:20.000000000 +0000
+++ GCC.cexp/gcc/c-tree.h	2004-07-17 23:42:26.000000000 +0000
@@ -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, t
 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);
diff -rupN GCC.bosscher/gcc/c-typeck.c GCC.cexp/gcc/c-typeck.c
--- GCC.bosscher/gcc/c-typeck.c	2004-07-17 09:17:30.000000000 +0000
+++ GCC.cexp/gcc/c-typeck.c	2004-07-18 14:26:34.000000000 +0000
@@ -62,7 +62,6 @@ static tree default_function_array_conve
 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 = 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 v
    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 c
 
     }
 
-  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
   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)
-{
-  return internal_build_compound_expr (list, TRUE);
-}
-
-static tree
-internal_build_compound_expr (tree list, int first_p)
+build_compound_expr (tree expr1, tree expr2)
 {
-  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,
      `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.  */
diff -rupN GCC.bosscher/gcc/cp/typeck.c GCC.cexp/gcc/cp/typeck.c
--- GCC.bosscher/gcc/cp/typeck.c	2004-07-12 16:22:29.000000000 +0000
+++ GCC.cexp/gcc/cp/typeck.c	2004-07-18 00:15:03.000000000 +0000
@@ -4977,6 +4977,7 @@ build_modify_expr (tree lhs, enum tree_c
   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)
@@ -5236,6 +5237,8 @@ build_modify_expr (tree lhs, enum tree_c
 		  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
@@ -5267,7 +5270,10 @@ build_x_modify_expr (tree lhs, enum tree
 				make_node (modifycode),
 				/*overloaded_p=*/NULL);
       if (rval)
-	return rval;
+	{
+	  TREE_NO_WARNING (rval) = 1;
+	  return rval;
+	}
     }
   return build_modify_expr (lhs, modifycode, rhs);
 }
diff -rupN GCC.bosscher/gcc/objc/objc-act.c GCC.cexp/gcc/objc/objc-act.c
--- GCC.bosscher/gcc/objc/objc-act.c	2004-07-10 07:51:49.000000000 +0000
+++ GCC.cexp/gcc/objc/objc-act.c	2004-07-17 21:56:19.000000000 +0000
@@ -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
     {
diff -rupN GCC.bosscher/gcc/testsuite/g++.dg/warn/Wparentheses-1.C GCC.cexp/gcc/testsuite/g++.dg/warn/Wparentheses-1.C
--- GCC.bosscher/gcc/testsuite/g++.dg/warn/Wparentheses-1.C	1970-01-01 00:00:00.000000000 +0000
+++ GCC.cexp/gcc/testsuite/g++.dg/warn/Wparentheses-1.C	2004-07-17 23:59:12.000000000 +0000
@@ -0,0 +1,68 @@
+// 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);
+}
diff -rupN GCC.bosscher/gcc/testsuite/g++.dg/warn/Wparentheses-2.C GCC.cexp/gcc/testsuite/g++.dg/warn/Wparentheses-2.C
--- GCC.bosscher/gcc/testsuite/g++.dg/warn/Wparentheses-2.C	1970-01-01 00:00:00.000000000 +0000
+++ GCC.cexp/gcc/testsuite/g++.dg/warn/Wparentheses-2.C	2004-07-18 00:00:03.000000000 +0000
@@ -0,0 +1,43 @@
+// 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);
+}
diff -rupN GCC.bosscher/gcc/testsuite/gcc.dg/Wparentheses-10.c GCC.cexp/gcc/testsuite/gcc.dg/Wparentheses-10.c
--- GCC.bosscher/gcc/testsuite/gcc.dg/Wparentheses-10.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC.cexp/gcc/testsuite/gcc.dg/Wparentheses-10.c	2004-07-18 00:00:10.000000000 +0000
@@ -0,0 +1,42 @@
+/* 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);
+}
diff -rupN GCC.bosscher/gcc/testsuite/gcc.dg/Wparentheses-5.c GCC.cexp/gcc/testsuite/gcc.dg/Wparentheses-5.c
--- GCC.bosscher/gcc/testsuite/gcc.dg/Wparentheses-5.c	2004-07-17 09:17:30.000000000 +0000
+++ GCC.cexp/gcc/testsuite/gcc.dg/Wparentheses-5.c	2004-07-17 23:46:51.000000000 +0000
@@ -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" } */


More information about the Gcc-patches mailing list