[cxx-interop] Instantiate C++ class templates from Swift (#33284)

This PR makes it possible to instantiate C++ class templates from Swift. Given a C++ header:

```c++
// C++ module `ClassTemplates`
template<class T>
struct MagicWrapper {
  T t;
};

struct MagicNumber {};
```

it is now possible to write in Swift:

```swift
import ClassTemplates

func x() -> MagicWrapper<MagicNumber> {
  return MagicWrapper<MagicNumber>()
}
```

This is achieved by importing C++ class templates as generic structs, and then when Swift type checker calls `applyGenericArguments` we detect when the generic struct is backed by the C++ class template and call Clang to instantiate the template. In order to make it possible to put class instantiations such as `MagicWrapper<MagicNumber>` into Swift signatures, we have created a new field in `StructDecl` named `TemplateInstantiationType` where the typechecker stores the `BoundGenericType` which we serialize. Deserializer then notices that the `BoundGenericType` is actually a C++ class template and performs the instantiation logic.

Depends on https://github.com/apple/swift/pull/33420.
Progress towards https://bugs.swift.org/browse/SR-13261.
Fixes https://bugs.swift.org/browse/SR-13775.

Co-authored-by: Dmitri Gribenko <gribozavr@gmail.com>
Co-authored-by: Rosica Dejanovska <rosica@google.com>
This commit is contained in:
Marcel Hlopko
2021-01-27 13:01:20 +01:00
committed by GitHub
parent c4cfcc7780
commit 4f5c75a236
35 changed files with 520 additions and 40 deletions

View File

@@ -34,6 +34,7 @@
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Statistic.h"
#include "clang/AST/DeclTemplate.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
@@ -5353,6 +5354,31 @@ public:
genericArgs.push_back(argTy.get());
}
if (auto clangDecl = nominal->getClangDecl()) {
if (auto ctd = dyn_cast<clang::ClassTemplateDecl>(clangDecl)) {
auto clangImporter = static_cast<ClangImporter *>(
nominal->getASTContext().getClangModuleLoader());
SmallVector<Type, 2> typesOfGenericArgs;
for (auto arg : genericArgs) {
typesOfGenericArgs.push_back(arg);
}
SmallVector<clang::TemplateArgument, 2> templateArguments;
std::unique_ptr<TemplateInstantiationError> error =
ctx.getClangTemplateArguments(ctd->getTemplateParameters(),
typesOfGenericArgs,
templateArguments);
auto instantiation = clangImporter->instantiateCXXClassTemplate(
const_cast<clang::ClassTemplateDecl *>(ctd), templateArguments);
instantiation->setTemplateInstantiationType(
BoundGenericType::get(nominal, parentTy, genericArgs));
return instantiation->getDeclaredInterfaceType();
}
}
return BoundGenericType::get(nominal, parentTy, genericArgs);
}