commit 196599301ea3a46cda7eb633623b0dfd2079bc45
Author: Jason Merrill <jason@redhat.com>
Date: Sat Mar 5 07:45:02 2016 -0500
P08184R0: Generalizing the Range-Based For Loop
* parser.c (cp_convert_range_for): Set the type of __end separately.
(cp_parser_perform_range_for_lookup): Allow different begin/end
types if they are comparable.
@@ -11353,6 +11353,8 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
/*is_constant_init*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING);
+ if (cxx_dialect >= cxx1z)
+ iter_type = cv_unqualified (TREE_TYPE (end_expr));
end = build_decl (input_location, VAR_DECL,
get_identifier ("__for_end"), iter_type);
TREE_USED (end) = 1;
@@ -11488,9 +11490,21 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
/* The unqualified type of the __begin and __end temporaries should
be the same, as required by the multiple auto declaration. */
if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (*end))))
- error ("inconsistent begin/end types in range-based %<for%> "
- "statement: %qT and %qT",
- TREE_TYPE (*begin), TREE_TYPE (*end));
+ {
+ if (cxx_dialect >= cxx1z
+ && (build_x_binary_op (input_location, NE_EXPR,
+ *begin, ERROR_MARK,
+ *end, ERROR_MARK,
+ NULL, tf_none)
+ != error_mark_node))
+ /* P08184R0 allows __begin and __end to have different types,
+ but make sure they are comparable so we can give a better
+ diagnostic. */;
+ else
+ error ("inconsistent begin/end types in range-based %<for%> "
+ "statement: %qT and %qT",
+ TREE_TYPE (*begin), TREE_TYPE (*end));
+ }
return iter_type;
}
}
@@ -31,7 +31,7 @@ struct Explicit
void test1()
{
container c;
- for (int x : c) // { dg-error "inconsistent|conversion" }
+ for (int x : c) // { dg-error "inconsistent|conversion|comparison" }
;
int a[2] = {1,2};
new file mode 100644
@@ -0,0 +1,23 @@
+// P08184R0: Generalizing the Range-Based For Loop
+// { dg-options "-std=c++1z" }
+
+struct A {
+ int ar[4];
+ int *begin() { return ar; }
+ struct end_t {
+ int *p;
+ friend bool operator!= (int *p, end_t e) { return p != e.p; }
+ };
+ end_t end() { return { &ar[4] }; }
+};
+
+int main()
+{
+ A a { 1, 2, 3, 4 };
+ int i = 1;
+ for (auto x: a)
+ if (x != i++)
+ __builtin_abort ();
+ if (i != 5)
+ __builtin_abort ();
+}