diff mbox

C++ PATCH for range-for tweak

Message ID 56E717A7.4020405@redhat.com
State New
Headers show

Commit Message

Jason Merrill March 14, 2016, 7:57 p.m. UTC
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.

Comments

Florian Weimer March 14, 2016, 9:30 p.m. UTC | #1
* Jason Merrill:

>     	P08184R0: Generalizing the Range-Based For Loop

How can one resolve this reference?  It's obviously not a PR number in
GCC Bugzilla.

I found this after some searching:

<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0184r0.html>

But it lacks the additional “8”.
diff mbox

Patch

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.

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 ();
+}