From 598a208cc0442bf7109ee545fa82d6c0607b9adf Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 14 Mar 2016 19:57:54 +0000 Subject: [PATCH] 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. Co-Authored-By: Jason Merrill From-SVN: r234191 --- gcc/cp/ChangeLog | 8 ++++++++ gcc/cp/parser.c | 20 +++++++++++++++++--- gcc/testsuite/g++.dg/cpp0x/range-for5.C | 2 +- gcc/testsuite/g++.dg/cpp1z/range-for1.C | 23 +++++++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/range-for1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 94e44275507..1a668e89fdc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2016-03-14 Casey Carter + Jason Merrill + + 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. + 2016-03-12 Patrick Palka PR c++/70106 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6ae45b0ca1a..d38f1dd9a5c 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 % " - "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 % " + "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 bf044068ba6..2a20db47599 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 00000000000..370381ab60f --- /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 (); +} -- 2.30.2