A proposal accepted at the last meeting allows the deduced iterator and
end variables in range-based for to have different types, as long as
they can be compared. This is a very simple change, limited to C++1z
mode, and desired by some of the heaviest users of concepts, so I'm
going to go ahead and make it.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 196599301ea3a46cda7eb633623b0dfd2079bc45
Author: Jason Merrill <ja...@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.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6ae45b0..d38f1dd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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;
}
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for5.C b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
index bf04406..2a20db4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/range-for5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for5.C
@@ -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};
diff --git a/gcc/testsuite/g++.dg/cpp1z/range-for1.C b/gcc/testsuite/g++.dg/cpp1z/range-for1.C
new file mode 100644
index 0000000..370381a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/range-for1.C
@@ -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 ();
+}