aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog31
-rw-r--r--gcc/c-common.c4
-rw-r--r--gcc/c-common.h4
-rw-r--r--gcc/c-parse.in253
-rw-r--r--gcc/c-tree.h21
-rw-r--r--gcc/c-typeck.c103
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/typeck.c8
-rw-r--r--gcc/objc/objc-act.c8
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/warn/Wparentheses-1.C68
-rw-r--r--gcc/testsuite/g++.dg/warn/Wparentheses-2.C43
-rw-r--r--gcc/testsuite/gcc.dg/Wparentheses-10.c42
-rw-r--r--gcc/testsuite/gcc.dg/Wparentheses-5.c4
14 files changed, 399 insertions, 201 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ec21efa..b1053bf 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,34 @@
+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.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index b729fd8..1966b0d 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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;
diff --git a/gcc/c-common.h b/gcc/c-common.h
index ba7a2f8..89fc7ee 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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 --git a/gcc/c-parse.in b/gcc/c-parse.in
index d701391..b56bfee 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -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 --git a/gcc/c-tree.h b/gcc/c-tree.h
index 7cb69ba..d6cdc97 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -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);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 4befd126..29a9ec3 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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. */
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 66c5480..00ef4b5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,8 @@
+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>
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 21e7fe4..0e23e9a 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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);
}
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index cdb59d0..0da09ae 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 59db09f..6df5bc9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+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
diff --git a/gcc/testsuite/g++.dg/warn/Wparentheses-1.C b/gcc/testsuite/g++.dg/warn/Wparentheses-1.C
new file mode 100644
index 0000000..34cb58f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wparentheses-1.C
@@ -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 --git a/gcc/testsuite/g++.dg/warn/Wparentheses-2.C b/gcc/testsuite/g++.dg/warn/Wparentheses-2.C
new file mode 100644
index 0000000..286e2f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wparentheses-2.C
@@ -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 --git a/gcc/testsuite/gcc.dg/Wparentheses-10.c b/gcc/testsuite/gcc.dg/Wparentheses-10.c
new file mode 100644
index 0000000..aafcae2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wparentheses-10.c
@@ -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 --git a/gcc/testsuite/gcc.dg/Wparentheses-5.c b/gcc/testsuite/gcc.dg/Wparentheses-5.c
index be12f73..49c65c2 100644
--- a/gcc/testsuite/gcc.dg/Wparentheses-5.c
+++ b/gcc/testsuite/gcc.dg/Wparentheses-5.c
@@ -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" } */