Skip to content

Commit e6a99cb

Browse files
committed
[cxx-interop] Cache specialized function templates.
This not only prevents us from creating a bunch of FuncDecls but actually is required to prevent duplicate symbol errors.
1 parent 680d5d2 commit e6a99cb

File tree

4 files changed

+29
-1
lines changed

4 files changed

+29
-1
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5527,6 +5527,9 @@ ClangImporter::getCXXFunctionTemplateSpecialization(SubstitutionMap subst,
55275527
if (!newFn)
55285528
return ConcreteDeclRef(decl);
55295529

5530+
if (Impl.specializedFunctionTemplates.count(newFn))
5531+
return ConcreteDeclRef(Impl.specializedFunctionTemplates[newFn]);
5532+
55305533
auto newDecl = cast_or_null<ValueDecl>(
55315534
decl->getASTContext().getClangModuleLoader()->importDeclDirectly(
55325535
newFn));
@@ -5548,6 +5551,7 @@ ClangImporter::getCXXFunctionTemplateSpecialization(SubstitutionMap subst,
55485551
}
55495552
}
55505553

5554+
Impl.specializedFunctionTemplates[newFn] = newDecl;
55515555
return ConcreteDeclRef(newDecl);
55525556
}
55535557

lib/ClangImporter/ImporterImpl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,16 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
572572

573573
/// Keep track of cxx function names, params etc in order to
574574
/// allow for de-duping functions that differ strictly on "constness".
575-
llvm::DenseMap<llvm::StringRef, std::pair<llvm::DenseSet<clang::FunctionDecl *>, llvm::DenseSet<clang::FunctionDecl *>>> cxxMethods;
575+
llvm::DenseMap<llvm::StringRef,
576+
std::pair<
577+
llvm::DenseSet<clang::FunctionDecl *>,
578+
llvm::DenseSet<clang::FunctionDecl *>>>
579+
cxxMethods;
580+
581+
// Cache for already-specialized function templates and any thunks they may
582+
// have.
583+
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>
584+
specializedFunctionTemplates;
576585

577586
/// Keeps track of the Clang functions that have been turned into
578587
/// properties.

test/Interop/Cxx/templates/dependent-types.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ DependentTypesTestSuite.test("Different dependent inferred by arg.") {
2323
expectEqual(m.getValue(), 42)
2424
}
2525

26+
DependentTypesTestSuite.test("Instanciate the same function twice") {
27+
// Intentionally test the same thing twice.
28+
let m = dependantReturnTypeInffered(42) as! M<Int>
29+
expectEqual(m.getValue(), 42)
30+
31+
let m2 = dependantReturnTypeInffered(42) as! M<Int>
32+
expectEqual(m2.getValue(), 42)
33+
}
34+
2635
DependentTypesTestSuite.test("Multiple arguments (inferred type).") {
2736
let m = multipleArgs(M<Int>(value: 40), 2, 10) as! M<Int>
2837
expectEqual(m.getValue(), 42)

test/Interop/Cxx/templates/template-type-parameter-not-in-signature.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ TemplateNotInSignatureTestSuite.test("Function with defaulted template type para
1717
expectEqual(y, 10)
1818
}
1919

20+
TemplateNotInSignatureTestSuite.test("Instanciate the same function template twice.") {
21+
// Intentionally test the same thing twice.
22+
templateTypeParamNotUsedInSignature(T: Int.self)
23+
templateTypeParamNotUsedInSignature(T: Int.self)
24+
}
25+
2026
TemplateNotInSignatureTestSuite.test("Pointer types") {
2127
var x = 1
2228
x = templateTypeParamUsedInReferenceParam(&x)

0 commit comments

Comments
 (0)