aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2025-04-18 18:00:34 -0400
committerJonathan Wakely <redi@gcc.gnu.org>2025-04-25 11:47:47 +0100
commit8acea9ffa82ed84bbf15d75b9dd034b2bb82724e (patch)
treefe340a61f4b9b3f7eb594440fc21ba7ab42ca765
parent901900bc37566c59b4eb62c1427f3150b800d8a0 (diff)
downloadgcc-8acea9ffa82ed84bbf15d75b9dd034b2bb82724e.zip
gcc-8acea9ffa82ed84bbf15d75b9dd034b2bb82724e.tar.gz
gcc-8acea9ffa82ed84bbf15d75b9dd034b2bb82724e.tar.bz2
c++: bad pending_template recursion
limit_bad_template_recursion currently avoids immediate instantiation of templates from uses in an already ill-formed instantiation, but we still can get unnecessary recursive instantiation in pending_templates if the instantiation was queued before the error. Initially this regressed several libstdc++ tests which seemed to rely on a static_assert in a function called from another that is separately ill-formed. For instance, in the 48101_neg.cc tests, we first got an error in find(), then later instantiate _S_key() (called from find) and got the static_assert error from there. r16-131-g876d1a22dfaf87 and r16-132-g901900bc37566c changed the library code (and tests) to make the expected static_assert errors happen earlier. gcc/cp/ChangeLog: * cp-tree.h (struct tinst_level): Add had_errors bit. * pt.cc (push_tinst_level_loc): Clear it. (pop_tinst_level): Set it. (reopen_tinst_level): Check it. (instantiate_pending_templates): Call limit_bad_template_recursion. gcc/testsuite/ChangeLog: * g++.dg/template/recurse5.C: New test.
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/pt.cc10
-rw-r--r--gcc/testsuite/g++.dg/template/recurse5.C17
3 files changed, 33 insertions, 4 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7798efb..856202c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6755,8 +6755,14 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
/* The location where the template is instantiated. */
location_t locus;
- /* errorcount + sorrycount when we pushed this level. */
- unsigned short errors;
+ /* errorcount + sorrycount when we pushed this level. If the value
+ overflows, it will always seem like we currently have more errors, so we
+ will limit template recursion even from non-erroneous templates. In a TU
+ with over 32k errors, that's fine. */
+ unsigned short errors : 15;
+
+ /* set in pop_tinst_level if there have been errors since we pushed. */
+ bool had_errors : 1;
/* Count references to this object. If refcount reaches
refcount_infinity value, we don't increment or decrement the
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a71705f..e8d342f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11418,6 +11418,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
new_level->targs = targs;
new_level->locus = loc;
new_level->errors = errorcount + sorrycount;
+ new_level->had_errors = false;
new_level->next = NULL;
new_level->refcount = 0;
new_level->path = new_level->visible = nullptr;
@@ -11468,6 +11469,9 @@ pop_tinst_level (void)
/* Restore the filename and line number stashed away when we started
this instantiation. */
input_location = current_tinst_level->locus;
+ if (unsigned errs = errorcount + sorrycount)
+ if (errs > current_tinst_level->errors)
+ current_tinst_level->had_errors = true;
set_refcount_ptr (current_tinst_level, current_tinst_level->next);
--tinst_depth;
}
@@ -11487,7 +11491,7 @@ reopen_tinst_level (struct tinst_level *level)
set_refcount_ptr (current_tinst_level, level);
pop_tinst_level ();
- if (current_tinst_level)
+ if (current_tinst_level && !current_tinst_level->had_errors)
current_tinst_level->errors = errorcount+sorrycount;
tree decl = level->maybe_get_node ();
@@ -28072,7 +28076,9 @@ instantiate_pending_templates (int retries)
tree instantiation = reopen_tinst_level ((*t)->tinst);
bool complete = false;
- if (TYPE_P (instantiation))
+ if (limit_bad_template_recursion (instantiation))
+ /* Do nothing. */;
+ else if (TYPE_P (instantiation))
{
if (!COMPLETE_TYPE_P (instantiation))
{
diff --git a/gcc/testsuite/g++.dg/template/recurse5.C b/gcc/testsuite/g++.dg/template/recurse5.C
new file mode 100644
index 0000000..7bfe523
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/recurse5.C
@@ -0,0 +1,17 @@
+// Test that we don't bother to instantiate add since there were errors in
+// checked_add.
+
+template <class T> T add (T t) { return t+1; } // { dg-bogus "no match" }
+
+template <class T> T checked_add (T t)
+{
+ add (t);
+ return t+1; // { dg-error "no match" }
+}
+
+struct A { };
+
+int main()
+{
+ checked_add (A());
+}