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.
Currently this regresses several libstdc++ tests which seem 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 get an error in find(), then later instantiate _S_key() (called from find) and get the static_assert error from there. Thoughts? Is this a desirable change, or is the fact that the use precedes the error reason to go ahead with the instantiation? > FAIL: 23_containers/map/48101_neg.cc -std=gnu++17 (test for errors, line ) > FAIL: 23_containers/multimap/48101_neg.cc -std=gnu++17 (test for errors, > line ) > FAIL: 23_containers/multiset/48101_neg.cc -std=gnu++17 (test for errors, > line ) > FAIL: 23_containers/set/48101_neg.cc -std=gnu++17 (test for errors, line ) > FAIL: 30_threads/packaged_task/cons/dangling_ref.cc -std=gnu++17 (test for > errors, line ) > FAIL: 30_threads/packaged_task/cons/lwg4154_neg.cc -std=gnu++17 (test for > errors, line ) 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. --- gcc/cp/cp-tree.h | 10 ++++++++-- gcc/cp/pt.cc | 10 ++++++++-- gcc/testsuite/g++.dg/template/recurse5.C | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/recurse5.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7798efba3db..856202c65dd 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 a71705fd085..e8d342f99f6 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 00000000000..7bfe5239f0a --- /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()); +} base-commit: 6808f74b4f07decb3727624f0e62e7c57ae87022 -- 2.49.0