From patchwork Sun Sep 5 15:53:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ed Smith-Rowland <3dw4rd@verizon.net> X-Patchwork-Id: 63848 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 23568B70FD for ; Mon, 6 Sep 2010 01:54:28 +1000 (EST) Received: (qmail 6543 invoked by alias); 5 Sep 2010 15:54:26 -0000 Received: (qmail 6532 invoked by uid 22791); 5 Sep 2010 15:54:24 -0000 X-SWARE-Spam-Status: No, hits=4.6 required=5.0 tests=AWL, BAYES_00, BOTNET, RCVD_IN_DNSWL_NONE, TW_CX, TW_FN, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from vms173001pub.verizon.net (HELO vms173001pub.verizon.net) (206.46.173.1) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 05 Sep 2010 15:54:16 +0000 Received: from [192.168.1.3] ([unknown] [173.64.82.232]) by vms173001.mailsrvcs.net (Sun Java(tm) System Messaging Server 7u2-7.02 32bit (built Apr 16 2009)) with ESMTPA id <0L8A00J2U6U0BLHC@vms173001.mailsrvcs.net> for gcc-patches@gcc.gnu.org; Sun, 05 Sep 2010 10:54:02 -0500 (CDT) Message-id: <4C83BD10.2030901@verizon.net> Date: Sun, 05 Sep 2010 11:53:52 -0400 From: Ed Smith-Rowland <3dw4rd@verizon.net> User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100713 Thunderbird/3.0.6 MIME-version: 1.0 To: rodrigorivascosta@gmail.com, gcc-patches@gcc.gnu.org Cc: Paolo Carlini , Jason Merrill Subject: Re: [C++0x patch] implement range-based for loops Content-type: multipart/mixed; boundary=------------060706040509080903010303 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 Greetings Rodrigo, Thank you for your contribution of range-for. I was considering the same thing myself but you beat me to it. ;-) 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. Here is a revised patch and a toy program Also, in the latest draft n3126.pdf on is allowed to use an initilizer list: for (int a : {1, 2, 3, 4, 5}) a += 2; Thank you again for your work, Ed Smith-Rowland Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 163798) +++ gcc/cp/pt.c (working copy) @@ -12523,7 +12523,7 @@ 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 163798) +++ gcc/cp/semantics.c (working copy) @@ -1839,11 +1839,12 @@ /* 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 +1880,7 @@ 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 163798) +++ gcc/cp/parser.c (working copy) @@ -1825,6 +1825,10 @@ (cp_parser *); static void cp_parser_for_init_statement (cp_parser *); +static bool cp_parser_for_range + (cp_parser *, tree *, tree *); +static void cp_finish_range_based_for + (tree, tree, tree); static tree cp_parser_jump_statement (cp_parser *); static void cp_parser_declaration_statement @@ -5167,7 +5171,7 @@ koenig_p = true; if (!any_type_dependent_arguments_p (args)) postfix_expression - = perform_koenig_lookup (postfix_expression, args); + = perform_koenig_lookup (postfix_expression, args, false); } else postfix_expression @@ -5191,7 +5195,7 @@ koenig_p = true; if (!any_type_dependent_arguments_p (args)) postfix_expression - = perform_koenig_lookup (postfix_expression, args); + = perform_koenig_lookup (postfix_expression, args, false); } } } @@ -8576,6 +8580,172 @@ return cp_parser_expression (parser, /*cast_p=*/false, NULL); } +/* Tries to parse a range-based for: + + 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 it should call cp_finish_decl(). + + Returns TRUE iff a range-based for is parsed. */ + +static bool +cp_parser_for_range(cp_parser *parser, tree *decl, tree *expr) +{ + cp_decl_specifier_seq type_specifiers; + const char *saved_message; + cp_declarator *declarator; + 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); + *expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + + /* Create the declaration. */ + *decl = start_decl (declarator, &type_specifiers, + /*initialized_p=*/SD_INITIALIZED, + attributes, /*prefix_attributes=*/NULL_TREE, + &pushed_scope); + if (pushed_scope) /* No scopes allowed here */ + pop_scope(pushed_scope); + return true; +} + +/* Builds a range-based for loop. + The parameters RANGE_DECL and RANGE_EXPR are as returned + from the cp_parser_for_range() function. + + for (RANGE_DECL : RANGE_EXPR) + BLOCK + + should be built as: + { + 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 + countof(__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. +*/ +static void +cp_finish_range_based_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; + 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)); + + /* 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)); /* tf_none */ + + /* We must call begin(__range)/end__range() */ + 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 type of the __begin and __end temporaries should be the same + * as required by the multiple auto declaration */ + if (!same_type_p (TREE_TYPE (begin_expr), TREE_TYPE (end_expr))) + { + error ("inconsistent begin/end types in range-based for: %qT and %qT", + TREE_TYPE (begin_expr), TREE_TYPE (end_expr)); + } + iter_type = TREE_TYPE (begin_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); +} + + /* Parse an iteration-statement. iteration-statement: @@ -8657,31 +8827,41 @@ 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_for_range (parser, &range_decl, &range_expr)) + { + cp_finish_range_based_for (statement, range_decl, range_expr); + } + else + { + tree condition = NULL_TREE; + tree expression = NULL_TREE; - /* 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); + /* 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); + /* Parse the body of the for-statement. */ parser->in_statement = IN_ITERATION_STMT; cp_parser_already_scoped_statement (parser); Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 163798) +++ gcc/cp/cp-tree.h (working copy) @@ -5229,7 +5229,7 @@ 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/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 163798) +++ gcc/cp/name-lookup.c (working copy) @@ -4389,7 +4389,7 @@ lookup_arg_dependent (name, lookup_name_real (name, 0, 1, block_p, 0, LOOKUP_COMPLAIN), - args); + args, false); } tree @@ -5063,7 +5063,7 @@ 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 +5086,8 @@ 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/name-lookup.h =================================================================== --- gcc/cp/name-lookup.h (revision 163798) +++ gcc/cp/name-lookup.h (working copy) @@ -342,7 +342,7 @@ 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);