[C++ PATCH] PR c++/92268 - hard error satisfying return-type-requirement

Jason Merrill jason@redhat.com
Thu Oct 31 02:19:00 GMT 2019


Previously we would put the template arguments for the concept-check in a
TEMPLATE_ID and then also pass them to constraints_satisfied_p, which meant
that we would try to normalize the concept-check with the fully instantiated
arguments, leading to sadness.  Simply not passing the args to
constraints_satisfied_p fixes the problem.

I also noticed that we weren't detecting substitution failure in the
constraints, but were silently treating it as success.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* constraint.cc (type_deducible_p): Check for substitution failure.
	(diagnose_compound_requirement): Adjust diagnostic.
	* pt.c (do_auto_deduction): Don't pass cargs to
	constraints_satisfied_p.
---
 gcc/cp/constraint.cc                          | 15 +++++++++------
 gcc/cp/pt.c                                   |  2 +-
 gcc/testsuite/g++.dg/concepts/diagnostic1.C   |  4 ++--
 gcc/testsuite/g++.dg/concepts/placeholder3.C  |  2 +-
 gcc/testsuite/g++.dg/concepts/placeholder4.C  |  2 +-
 gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C |  2 +-
 .../g++.dg/cpp2a/concepts-requires6.C         |  2 +-
 .../g++.dg/cpp2a/concepts-return-req1.C       | 19 +++++++++++++++++++
 8 files changed, 35 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-return-req1.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b8a2645d8c9..db2a30ced7c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1822,10 +1822,7 @@ tsubst_type_requirement (tree t, tree args, subst_info info)
   return finish_type_requirement (EXPR_LOCATION (t), type);
 }
 
-/* True if TYPE can be deduced from EXPR.
-
-   FIXME: C++20 compound requirement constraints should be normalized and then
-   satisfied rather than substituted.  */
+/* True if TYPE can be deduced from EXPR.  */
 
 static bool
 type_deducible_p (tree expr, tree type, tree placeholder, tree args,
@@ -1839,12 +1836,17 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
      substitutes args into any template parameters in the trailing
      result type.  */
   tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
-  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder)
+  tree subst_constr
     = tsubst_constraint (saved_constr,
 			 args,
 			 info.complain | tf_partial,
 			 info.in_decl);
 
+  if (subst_constr == error_mark_node)
+    return false;
+
+  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = subst_constr;
+
   /* Temporarily unlink the canonical type.  */
   tree saved_type = TYPE_CANONICAL (placeholder);
   TYPE_CANONICAL (placeholder) = NULL_TREE;
@@ -3139,7 +3141,8 @@ diagnose_compound_requirement (tree req, tree args, tree in_decl)
 	  if (!type_deducible_p (expr, type, placeholder, args, quiet))
 	    {
 	      tree orig_expr = TREE_OPERAND (req, 0);
-	      inform (loc, "type deduction from %qE failed", orig_expr);
+	      inform (loc, "%qE does not satisfy return-type-requirement",
+		      orig_expr);
 
 	      /* Further explain the reason for the error.  */
 	      type_deducible_p (expr, type, placeholder, args, noisy);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c5675dd8e3f..414140ade6c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28138,7 +28138,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 	/* Rebuild the check using the deduced arguments.  */
 	check = build_concept_check (cdecl, cargs, tf_none);
 
-	if (!constraints_satisfied_p (check, cargs))
+	if (!constraints_satisfied_p (check))
           {
             if (complain & tf_warning_or_error)
               {
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic1.C b/gcc/testsuite/g++.dg/concepts/diagnostic1.C
index ced56d400ba..7da08db2792 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic1.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic1.C
@@ -8,12 +8,12 @@ concept bool SameAs = __is_same_as(T, U);
 template <class T>
 concept bool R1 = requires (T& t) { // { dg-message "in requirements" }
   { t.begin() } -> T;		// { dg-error "no match" }
-  { t.end() } -> SameAs<T*>;	// { dg-error "does not satisfy" }
+  { t.end() } -> SameAs<T*>;	// { dg-message "does not satisfy" }
 };
 
 template <class T>
 concept bool R2 = requires (T& t) { // { dg-message "in requirements" }
-  { t.end() } -> SameAs<T*>;	// { dg-error "does not satisfy" }
+  { t.end() } -> SameAs<T*>;	// { dg-message "does not satisfy" }
 };
 
 struct foo {
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder3.C b/gcc/testsuite/g++.dg/concepts/placeholder3.C
index 4f8600bd07f..d90e5cfb02f 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder3.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder3.C
@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U);
 template <class T>
 concept bool C =
   requires { // { dg-message "in requirements" }
-    { 0 } -> Same<T>;		// { dg-error "does not satisfy" }
+    { 0 } -> Same<T>;		// { dg-message "does not satisfy" }
   };
 
 template <C c>
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder4.C b/gcc/testsuite/g++.dg/concepts/placeholder4.C
index 2b5afbbc6f2..ab9d8e632af 100644
--- a/gcc/testsuite/g++.dg/concepts/placeholder4.C
+++ b/gcc/testsuite/g++.dg/concepts/placeholder4.C
@@ -8,7 +8,7 @@ concept bool Same = __is_same_as(T, U);
 template <class T>
 concept bool C =
   requires { // { dg-message "in requirements" }
-    { 0 } -> Same<T>;		// { dg-error "does not satisfy" }
+    { 0 } -> Same<T>;		// { dg-message "does not satisfy" }
   };
 
 template <class T>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C
index f76f2e3fc86..264b873c7f4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr67178.C
@@ -12,7 +12,7 @@ concept C0 = requires (auto x) { // { dg-error "placeholder type" }
 template<typename T>
 concept C1 = requires (C1 auto x) { // { dg-error "not been declared|placeholder|two or more|in requirements" }
   x; // { dg-error "not declared" }
-  { x } -> c; // { dg-error "not declared|does not satisfy" }
+  { x } -> c; // { dg-message "not declared|does not satisfy" }
 };
 
 template<typename T>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C
index 20df78bebf1..065876e94e4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires6.C
@@ -10,7 +10,7 @@ concept SameAs = __is_same_as(T, U);
 template <typename T>
 concept C1 = requires(T t) { // { dg-message "in requirements" }
   { t } -> SameAs<T>; // NOTE: t deduced as decltype((t))
-  // { dg-error "does not satisfy placeholder constraints" "" { target *-*-* } .-1 }
+  // { dg-message "does not satisfy" "" { target *-*-* } .-1 }
 };
 
 template <typename T>
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-return-req1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req1.C
new file mode 100644
index 00000000000..1d005f059d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-return-req1.C
@@ -0,0 +1,19 @@
+// PR c++/92268
+// { dg-do compile { target c++2a } }
+
+template <class T> concept Two = true;
+template <class T> concept One = Two<typename T::type>;
+template <class T> concept Zero = requires
+  {
+   { T() } -> One;
+  };
+
+template <class T>
+void f() requires Zero<T>;
+template <class T>
+int f(...);
+
+int main()
+{
+  f<int>();
+}

base-commit: 686659a1eb0ec0cb08cf8a2fdc2b4f152ccc7f2d
-- 
2.18.1



More information about the Gcc-patches mailing list