public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r11-6245] c++: Diagnose self-recursive satisfaction
@ 2020-12-18  3:36 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2020-12-18  3:36 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:79f57d5cb070bb02ea0a34b5f42658d6659b19a8

commit r11-6245-g79f57d5cb070bb02ea0a34b5f42658d6659b19a8
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Dec 17 22:18:07 2020 -0500

    c++: Diagnose self-recursive satisfaction
    
    This patch further extends the satisfaction_cache class to diagnose
    self-recursive satisfaction.
    
    gcc/cp/ChangeLog:
    
            * constraint.cc (sat_entry::evaluating): New member.
            (satisfaction_cache::get): If entry->evaluating, diagnose
            self-recursive satisfaction.  Otherwise, set entry->evaluating
            if we're not reusing a cached satisfaction result.
            (satisfaction_cache::save): Clear entry->evaluating.
            (satisfy_atom): Set up diagnosing_failed_constraint before the
            first call to get().
    
    gcc/testsuite/ChangeLog:
    
            PR c++/96840
            * g++.dg/cpp2a/concepts-pr88395.C: Adjust to expect the
            self-recursive satisfaction to get directly diagnosed.
            * g++.dg/cpp2a/concepts-recursive-sat2.C: Likewise.
            * g++.dg/cpp2a/concepts-recursive-sat4.C: New test.

Diff:
---
 gcc/cp/constraint.cc                               | 39 +++++++++++++++++-----
 gcc/testsuite/g++.dg/cpp2a/concepts-pr88395.C      |  8 ++---
 .../g++.dg/cpp2a/concepts-recursive-sat2.C         |  6 ++--
 .../g++.dg/cpp2a/concepts-recursive-sat4.C         | 13 ++++++++
 4 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 47cf882a704..40e499bbbd1 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2428,6 +2428,11 @@ struct GTY((for_user)) sat_entry
      We don't always want to do so, in order to avoid emitting duplicate
      diagnostics in some cases.  */
   bool diagnose_instability;
+
+  /* True if we're in the middle of computing this satisfaction result.
+     Used during both quiet and noisy satisfaction to detect self-recursive
+     satisfaction.  */
+  bool evaluating;
 };
 
 struct sat_hasher : ggc_ptr_hash<sat_entry>
@@ -2572,6 +2577,7 @@ satisfaction_cache
 	   mapping, we set this flag (in satisfy_atom) only if substitution
 	   into its mapping previously failed.  */
 	entry->diagnose_instability = true;
+      entry->evaluating = false;
       *slot = entry;
     }
   else
@@ -2590,9 +2596,23 @@ satisfaction_cache::get ()
   if (!entry)
     return NULL_TREE;
 
-  if (info.noisy () || entry->maybe_unstable)
-    /* We're recomputing the satisfaction result from scratch.  */
-    return NULL_TREE;
+  if (entry->evaluating)
+    {
+      /* If we get here, it means satisfaction is self-recursive.  */
+      gcc_checking_assert (!entry->result);
+      if (info.noisy ())
+	error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (entry->atom)),
+		  "satisfaction of atomic constraint %qE depends on itself",
+		  entry->atom);
+      return error_mark_node;
+    }
+
+  if (info.noisy () || entry->maybe_unstable || !entry->result)
+    {
+      /* We're computing the satisfaction result from scratch.  */
+      entry->evaluating = true;
+      return NULL_TREE;
+    }
   else
     return entry->result;
 }
@@ -2607,6 +2627,9 @@ satisfaction_cache::save (tree result)
   if (!entry)
     return result;
 
+  gcc_checking_assert (entry->evaluating);
+  entry->evaluating = false;
+
   if (entry->result && result != entry->result)
     {
       if (info.quiet ())
@@ -2856,6 +2879,11 @@ static void diagnose_atomic_constraint (tree, tree, tree, subst_info);
 static tree
 satisfy_atom (tree t, tree args, sat_info info)
 {
+  /* In case there is a diagnostic, we want to establish the context
+     prior to printing errors.  If no errors occur, this context is
+     removed before returning.  */
+  diagnosing_failed_constraint failure (t, args, info.noisy ());
+
   satisfaction_cache cache (t, args, info);
   if (tree r = cache.get ())
     return r;
@@ -2863,11 +2891,6 @@ satisfy_atom (tree t, tree args, sat_info info)
   /* Perform substitution quietly.  */
   subst_info quiet (tf_none, NULL_TREE);
 
-  /* In case there is a diagnostic, we want to establish the context
-     prior to printing errors.  If no errors occur, this context is
-     removed before returning.  */
-  diagnosing_failed_constraint failure (t, args, info.noisy ());
-
   /* Instantiate the parameter mapping.  */
   tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet);
   if (map == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr88395.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr88395.C
index 1c25252d47b..e1792e19005 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr88395.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr88395.C
@@ -1,9 +1,9 @@
 // { dg-do compile { target c++20 } }
 
 template <class T, class U>
-concept Concept2 = requires (T t, U u)
+concept Concept2 = requires (T t, U u) // { dg-error "depends on itself" }
 {
-    t += u; // { dg-error "template instantiation depth" }
+    t += u;
 };
 
 template <class T>
@@ -17,7 +17,5 @@ struct S
 
 constexpr S operator * (S a, S b)
 {
-    return a += b;
+    return a += b; // { dg-error "no match" }
 }
-
-// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat2.C
index 992fcbbfccb..9bc96f58979 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat2.C
@@ -1,7 +1,7 @@
 // { dg-do compile { target c++20 } }
 
 template<typename T>
-concept Fooable = requires(T t) { foo(t); }; // { dg-error "template instantiation depth" }
+concept Fooable = requires(T t) { foo(t); }; // { dg-error "depends on itself" }
 
 template<Fooable T>
 void foo(T t) { }
@@ -9,7 +9,5 @@ void foo(T t) { }
 void test()
 {
   struct S {} s;
-  foo(s);
+  foo(s); // { dg-error "no match" }
 }
-
-// { dg-prune-output "compilation terminated" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat4.C
new file mode 100644
index 00000000000..18d126e05ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat4.C
@@ -0,0 +1,13 @@
+// PR c++/96840
+// { dg-do compile { target c++20 } }
+
+template <class T, class U> concept C = requires(T t, U u) { t * u; };
+// { dg-message "required for the satisfaction of 'C<T, Rep>' .with T = Int<int>; Rep = int." "" { target *-*-* } .-1 }
+// { dg-error "depends on itself" "" { target *-*-* } .-2 }
+
+template <class Rep> struct Int {
+  template <class T> requires C<T, Rep> friend void operator*(T, Int) { }
+  template <class T> requires C<T, Rep> friend void operator*(Int, T) { }
+};
+
+void f() { 0 * Int<int>{}; }


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-12-18  3:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-18  3:36 [gcc r11-6245] c++: Diagnose self-recursive satisfaction Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).