diff mbox

[c++-concepts] Change constraint equivalence

Message ID 53AD1BBF.9050904@maniacsvault.net
State New
Headers show

Commit Message

Braden Obrzut June 27, 2014, 7:22 a.m. UTC
To bring the implementation in line with changes going into the concepts 
draft, use syntactical equivalence in place of logical equivalence when 
matching declarations.

2014-06-27  Braden Obrzut <admin@maniacsvault.net>
     * gcc/cp/constraint.c (equivalent_constraints): Compare the trees 
directly
     instead of logically to bring implementation in line with standard 
changes.
     * gcc/cp/tree.c (cp_tree_equal): Handle comparison of constraints.
     * gcc/testsuite/g++.dg/concepts/equiv.C: New test.
     * gcc/testsuite/g++.dg/concepts/equiv-err.C: New test.

Comments

Marek Polacek June 27, 2014, 7:27 a.m. UTC | #1
On Fri, Jun 27, 2014 at 03:22:39AM -0400, Braden Obrzut wrote:
> To bring the implementation in line with changes going into the concepts
> draft, use syntactical equivalence in place of logical equivalence when
> matching declarations.
> 
> 2014-06-27  Braden Obrzut <admin@maniacsvault.net>

Two spaces after you name.

>     * gcc/cp/constraint.c (equivalent_constraints): Compare the trees
> directly
>     instead of logically to bring implementation in line with standard
> changes.
>     * gcc/cp/tree.c (cp_tree_equal): Handle comparison of constraints.
>     * gcc/testsuite/g++.dg/concepts/equiv.C: New test.
>     * gcc/testsuite/g++.dg/concepts/equiv-err.C: New test.

Please drop gcc/ and gcc/testsuite/ prefixes (the former goes to
cp/ChangeLog, the latter to testsuite/ChangeLog).

	Marek
Paolo Carlini June 27, 2014, 7:41 a.m. UTC | #2
Hi,

On 06/27/2014 09:41 AM, Braden Obrzut wrote:
> Are you sure about this?  Andrew has been putting everything in 
> ChangeLog.concepts in the root.
In terms of general GCC rules, Marek is certainly right. Whether Andrew 
has (very) special reasons for doing that I don't know, meant to ask for 
some time, actually.

Paolo.
Braden Obrzut June 27, 2014, 7:41 a.m. UTC | #3
On 06/27/2014 03:27 AM, Marek Polacek wrote:
> Two spaces after you name.
I'm not sure what happened to the second space.  It's there in the 
source I copied.  I'll have to be sure to double check the paste next time.
> Please drop gcc/ and gcc/testsuite/ prefixes (the former goes to
> cp/ChangeLog, the latter to testsuite/ChangeLog).
>
> 	Marek
Are you sure about this?  Andrew has been putting everything in 
ChangeLog.concepts in the root.

- Braden Obrzut
Marek Polacek June 27, 2014, 7:45 a.m. UTC | #4
On Fri, Jun 27, 2014 at 03:41:36AM -0400, Braden Obrzut wrote:
> On 06/27/2014 03:27 AM, Marek Polacek wrote:
> >Two spaces after you name.
> I'm not sure what happened to the second space.  It's there in the source I
> copied.  I'll have to be sure to double check the paste next time.
> >Please drop gcc/ and gcc/testsuite/ prefixes (the former goes to
> >cp/ChangeLog, the latter to testsuite/ChangeLog).
> >
> >	Marek
> Are you sure about this?  Andrew has been putting everything in
> ChangeLog.concepts in the root.

Ah, sorry, for concepts you indeed might be using ChangeLog.concepts.

	Marek
Andrew Sutton June 27, 2014, 10:53 a.m. UTC | #5
> Please drop gcc/ and gcc/testsuite/ prefixes (the former goes to
> cp/ChangeLog, the latter to testsuite/ChangeLog).

This is the format (and file) that Gaby requested when we started the
project. We can certainly distribute the entries, but I don't know if
its worthwhile right now.

Andrew
diff mbox

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 01e83ba..5a3cf4d 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1199,7 +1199,7 @@  equivalent_constraints (tree a, tree b)
   if (a == b)
     return true;
   else
-    return subsumes (a, b) && subsumes (b, a);
+    return cp_tree_equal (a, b);
 }
 
 // Returns true if the template declarations A and B have equivalent
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 5d88806..f1d8545 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2775,6 +2775,10 @@  cp_tree_equal (tree t1, tree t2)
 	      && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)),
 			      TREE_TYPE (TEMPLATE_PARM_DECL (t2))));
 
+    case CONSTRAINT_INFO:
+      return cp_tree_equal (CI_SPELLING (t1), CI_SPELLING (t2));
+
+    case REQUIRES_EXPR:
     case TEMPLATE_ID_EXPR:
       return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
 	      && cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
