From fed7373f309aa7595b7c2e8690b06a3686a4617d Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Fri, 15 Aug 2025 12:50:01 +0100 Subject: [PATCH] [cxx-interop] Allow many specializations of a class template An old piece of logic in ClangImporter was trying to limit the number of instantiations for each C++ class template to prevent long compile times. Unfortunately this started causing hard-to-reproduce deserialization errors on large projects which use many different instantiations of `std::vector` and `std::allocator`. The instantiation limit was arbitrary, it serves no real purpose and causes issues. This change removes it. rdar://158397914 --- lib/ClangImporter/ImportDecl.cpp | 24 ++++--------------- .../Cxx/templates/many-specializations.swift | 2 +- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 3b4c076227277..2ab6224eeb057 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3237,26 +3237,12 @@ namespace { Decl *VisitClassTemplateSpecializationDecl( const clang::ClassTemplateSpecializationDecl *decl) { - bool isPair = decl->getSpecializedTemplate()->isInStdNamespace() && - decl->getSpecializedTemplate()->getName() == "pair"; - - // Before we go any further, check if we've already got tens of thousands - // of specializations. If so, it means we're likely instantiating a very - // deep/complex template, or we've run into an infinite loop. In either - // case, its not worth the compile time, so bail. - // TODO: this could be configurable at some point. - size_t specializationLimit = !isPair ? 1000 : 10000; - if (size_t( - llvm::size(decl->getSpecializedTemplate()->specializations())) > - specializationLimit) { - // Note: it would be nice to import a dummy unavailable struct, - // but we would then need to instantiate the template here, - // as we cannot import a struct without a definition. That would - // defeat the purpose. Also, we can't make the dummy - // struct simply unavailable, as that still makes the - // typelias that references it available. + // Importing std::conditional substantially increases compile times when + // building with libstdc++, i.e. on most Linux distros. + if (decl->isInStdNamespace() && decl->getIdentifier() && + (decl->getName() == "conditional" || decl->getName() == "__or_" || + decl->getName() == "_Expr")) return nullptr; - } // `decl->getDefinition()` can return nullptr before the call to sema and // return its definition afterwards. diff --git a/test/Interop/Cxx/templates/many-specializations.swift b/test/Interop/Cxx/templates/many-specializations.swift index a1ae3f5f43a75..cc6f6820a15b5 100644 --- a/test/Interop/Cxx/templates/many-specializations.swift +++ b/test/Interop/Cxx/templates/many-specializations.swift @@ -5,4 +5,4 @@ // CHECK-NEXT: struct TemplateStruct { // CHECK-NEXT: } -// CHECK-NOT: typealias +// CHECK: typealias T1000