[PATCH 4/1] c++: More precise tracking of potentially unstable satisfaction

Patrick Palka ppalka@redhat.com
Mon Dec 14 18:07:04 GMT 2020


This makes tracking of potentially unstable satisfaction results more
precise by recording the specific types for which completion failed
during satisfaction.  We now recompute a satisfaction result only if one
of these types has been completed since the last time we computed the
satisfaction result.  Thus the number of times that we recompute a
satisfaction result is now bounded by the number of such incomplete
types, rather than being effectively unbounded.  This allows us to
remove the invalid assumption in note_ftc_for_satisfaction that was
added to avoid a compile time performance regression in cmcstl2 due to
repeated re-computation of a satisfaction result that depended on
completion of a permanently incomplete class template specialization.

In order to continue to detect the instability in concepts-complete3.C,
we also need to explicitly keep track of return type deduction failure
alongside type completion failure.  So this patch also adds a call to
note_ftc_for_satisfaction in require_deduced_type.

gcc/cp/ChangeLog:

	* constraint.cc (failed_type_completion_count): Remove.
	(failed_type_completions): Define.
	(note_failed_type_completion_for_satisfaction): Append the
	supplied argument to failed_type_completions.
	(some_type_complete_p): Define.
	(sat_entry::maybe_unstable): Replace with ...
	(sat_entry::ftc_begin, sat_entry::ftc_end): ... these.
	(satisfaction_cache::ftc_count): Replace with ...
	(satisfaction_cache::ftc_begin): ... this.
	(satisfaction_cache::satisfaction_cache): Adjust accordingly.
	(satisfaction_cache::get): Adjust accordingly, using
	some_type_complete_p.
	(satisfaction_cache::save): Adjust accordingly.
	(satisfy_declaration_constraints): Likewise.
	* decl.c (require_deduced_type): Call
	note_failed_type_completion_for_satisfaction.
---
 gcc/cp/constraint.cc | 89 +++++++++++++++++++++++++++-----------------
 gcc/cp/decl.c        |  1 +
 2 files changed, 56 insertions(+), 34 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index dc5c34e7e91..fd5d9429c9d 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2374,26 +2374,44 @@ tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_
                         Constraint satisfaction
 ---------------------------------------------------------------------------*/
 
-/* A counter incremented by note_failed_type_completion_for_satisfaction().
-   It's used by the satisfaction caches in order to flag "potentially unstable"
-   satisfaction results.  */
+/* A vector of incomplete types (and declarations with undeduced return types),
+   appended to by note_failed_type_completion_for_satisfaction.  The
+   satisfaction caches use this in order to keep track of "potentially unstable"
+   satisfaction results.
 
-static unsigned failed_type_completion_count;
+   Since references to entries in vector are stored only in the GC-deletable
+   sat_cache, it's safe to make this deletable as well.  */
 
-/* Called whenever a type completion failure occurs that definitely affects
-   the semantics of the program, by e.g. inducing substitution failure.  */
+static GTY((deletable)) vec<tree, va_gc> *failed_type_completions;
+
+/* Called whenever a type completion (or return type deduction) failure occurs
+   that definitely affects the semantics of the program, by e.g. inducing
+   substitution failure.  */
 
 void
-note_failed_type_completion_for_satisfaction (tree type)
-{
-  gcc_checking_assert (!COMPLETE_TYPE_P (type));
-  if (CLASS_TYPE_P (type)
-      && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
-    /* After instantiation, a class template specialization that's
-       incomplete will remain incomplete, so for our purposes we can
-       ignore this completion failure event.  */;
-  else
-    ++failed_type_completion_count;
+note_failed_type_completion_for_satisfaction (tree t)
+{
+  gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t))
+		       || (DECL_P (t) && undeduced_auto_decl (t)));
+  vec_safe_push (failed_type_completions, t);
+}
+
+/* Returns true if the range [BEGIN, END) of elements within the
+   failed_type_completions vector contains a complete type (or a declaration
+   with a non-placeholder return type).  */
+
+static bool
+some_type_complete_p (int begin, int end)
+{
+  for (int i = begin; i < end; i++)
+    {
+      tree t = (*failed_type_completions)[i];
+      if (TYPE_P (t) && COMPLETE_TYPE_P (t))
+	return true;
+      if (DECL_P (t) && !undeduced_auto_decl (t))
+	return true;
+    }
+  return false;
 }
 
 /* Hash functions and data types for satisfaction cache entries.  */
@@ -2417,12 +2435,10 @@ struct GTY((for_user)) sat_entry
      performed.  */
   location_t location;
 
