diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 536221ec0ac..c4d01e69579 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,39 @@ +2003-07-16 Mark Mitchell + + PR c++/11547 + * cp-tree.h (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P): New + macro. + (DECL_PRETTY_FUNCTION_P): Use VAR_DECL_CHECK. + * decl.c (duplicate_decls): Merge + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. + * parser.c (cp_parser_postfix_expression): Adjust call to + cp_parser_initializer_list and + cp_parser_parenthesized_expression_list. + (cp_parser_parenthesized_expression_list): Add non_constant_p. + (cp_parser_new_placement): Adjust call to + cp_parser_parenthesized_expression_list. + (cp_parser_direct_new_declarator): Likewise. + (cp_parser_conditional_expression): Remove. + (cp_parser_constant_expression): Parse an assignment-expression, + not a conditional-expression. + (cp_parser_simple_declaration): Resolve expression/declaration + ambiguity more quickly. + (cp_parser_mem_initializer): Adjust call to + cp_parser_parenthesized_expression_list. + (cp_parser_init_declarator): Keep track of whether or not the + initializer is a constant-expression. + (cp_parser_initializer): Add non_constant_p parameter. + (cp_parser_initializer_clause): Likewise. + (cp_parser_initializer_list): Likewise. + (cp_parser_attribute_list): Adjust call to + cp_parser_parenthesized_expression_list. + (cp_parser_functional_cast): Likewise. + * pt.c (tsubst_decl): Copy + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. + (tsubst_expr): Tweak use of DECL_PRETTY_FUNCTION_P. + * semantics.c (finish_id_expression): Use + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. + 2003-07-16 Neil Booth * lang-options.h: Remove. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 40f3784fc9b..1728b379353 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -45,6 +45,7 @@ struct diagnostic_context; AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF) PARMLIST_ELLIPSIS_P (in PARMLIST) + DECL_PRETTY_FUNCTION_P (in VAR_DECL) 1: IDENTIFIER_VIRTUAL_P. TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -59,6 +60,7 @@ struct diagnostic_context; ICS_THIS_FLAG (in _CONV) BINFO_LOST_PRIMARY_P (in BINFO) TREE_PARMLIST (in TREE_LIST) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) 3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE). BINFO_VTABLE_PATH_MARKED. BINFO_PUSHDECLS_MARKED. @@ -1926,6 +1928,11 @@ struct lang_decl GTY(()) #define DECL_INITIALIZED_P(NODE) \ (TREE_LANG_FLAG_1 (VAR_DECL_CHECK (NODE))) +/* Nonzero for a VAR_DECL that was initialized with a + constant-expression. */ +#define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE) \ + (TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE))) + /* Nonzero if the DECL was initialized in the class definition itself, rather than outside the class. This is used for both static member VAR_DECLS, and FUNTION_DECLS that are defined in the class. */ @@ -2033,7 +2040,7 @@ struct lang_decl GTY(()) /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a template function. */ #define DECL_PRETTY_FUNCTION_P(NODE) \ - (TREE_LANG_FLAG_0 (NODE)) + (TREE_LANG_FLAG_0 (VAR_DECL_CHECK (NODE))) /* The _TYPE context in which this _DECL appears. This field holds the class where a virtual function instance is actually defined. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1dd2ddf7a94..62ecbc487b4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3306,6 +3306,8 @@ duplicate_decls (tree newdecl, tree olddecl) { DECL_THIS_EXTERN (newdecl) |= DECL_THIS_EXTERN (olddecl); DECL_INITIALIZED_P (newdecl) |= DECL_INITIALIZED_P (olddecl); + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl) + |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); } /* Do this after calling `merge_types' so that default diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 33f1d793ce0..8af9f46d7f1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1311,7 +1311,7 @@ static tree cp_parser_class_or_namespace_name static tree cp_parser_postfix_expression (cp_parser *, bool); static tree cp_parser_parenthesized_expression_list - (cp_parser *, bool); + (cp_parser *, bool, bool *); static void cp_parser_pseudo_destructor_name (cp_parser *, tree *, tree *); static tree cp_parser_unary_expression @@ -1356,8 +1356,6 @@ static tree cp_parser_logical_and_expression (cp_parser *); static tree cp_parser_logical_or_expression (cp_parser *); -static tree cp_parser_conditional_expression - (cp_parser *); static tree cp_parser_question_colon_clause (cp_parser *, tree); static tree cp_parser_assignment_expression @@ -1479,11 +1477,11 @@ static tree cp_parser_function_definition static void cp_parser_function_body (cp_parser *); static tree cp_parser_initializer - (cp_parser *, bool *); + (cp_parser *, bool *, bool *); static tree cp_parser_initializer_clause - (cp_parser *); + (cp_parser *, bool *); static tree cp_parser_initializer_list - (cp_parser *); + (cp_parser *, bool *); static bool cp_parser_ctor_initializer_opt_and_function_body (cp_parser *); @@ -3375,9 +3373,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) keep going. */ if (!cp_parser_error_occurred (parser)) { + bool non_constant_p; /* Parse the initializer-list. */ initializer_list - = cp_parser_initializer_list (parser); + = cp_parser_initializer_list (parser, &non_constant_p); /* Allow a trailing `,'. */ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) cp_lexer_consume_token (parser->lexer); @@ -3472,7 +3471,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) case CPP_OPEN_PAREN: /* postfix-expression ( expression-list [opt] ) */ { - tree args = cp_parser_parenthesized_expression_list (parser, false); + tree args = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); if (args == error_mark_node) { @@ -3735,14 +3735,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) error_mark_node is returned if the ( and or ) are missing. NULL_TREE is returned on no expressions. The parentheses are eaten. IS_ATTRIBUTE_LIST is true if this is really an attribute - list being parsed. */ + list being parsed. If NON_CONSTANT_P is non-NULL, *NON_CONSTANT_P + indicates whether or not all of the expressions in the list were + constant. */ static tree -cp_parser_parenthesized_expression_list (cp_parser* parser, bool is_attribute_list) +cp_parser_parenthesized_expression_list (cp_parser* parser, + bool is_attribute_list, + bool *non_constant_p) { tree expression_list = NULL_TREE; tree identifier = NULL_TREE; - + + /* Assume all the expressions will be constant. */ + if (non_constant_p) + *non_constant_p = false; + if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('")) return error_mark_node; @@ -3767,7 +3775,17 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, bool is_attribute_li else { /* Parse the next assignment-expression. */ - expr = cp_parser_assignment_expression (parser); + if (non_constant_p) + { + bool expr_non_constant_p; + expr = (cp_parser_constant_expression + (parser, /*allow_non_constant_p=*/true, + &expr_non_constant_p)); + if (expr_non_constant_p) + *non_constant_p = true; + } + else + expr = cp_parser_assignment_expression (parser); /* Add it to the list. We add error_mark_node expressions to the list, so that we can still tell if @@ -4177,7 +4195,8 @@ cp_parser_new_placement (cp_parser* parser) tree expression_list; /* Parse the expression-list. */ - expression_list = cp_parser_parenthesized_expression_list (parser, false); + expression_list = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); return expression_list; } @@ -4341,7 +4360,8 @@ cp_parser_new_initializer (cp_parser* parser) { tree expression_list; - expression_list = cp_parser_parenthesized_expression_list (parser, false); + expression_list = (cp_parser_parenthesized_expression_list + (parser, false, /*non_constant_p=*/NULL)); if (!expression_list) expression_list = void_zero_node; @@ -4755,43 +4775,12 @@ cp_parser_logical_or_expression (cp_parser* parser) cp_parser_logical_and_expression); } -/* Parse a conditional-expression. - - conditional-expression: - logical-or-expression - logical-or-expression ? expression : assignment-expression - - GNU Extensions: - - conditional-expression: - logical-or-expression ? : assignment-expression - - Returns a representation of the expression. */ - -static tree -cp_parser_conditional_expression (cp_parser* parser) -{ - tree logical_or_expr; - - /* Parse the logical-or-expression. */ - logical_or_expr = cp_parser_logical_or_expression (parser); - /* If the next token is a `?', then we have a real conditional - expression. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) - return cp_parser_question_colon_clause (parser, logical_or_expr); - /* Otherwise, the value is simply the logical-or-expression. */ - else - return logical_or_expr; -} - /* Parse the `? expression : assignment-expression' part of a conditional-expression. The LOGICAL_OR_EXPR is the logical-or-expression that started the conditional-expression. Returns a representation of the entire conditional-expression. - This routine exists only so that it can be shared between - cp_parser_conditional_expression and - cp_parser_assignment_expression. + This routine is used by cp_parser_assignment_expression. ? expression : assignment-expression @@ -5071,8 +5060,16 @@ cp_parser_constant_expression (cp_parser* parser, parser->constant_expression_p = true; parser->allow_non_constant_expression_p = allow_non_constant_p; parser->non_constant_expression_p = false; - /* Parse the conditional-expression. */ - expression = cp_parser_conditional_expression (parser); + /* Although the grammar says "conditional-expression", we parse an + "assignment-expression", which also permits "throw-expression" + and the use of assignment operators. In the case that + ALLOW_NON_CONSTANT_P is false, we get better errors than we would + otherwise. In the case that ALLOW_NON_CONSTANT_P is true, it is + actually essential that we look for an assignment-expression. + For example, cp_parser_initializer_clauses uses this function to + determine whether a particular assignment-expression is in fact + constant. */ + expression = cp_parser_assignment_expression (parser); /* Restore the old settings. */ parser->constant_expression_p = saved_constant_expression_p; parser->allow_non_constant_expression_p @@ -6081,6 +6078,15 @@ cp_parser_simple_declaration (cp_parser* parser, /* We no longer need to defer access checks. */ stop_deferring_access_checks (); + /* In a block scope, a valid declaration must always have a + decl-specifier-seq. By not trying to parse declarators, we can + resolve the declaration/expression ambiguity more quickly. */ + if (!function_definition_allowed_p && !decl_specifiers) + { + cp_parser_error (parser, "expected declaration"); + goto done; + } + /* If the next two tokens are both identifiers, the code is erroneous. The usual cause of this situation is code like: @@ -6093,7 +6099,7 @@ cp_parser_simple_declaration (cp_parser* parser, looking at a declaration. */ cp_parser_commit_to_tentative_parse (parser); /* Give up. */ - return; + goto done; } /* Keep going until we hit the `;' at the end of the simple @@ -6116,10 +6122,7 @@ cp_parser_simple_declaration (cp_parser* parser, statement is treated as a declaration-statement until proven otherwise.) */ if (cp_parser_error_occurred (parser)) - { - pop_deferring_access_checks (); - return; - } + goto done; /* Handle function definitions specially. */ if (function_definition_p) { @@ -6152,8 +6155,7 @@ cp_parser_simple_declaration (cp_parser* parser, cp_parser_error (parser, "expected `,' or `;'"); /* Skip tokens until we reach the end of the statement. */ cp_parser_skip_to_end_of_statement (parser); - pop_deferring_access_checks (); - return; + goto done; } /* After the first time around, a function-definition is not allowed -- even if it was OK at first. For example: @@ -6175,14 +6177,15 @@ cp_parser_simple_declaration (cp_parser* parser, perform_deferred_access_checks (); } - pop_deferring_access_checks (); - /* Consume the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, "`;'"); /* Mark all the classes that appeared in the decl-specifier-seq as having received a `;'. */ note_list_got_semicolon (decl_specifiers); + + done: + pop_deferring_access_checks (); } /* Parse a decl-specifier-seq. @@ -6774,7 +6777,9 @@ cp_parser_mem_initializer (cp_parser* parser) if (member && !DECL_P (member)) in_base_initializer = 1; - expression_list = cp_parser_parenthesized_expression_list (parser, false); + expression_list + = cp_parser_parenthesized_expression_list (parser, false, + /*non_constant_p=*/NULL); if (!expression_list) expression_list = void_type_node; @@ -9156,6 +9161,7 @@ cp_parser_init_declarator (cp_parser* parser, tree scope; bool is_initialized; bool is_parenthesized_init; + bool is_non_constant_init; int ctor_dtor_or_conv_p; bool friend_p; @@ -9325,11 +9331,14 @@ cp_parser_init_declarator (cp_parser* parser, /* Parse the initializer. */ if (is_initialized) - initializer = cp_parser_initializer (parser, &is_parenthesized_init); + initializer = cp_parser_initializer (parser, + &is_parenthesized_init, + &is_non_constant_init); else { initializer = NULL_TREE; is_parenthesized_init = false; + is_non_constant_init = true; } /* The old parser allows attributes to appear after a parenthesized @@ -9371,6 +9380,12 @@ cp_parser_init_declarator (cp_parser* parser, ((is_parenthesized_init || !is_initialized) ? 0 : LOOKUP_ONLYCONVERTING)); + /* Remember whether or not variables were initialized by + constant-expressions. */ + if (decl && TREE_CODE (decl) == VAR_DECL + && is_initialized && !is_non_constant_init) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; + return decl; } @@ -10729,10 +10744,13 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser) *IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )' production is used, and zero otherwise. *IS_PARENTHESIZED_INIT is - set to FALSE if there is no initializer present. */ + set to FALSE if there is no initializer present. If there is an + initializer, and it is not a constant-expression, *NON_CONSTANT_P + is set to true; otherwise it is set to false. */ static tree -cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init) +cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init, + bool* non_constant_p) { cp_token *token; tree init; @@ -10743,16 +10761,19 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init) /* Let our caller know whether or not this initializer was parenthesized. */ *is_parenthesized_init = (token->type == CPP_OPEN_PAREN); + /* Assume that the initializer is constant. */ + *non_constant_p = false; if (token->type == CPP_EQ) { /* Consume the `='. */ cp_lexer_consume_token (parser->lexer); /* Parse the initializer-clause. */ - init = cp_parser_initializer_clause (parser); + init = cp_parser_initializer_clause (parser, non_constant_p); } else if (token->type == CPP_OPEN_PAREN) - init = cp_parser_parenthesized_expression_list (parser, false); + init = cp_parser_parenthesized_expression_list (parser, false, + non_constant_p); else { /* Anything else is an error. */ @@ -10779,17 +10800,21 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init) the elements of the initializer-list (or NULL_TREE, if the last production is used). The TREE_TYPE for the CONSTRUCTOR will be NULL_TREE. There is no way to detect whether or not the optional - trailing `,' was provided. */ + trailing `,' was provided. NON_CONSTANT_P is as for + cp_parser_initializer. */ static tree -cp_parser_initializer_clause (cp_parser* parser) +cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) { tree initializer; /* If it is not a `{', then we are looking at an assignment-expression. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) - initializer = cp_parser_assignment_expression (parser); + initializer + = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/true, + non_constant_p); else { /* Consume the `{' token. */ @@ -10805,12 +10830,11 @@ cp_parser_initializer_clause (cp_parser* parser) { /* Parse the initializer list. */ CONSTRUCTOR_ELTS (initializer) - = cp_parser_initializer_list (parser); + = cp_parser_initializer_list (parser, non_constant_p); /* A trailing `,' token is allowed. */ if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) cp_lexer_consume_token (parser->lexer); } - /* Now, there should be a trailing `}'. */ cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'"); } @@ -10832,20 +10856,25 @@ cp_parser_initializer_clause (cp_parser* parser) Returns a TREE_LIST. The TREE_VALUE of each node is an expression for the initializer. If the TREE_PURPOSE is non-NULL, it is the - IDENTIFIER_NODE naming the field to initialize. */ + IDENTIFIER_NODE naming the field to initialize. NON_CONSTANT_P is + as for cp_parser_initializer. */ static tree -cp_parser_initializer_list (cp_parser* parser) +cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) { tree initializers = NULL_TREE; + /* Assume all of the expressions are constant. */ + *non_constant_p = false; + /* Parse the rest of the list. */ while (true) { cp_token *token; tree identifier; tree initializer; - + bool clause_non_constant_p; + /* If the next token is an identifier and the following one is a colon, we are looking at the GNU designated-initializer syntax. */ @@ -10862,8 +10891,11 @@ cp_parser_initializer_list (cp_parser* parser) identifier = NULL_TREE; /* Parse the initializer. */ - initializer = cp_parser_initializer_clause (parser); - + initializer = cp_parser_initializer_clause (parser, + &clause_non_constant_p); + /* If any clause is non-constant, so is the entire initializer. */ + if (clause_non_constant_p) + *non_constant_p = true; /* Add it to the list. */ initializers = tree_cons (identifier, initializer, initializers); @@ -11821,12 +11853,18 @@ cp_parser_member_declaration (cp_parser* parser) (cp_lexer_peek_token (parser->lexer))) decl = error_mark_node; else - /* Create the declaration. */ - decl = grokfield (declarator, - decl_specifiers, - initializer, - asm_specification, - attributes); + { + /* Create the declaration. */ + decl = grokfield (declarator, + decl_specifiers, + initializer, + asm_specification, + attributes); + /* Any initialization must have been from a + constant-expression. */ + if (decl && TREE_CODE (decl) == VAR_DECL && initializer) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; + } } /* Reset PREFIX_ATTRIBUTES. */ @@ -12616,8 +12654,8 @@ cp_parser_attribute_list (cp_parser* parser) { tree arguments; - arguments = cp_parser_parenthesized_expression_list (parser, true); - + arguments = (cp_parser_parenthesized_expression_list + (parser, true, /*non_constant_p=*/NULL)); /* Save the identifier and arguments away. */ TREE_VALUE (attribute) = arguments; } @@ -13583,7 +13621,9 @@ cp_parser_functional_cast (cp_parser* parser, tree type) { tree expression_list; - expression_list = cp_parser_parenthesized_expression_list (parser, false); + expression_list + = cp_parser_parenthesized_expression_list (parser, false, + /*non_constant_p=*/NULL); return build_functional_cast (type, expression_list); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1a8ea15c040..6c4a5a86815 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6190,7 +6190,11 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain) r = copy_decl (t); if (TREE_CODE (r) == VAR_DECL) - type = complete_type (type); + { + type = complete_type (type); + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) + = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t); + } else if (DECL_SELF_REFERENCE_P (t)) SET_DECL_SELF_REFERENCE_P (r); TREE_TYPE (r) = type; @@ -7620,7 +7624,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) else { maybe_push_decl (decl); - if (DECL_PRETTY_FUNCTION_P (decl)) + if (TREE_CODE (decl) == VAR_DECL + && DECL_PRETTY_FUNCTION_P (decl)) { /* For __PRETTY_FUNCTION__ we have to adjust the initializer. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 02783859cb4..3d704ebe194 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2478,17 +2478,11 @@ finish_id_expression (tree id_expression, ; /* Const variables or static data members of integral or enumeration types initialized with constant expressions - are OK. We also accept dependent initializers; they may - turn out to be constant at instantiation-time. */ + are OK. */ else if (TREE_CODE (decl) == VAR_DECL && CP_TYPE_CONST_P (TREE_TYPE (decl)) && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)) - && DECL_INITIAL (decl) - && (TREE_CONSTANT (DECL_INITIAL (decl)) - || type_dependent_expression_p (DECL_INITIAL - (decl)) - || value_dependent_expression_p (DECL_INITIAL - (decl)))) + && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)) ; else { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4b96542b92f..d6cced3bbc6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2003-07-16 Mark Mitchell + + PR c++/11547 + * g++.dg/parse/constant3.C: New test. + * g++.dg/parse/crash7.C: Likewise. + 2003-07-16 Andrew Pinski PR target/11008 diff --git a/gcc/testsuite/g++.dg/parse/constant3.C b/gcc/testsuite/g++.dg/parse/constant3.C new file mode 100644 index 00000000000..c029e33ed58 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/constant3.C @@ -0,0 +1,7 @@ +const int i = 1; +const int j (2); +const int k = { 3 }; + +enum { a = i, b = j, c = k }; + + diff --git a/gcc/testsuite/g++.dg/parse/crash7.C b/gcc/testsuite/g++.dg/parse/crash7.C new file mode 100644 index 00000000000..86fa477266b --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash7.C @@ -0,0 +1,10 @@ +struct A +{ + int foo () const { return 0; } +}; + +template void bar (int x[], const A &a) +{ + const int i=a.foo(); + x[i]=0; +}