[C++0x] avoid extra tentative parse in range-based for loops
Rodrigo Rivas
rodrigorivascosta@gmail.com
Mon Nov 29 21:00:00 GMT 2010
On Fri, Nov 26, 2010 at 5:20 PM, Jason Merrill <jason@redhat.com> wrote:
>> That was my first option but sadly it doesn't work. The problem is
>> that cp_parser_expression_statement must be called after
>> begin_for_stmt.
>
> Why? You moved the scope stuff into begin_for_scope, which is called before
> cp_parser_for_init_statement.
Oh, actually you are right! In a previous unreleased version of this
patch, it needed to be here, but now it can be moved to
cp_parser_for_init_statement. In this way we don't need the kind_for
enumeration, since only two cases are needed a bool is enough.
> That still doesn't cover what happens to *just_one_declarator in the other
> cases.
Please see the new comments in the patch.
> I don't think either message is significantly better, so I'd go with the
> simpler logic.
Ok.
>> * Do not issue the error "expected initializer".
>> * Pass SD_INITIALIZED to start_decl.
>> * Do not parse the initializer, since it is not here.
>> * Do not call cp_finish_decl, since it will be called by the upper
>> function.
>
> Right. Not setting is_initialized covers #3, and I think the others should
> be handled by a separate flag instead of special values of the
> initialization variables.
> ...
> I think it's definitely worth it; that's a lot clearer than the magic
> CPP_EOF. Also, let's rename just_one_declarator to maybe_range_for_decl to
> make it clearer what's going on.
Done and done. I named the flag "range_for_decl_p".
Also I added two testcases (hope that's enough) and rewrote a few more comments.
Regards.
--
Rodrigo
Changelog:
gcc/cp/
2010-11-29 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
* 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.
gcc/testsuite/
2010-11-29 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
* 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.
-------------- next part --------------
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 67f4f93..efac88d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5221,12 +5221,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 670c7a5..003eb01 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3108,7 +3108,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 917f750..37fb7e0 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1860,12 +1860,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
@@ -1885,7 +1887,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
@@ -1935,7 +1937,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
@@ -8659,21 +8661,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. */
@@ -8694,57 +8713,24 @@ cp_parser_c_for (cp_parser *parser)
/* Tries to parse a range-based for-statement:
range-based-for:
- type-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().
+ decl-specifier-seq declarator : expression
- 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;
-
- 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))
- {
- cp_parser_abort_tentative_parse (parser);
- return NULL_TREE;
- }
- /* 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);
+ tree stmt, range_expr;
- /* Check if it is a range-based for */
- if (!cp_parser_parse_definitely (parser))
- return NULL_TREE;
+ /* 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. */
+ TREE_USED (range_decl) = 1;
+ DECL_READ_P (range_decl) = 1;
- cp_parser_require (parser, CPP_COLON, RT_COLON);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
bool expr_non_constant_p;
@@ -8753,26 +8739,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 ();
- 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);
+ {
+ stmt = begin_range_for_stmt (scope, init);
+ 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);
+ {
+ stmt = begin_for_stmt (scope, init);
+ stmt = cp_convert_range_for (stmt, range_decl, range_expr);
+ }
return stmt;
}
@@ -8999,12 +8977,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);
@@ -9028,14 +9001,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
@@ -9045,19 +9019,42 @@ 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;
/* 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);
/* If the tentative parse failed, then we shall need to look for an
expression-statement. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ /* It is a range-for, consume the ':' */
+ cp_lexer_consume_token (parser->lexer);
+ if (cxx_dialect < cxx0x)
+ {
+ error_at (cp_lexer_peek_token (parser->lexer)->location,
+ "range-based-for loops are not allowed "
+ "in C++98 mode");
+ }
+ else if (*decl && *decl != error_mark_node )
+ is_range_for = true;
+ /* Else an error has been found in the declaration. It should have
+ been reported by now, so no message is required. */
+ }
+ 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;
+ return is_range_for;
}
-
+ /* If we are here, it is an expression. */
cp_parser_expression_statement (parser, NULL_TREE);
+ return false;
}
/* Parse a jump-statement.
@@ -9544,7 +9541,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.
@@ -9557,16 +9555,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. */
@@ -9641,6 +9648,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;
@@ -9651,7 +9660,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
@@ -9681,13 +9691,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
@@ -9725,7 +9737,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 ();
@@ -14327,7 +14340,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,
@@ -14336,7 +14355,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;
@@ -14357,6 +14377,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. */
@@ -14500,6 +14521,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))
@@ -14518,8 +14541,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;
@@ -14552,7 +14580,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
@@ -14666,7 +14695,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,
@@ -20006,7 +20035,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 c4b4a03..a62eeb6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12051,7 +12051,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));
@@ -12065,7 +12065,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 9b565da..cb80199 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -826,21 +826,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;
}
@@ -924,18 +947,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/g++.dg/cpp0x/range-for4.C b/gcc/testsuite/g++.dg/cpp0x/range-for4.C
index 96c0d90..afbcf14 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 <cstdio>
-
/* Preliminary declarations */
namespace pre
{
@@ -48,7 +46,6 @@ container run_me_just_once()
}
/* Template with dependent expression. */
-/* Template with dependent expression. */
template<typename T> int test1(const T &r)
{
int t = 0;
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 0000000..641dfe0
--- /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 <initializer_list>
+
+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 0000000..56bd728
--- /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|expected" }
+ ;
+}
More information about the Gcc-patches
mailing list