From patchwork Mon Sep 6 11:06:23 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rodrigo Rivas X-Patchwork-Id: 63914 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id DCACFB6EF7 for ; Mon, 6 Sep 2010 21:07:14 +1000 (EST) Received: (qmail 32231 invoked by alias); 6 Sep 2010 11:07:11 -0000 Received: (qmail 32216 invoked by uid 22791); 6 Sep 2010 11:07:07 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, TW_CX, TW_FN, TW_TM X-Spam-Check-By: sourceware.org Received: from mail-wy0-f175.google.com (HELO mail-wy0-f175.google.com) (74.125.82.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 06 Sep 2010 11:06:26 +0000 Received: by wye20 with SMTP id 20so4664213wye.20 for ; Mon, 06 Sep 2010 04:06:23 -0700 (PDT) MIME-Version: 1.0 Received: by 10.216.231.73 with SMTP id k51mr797572weq.5.1283771183364; Mon, 06 Sep 2010 04:06:23 -0700 (PDT) Received: by 10.216.53.137 with HTTP; Mon, 6 Sep 2010 04:06:23 -0700 (PDT) In-Reply-To: <4C83BD10.2030901@verizon.net> References: <4C83BD10.2030901@verizon.net> Date: Mon, 6 Sep 2010 13:06:23 +0200 Message-ID: Subject: Re: [C++0x patch] implement range-based for loops From: Rodrigo Rivas To: Ed Smith-Rowland <3dw4rd@verizon.net> Cc: gcc-patches@gcc.gnu.org, Paolo Carlini , Jason Merrill Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, Ed. > Thank you for your contribution of range-for.  I was considering the same > thing myself but you beat me to it. ;-) Well, that was my fear while I was writing it, as it took me quite a while, but here it is! > I did notice one simplification.  Since std::begin and std::end are > available for C-style arrays you can collapse the logic in parser.c to just > call those. Actually, you cannot do that. The C++ standard requires the special behavior for arrays so that you can use the range-for without any #include at all. With your simplification the testcase "range-for1.C" would fail, as there is no "begin" nor "end" declared. > Also, in the latest draft n3126.pdf on is allowed to use an initilizer list: Oh! I didn't even know that a new draft was available... checking it right now. ... Well, adding the initializer list is quite trivial, just changed in "cp_parser_range_for()" + *expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); for + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_non_constant_p; + *expr = cp_parser_braced_list (parser, &expr_non_constant_p); + } + else + *expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); But this triggered a curious bug in "cp_convert_range_for()". The problem is that I was using "range_expr" all the time, instead of "range_temp". This temporary was declared but never used. When I tried to use it, it failed because of a missing call to "convert_from_reference()". I think that all these issues are solved now in this new patch. Also, a new testcase is added to test the initializer_list case. Thank you for your comments. Rodrigo. --- Changelog -- gcc/cp 2010-09-06 Rodrigo Rivas Implement range-based for-statements. * cp-tree.def (RANGE_FOR_STMT): New. * cp-tree.h (RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY): New. * cp-tree.h (cp_convert_range_for): Declare. * pt.c (tsubst_expr): Add RANGE_FOR_STMT. (tsubst_copy_and_build): perform_koenig_lookup takes extra argument. * semantics.c (begin_range_for_stmt): New. (finish_range_for_decl): New. (finish_range_for_stmt): New. (perform_koenig_lookup): Add extra argument include_std. * parser.c (cp_parser_range_for): New. (cp_convert_range_for): New. (cp_parser_iteration_statement): Add range-for support. (cp_parser_condition): Adjust comment. (cp_parser_postfix_expression): perform_koenig_lookup takes extra argument. * dump.c (cp_dump_tree): Add RANGE_FOR_STMT. * cxx-pretty-print.c (): Likewise. * lex.c (cxx_init): Likewise. * name-lookup.c (lookup_function_nonclass): Add extra argument include_std. (lookup_arg_dependent): Likewise. * name-lookup.h (): Likewise. gcc/testsuite/ 2010-09-06 Rodrigo Rivas * g++.dg/cpp0x/range-for1.C: New. * g++.dg/cpp0x/range-for2.C: New. * g++.dg/cpp0x/range-for3.C: New. * g++.dg/cpp0x/range-for4.C: New. * g++.dg/cpp0x/range-for5.C: New. * g++.dg/cpp0x/range-for6.C: New. Index: gcc/cp/cxx-pretty-print.c =================================================================== --- gcc/cp/cxx-pretty-print.c (revision 163740) +++ gcc/cp/cxx-pretty-print.c (working copy) @@ -1921,6 +1921,23 @@ pp_cxx_statement (cxx_pretty_printer *pp, tree t) pp_needs_newline (pp) = true; break; + case RANGE_FOR_STMT: + pp_cxx_ws_string (pp, "for"); + pp_space (pp); + pp_cxx_left_paren (pp); + pp_cxx_statement (pp, RANGE_FOR_DECL (t)); + pp_space (pp); + pp_needs_newline (pp) = false; + pp_colon (pp); + pp_space (pp); + pp_cxx_statement (pp, RANGE_FOR_EXPR (t)); + pp_cxx_right_paren (pp); + pp_newline_and_indent (pp, 3); + pp_cxx_statement (pp, FOR_BODY (t)); + pp_indentation (pp) -= 3; + pp_needs_newline (pp) = true; + break; + /* jump-statement: goto identifier; continue ; Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 163740) +++ gcc/cp/pt.c (working copy) @@ -11729,7 +11729,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t com case FOR_STMT: stmt = begin_for_stmt (); - RECUR (FOR_INIT_STMT (t)); + RECUR (FOR_INIT_STMT (t)); finish_for_init_stmt (stmt); tmp = RECUR (FOR_COND (t)); finish_for_cond (tmp, stmt); @@ -11739,6 +11739,20 @@ tsubst_expr (tree t, tree args, tsubst_flags_t com finish_for_stmt (stmt); break; + case RANGE_FOR_STMT: + { + tree decl, expr; + stmt = begin_for_stmt (); + decl = RANGE_FOR_DECL (t); + decl = tsubst (decl, args, complain, in_decl); + maybe_push_decl (decl); + expr = RECUR (RANGE_FOR_EXPR (t)); + stmt = cp_convert_range_for (stmt, decl, expr); + RECUR (RANGE_FOR_BODY (t)); + finish_for_stmt (stmt); + } + break; + case WHILE_STMT: stmt = begin_while_stmt (); tmp = RECUR (WHILE_COND (t)); @@ -12523,7 +12537,7 @@ tsubst_copy_and_build (tree t, into a non-dependent call. */ && type_dependent_expression_p_push (t) && !any_type_dependent_arguments_p (call_args)) - function = perform_koenig_lookup (function, call_args); + function = perform_koenig_lookup (function, call_args, false); if (TREE_CODE (function) == IDENTIFIER_NODE) { Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 163740) +++ gcc/cp/semantics.c (working copy) @@ -894,6 +894,53 @@ finish_for_stmt (tree for_stmt) finish_stmt (); } +/* Begin a range-for-statement. Returns a new RANGE_FOR_STMT. */ + +tree +begin_range_for_stmt (void) +{ + 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); + + return r; +} + +/* Finish the head of a range-based for statement, which may + be given by RANGE_FOR_STMT. DECL must be the declaration + and EXPR must be the loop expression. */ + +void +finish_range_for_decl (tree range_for_stmt, tree decl, tree expr) +{ + RANGE_FOR_DECL (range_for_stmt) = decl; + RANGE_FOR_EXPR (range_for_stmt) = expr; + add_stmt (range_for_stmt); + RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block); +} + +/* Finish the body of a range-for-statement, which may be given by + RANGE_FOR_STMT. */ + +void +finish_range_for_stmt (tree range_for_stmt) +{ + RANGE_FOR_BODY (range_for_stmt) + = do_poplevel (RANGE_FOR_BODY (range_for_stmt)); + + /* Pop the scope for the body of the loop. */ + if (flag_new_for_scope > 0) + { + tree scope = TREE_CHAIN (range_for_stmt); + TREE_CHAIN (range_for_stmt) = NULL; + add_stmt (do_poplevel (scope)); + } + + finish_stmt (); +} + /* Finish a break-statement. */ tree @@ -1839,11 +1886,12 @@ empty_expr_stmt_p (tree expr_stmt) /* Perform Koenig lookup. FN is the postfix-expression representing the function (or functions) to call; ARGS are the arguments to the - call. Returns the functions to be considered by overload - resolution. */ + call; if INCLUDE_STD then the `std' namespace is automatically + considered an associated namespace (used in range-based for loops). + Returns the functions to be considered by overload resolution. */ tree -perform_koenig_lookup (tree fn, VEC(tree,gc) *args) +perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std) { tree identifier = NULL_TREE; tree functions = NULL_TREE; @@ -1879,7 +1927,7 @@ tree if (!any_type_dependent_arguments_p (args) && !any_dependent_template_arguments_p (tmpl_args)) { - fn = lookup_arg_dependent (identifier, functions, args); + fn = lookup_arg_dependent (identifier, functions, args, include_std); if (!fn) /* The unqualified name could not be resolved. */ fn = unqualified_fn_lookup_error (identifier); Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 163740) +++ gcc/cp/parser.c (working copy) @@ -1825,6 +1825,8 @@ static tree cp_parser_iteration_statement (cp_parser *); static void cp_parser_for_init_statement (cp_parser *); +static bool cp_parser_range_for + (cp_parser *, tree *, tree *, tree *); static tree cp_parser_jump_statement (cp_parser *); static void cp_parser_declaration_statement @@ -5167,7 +5169,8 @@ cp_parser_postfix_expression (cp_parser *parser, b koenig_p = true; if (!any_type_dependent_arguments_p (args)) postfix_expression - = perform_koenig_lookup (postfix_expression, args); + = perform_koenig_lookup (postfix_expression, args, + /*include_std=*/false); } else postfix_expression @@ -5191,7 +5194,8 @@ cp_parser_postfix_expression (cp_parser *parser, b koenig_p = true; if (!any_type_dependent_arguments_p (args)) postfix_expression - = perform_koenig_lookup (postfix_expression, args); + = perform_koenig_lookup (postfix_expression, args, + /*include_std=*/false); } } } @@ -8576,6 +8580,210 @@ cp_parser_condition (cp_parser* parser) return cp_parser_expression (parser, /*cast_p=*/false, NULL); } +/* 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(). + + Returns TRUE iff a range-based for is parsed. */ + +static bool +cp_parser_range_for (cp_parser *parser, tree *stmt, tree *decl, tree *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 false; + } + /* 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 false; + + cp_parser_require (parser, CPP_COLON, RT_COLON); + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_non_constant_p; + *expr = cp_parser_braced_list (parser, &expr_non_constant_p); + } + else + *expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + + /* If in template, STMT is converted to a normal for-statements + at instantiation. If not, it is done just now. */ + if (processing_template_decl) + *stmt = begin_range_for_stmt (); + else + *stmt = begin_for_stmt (); + + /* Create the declaration. */ + *decl = start_decl (declarator, &type_specifiers, + /*initialized_p=*/SD_INITIALIZED, + attributes, /*prefix_attributes=*/NULL_TREE, + &pushed_scope); + pop_scope (pushed_scope); + return true; +} + +/* Converts a range-based for-statement into a normal + for-statement, as per the definition. + + for (RANGE_DECL : RANGE_EXPR) + BLOCK + + should be equivalent to: + + { + auto &&__range = RANGE_EXPR; + for (auto __begin = BEGIN_EXPR, end = END_EXPR; + __begin != __end; + ++__begin) + { + RANGE_DECL = *__begin; + BLOCK + } + } + + If RANGE_EXPR is an array: + BEGIN_EXPR = __range + END_EXPR = __range + ARRAY_SIZE(__range) + Else: + BEGIN_EXPR = begin(__range) + END_EXPR = end(__range); + + When calling begin()/end() we must use argument dependent + lookup, but always considering 'std' as an associated namespace. +*/ + +tree +cp_convert_range_for (tree statement, tree range_decl, tree range_expr) +{ + tree range_type, range_temp; + tree begin, end; + 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 = create_temporary_var (range_type); + add_decl_expr (range_temp); + finish_expr_stmt (cp_build_modify_expr (range_temp, INIT_EXPR, range_expr, + tf_warning_or_error)); + 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); + } + 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 */ + begin = create_temporary_var (iter_type); + add_decl_expr (begin); + finish_expr_stmt (cp_build_modify_expr (begin, INIT_EXPR, begin_expr, + tf_warning_or_error)); + end = create_temporary_var (iter_type); + add_decl_expr (end); + finish_expr_stmt (cp_build_modify_expr (end, INIT_EXPR, end_expr, + tf_warning_or_error)); + + finish_for_init_stmt (statement); + +/* The new for condition */ + condition = build_x_binary_op (NE_EXPR, + begin, ERROR_MARK, + end, ERROR_MARK, + NULL, tf_warning_or_error); + finish_for_cond (condition, statement); + + /* The new increment expression */ + expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin); + finish_for_expr (expression, statement); + + /* The declaration is initialized with *__begin inside the loop body */ + cp_finish_decl (range_decl, + build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error), + /*is_constant_init*/false, NULL_TREE, + LOOKUP_ONLYCONVERTING); + + return statement; +} + + /* Parse an iteration-statement. iteration-statement: @@ -8584,7 +8792,7 @@ cp_parser_condition (cp_parser* parser) for ( for-init-statement condition [opt] ; expression [opt] ) statement - Returns the new WHILE_STMT, DO_STMT, or FOR_STMT. */ + Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT. */ static tree cp_parser_iteration_statement (cp_parser* parser) @@ -8657,28 +8865,59 @@ cp_parser_iteration_statement (cp_parser* parser) case RID_FOR: { - tree condition = NULL_TREE; - tree expression = NULL_TREE; + tree range_decl, range_expr; - /* Begin the for-statement. */ - statement = begin_for_stmt (); /* Look for the `('. */ cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); - /* Parse the initialization. */ - cp_parser_for_init_statement (parser); - finish_for_init_stmt (statement); - /* If there's a condition, process it. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) - condition = cp_parser_condition (parser); - finish_for_cond (condition, statement); - /* Look for the `;'. */ - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + if (cxx_dialect == cxx0x && + cp_parser_range_for (parser, &statement, &range_decl, &range_expr)) + { + if (TREE_CODE (statement) == RANGE_FOR_STMT) + { + finish_range_for_decl (statement, range_decl, range_expr); + /* Look for the `)'. */ + cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - /* If there's an expression, process it. */ - if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) - expression = cp_parser_expression (parser, /*cast_p=*/false, NULL); - finish_for_expr (expression, statement); + /* Parse the body of the range-based for-statement. */ + parser->in_statement = IN_ITERATION_STMT; + cp_parser_already_scoped_statement (parser); + parser->in_statement = in_statement; + + finish_range_for_stmt (statement); + break; + } + gcc_assert (TREE_CODE (statement) == FOR_STMT); + /* Convert the range-based for loon into a normal for-statement. */ + statement + = cp_convert_range_for (statement, range_decl, range_expr); + /* The body is then parsed as usual */ + } + else + { + /* Normal for loop */ + tree condition = NULL_TREE; + tree expression = NULL_TREE; + + /* Begin the for-statement. */ + statement = begin_for_stmt (); + + /* Parse the initialization. */ + cp_parser_for_init_statement (parser); + finish_for_init_stmt (statement); + + /* If there's a condition, process it. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) + condition = cp_parser_condition (parser); + finish_for_cond (condition, statement); + /* Look for the `;'. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + /* If there's an expression, process it. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)) + expression = cp_parser_expression (parser, /*cast_p=*/false, NULL); + finish_for_expr (expression, statement); + } /* Look for the `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); Index: gcc/cp/cp-tree.def =================================================================== --- gcc/cp/cp-tree.def (revision 163740) +++ gcc/cp/cp-tree.def (working copy) @@ -293,6 +293,10 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 3) FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively. */ DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 4) +/* Used to represent a range-based `for' statement. The operands are + RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, respectively. */ +DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 3) + /* Used to represent a 'while' statement. The operands are WHILE_COND and WHILE_BODY, respectively. */ DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2) Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 163740) +++ gcc/cp/cp-tree.h (working copy) @@ -3799,6 +3801,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a #define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) #define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) +/* RANGE_FOR_STMT accessors. These give access to the declarator, + expression and body of the statement, respectively. */ +#define RANGE_FOR_DECL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 0) +#define RANGE_FOR_EXPR(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 1) +#define RANGE_FOR_BODY(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 2) + #define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) #define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) #define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) @@ -4009,6 +4017,7 @@ extern int function_depth; sizeof can be nested. */ extern int cp_unevaluated_operand; +extern tree cp_convert_range_for (tree, tree, tree); /* in pt.c */ @@ -5189,6 +5198,9 @@ 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 void finish_range_for_decl (tree, tree, tree); +extern void finish_range_for_stmt (tree); extern tree finish_break_stmt (void); extern tree finish_continue_stmt (void); extern tree begin_switch_stmt (void); @@ -5229,7 +5241,7 @@ extern tree finish_stmt_expr_expr (tree, tree); extern tree finish_stmt_expr (tree, bool); extern tree stmt_expr_value_expr (tree); bool empty_expr_stmt_p (tree); -extern tree perform_koenig_lookup (tree, VEC(tree,gc) *); +extern tree perform_koenig_lookup (tree, VEC(tree,gc) *, bool); extern tree finish_call_expr (tree, VEC(tree,gc) **, bool, bool, tsubst_flags_t); extern tree finish_increment_expr (tree, enum tree_code); Index: gcc/cp/dump.c =================================================================== --- gcc/cp/dump.c (revision 163740) +++ gcc/cp/dump.c (working copy) @@ -453,6 +453,13 @@ cp_dump_tree (void* dump_info, tree t) dump_child ("body", FOR_BODY (t)); break; + case RANGE_FOR_STMT: + dump_stmt (di, t); + dump_child ("decl", RANGE_FOR_DECL (t)); + dump_child ("expr", RANGE_FOR_EXPR (t)); + dump_child ("body", RANGE_FOR_BODY (t)); + break; + case SWITCH_STMT: dump_stmt (di, t); dump_child ("cond", SWITCH_STMT_COND (t)); Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 163740) +++ gcc/cp/name-lookup.c (working copy) @@ -4389,7 +4389,7 @@ lookup_function_nonclass (tree name, VEC(tree,gc) lookup_arg_dependent (name, lookup_name_real (name, 0, 1, block_p, 0, LOOKUP_COMPLAIN), - args); + args, false); } tree @@ -5063,7 +5063,8 @@ arg_assoc (struct arg_lookup *k, tree n) are the functions found in normal lookup. */ tree -lookup_arg_dependent (tree name, tree fns, VEC(tree,gc) *args) +lookup_arg_dependent (tree name, tree fns, VEC(tree,gc) *args, + bool include_std) { struct arg_lookup k; @@ -5086,6 +5087,8 @@ tree picking up later definitions) in the second stage. */ k.namespaces = make_tree_vector (); + if (include_std) + arg_assoc_namespace(&k, std_node); arg_assoc_args_vec (&k, args); fns = k.functions; Index: gcc/cp/lex.c =================================================================== --- gcc/cp/lex.c (revision 163740) +++ gcc/cp/lex.c (working copy) @@ -226,8 +226,9 @@ cxx_init (void) CTOR_INITIALIZER, TRY_BLOCK, HANDLER, EH_SPEC_BLOCK, USING_STMT, TAG_DEFN, IF_STMT, CLEANUP_STMT, FOR_STMT, - WHILE_STMT, DO_STMT, BREAK_STMT, - CONTINUE_STMT, SWITCH_STMT, EXPR_STMT + RANGE_FOR_STMT, WHILE_STMT, DO_STMT, + BREAK_STMT, CONTINUE_STMT, SWITCH_STMT, + EXPR_STMT }; memset (&statement_code_p, 0, sizeof (statement_code_p)); Index: gcc/cp/name-lookup.h =================================================================== --- gcc/cp/name-lookup.h (revision 163740) +++ gcc/cp/name-lookup.h (working copy) @@ -342,7 +342,7 @@ extern void do_toplevel_using_decl (tree, tree, tr extern void do_local_using_decl (tree, tree, tree); extern tree do_class_using_decl (tree, tree); extern void do_using_directive (tree); -extern tree lookup_arg_dependent (tree, tree, VEC(tree,gc) *); +extern tree lookup_arg_dependent (tree, tree, VEC(tree,gc) *, bool); extern bool is_associated_namespace (tree, tree); extern void parse_using_directive (tree, tree); extern tree innermost_non_namespace_value (tree); Index: gcc/testsuite/g++.dg/cpp0x/range-for1.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for1.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for1.C (revision 0) @@ -0,0 +1,17 @@ +// Test for range-based for loop +// Test the loop with an array + +// { dg-do run } +// { dg-options "-std=c++0x" } + +extern "C" void abort(); + +int main() +{ + int a[] = {1,2,3,4}; + int sum = 0; + for (int x : a) + sum += x; + if (sum != 10) + abort(); +} Index: gcc/testsuite/g++.dg/cpp0x/range-for2.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for2.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for2.C (revision 0) @@ -0,0 +1,41 @@ +// Test for range-based for loop +// Test the loop with a custom iterator +// with begin/end in an associated namespace + +// { dg-do compile } +// { dg-options "-std=c++0x" } + +struct iterator +{ + int x; + iterator(int v) :x(v) {} + iterator &operator ++() { ++x; return *this; } + int operator *() { return x; } + bool operator != (const iterator &o) { return x != o.x; } +}; + +namespace foo +{ + struct container + { + int min, max; + container(int a, int b) :min(a), max(b) {} + }; + + iterator begin(container &c) + { + return iterator(c.min); + } + + iterator end(container &c) + { + return iterator(c.max + 1); + } +} + +int main() +{ + foo::container c(1,4); + for (iterator it : c) + ; +} Index: gcc/testsuite/g++.dg/cpp0x/range-for3.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for3.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for3.C (revision 0) @@ -0,0 +1,42 @@ +// Test for range-based for loop +// Test the loop with a custom iterator +// with begin/end in std + +// { dg-do compile } +// { dg-options "-std=c++0x" } + +struct iterator +{ + int x; + iterator(int v) :x(v) {} + iterator &operator ++() { ++x; return *this; } + int operator *() { return x; } + bool operator != (const iterator &o) { return x != o.x; } +}; + +struct container +{ + int min, max; + container(int a, int b) :min(a), max(b) {} +}; + +namespace std +{ + iterator begin(container &c) + { + return iterator(c.min); + } + + iterator end(container &c) + { + return iterator(c.max + 1); + } +} + +int main() +{ + container c(1,4); + for (iterator it : c) + { + } +} Index: gcc/testsuite/g++.dg/cpp0x/range-for4.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for4.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for4.C (revision 0) @@ -0,0 +1,107 @@ +// Test for range-based for loop with templates + +// { dg-do run } +// { dg-options "-std=c++0x" } + +#include + +/* Preliminary declarations */ +namespace pre +{ + struct iterator + { + int x; + iterator (int v) :x(v) {} + iterator &operator ++() { ++x; return *this; } + int operator *() { return x; } + bool operator != (const iterator &o) { return x != o.x; } + }; + + struct container + { + int min, max; + container(int a, int b) :min(a), max(b) {} + }; + + iterator begin(const container &c) + { + return iterator(c.min); + } + + iterator end(const container &c) + { + return iterator(c.max); + } + +} //namespace pre + +using pre::container; + +/* Template with dependent expression. */ +/* Template with dependent expression. */ +template int test1(const T &r) +{ + int t = 0; + for (int i : r) + t += i; + return t; +} + +/* Template with non-dependent expression and dependent declaration. */ +template int test2(const container &r) +{ + int t = 0; + for (T i : r) + t += i; + return t; +} + +/* Template with non-dependent expression (array) and dependent declaration. */ +template int test2(const int (&r)[4]) +{ + int t = 0; + for (T i : r) + t += i; + return t; +} + +/* Template with non-dependent expression and auto declaration. */ +template int test3(const container &r) +{ + int t = 0; + for (auto i : r) + t += i; + return t; +} + +/* Template with non-dependent expression (array) and auto declaration. */ +template int test3(const int (&r)[4]) +{ + int t = 0; + for (auto i : r) + t += i; + return t; +} + +extern "C" void abort(void); +int main () +{ + container c(1,5); + int a[4] = {5,6,7,8}; + + if (test1 (c) != 10) + abort(); + if (test1 (a) != 26) + abort(); + + if (test2 (c) != 10) + abort(); + if (test2 (a) != 26) + abort(); + + if (test3 (c) != 10) + abort(); + if (test3 (a) != 26) + abort(); + return 0; +} Index: gcc/testsuite/g++.dg/cpp0x/range-for5.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for5.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for5.C (revision 0) @@ -0,0 +1,54 @@ +// Test for errors in range-based for loops + +// { dg-do compile } +// { dg-options "-std=c++0x" } + +struct container +{ +}; + +int *begin(const container &c) +{ + return 0; +} + +int end(const container &c) //Ops! wrong type +{ + return 0; +} + + +struct Implicit +{ + Implicit(int x) + {} +}; +struct Explicit +{ + explicit Explicit(int x) + {} +}; + +void test1() +{ + container c; + for (int x : c) // { dg-error "inconsistent|conversion" } + ; + + int a[2] = {1,2}; + for (Implicit x : a) + ; + for (Explicit x : a) // { dg-error "conversion" } + ; + for (const Implicit &x : a) + ; + for (Implicit &&x : a) + ; + + //Check the correct scopes + int i; + for (int i : a) + { + int i; + } +} Index: gcc/testsuite/g++.dg/cpp0x/range-for6.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/range-for6.C (revision 0) +++ gcc/testsuite/g++.dg/cpp0x/range-for6.C (revision 0) @@ -0,0 +1,29 @@ +// Test for range-based for loop +// Test the loop with an initializer_list + +// { dg-do run } +// { dg-options "-std=c++0x" } + +#include + +extern "C" void abort(); + +template T foo() +{ + T sum = 0; + for (T x : {T(1),T(2),T(3),T(4)}) + sum += x; + if (sum != T(10)) + abort(); +} + +int main() +{ + int sum = 0; + for (int x : {1,2,3,4}) + sum += x; + if (sum != 10) + abort(); + + foo(); +}