From 3f43ac31cc7db4a07a699dafc07ee012d333ce18 Mon Sep 17 00:00:00 2001 From: Rodrigo Rivas Costa Date: Wed, 12 Jan 2011 23:52:56 +0000 Subject: [PATCH] cp-tree.h (begin_for_scope): New prototype. * cp-tree.h (begin_for_scope): New prototype. (begin_for_stmt): Update prototype. (begin_range_for_stmt): Update prototype. * init.c (build_vec_init): Update call to begin_for_stmt. * parser.c (cp_parser_for): New. (cp_parser_c_for): Add three new parameters. (cp_parser_range_for): Likewise. Most parsing code removed. (cp_parser_iteration_statement): Call cp_parser_for instead of cp_parser_c_for and cp_parser_range_for. (cp_parser_for_init_statement): Add new parameter and return type. (cp_parser_block_declaration): Update call to cp_parser_simple_declaration. (cp_parser_simple_declaration): Add new parameter. Update call to cp_parser_init_declarator. (cp_parser_init_declarator): Add new parameter. * pt.c (tsubst_expr): Update call to begin_for_stmt. * semantics.c (begin_for_scope): New. (begin_for_stmt): Add two new parameters. (begin_range_for_stmt): Likewise. From-SVN: r168731 --- gcc/cp/ChangeLog | 22 ++ gcc/cp/cp-tree.h | 5 +- gcc/cp/init.c | 2 +- gcc/cp/parser.c | 356 +++++++++++++----------- gcc/cp/pt.c | 4 +- gcc/cp/semantics.c | 54 +++- gcc/testsuite/ChangeLog | 7 + gcc/testsuite/g++.dg/cpp0x/range-for4.C | 3 - gcc/testsuite/g++.dg/cpp0x/range-for8.C | 16 ++ gcc/testsuite/g++.dg/cpp0x/range-for9.C | 11 + 10 files changed, 303 insertions(+), 177 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/range-for8.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/range-for9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0616dccc251..5088ba06f71 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2011-01-12 Rodrigo Rivas Costa + + * cp-tree.h (begin_for_scope): New prototype. + (begin_for_stmt): Update prototype. + (begin_range_for_stmt): Update prototype. + * init.c (build_vec_init): Update call to begin_for_stmt. + * parser.c (cp_parser_for): New. + (cp_parser_c_for): Add three new parameters. + (cp_parser_range_for): Likewise. Most parsing code removed. + (cp_parser_iteration_statement): Call cp_parser_for instead of + cp_parser_c_for and cp_parser_range_for. + (cp_parser_for_init_statement): Add new parameter and return type. + (cp_parser_block_declaration): Update call to + cp_parser_simple_declaration. + (cp_parser_simple_declaration): Add new parameter. + Update call to cp_parser_init_declarator. + (cp_parser_init_declarator): Add new parameter. + * pt.c (tsubst_expr): Update call to begin_for_stmt. + * semantics.c (begin_for_scope): New. + (begin_for_stmt): Add two new parameters. + (begin_range_for_stmt): Likewise. + 2011-01-12 Nicola Pero * parser.c (cp_parser_objc_at_property_declaration): Improved diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7b18973c493..dddbc01fb4a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5214,12 +5214,13 @@ extern tree begin_do_stmt (void); extern void finish_do_body (tree); extern void finish_do_stmt (tree, tree); extern tree finish_return_stmt (tree); -extern tree begin_for_stmt (void); +extern tree begin_for_scope (tree *); +extern tree begin_for_stmt (tree, tree); extern void finish_for_init_stmt (tree); extern void finish_for_cond (tree, tree); extern void finish_for_expr (tree, tree); extern void finish_for_stmt (tree); -extern tree begin_range_for_stmt (void); +extern tree begin_range_for_stmt (tree, tree); extern void finish_range_for_decl (tree, tree, tree); extern void finish_range_for_stmt (tree); extern tree finish_break_stmt (void); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1546bf887f8..6ffdc2f3f36 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3125,7 +3125,7 @@ build_vec_init (tree base, tree maxindex, tree init, tree elt_init; tree to; - for_stmt = begin_for_stmt (); + for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE); finish_for_init_stmt (for_stmt); finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator, build_int_cst (TREE_TYPE (iterator), -1)), diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e63d9765c58..061e8cc7fee 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1863,12 +1863,14 @@ static tree cp_parser_condition (cp_parser *); static tree cp_parser_iteration_statement (cp_parser *); -static void cp_parser_for_init_statement - (cp_parser *); -static tree cp_parser_c_for - (cp_parser *); -static tree cp_parser_range_for +static bool cp_parser_for_init_statement + (cp_parser *, tree *decl); +static tree cp_parser_for (cp_parser *); +static tree cp_parser_c_for + (cp_parser *, tree, tree); +static tree cp_parser_range_for + (cp_parser *, tree, tree, tree); static tree cp_parser_jump_statement (cp_parser *); static void cp_parser_declaration_statement @@ -1888,7 +1890,7 @@ static void cp_parser_declaration static void cp_parser_block_declaration (cp_parser *, bool); static void cp_parser_simple_declaration - (cp_parser *, bool); + (cp_parser *, bool, tree *); static void cp_parser_decl_specifier_seq (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *); static tree cp_parser_storage_class_specifier_opt @@ -1938,7 +1940,7 @@ static tree cp_parser_decltype /* Declarators [gram.dcl.decl] */ static tree cp_parser_init_declarator - (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *); + (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *, tree *); static cp_declarator *cp_parser_declarator (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool); static cp_declarator *cp_parser_direct_declarator @@ -8694,21 +8696,38 @@ cp_parser_condition (cp_parser* parser) return cp_parser_expression (parser, /*cast_p=*/false, NULL); } -/* Parses a traditional for-statement until the closing ')', not included. */ +/* Parses a for-statement or range-for-statement until the closing ')', + not included. */ static tree -cp_parser_c_for (cp_parser *parser) +cp_parser_for (cp_parser *parser) { - /* Normal for loop */ - tree stmt; - tree condition = NULL_TREE; - tree expression = NULL_TREE; + tree init, scope, decl; + bool is_range_for; /* Begin the for-statement. */ - stmt = begin_for_stmt (); + scope = begin_for_scope (&init); /* Parse the initialization. */ - cp_parser_for_init_statement (parser); + is_range_for = cp_parser_for_init_statement (parser, &decl); + + if (is_range_for) + return cp_parser_range_for (parser, scope, init, decl); + else + return cp_parser_c_for (parser, scope, init); +} + +static tree +cp_parser_c_for (cp_parser *parser, tree scope, tree init) +{ + /* Normal for loop */ + tree condition = NULL_TREE; + tree expression = NULL_TREE; + tree stmt; + + stmt = begin_for_stmt (scope, init); + /* The for-init-statement has already been parsed in + cp_parser_for_init_statement, so no work is needed here. */ finish_for_init_stmt (stmt); /* If there's a condition, process it. */ @@ -8729,60 +8748,27 @@ cp_parser_c_for (cp_parser *parser) /* Tries to parse a range-based for-statement: range-based-for: - type-specifier-seq declarator : expression + decl-specifier-seq declarator : expression - If succesful, assigns to *DECL the DECLARATOR and to *EXPR the - expression. Note that the *DECL is returned unfinished, so - later you should call cp_finish_decl(). - - Returns TRUE iff a range-based for is parsed. */ + The decl-specifier-seq declarator and the `:' are already parsed by + cp_parser_for_init_statement. If processing_template_decl it returns a + newly created RANGE_FOR_STMT; if not, it is converted to a + regular FOR_STMT. */ static tree -cp_parser_range_for (cp_parser *parser) +cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl) { - tree stmt, range_decl, range_expr; - cp_decl_specifier_seq type_specifiers; - cp_declarator *declarator; - const char *saved_message; - tree attributes, pushed_scope; - bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + tree stmt, range_expr; - parser->colon_corrects_to_scope_p = false; - cp_parser_parse_tentatively (parser); - /* New types are not allowed in the type-specifier-seq for a - range-based for loop. */ - saved_message = parser->type_definition_forbidden_message; - parser->type_definition_forbidden_message - = G_("types may not be defined in range-based for loops"); - /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_declaration==*/true, - /*is_trailing_return=*/false, - &type_specifiers); - /* Restore the saved message. */ - parser->type_definition_forbidden_message = saved_message; - /* If all is well, we might be looking at a declaration. */ - if (cp_parser_error_occurred (parser)) + /* If the variable from a range-for is not actually used, GCC would issue + "unused variable" warnings, and the user could do little to prevent them. + So we always mark it as used. */ + if (range_decl != error_mark_node) { - cp_parser_abort_tentative_parse (parser); - stmt = NULL_TREE; - goto out; + TREE_USED (range_decl) = 1; + DECL_READ_P (range_decl) = 1; } - /* Parse the declarator. */ - declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED, - /*ctor_dtor_or_conv_p=*/NULL, - /*parenthesized_p=*/NULL, - /*member_p=*/false); - /* Parse the attributes. */ - attributes = cp_parser_attributes_opt (parser); - /* The next token should be `:'. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) - cp_parser_simulate_error (parser); - /* Check if it is a range-based for */ - if (!cp_parser_parse_definitely (parser)) - return NULL_TREE; - - cp_parser_require (parser, CPP_COLON, RT_COLON); if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { bool expr_non_constant_p; @@ -8791,29 +8777,18 @@ cp_parser_range_for (cp_parser *parser) else range_expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); - /* If in template, STMT is converted to a normal for-statements + /* If in template, STMT is converted to a normal for-statement at instantiation. If not, it is done just ahead. */ if (processing_template_decl) - stmt = begin_range_for_stmt (); + { + stmt = begin_range_for_stmt (scope, init); + finish_range_for_decl (stmt, range_decl, range_expr); + } else - stmt = begin_for_stmt (); - - /* Create the declaration. It must be after begin{,_range}_for_stmt(). */ - range_decl = start_decl (declarator, &type_specifiers, - /*initialized_p=*/SD_INITIALIZED, - attributes, /*prefix_attributes=*/NULL_TREE, - &pushed_scope); - /* No scope allowed here */ - pop_scope (pushed_scope); - - if (TREE_CODE (stmt) == RANGE_FOR_STMT) - finish_range_for_decl (stmt, range_decl, range_expr); - else - /* Convert the range-based for loop into a normal for-statement. */ - stmt = cp_convert_range_for (stmt, range_decl, range_expr); - - out: - parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + { + stmt = begin_for_stmt (scope, init); + stmt = cp_convert_range_for (stmt, range_decl, range_expr); + } return stmt; } @@ -8854,63 +8829,71 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr) tree iter_type, begin_expr, end_expr; tree condition, expression; - /* Find out the type deduced by the declaration - * `auto &&__range = range_expr' */ - range_type = cp_build_reference_type (make_auto (), true); - range_type = do_auto_deduction (range_type, range_expr, - type_uses_auto (range_type)); - - /* Create the __range variable */ - range_temp = build_decl (input_location, VAR_DECL, - get_identifier ("__for_range"), range_type); - TREE_USED (range_temp) = 1; - DECL_ARTIFICIAL (range_temp) = 1; - pushdecl (range_temp); - cp_finish_decl (range_temp, range_expr, - /*is_constant_init*/false, NULL_TREE, - LOOKUP_ONLYCONVERTING); - - range_temp = convert_from_reference (range_temp); - - if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE) - { - /* If RANGE_TEMP is an array we will use pointer arithmetic */ - iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp))); - begin_expr = range_temp; - end_expr - = build_binary_op (input_location, PLUS_EXPR, - range_temp, - array_type_nelts_top (TREE_TYPE (range_temp)), 0); - } + if (range_decl == error_mark_node || range_expr == error_mark_node) + /* If an error happened previously do nothing or else a lot of + unhelpful errors would be issued. */ + begin_expr = end_expr = iter_type = error_mark_node; else { - /* If it is not an array, we must call begin(__range)/end__range() */ - VEC(tree,gc) *vec; + /* Find out the type deduced by the declaration + * `auto &&__range = range_expr' */ + range_type = cp_build_reference_type (make_auto (), true); + range_type = do_auto_deduction (range_type, range_expr, + type_uses_auto (range_type)); - begin_expr = get_identifier ("begin"); - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, range_temp); - begin_expr = perform_koenig_lookup (begin_expr, vec, - /*include_std=*/true); - begin_expr = finish_call_expr (begin_expr, &vec, false, true, - tf_warning_or_error); - release_tree_vector (vec); + /* Create the __range variable */ + range_temp = build_decl (input_location, VAR_DECL, + get_identifier ("__for_range"), range_type); + TREE_USED (range_temp) = 1; + DECL_ARTIFICIAL (range_temp) = 1; + pushdecl (range_temp); + cp_finish_decl (range_temp, range_expr, + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); - end_expr = get_identifier ("end"); - vec = make_tree_vector (); - VEC_safe_push (tree, gc, vec, range_temp); - end_expr = perform_koenig_lookup (end_expr, vec, - /*include_std=*/true); - end_expr = finish_call_expr (end_expr, &vec, false, true, - tf_warning_or_error); - release_tree_vector (vec); + range_temp = convert_from_reference (range_temp); - /* The unqualified type of the __begin and __end temporaries should - * be the same as required by the multiple auto declaration */ - iter_type = cv_unqualified (TREE_TYPE (begin_expr)); - if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr)))) - error ("inconsistent begin/end types in range-based for: %qT and %qT", - TREE_TYPE (begin_expr), TREE_TYPE (end_expr)); + if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE) + { + /* If RANGE_TEMP is an array we will use pointer arithmetic */ + iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp))); + begin_expr = range_temp; + end_expr + = build_binary_op (input_location, PLUS_EXPR, + range_temp, + array_type_nelts_top (TREE_TYPE (range_temp)), + 0); + } + else + { + /* If it is not an array, we must call begin(__range)/end__range() */ + VEC(tree,gc) *vec; + + begin_expr = get_identifier ("begin"); + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, range_temp); + begin_expr = perform_koenig_lookup (begin_expr, vec, + /*include_std=*/true); + begin_expr = finish_call_expr (begin_expr, &vec, false, true, + tf_warning_or_error); + release_tree_vector (vec); + + end_expr = get_identifier ("end"); + vec = make_tree_vector (); + VEC_safe_push (tree, gc, vec, range_temp); + end_expr = perform_koenig_lookup (end_expr, vec, + /*include_std=*/true); + end_expr = finish_call_expr (end_expr, &vec, false, true, + tf_warning_or_error); + release_tree_vector (vec); + + /* The unqualified type of the __begin and __end temporaries should + * be the same as required by the multiple auto declaration */ + iter_type = cv_unqualified (TREE_TYPE (begin_expr)); + if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr)))) + error ("inconsistent begin/end types in range-based for: %qT and %qT", + TREE_TYPE (begin_expr), TREE_TYPE (end_expr)); + } } /* The new for initialization statement */ @@ -9039,12 +9022,7 @@ cp_parser_iteration_statement (cp_parser* parser) /* Look for the `('. */ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); - if (cxx_dialect == cxx0x) - statement = cp_parser_range_for (parser); - else - statement = NULL_TREE; - if (statement == NULL_TREE) - statement = cp_parser_c_for (parser); + statement = cp_parser_for (parser); /* Look for the `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -9068,14 +9046,15 @@ cp_parser_iteration_statement (cp_parser* parser) return statement; } -/* Parse a for-init-statement. +/* Parse a for-init-statement or the declarator of a range-based-for. + Returns true if a range-based-for declaration is seen. for-init-statement: expression-statement simple-declaration */ -static void -cp_parser_for_init_statement (cp_parser* parser) +static bool +cp_parser_for_init_statement (cp_parser* parser, tree *decl) { /* If the next token is a `;', then we have an empty expression-statement. Grammatically, this is also a @@ -9085,19 +9064,45 @@ cp_parser_for_init_statement (cp_parser* parser) declaration. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { + bool is_range_for = false; + bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + + parser->colon_corrects_to_scope_p = false; + /* We're going to speculatively look for a declaration, falling back to an expression, if necessary. */ cp_parser_parse_tentatively (parser); /* Parse the declaration. */ cp_parser_simple_declaration (parser, - /*function_definition_allowed_p=*/false); + /*function_definition_allowed_p=*/false, + decl); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + /* It is a range-for, consume the ':' */ + cp_lexer_consume_token (parser->lexer); + is_range_for = true; + if (cxx_dialect < cxx0x) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "range-based-for loops are not allowed " + "in C++98 mode"); + *decl = error_mark_node; + } + } + else + /* The ';' is not consumed yet because we told + cp_parser_simple_declaration not to. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + if (cp_parser_parse_definitely (parser)) + return is_range_for; /* If the tentative parse failed, then we shall need to look for an expression-statement. */ - if (cp_parser_parse_definitely (parser)) - return; } - + /* If we are here, it is an expression-statement. */ cp_parser_expression_statement (parser, NULL_TREE); + return false; } /* Parse a jump-statement. @@ -9584,7 +9589,8 @@ cp_parser_block_declaration (cp_parser *parser, cp_parser_static_assert (parser, /*member_p=*/false); /* Anything else must be a simple-declaration. */ else - cp_parser_simple_declaration (parser, !statement_p); + cp_parser_simple_declaration (parser, !statement_p, + /*maybe_range_for_decl*/NULL); } /* Parse a simple-declaration. @@ -9597,16 +9603,25 @@ cp_parser_block_declaration (cp_parser *parser, init-declarator-list , init-declarator If FUNCTION_DEFINITION_ALLOWED_P is TRUE, then we also recognize a - function-definition as a simple-declaration. */ + function-definition as a simple-declaration. + + If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the + parsed declaration if it is an uninitialized single declarator not followed + by a `;', or to error_mark_node otherwise. Either way, the trailing `;', + if present, will not be consumed. */ static void cp_parser_simple_declaration (cp_parser* parser, - bool function_definition_allowed_p) + bool function_definition_allowed_p, + tree *maybe_range_for_decl) { cp_decl_specifier_seq decl_specifiers; int declares_class_or_enum; bool saw_declarator; + if (maybe_range_for_decl) + *maybe_range_for_decl = NULL_TREE; + /* Defer access checks until we know what is being declared; the checks for names appearing in the decl-specifier-seq should be done as if we were in the scope of the thing being declared. */ @@ -9681,6 +9696,8 @@ cp_parser_simple_declaration (cp_parser* parser, token = cp_lexer_peek_token (parser->lexer); gcc_assert (token->type == CPP_COMMA); cp_lexer_consume_token (parser->lexer); + if (maybe_range_for_decl) + *maybe_range_for_decl = error_mark_node; } else saw_declarator = true; @@ -9691,7 +9708,8 @@ cp_parser_simple_declaration (cp_parser* parser, function_definition_allowed_p, /*member_p=*/false, declares_class_or_enum, - &function_definition_p); + &function_definition_p, + maybe_range_for_decl); /* If an error occurred while parsing tentatively, exit quickly. (That usually happens when in the body of a function; each statement is treated as a declaration-statement until proven @@ -9721,13 +9739,15 @@ cp_parser_simple_declaration (cp_parser* parser, return; } } + if (maybe_range_for_decl && *maybe_range_for_decl == NULL_TREE) + *maybe_range_for_decl = decl; /* The next token should be either a `,' or a `;'. */ token = cp_lexer_peek_token (parser->lexer); /* If it's a `,', there are more declarators to come. */ if (token->type == CPP_COMMA) /* will be consumed next time around */; /* If it's a `;', we are done. */ - else if (token->type == CPP_SEMICOLON) + else if (token->type == CPP_SEMICOLON || maybe_range_for_decl) break; /* Anything else is an error. */ else @@ -9765,7 +9785,8 @@ cp_parser_simple_declaration (cp_parser* parser, } /* Consume the `;'. */ - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + if (!maybe_range_for_decl) + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); done: pop_deferring_access_checks (); @@ -14378,7 +14399,13 @@ cp_parser_asm_definition (cp_parser* parser) have been completely parsed. FUNCTION_DEFINITION_P may be NULL if FUNCTION_DEFINITION_ALLOWED_P - is FALSE. */ + is FALSE. + + If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the + parsed declaration if it is an uninitialized single declarator not followed + by a `;', or to error_mark_node otherwise. Either way, the trailing `;', + if present, will not be consumed. If returned, this declarator will be + created with SD_INITIALIZED but will not call cp_finish_decl. */ static tree cp_parser_init_declarator (cp_parser* parser, @@ -14387,7 +14414,8 @@ cp_parser_init_declarator (cp_parser* parser, bool function_definition_allowed_p, bool member_p, int declares_class_or_enum, - bool* function_definition_p) + bool* function_definition_p, + tree* maybe_range_for_decl) { cp_token *token = NULL, *asm_spec_start_token = NULL, *attributes_start_token = NULL; @@ -14408,6 +14436,7 @@ cp_parser_init_declarator (cp_parser* parser, int ctor_dtor_or_conv_p; bool friend_p; tree pushed_scope = NULL; + bool range_for_decl_p = false; /* Gather the attributes that were provided with the decl-specifiers. */ @@ -14551,6 +14580,8 @@ cp_parser_init_declarator (cp_parser* parser, { is_initialized = SD_INITIALIZED; initialization_kind = token->type; + if (maybe_range_for_decl) + *maybe_range_for_decl = error_mark_node; if (token->type == CPP_EQ && function_declarator_p (declarator)) @@ -14569,8 +14600,13 @@ cp_parser_init_declarator (cp_parser* parser, if (token->type != CPP_COMMA && token->type != CPP_SEMICOLON) { - cp_parser_error (parser, "expected initializer"); - return error_mark_node; + if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node) + range_for_decl_p = true; + else + { + cp_parser_error (parser, "expected initializer"); + return error_mark_node; + } } is_initialized = SD_UNINITIALIZED; initialization_kind = CPP_EOF; @@ -14603,7 +14639,8 @@ cp_parser_init_declarator (cp_parser* parser, if (parser->in_unbraced_linkage_specification_p) decl_specifiers->storage_class = sc_extern; decl = start_decl (declarator, decl_specifiers, - is_initialized, attributes, prefix_attributes, + range_for_decl_p? SD_INITIALIZED : is_initialized, + attributes, prefix_attributes, &pushed_scope); /* Adjust location of decl if declarator->id_loc is more appropriate: set, and decl wasn't merged with another decl, in which case its @@ -14717,7 +14754,7 @@ cp_parser_init_declarator (cp_parser* parser, /* Finish processing the declaration. But, skip friend declarations. */ - if (!friend_p && decl && decl != error_mark_node) + if (!friend_p && decl && decl != error_mark_node && !range_for_decl_p) { cp_finish_decl (decl, initializer, !is_non_constant_init, @@ -20071,7 +20108,8 @@ cp_parser_single_declaration (cp_parser* parser, /*function_definition_allowed_p=*/true, member_p, declares_class_or_enum, - &function_definition_p); + &function_definition_p, + NULL); /* 7.1.1-1 [dcl.stc] diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d9dbbe0aa85..54c1a59a5eb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12052,7 +12052,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } case FOR_STMT: - stmt = begin_for_stmt (); + stmt = begin_for_stmt (NULL_TREE, NULL_TREE); RECUR (FOR_INIT_STMT (t)); finish_for_init_stmt (stmt); tmp = RECUR (FOR_COND (t)); @@ -12066,7 +12066,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case RANGE_FOR_STMT: { tree decl, expr; - stmt = begin_for_stmt (); + stmt = begin_for_stmt (NULL_TREE, NULL_TREE); decl = RANGE_FOR_DECL (t); decl = tsubst (decl, args, complain, in_decl); maybe_push_decl (decl); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index aeb10fec8ac..b9775f4b909 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -827,21 +827,44 @@ finish_return_stmt (tree expr) return r; } -/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */ +/* Begin the scope of a for-statement or a range-for-statement. + Both the returned trees are to be used in a call to + begin_for_stmt or begin_range_for_stmt. */ tree -begin_for_stmt (void) +begin_for_scope (tree *init) +{ + tree scope = NULL_TREE; + if (flag_new_for_scope > 0) + scope = do_pushlevel (sk_for); + + if (processing_template_decl) + *init = push_stmt_list (); + else + *init = NULL_TREE; + + return scope; +} + +/* Begin a for-statement. Returns a new FOR_STMT. + SCOPE and INIT should be the return of begin_for_scope, + or both NULL_TREE */ + +tree +begin_for_stmt (tree scope, tree init) { tree r; r = build_stmt (input_location, FOR_STMT, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); - if (flag_new_for_scope > 0) - TREE_CHAIN (r) = do_pushlevel (sk_for); - - if (processing_template_decl) - FOR_INIT_STMT (r) = push_stmt_list (); + if (scope == NULL_TREE) + { + gcc_assert (!init); + scope = begin_for_scope (&init); + } + FOR_INIT_STMT (r) = init; + TREE_CHAIN (r) = scope; return r; } @@ -925,18 +948,29 @@ finish_for_stmt (tree for_stmt) } /* Begin a range-for-statement. Returns a new RANGE_FOR_STMT. + SCOPE and INIT should be the return of begin_for_scope, + or both NULL_TREE . To finish it call finish_for_stmt(). */ tree -begin_range_for_stmt (void) +begin_range_for_stmt (tree scope, tree init) { tree r; r = build_stmt (input_location, RANGE_FOR_STMT, NULL_TREE, NULL_TREE, NULL_TREE); - if (flag_new_for_scope > 0) - TREE_CHAIN (r) = do_pushlevel (sk_for); + if (scope == NULL_TREE) + { + gcc_assert (!init); + scope = begin_for_scope (&init); + } + + /* RANGE_FOR_STMTs do not use nor save the init tree, so we + pop it now. */ + if (init) + pop_stmt_list (init); + TREE_CHAIN (r) = scope; return r; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f7ab937a58a..eb0ffefc302 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2011-01-12 Rodrigo Rivas Costa + + * g++.dg/cpp0x/range-for4.C: Delete useless include and duplicated + comment. + * g++.dg/cpp0x/range-for8.C: New. + * g++.dg/cpp0x/range-for9.C: New. + 2011-01-12 Kai Tietz PR debug/47209 diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for4.C b/gcc/testsuite/g++.dg/cpp0x/range-for4.C index 96c0d90f0f0..afbcf14b26e 100644 --- a/gcc/testsuite/g++.dg/cpp0x/range-for4.C +++ b/gcc/testsuite/g++.dg/cpp0x/range-for4.C @@ -3,8 +3,6 @@ // { dg-do run } // { dg-options "-std=c++0x" } -#include - /* Preliminary declarations */ namespace pre { @@ -47,7 +45,6 @@ container run_me_just_once() return container(1,2); } -/* Template with dependent expression. */ /* Template with dependent expression. */ template int test1(const T &r) { diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for8.C b/gcc/testsuite/g++.dg/cpp0x/range-for8.C new file mode 100644 index 00000000000..641dfe052c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/range-for8.C @@ -0,0 +1,16 @@ +// Test for range-based for loop when the declarator declares +// a new type + +// { dg-do compile } +// { dg-options "-std=c++0x" } + +#include + +void test() +{ + for (struct S { } *x : { (S*)0, (S*)0 } ) + ; + + for (struct S { } x : { S(), S() } ) + ; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for9.C b/gcc/testsuite/g++.dg/cpp0x/range-for9.C new file mode 100644 index 00000000000..96e9cb61fd6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/range-for9.C @@ -0,0 +1,11 @@ +// Test for range-based for loop error in C++98 mode + +// { dg-do compile } +// { dg-options "-std=c++98" } + +void test() +{ + int a[] = {0,1,2}; + for (int x : a) // { dg-error "range-based-for" } + ; +}