Skip to content

Commit 2f0e7fc

Browse files
committed
[cxx-interop] Bail on deep template specializations.
If a template specialization is more than 8 types deep, bail. In future we could make this number (much) greater than 8 but first we'll need to somehow make instantiating these types much fater. Currently, I think there is some exponential type behavior happening so this is super slow.
1 parent 6eb00d5 commit 2f0e7fc

File tree

4 files changed

+45
-0
lines changed

4 files changed

+45
-0
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3697,6 +3697,22 @@ namespace {
36973697
return VisitRecordDecl(decl);
36983698
}
36993699

3700+
bool isSpecializationDepthGreaterThan(
3701+
const clang::ClassTemplateSpecializationDecl *decl, unsigned maxDepth) {
3702+
for (auto arg : decl->getTemplateArgs().asArray()) {
3703+
if (arg.getKind() == clang::TemplateArgument::Type) {
3704+
if (auto classSpec =
3705+
dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
3706+
arg.getAsType()->getAsCXXRecordDecl())) {
3707+
if (maxDepth == 0 ||
3708+
isSpecializationDepthGreaterThan(classSpec, maxDepth - 1))
3709+
return true;
3710+
}
3711+
}
3712+
}
3713+
return false;
3714+
}
3715+
37003716
Decl *VisitClassTemplateSpecializationDecl(
37013717
const clang::ClassTemplateSpecializationDecl *decl) {
37023718
// `Sema::isCompleteType` will try to instantiate the class template as a
@@ -3714,6 +3730,13 @@ namespace {
37143730
decl->getDefinition());
37153731
assert(def && "Class template instantiation didn't have definition");
37163732

3733+
// Currently this is a relatively low number, in the future we might
3734+
// consider increasing it, but this should keep compile time down,
3735+
// especially for types that become exponentially large when
3736+
// instantiating.
3737+
if (isSpecializationDepthGreaterThan(def, 8))
3738+
return nullptr;
3739+
37173740
// FIXME: This will instantiate all members of the specialization (and detect
37183741
// instantiation failures in them), which can be more than is necessary
37193742
// and is more than what Clang does. As a result we reject some C++
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
template <class T>
2+
struct HasTypeWithSelfAsParam {
3+
using TT = HasTypeWithSelfAsParam<HasTypeWithSelfAsParam<T>>;
4+
};
5+
6+
using WillBeInfinite = HasTypeWithSelfAsParam<int>;

test/Interop/Cxx/templates/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,8 @@ module MemberTemplates {
112112
header "member-templates.h"
113113
requires cplusplus
114114
}
115+
116+
module LargeClassTemplates {
117+
header "large-class-templates.h"
118+
requires cplusplus
119+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=LargeClassTemplates -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s
2+
3+
// CHECK: struct HasTypeWithSelfAsParam<T> {
4+
// CHECK: }
5+
6+
// CHECK: struct __CxxTemplateInst22HasTypeWithSelfAsParamIiE {
7+
// CHECK: typealias TT = __CxxTemplateInst22HasTypeWithSelfAsParamIS_IiEE
8+
// CHECK: init()
9+
// CHECK: }
10+
11+
// CHECK: typealias WillBeInfinite = __CxxTemplateInst22HasTypeWithSelfAsParamIiE

0 commit comments

Comments
 (0)