From patchwork Fri Aug 27 13:18:37 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [C++0x] implement range-based for loops From: Rodrigo Rivas X-Patchwork-Id: 62852 Message-Id: To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Date: Fri, 27 Aug 2010 15:18:37 +0200 Thank you for your comments. They've been most helpful. Creating a new TREE type is 'major words' but I think I've done it right. The attached patch now fully (hopefully) supports templates. I've added several testcases for the template cases and the error messages, but I don't know if they are too many or too few... Comments welcome. --- Rodrigo Changelog -- gcc/cp 2010-08-27 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-08-27 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. Index: gcc/cp/cxx-pretty-print.c =================================================================== --- gcc/cp/cxx-pretty-print.c (revision 163579) +++ 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 163579) +++ gcc/cp/pt.c (working copy) @@ -11728,12 +11728,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t com /* A DECL_EXPR can also be used as an expression, in the condition clause of an if/for/while construct. */ return decl; } 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 163579) +++ 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 163579) +++ 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,203 @@ 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-statements"); + /* 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); + *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)); + + if (TREE_CODE (TREE_TYPE (range_expr)) == ARRAY_TYPE) + { + /* If RANGE_EXPR is an array we will use pointer arithmetic */ + iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_expr))); + begin_expr = range_expr; + end_expr + = build_binary_op (input_location, PLUS_EXPR, + range_expr, + array_type_nelts_top (TREE_TYPE (range_expr)), 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_expr); + 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_expr); + 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 +8785,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 +8858,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 163579) +++ 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 163579) +++ 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 163579) +++ 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 ("init", 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 163579) +++ 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 163579) +++ 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 163579) +++ 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-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-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,99 @@ +// 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 dependant expression. */ +/* Template with dependant expression. */ +template int test1(const T &r) +{ + int t = 0; + for (int i : r) + t += i; + return t; +} + +/* Template with non-dependant expression and dependant declaration. */ +template int test2(const container &r) +{ + int t = 0; + for (T i : r) + t += i; + return t; +} + +/* Template with non-dependant expression (array) and dependant declaration. */ +template int test2(const int (&r)[4]) +{ + int t = 0; + for (T i : r) + t += i; + return t; +} + +/* Template with non-dependant expression and auto declaration. */ +template int test3(const container &r) +{ + int t = 0; + for (auto i : r) + t += i; + return t; +} + +/* Template with non-dependant expression (array) and auto declaration. */ +template int test3(const int (&r)[4]) +{ + int t = 0; + for (auto i : r) + t += i; + return t; +} + +int main () +{ + container c (1,5); + int a[4] = {5,6,7,8}; + + std::printf ("%d ", test1 (c)); // { dg-output "10 " } + std::printf ("%d ", test1 (a)); // { dg-output "26 " } + + std::printf ("%d ", test2 (c)); // { dg-output "10 " } + std::printf ("%d ", test2 (a)); // { dg-output "26 " } + + std::printf ("%d ", test3 (c)); // { dg-output "10 " } + std::printf ("%d ", test3 (a)); // { dg-output "26 " } +}