Skip to content

Commit f0f2246

Browse files
authored
[cxx-interop] Support C++ function templates in Swift. (swiftlang#33053)
This patch adds rudimentary support for C++ template functions in swift.
1 parent 8145566 commit f0f2246

23 files changed

+531
-88
lines changed

include/swift/AST/ASTContext.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
#include "swift/AST/Import.h"
2424
#include "swift/AST/SearchPathOptions.h"
2525
#include "swift/AST/Type.h"
26-
#include "swift/AST/Types.h"
2726
#include "swift/AST/TypeAlignments.h"
27+
#include "swift/AST/Types.h"
2828
#include "swift/Basic/LangOptions.h"
2929
#include "swift/Basic/Located.h"
3030
#include "swift/Basic/Malloc.h"
31+
#include "clang/AST/DeclTemplate.h"
3132
#include "llvm/ADT/ArrayRef.h"
3233
#include "llvm/ADT/DenseMap.h"
3334
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -628,6 +629,13 @@ class ASTContext final {
628629
ArrayRef<SILParameterInfo> params, Optional<SILResultInfo> result,
629630
SILFunctionType::Representation trueRep);
630631

632+
/// Instantiates "Impl.Converter" if needed, then calls
633+
/// ClangTypeConverter::getClangTemplateArguments.
634+
std::unique_ptr<TemplateInstantiationError> getClangTemplateArguments(
635+
const clang::TemplateParameterList *templateParams,
636+
ArrayRef<Type> genericArgs,
637+
SmallVectorImpl<clang::TemplateArgument> &templateArgs);
638+
631639
/// Get the Swift declaration that a Clang declaration was exported from,
632640
/// if applicable.
633641
const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl);

include/swift/AST/ClangModuleLoader.h

+14
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
#define SWIFT_AST_CLANG_MODULE_LOADER_H
1515

1616
#include "swift/AST/ModuleLoader.h"
17+
#include "swift/AST/SubstitutionMap.h"
1718
#include "swift/Basic/TaggedUnion.h"
19+
#include "clang/AST/DeclTemplate.h"
1820

1921
namespace clang {
2022
class ASTContext;
@@ -219,6 +221,18 @@ class ClangModuleLoader : public ModuleLoader {
219221
/// based on subtleties like the target module interface format.
220222
virtual bool isSerializable(const clang::Type *type,
221223
bool checkCanonical) const = 0;
224+
225+
virtual clang::FunctionDecl *
226+
instantiateCXXFunctionTemplate(ASTContext &ctx,
227+
clang::FunctionTemplateDecl *func,
228+
SubstitutionMap subst) = 0;
229+
};
230+
231+
/// Used to describe a template instantiation error.
232+
struct TemplateInstantiationError {
233+
/// Generic types that could not be converted to QualTypes using the
234+
/// ClangTypeConverter.
235+
SmallVector<Type, 4> failedTypes;
222236
};
223237

224238
} // namespace swift

include/swift/AST/Decl.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -5960,9 +5960,10 @@ class FuncDecl : public AbstractFunctionDecl {
59605960
DeclContext *Parent);
59615961

59625962
static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc,
5963-
DeclName Name, SourceLoc NameLoc,
5964-
bool Async, bool Throws,
5965-
ParameterList *BodyParams, Type FnRetType,
5963+
DeclName Name, SourceLoc NameLoc, bool Async,
5964+
bool Throws, ParameterList *BodyParams,
5965+
Type FnRetType,
5966+
GenericParamList *GenericParams,
59665967
DeclContext *Parent, ClangNode ClangN);
59675968

59685969
bool isStatic() const;

include/swift/AST/DiagnosticsSema.def

