Skip to content

Commit ff7cdc3

Browse files
committed
Addressing comments.
1 parent 435a796 commit ff7cdc3

File tree

7 files changed

+53
-28
lines changed

7 files changed

+53
-28
lines changed

include/swift/AST/Decl.h

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3401,14 +3401,41 @@ class EnumDecl final : public NominalTypeDecl {
34013401
/// to get the declared type ("Complex" in the above example).
34023402
class StructDecl final : public NominalTypeDecl {
34033403
SourceLoc StructLoc;
3404-
// We import C++ class template instantiations as non-generic structs
3405-
// with a name prefixed with `__CxxTemplateInst`. However for proper
3406-
// serialization we need to have an access to the bound generic type
3407-
// that would have produced this instantiation. This field contains
3408-
// that type.
3404+
3405+
// We import C++ class templates as generic structs. Then when in Swift code
3406+
// we want to substitude generic parameters with actual arguments, we
3407+
// convert the arguments to C++ equivalents and ask Clang to instantiate the
3408+
// C++ template. Then we import the C++ class template instantiation
3409+
// as a non-generic structs with a name prefixed with `__CxxTemplateInst`.
3410+
//
3411+
// To reiterate:
3412+
// 1) We need to have a C++ class template declaration in the Clang AST. This
3413+
// declaration is simply imported from a Clang module.
3414+
// 2) We need a Swift generic struct in the Swift AST. This will provide
3415+
// template arguments to Clang.
3416+
// 3) We produce a C++ class template instantiation in the Clang AST
3417+
// using 1) and 2). This declaration does not exist in the Clang module
3418+
// AST initially in the general case, it's added there on instantiation.
3419+
// 4) We import the instantiation as a Swift struct, with the name prefixed
3420+
// with `__CxxTemplateInst`.
3421+
//
3422+
// This causes a problem for serialization/deserialization of the Swift
3423+
// module. Imagine the Swift struct from 4) is used in the function return
3424+
// type. We cannot just serialize the non generic Swift struct, because on
3425+
// deserialization we would need to find its backing Clang declaration
3426+
// (the C++ class template instantiation), and it won't be found in the
3427+
// general case. Only the C++ class template from step 1) is in the Clang
3428+
// AST.
3429+
//
3430+
// What we need is to serialize enough information to be
3431+
// able to instantiate C++ class template on deserialization. It turns out
3432+
// that all that information is conveniently covered by the BoundGenericType,
3433+
// which we store in this field. The field is set during the typechecking at
3434+
// the time when we instantiate the C++ class template.
34093435
//
3410-
// The field is set during the typechecking at the time when we
3411-
// instantiate the C++ class template.
3436+
// Alternative, and likely better solution long term, is to serialize the
3437+
// C++ class template instantiation into a synthetic Clang module, and load
3438+
// this Clang module on deserialization.
34123439
Type TemplateInstantiationType = Type();
34133440

34143441
public:

lib/Sema/TypeCheckType.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -841,15 +841,15 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
841841
if (auto clangDecl = decl->getClangDecl()) {
842842
if (auto classTemplateDecl =
843843
dyn_cast<clang::ClassTemplateDecl>(clangDecl)) {
844-
SmallVector<Type, 2> typesOfgenericArgs;
844+
SmallVector<Type, 2> typesOfGenericArgs;
845845
for (auto typeRepr : generic->getGenericArgs()) {
846-
typesOfgenericArgs.push_back(resolution.resolveType(typeRepr));
846+
typesOfGenericArgs.push_back(resolution.resolveType(typeRepr));
847847
}
848848

849849
SmallVector<clang::TemplateArgument, 2> templateArguments;
850850
std::unique_ptr<TemplateInstantiationError> error =
851851
ctx.getClangTemplateArguments(
852-
classTemplateDecl->getTemplateParameters(), typesOfgenericArgs,
852+
classTemplateDecl->getTemplateParameters(), typesOfGenericArgs,
853853
templateArguments);
854854

855855
if (error) {

lib/Serialization/Deserialization.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5356,23 +5356,25 @@ class TypeDeserializer {
53565356

53575357
if (auto clangDecl = nominal->getClangDecl()) {
53585358
if (auto ctd = dyn_cast<clang::ClassTemplateDecl>(clangDecl)) {
5359-
auto clangImporter = static_cast<ClangImporter *>(nominal->getASTContext().getClangModuleLoader());
5359+
auto clangImporter = static_cast<ClangImporter *>(
5360+
nominal->getASTContext().getClangModuleLoader());
53605361

53615362
SmallVector<Type, 2> typesOfGenericArgs;
53625363
for (auto arg : genericArgs) {
5363-
typesOfgenericArgs.push_back(arg);
5364+
typesOfGenericArgs.push_back(arg);
53645365
}
53655366

53665367
SmallVector<clang::TemplateArgument, 2> templateArguments;
53675368
std::unique_ptr<TemplateInstantiationError> error =
5368-
ctx.getClangTemplateArguments(
5369-
ctd->getTemplateParameters(), typesOfgenericArgs,
5370-
templateArguments);
5369+
ctx.getClangTemplateArguments(ctd->getTemplateParameters(),
5370+
typesOfGenericArgs,
5371+
templateArguments);
53715372

53725373
auto instantiation = clangImporter->instantiateCXXClassTemplate(
5373-
const_cast<clang::ClassTemplateDecl *>(ctd), templateArguments);
5374+
const_cast<clang::ClassTemplateDecl *>(ctd), templateArguments);
53745375

5375-
instantiation->setTemplateInstantiationType(BoundGenericType::get(nominal, parentTy, genericArgs));
5376+
instantiation->setTemplateInstantiationType(
5377+
BoundGenericType::get(nominal, parentTy, genericArgs));
53765378
return instantiation->getDeclaredInterfaceType();
53775379
}
53785380
}

test/Interop/Cxx/templates/Inputs/class-template-in-namespace-for-swift-module.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_IN_NAMESPACE_FOR_SWIFT_MODULE_H
33

44
namespace Space {
5-
template <class T> struct Ship { T t; };
5+
template <class T> struct Ship { T t; };
66
} // namespace Space
77

88
namespace Engine {
9-
struct Turbojet {};
9+
struct Turbojet {};
1010
} // namespace Engine
1111

1212
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_IN_NAMESPACE_FOR_SWIFT_MODULE_H

test/Interop/Cxx/templates/Inputs/class-template-nested-type-for-swift-module.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_NESTED_TYPE_FOR_SWIFT_MODULE_H
33

44
template <class T> struct Ship {
5-
struct Engine {
6-
T power;
7-
};
5+
struct Engine {
6+
T power;
7+
};
88
};
99

10-
1110
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_NESTED_TYPE_FOR_SWIFT_MODULE_H

test/Interop/Cxx/templates/Inputs/class-template-non-type-parameter.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
using size_t = __SIZE_TYPE__;
66
#endif
77

8-
template<class T, size_t Size>
9-
struct MagicArray {
10-
T t[Size];
11-
};
8+
template <class T, size_t Size> struct MagicArray { T t[Size]; };
129

1310
typedef MagicArray<int, 2> MagicIntPair;
1411

test/Interop/Cxx/templates/class-template-in-namespace-module-interface.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
// CHECK: init()
66
// CHECK: }
77
// CHECK: typealias Orbiter = Space.__CxxTemplateInstN5Space4ShipIJFvbEEEE
8-
// CHECK: }
8+
// CHECK: }

0 commit comments

Comments
 (0)