-  /* True if this satisfaction result is flagged as "potentially unstable",
-     i.e. the result might change at different points in the program if
-     recomputed from scratch (which would be ill-formed).  This flag controls
-     whether to recompute a cached satisfaction result from scratch even when
-     evaluating quietly.  */
-  bool maybe_unstable;
+  /* The range of elements appended to the failed_type_completions vector
+     during computation of this satisfaction result, encoded as a begin/end
+     pair of offsets.  */
+  int ftc_begin, ftc_end;
 
   /* True if we want to diagnose the above instability when it's detected.
      We don't always want to do so, in order to avoid emitting duplicate
@@ -2531,7 +2547,7 @@ struct satisfaction_cache
 
   sat_entry *entry;
   sat_info info;
-  unsigned ftc_count;
+  int ftc_begin;
 };
 
 /* Constructor for the satisfaction_cache class.  We're performing satisfaction
@@ -2539,7 +2555,7 @@ struct satisfaction_cache
 
 satisfaction_cache
 ::satisfaction_cache (tree atom, tree args, sat_info info)
-  : entry(nullptr), info(info), ftc_count(failed_type_completion_count)
+  : entry(nullptr), info(info), ftc_begin(-1)
 {
   if (!sat_cache)
     sat_cache = hash_table<sat_hasher>::create_ggc (31);
@@ -2578,7 +2594,7 @@ satisfaction_cache
       entry->args = args;
       entry->result = NULL_TREE;
       entry->location = input_location;
-      entry->maybe_unstable = false;
+      entry->ftc_begin = entry->ftc_end = -1;
       entry->diagnose_instability = false;
       if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (atom))
 	/* We always want to diagnose instability of an atom with an
@@ -2616,10 +2632,16 @@ satisfaction_cache::get ()
       return error_mark_node;
     }
 
-  if (info.noisy () || entry->maybe_unstable || !entry->result)
+  /* This satisfaction result is "potentially unstable" if a type for which
+     type completion failed during its earlier computation is now complete.  */
+  bool maybe_unstable = some_type_complete_p (entry->ftc_begin,
+					      entry->ftc_end);
+
+  if (info.noisy () || maybe_unstable || !entry->result)
     {
       /* We're computing the satisfaction result from scratch.  */
       entry->evaluating = true;
+      ftc_begin = vec_safe_length (failed_type_completions);
       return NULL_TREE;
     }
   else
@@ -2667,11 +2689,11 @@ satisfaction_cache::save (tree result)
   if (info.quiet ())
     {
       entry->result = result;
-      /* We heuristically flag this satisfaction result as potentially unstable
-	 iff during its computation, completion of a type failed.  Note that
-	 this may also clear the flag if the result turned out to be
-	 independent of the previously detected type completion failure.  */
-      entry->maybe_unstable = (ftc_count != failed_type_completion_count);
+      /* Record the list of relevant failed type completions that occurred
+	 during (re)computation of the satisfaction result.  */
+      gcc_checking_assert (ftc_begin != -1);
+      entry->ftc_begin = ftc_begin;
+      entry->ftc_end = vec_safe_length (failed_type_completions);
     }
 
   return result;
@@ -3120,7 +3142,7 @@ satisfy_declaration_constraints (tree t, sat_info info)
       norm = normalize_nontemplate_requirements (t, info.noisy ());
     }
 
-  unsigned ftc_count = failed_type_completion_count;
+  unsigned ftc_count = vec_safe_length (failed_type_completions);
 
   tree result = boolean_true_node;
   if (norm)
@@ -3136,8 +3158,7 @@ satisfy_declaration_constraints (tree t, sat_info info)
   /* True if this satisfaction is (heuristically) potentially unstable, i.e.
      if its result may depend on where in the program it was performed.  */
   bool maybe_unstable_satisfaction = false;
-
-  if (ftc_count != failed_type_completion_count)
+  if (ftc_count != vec_safe_length (failed_type_completions))
     /* Type completion failure occurred during satisfaction.  The satisfaction
        result may (or may not) materially depend on the completeness of a type,
        so we consider it potentially unstable.   */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b56eb113fd6..6e8dd0b45fd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -17869,6 +17869,7 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
 	/* We probably already complained about deduction failure.  */;
       else if (complain & tf_error)
 	error ("use of %qD before deduction of %<auto%>", decl);
+      note_failed_type_completion_for_satisfaction (decl);
       return false;
     }
   return true;
-- 
2.29.2.540.g3cf59784d4



More information about the Gcc-patches mailing list