+5
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,11 @@ ERROR(where_nongeneric_ctx,none,
16741674
ERROR(where_nongeneric_toplevel,none,
16751675
"'where' clause cannot be applied to a non-generic top-level "
16761676
"declaration", ())
1677+
ERROR(unable_to_convert_generic_swift_types,none,
1678+
"could not generate C++ types from the generic Swift types provided. "
1679+
"The following Swift type(s) provided to '%0' were unable to be "
1680+
"converted: %1.",
1681+
(StringRef, StringRef))
16771682

16781683
// Type aliases
16791684
ERROR(type_alias_underlying_type_access,none,

include/swift/ClangImporter/ClangImporter.h

+5
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,11 @@ class ClangImporter final : public ClangModuleLoader {
472472

473473
bool isSerializable(const clang::Type *type,
474474
bool checkCanonical) const override;
475+
476+
clang::FunctionDecl *
477+
instantiateCXXFunctionTemplate(ASTContext &ctx,
478+
clang::FunctionTemplateDecl *func,
479+
SubstitutionMap subst) override;
475480
};
476481

477482
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

lib/AST/ASTContext.cpp

+19-4
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
#include "ClangTypeConverter.h"
1919
#include "ForeignRepresentationInfo.h"
2020
#include "SubstitutionMapStorage.h"
21-
#include "swift/AST/ForeignAsyncConvention.h"
2221
#include "swift/AST/ClangModuleLoader.h"
2322
#include "swift/AST/ConcreteDeclRef.h"
2423
#include "swift/AST/DiagnosticEngine.h"
2524
#include "swift/AST/DiagnosticsSema.h"
2625
#include "swift/AST/ExistentialLayout.h"
2726
#include "swift/AST/FileUnit.h"
27+
#include "swift/AST/ForeignAsyncConvention.h"
2828
#include "swift/AST/ForeignErrorConvention.h"
2929
#include "swift/AST/GenericEnvironment.h"
3030
#include "swift/AST/GenericSignature.h"
@@ -41,19 +41,19 @@
4141
#include "swift/AST/PropertyWrappers.h"
4242
#include "swift/AST/ProtocolConformance.h"
4343
#include "swift/AST/RawComment.h"
44+
#include "swift/AST/SILLayout.h"
4445
#include "swift/AST/SemanticAttrs.h"
4546
#include "swift/AST/SourceFile.h"
4647
#include "swift/AST/SubstitutionMap.h"
47-
#include "swift/AST/SILLayout.h"
4848
#include "swift/AST/TypeCheckRequests.h"
4949
#include "swift/Basic/Compiler.h"
5050
#include "swift/Basic/SourceManager.h"
5151
#include "swift/Basic/Statistic.h"
5252
#include "swift/Basic/StringExtras.h"
53-
#include "swift/Syntax/References.h"
54-
#include "swift/Syntax/SyntaxArena.h"
5553
#include "swift/Strings.h"
5654
#include "swift/Subsystems.h"
55+
#include "swift/Syntax/References.h"
56+
#include "swift/Syntax/SyntaxArena.h"
5757
#include "llvm/ADT/DenseMap.h"
5858
#include "llvm/ADT/Statistic.h"
5959
#include "llvm/ADT/StringMap.h"
@@ -4563,6 +4563,21 @@ ASTContext::getCanonicalClangFunctionType(
45634563
return ty ? ty->getCanonicalTypeInternal().getTypePtr() : nullptr;
45644564
}
45654565

4566+
std::unique_ptr<TemplateInstantiationError>
4567+
ASTContext::getClangTemplateArguments(
4568+
const clang::TemplateParameterList *templateParams,
4569+
ArrayRef<Type> genericArgs,
4570+
SmallVectorImpl<clang::TemplateArgument> &templateArgs) {
4571+
auto &impl = getImpl();
4572+
if (!impl.Converter) {
4573+
auto *cml = getClangModuleLoader();
4574+
impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target);
4575+
}
4576+
4577+
return impl.Converter->getClangTemplateArguments(templateParams, genericArgs,
4578+
templateArgs);
4579+
}
4580+
45664581
const Decl *
45674582
ASTContext::getSwiftDeclForExportedClangDecl(const clang::Decl *decl) {
45684583
auto &impl = getImpl();

lib/AST/ClangTypeConverter.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -807,3 +807,33 @@ Decl *ClangTypeConverter::getSwiftDeclForExportedClangDecl(
807807
auto it = ReversedExportMap.find(decl);
808808
return (it != ReversedExportMap.end() ? it->second : nullptr);
809809
}
810+
811+
std::unique_ptr<TemplateInstantiationError>
812+
ClangTypeConverter::getClangTemplateArguments(
813+
const clang::TemplateParameterList *templateParams,
814+
ArrayRef<Type> genericArgs,
815+
SmallVectorImpl<clang::TemplateArgument> &templateArgs) {
816+
// Keep track of the types we failed to convert so we can return a useful
817+
// error.
818+
SmallVector<Type, 2> failedTypes;
819+
for (clang::NamedDecl *param : *templateParams) {
820+
// Note: all template parameters must be template type parameters. This is
821+
// verified when we import the clang decl.
822+
auto templateParam = cast<clang::TemplateTypeParmDecl>(param);
823+
auto replacement = genericArgs[templateParam->getIndex()];
824+
auto qualType = convert(replacement);
825+
if (qualType.isNull()) {
826+
failedTypes.push_back(replacement);
827+
// Find all the types we can't convert.
828+
continue;
829+
}
830+
templateArgs.push_back(clang::TemplateArgument(qualType));
831+
}
832+
if (failedTypes.empty())
833+
return nullptr;
834+
auto errorInfo = std::make_unique<TemplateInstantiationError>();
835+
llvm::for_each(failedTypes, [&errorInfo](auto type) {
836+
errorInfo->failedTypes.push_back(type);
837+
});
838+
return errorInfo;
839+
}

lib/AST/ClangTypeConverter.h

+10
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,18 @@ class ClangTypeConverter :
8484
/// Swift declaration.
8585
Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl) const;
8686

87+
/// Translate Swift generic arguments to template arguments.
88+
///
89+
/// \returns nullptr if successful. If an error occors, returns a unique_ptr
90+
/// to a `TemplateInstantiationError` with a list of the failed types.
91+
std::unique_ptr<TemplateInstantiationError> getClangTemplateArguments(
92+
const clang::TemplateParameterList *templateParams,
93+
ArrayRef<Type> genericArgs,
94+
SmallVectorImpl<clang::TemplateArgument> &templateArgs);
95+
8796
private:
8897
clang::QualType convert(Type type);
98+
8999
clang::QualType convertMemberType(NominalTypeDecl *DC,
90100
StringRef memberName);
91101

lib/AST/Decl.cpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -7227,16 +7227,15 @@ FuncDecl *FuncDecl::createImplicit(ASTContext &Context,
72277227
}
72287228

72297229
FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc,
7230-
DeclName Name, SourceLoc NameLoc,
7231-
bool Async, bool Throws,
7232-
ParameterList *BodyParams,
7233-
Type FnRetType, DeclContext *Parent,
7234-
ClangNode ClangN) {
7230+
DeclName Name, SourceLoc NameLoc, bool Async,
7231+
bool Throws, ParameterList *BodyParams,
7232+
Type FnRetType,
7233+
GenericParamList *GenericParams,
7234+
DeclContext *Parent, ClangNode ClangN) {
72357235
assert(ClangN && FnRetType);
72367236
auto *const FD = FuncDecl::createImpl(
72377237
Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc,
7238-
Async, SourceLoc(), Throws, SourceLoc(),
7239-
/*GenericParams=*/nullptr, Parent, ClangN);
7238+
Async, SourceLoc(), Throws, SourceLoc(), GenericParams, Parent, ClangN);
72407239
FD->setParameters(BodyParams);
72417240
FD->setResultInterfaceType(FnRetType);
72427241
return FD;

