Skip to content

Commit 1b98f23

Browse files
committed
[cxx-interop] Support C++ function templates in Swift.
This patch adds rudimentary support for C++ template functions in swift.
1 parent 2d09bc3 commit 1b98f23

23 files changed

+518
-68
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+
generateCXXFunctionTemplateSpecializations(ASTContext &ctx,
227+
clang::FunctionTemplateDecl *func,
228+
SubstitutionMap subst) = 0;
229+
};
230+
231+
/// Used to describe an error when instanciated a template.
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

+1
Original file line numberDiff line numberDiff line change
@@ -5947,6 +5947,7 @@ class FuncDecl : public AbstractFunctionDecl {
59475947
DeclName Name, SourceLoc NameLoc,
59485948
bool Async, bool Throws,
59495949
ParameterList *BodyParams, Type FnRetType,
5950+
GenericParamList *GenericParams,
59505951
DeclContext *Parent, ClangNode ClangN);
59515952

59525953
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+
generateCXXFunctionTemplateSpecializations(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

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

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -7217,13 +7217,14 @@ FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc,
72177217
DeclName Name, SourceLoc NameLoc,
72187218
bool Async, bool Throws,
72197219
ParameterList *BodyParams,
7220-
Type FnRetType, DeclContext *Parent,
7220+
Type FnRetType,
7221+
GenericParamList *GenericParams,
7222+
DeclContext *Parent,
72217223
ClangNode ClangN) {
72227224
assert(ClangN && FnRetType);
72237225
auto *const FD = FuncDecl::createImpl(
72247226
Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc,
7225-
Async, SourceLoc(), Throws, SourceLoc(),
7226-
/*GenericParams=*/nullptr, Parent, ClangN);
7227+
Async, SourceLoc(), Throws, SourceLoc(), GenericParams, Parent, ClangN);
72277228
FD->setParameters(BodyParams);
72287229
FD->setResultInterfaceType(FnRetType);
72297230
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"
@@ -4077,3 +4076,32 @@ swift::getModuleCachePathFromClang(const clang::CompilerInstance &Clang) {
40774076
return llvm::sys::path::parent_path(SpecificModuleCachePath).str();
40784077
}
40794078

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

0 commit comments

Comments
 (0)