Hello all.

I've just read the paper titled "Range-based for statements and ADL"
by Jonathan Wakely and Bjarne Stroustrup at:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3257.pdf

The point of this article is that the argument dependent lookup in the
range-for specification will make some trouble in the real world. E.g:
#include <vector>
namespace n
{
    struct X { void begin(); };
    struct Y { void begin(); };
    template<typename T> void begin(T& t) { t.begin(); }
}
int main()
{
    std::vector<n::X> v;
    for (auto i : v)  // error: call to begin is ambiguous: std::begin
or n::begin?
    {
        //...
    }
}

I've implemented Option 5 from the paper (which is the coolest, IMHO):
 - [...], if _rangeT has a member begin or a member end, begin-expr
and end-expr are __range.begin() and __range.end(), respectively
 - otherwise, begin-expr and end-expr are begin(__range) and
end(__range), respectively, where begin and end are looked up with
argument-dependent lookup [...]

I'm not sure about what should happen if _rangeT has a member begin
but not a member end. I think that there are just two sensible
options:
 * Use them only if both members, begin and end, exist.
 * Look for them independently. This is what my patch does.

Also, if the member begin/end is not accessible or not callable, a
compiler error will follow immediately (this is as expected).

I'll appreciate any comments.

Best regards
--
Rodrigo
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a9fd201..8fc77a0 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1871,6 +1871,8 @@ 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_perform_range_for_lookup
+  (const char *, tree);
 static tree cp_parser_jump_statement
   (cp_parser *);
 static void cp_parser_declaration_statement
@@ -8870,25 +8872,8 @@ cp_convert_range_for (tree statement, tree range_decl, 
tree range_expr)
       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);
+         begin_expr = cp_parser_perform_range_for_lookup("begin", range_temp);
+         end_expr = cp_parser_perform_range_for_lookup("end", range_temp);
 
          /* The unqualified type of the __begin and __end temporaries should
           * be the same as required by the multiple auto declaration */
@@ -8940,6 +8925,42 @@ cp_convert_range_for (tree statement, tree range_decl, 
tree range_expr)
   return statement;
 }
 
+static tree
+cp_parser_perform_range_for_lookup (const char *name, tree range)
+{
+  tree ident, expr;
+
+  ident = get_identifier (name);
+  expr = build_qualified_name (/*type=*/NULL_TREE,
+                              TREE_TYPE (range),
+                              ident,
+                              /*template_p=*/false);
+  expr = finish_class_member_access_expr(range, expr, false, tf_none);
+
+  if (expr != error_mark_node)
+    {
+      tree instance, fn;
+      instance = TREE_OPERAND (expr, 0);
+      fn = TREE_OPERAND (expr, 1);
+
+      expr = build_new_method_call (instance, fn, NULL, NULL, LOOKUP_NORMAL,
+                                   NULL, tf_warning_or_error);
+    }
+  else
+    {
+      VEC(tree,gc) *vec;
+      vec = make_tree_vector ();
+      VEC_safe_push (tree, gc, vec, range);
+      expr = get_identifier (name);
+      expr = perform_koenig_lookup (expr, vec,
+                                   /*include_std=*/true);
+      expr = finish_call_expr (expr, &vec, false, true,
+                              tf_warning_or_error);
+      release_tree_vector (vec);
+    }
+  return expr;
+}
+
 
 /* Parse an iteration-statement.
 

Reply via email to