P08184R0: Generalizing the Range-Based For Loop
authorCasey Carter <casey@carter.net>
Mon, 14 Mar 2016 19:57:54 +0000 (19:57 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 14 Mar 2016 19:57:54 +0000 (15:57 -0400)
* 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 <jason@redhat.com>
From-SVN: r234191

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp0x/range-for5.C
gcc/testsuite/g++.dg/cpp1z/range-for1.C [new file with mode: 0644]

index 94e44275507baaf26e3f1542dcf75aafaf5b1107..1a668e89fdcfe78ddebcfed22681bbd66584c6af 100644 (file)
@@ -1,3 +1,11 @@
+2016-03-14  Casey Carter  <casey@carter.net>
+           Jason Merrill  <jason@redhat.com>
+
+       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  <ppalka@gcc.gnu.org>
 
        PR c++/70106
index 6ae45b0ca1add9b05c92c00e945e2116d6f2688f..d38f1dd9a5c228bdbadda028bfdddb12fe3173bb 100644 (file)
@@ -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;
        }
     }
index bf044068ba6bf1ad4099269cdde31a3781ca3193..2a20db47599cdc440f4bc45b7e1537ec16e06dd9 100644 (file)
@@ -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 (file)
index 0000000..370381a
--- /dev/null
@@ -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 ();
+}