diff --git a/gcc/testsuite/g++.dg/concepts/equiv-err.C b/gcc/testsuite/g++.dg/concepts/equiv-err.C
new file mode 100644
index 0000000..7dc8b10
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/equiv-err.C
@@ -0,0 +1,108 @@ 
+// { dg-options "-std=c++1y" }
+
+// Test case for determining syntactical equivalence in constraints.
+// Tests for compile time errors
+
+#include <cassert>
+
+int called;
+
+template<typename T>
+  concept bool C() { return __is_class(T); }
+
+template<typename T>
+  concept bool D() { return requires (T a) { { a + a } -> T }; }
+
+template<typename T>
+  concept bool CD()
+  {
+    return __is_class(T)
+           && requires (T a) { { a + a } -> T };
+  }
+
+template<typename T>
+  requires CD<T>()
+  void f1(T);
+
+struct S1
+{
+	void f2(CD); // { dg-error "candidate" }
+
+	static void f3(CD, CD); // { dg-error "candidate" }
+};
+
+struct S2
+{
+	S2 operator+ (const S2 &other) { return S2(); }
+};
+
+template<typename T>
+struct S3
+{
+	void f4(T);
+
+	static void f5(T);
+};
+
+template<CD T>
+struct S3<T>
+{
+	void f4(T);
+
+	static void f5(T);
+};
+
+int main()
+{
+	S1 s;
+	S2 v;
+	S3<S2> v2;
+	S3<int> v3;
+
+	f1(v); assert (called == 1);
+
+	s.f2(v); assert (called == 1);
+
+	S1::f3(v, v); assert (called == 1);
+
+	v2.f4(v); assert (called == 1);
+
+	S3<S2>::f5(v); assert (called == 1);
+	return 0;
+}
+
+// This template has the same atomic constraints in the same order, but is
+// not considered equivalent, so this should never get called.
+template<typename T>
+  requires C<T>() && D<T>()
+  void f1(T)
+  {
+    called = 3;
+  }
+
+template<typename T>
+  requires C<T>() && D<T>()
+  void S1::f2(T) // { dg-error "match any" }
+  {
+    called = 1;
+  }
+
+template<C T>
+  requires D<T>()
+  void S1::f3(T, T) // { dg-error "match any" }
+  {
+    called = 1;
+  }
+
+template<D T>
+  requires C<T>()
+  void S3<T>::f4(T)
+  {
+    called = 1;
+  }
+
+template<CD T>
+  void S3<T>::f5(T)
+  {
+    called = 1;
+  }
diff --git a/gcc/testsuite/g++.dg/concepts/equiv.C b/gcc/testsuite/g++.dg/concepts/equiv.C
new file mode 100644
index 0000000..e97d4db
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/equiv.C
@@ -0,0 +1,144 @@ 
+// { dg-do run }
+// { dg-options "-std=c++1y" }
+
+// Test case for determining syntactical equivalence in constraints.
+
+#include <cassert>
+
+int called;
+
+template<typename T>
+  concept bool C() { return __is_class(T); }
+
+template<typename T>
+  concept bool D() { return requires (T a) { { a + a } -> T }; }
+
+template<typename T>
+  concept bool CD()
+  {
+    return __is_class(T)
+           && requires (T a) { { a + a } -> T };
+  }
+
+template<typename T>
+  requires CD<T>()
+  void f1(T);
+void f1(auto) { called = 2; }
+
+struct S1
+{
+	void f2(C);
+	void f2(CD);
+
+	template<typename T>
+	  static void f3(T, T);
+	static void f3(CD, CD);
+};
+
+struct S2
+{
+	S2 operator+ (const S2 &other) { return S2(); }
+};
+
+template<typename T>
+struct S3
+{
+	void f4(T);
+
+	static void f5(T);
+};
+
+template<CD T>
+struct S3<T>
+{
+	void f4(T);
+
+	static void f5(T);
+};
+
+int main()
+{
+	S1 s;
+	S2 v;
+	S3<S2> v2;
+	S3<int> v3;
+
+	f1(v); assert (called == 1);
+	f1(123); assert (called == 2);
+
+	s.f2(v); assert (called == 1);
+	s.f2(s); assert (called == 2);
+
+	S1::f3(12, 34); assert (called == 2);
+	S1::f3(v, v); assert (called == 1);
+
+	v2.f4(v); assert (called == 1);
+	v3.f4(123); assert (called == 2);
+
+	S3<S2>::f5(v); assert (called == 1);
+	S3<int>::f5(123); assert (called == 2);
+	return 0;
+}
+
+// This template has the same atomic constraints in the same order, but is
+// not considered equivalent, so this should never get called.
+template<typename T>
+  requires C<T>() && D<T>()
+  void f1(T)
+  {
+    called = 3;
+  }
+
+void f1(CD)
+{
+	called = 1;
+}
+
+template<C T>
+  void S1::f2(T)
+  {
+     called = 2;
+  }
+
+void S1::f2(CD)
+{
+	called = 1;
+}
+
+template<typename T>
+  requires CD<T>()
+  void S1::f3(T, T)
+  {
+    called = 1;
+  }
+
+template<typename T>
+  void S1::f3(T, T)
+  {
+    called = 2;
+  }
+
+template<CD T>
+  void S3<T>::f4(T)
+  {
+    called = 1;
+  }
+
+template<typename T>
+  void S3<T>::f4(T)
+  {
+    called = 2;
+  }
+
+template<typename T>
+  requires CD<T>()
+  void S3<T>::f5(T)
+  {
+    called = 1;
+  }
+
+template<typename T>
+  void S3<T>::f5(T)
+  {
+    called = 2;
+  }