From c912fe765a1378f1b09d1095ab4e093d5205122a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 2 May 2023 14:54:46 -0400 Subject: [PATCH] c++: simplify member template substitution I noticed that for member class templates of a class template we were unnecessarily substituting both the template and its type. Avoiding that duplication speeds compilation of this silly testcase from ~12s to ~9s on my laptop. It's unlikely to make a difference on any real code, but the simplification is also nice. We still need to clear CLASSTYPE_USE_TEMPLATE on the partial instantiation of the template class, but it makes more sense to do that in tsubst_template_decl anyway. #define NC(X) \ template struct X##1; \ template struct X##2; \ template struct X##3; \ template struct X##4; \ template struct X##5; \ template struct X##6; #define NC2(X) NC(X##a) NC(X##b) NC(X##c) NC(X##d) NC(X##e) NC(X##f) #define NC3(X) NC2(X##A) NC2(X##B) NC2(X##C) NC2(X##D) NC2(X##E) template struct A { NC3(am) }; template void sink(Ts...); template void g() { sink(A()...); } template void f() { g<__integer_pack(I)...>(); } int main() { f<1000>(); } gcc/cp/ChangeLog: * pt.cc (instantiate_class_template): Skip the RECORD_TYPE of a class template. (tsubst_template_decl): Clear CLASSTYPE_USE_TEMPLATE. --- gcc/cp/pt.cc | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 3f1cf139bbd8..471fc20bc5b9 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -12285,21 +12285,13 @@ instantiate_class_template (tree type) Ignore it; it will be regenerated when needed. */ continue; - bool class_template_p = (TREE_CODE (t) != ENUMERAL_TYPE - && TYPE_LANG_SPECIFIC (t) - && CLASSTYPE_IS_TEMPLATE (t)); - - /* If the member is a class template, then -- even after - substitution -- there may be dependent types in the - template argument list for the class. We increment - PROCESSING_TEMPLATE_DECL so that dependent_type_p, as - that function will assume that no types are dependent - when outside of a template. */ - if (class_template_p) - ++processing_template_decl; + /* If the member is a class template, we've + already substituted its type. */ + if (CLASS_TYPE_P (t) + && CLASSTYPE_IS_TEMPLATE (t)) + continue; + tree newtag = tsubst (t, args, tf_error, NULL_TREE); - if (class_template_p) - --processing_template_decl; if (newtag == error_mark_node) continue; @@ -12307,19 +12299,6 @@ instantiate_class_template (tree type) { tree name = TYPE_IDENTIFIER (t); - if (class_template_p) - /* Unfortunately, lookup_template_class sets - CLASSTYPE_IMPLICIT_INSTANTIATION for a partial - instantiation (i.e., for the type of a member - template class nested within a template class.) - This behavior is required for - maybe_process_partial_specialization to work - correctly, but is not accurate in this case; - the TAG is not an instantiation of anything. - (The corresponding TEMPLATE_DECL is an - instantiation, but the TYPE is not.) */ - CLASSTYPE_USE_TEMPLATE (newtag) = 0; - /* Now, install the tag. We don't use pushtag because that does too much work -- creating an implicit typedef, which we've already done. */ @@ -14750,7 +14729,10 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, /* For a partial specialization, we need to keep pointing to the primary template. */ if (!DECL_TEMPLATE_SPECIALIZATION (t)) - CLASSTYPE_TI_TEMPLATE (inner) = r; + { + CLASSTYPE_TI_TEMPLATE (inner) = r; + CLASSTYPE_USE_TEMPLATE (inner) = 0; + } DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (inner); inner = TYPE_MAIN_DECL (inner);