lib/ClangImporter/ClangImporter.cpp

+31-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
#include "swift/AST/ClangModuleLoader.h"
2222
#include "swift/AST/DiagnosticEngine.h"
2323
#include "swift/AST/DiagnosticsClangImporter.h"
24-
#include "swift/AST/ImportCache.h"
24+
#include "swift/AST/DiagnosticsSema.h"
2525
#include "swift/AST/IRGenOptions.h"
26+
#include "swift/AST/ImportCache.h"
2627
#include "swift/AST/LinkLibrary.h"
2728
#include "swift/AST/Module.h"
2829
#include "swift/AST/NameLookup.h"
@@ -35,8 +36,6 @@
3536
#include "swift/ClangImporter/ClangModule.h"
3637
#include "swift/Config.h"
3738
#include "swift/Demangling/Demangle.h"
38-
#include "swift/ClangImporter/ClangModule.h"
39-
#include "swift/Config.h"
4039
#include "swift/Parse/Lexer.h"
4140
#include "swift/Parse/Parser.h"
4241
#include "swift/Strings.h"
@@ -4082,3 +4081,32 @@ swift::getModuleCachePathFromClang(const clang::CompilerInstance &Clang) {
40824081
return llvm::sys::path::parent_path(SpecificModuleCachePath).str();
40834082
}
40844083

4084+
clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate(
4085+
ASTContext &ctx, clang::FunctionTemplateDecl *func, SubstitutionMap subst) {
4086+
SmallVector<clang::TemplateArgument, 4> templateSubst;
4087+
std::unique_ptr<TemplateInstantiationError> error =
4088+
ctx.getClangTemplateArguments(func->getTemplateParameters(),
4089+
subst.getReplacementTypes(), templateSubst);
4090+
if (error) {
4091+
std::string failedTypesStr;
4092+
llvm::raw_string_ostream failedTypesStrStream(failedTypesStr);
4093+
llvm::interleaveComma(error->failedTypes, failedTypesStrStream);
4094+
// TODO: Use the location of the apply here.
4095+
// TODO: This error message should not reference implementation details.
4096+
// See: https://github.com/apple/swift/pull/33053#discussion_r477003350
4097+
ctx.Diags.diagnose(SourceLoc(),
4098+
diag::unable_to_convert_generic_swift_types.ID,
4099+
{func->getName(), StringRef(failedTypesStr)});
4100+
// Return a valid FunctionDecl but, we'll never use it.
4101+
return func->getAsFunction();
4102+
}
4103+
4104+
// Instanciate a specialization of this template using the substitution map.
4105+
auto *templateArgList = clang::TemplateArgumentList::CreateCopy(
4106+
func->getASTContext(), templateSubst);
4107+
auto &sema = getClangInstance().getSema();
4108+
auto *spec = sema.InstantiateFunctionDeclaration(func, templateArgList,
4109+
clang::SourceLocation());
4110+
sema.InstantiateFunctionDefinition(clang::SourceLocation(), spec);
4111+
return spec;
4112+
}

0 commit comments

Comments
 (0)