Skip to content

[NFC] Cleanup function templates implementation. Address post-commit review comments from #33053. #35416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,15 @@ class ASTContext final {
ArrayRef<SILParameterInfo> params, Optional<SILResultInfo> result,
SILFunctionType::Representation trueRep);

/// Instantiates "Impl.Converter" if needed, then calls
/// ClangTypeConverter::getClangTemplateArguments.
/// Instantiates "Impl.Converter" if needed, then translate Swift generic
/// substitutions to equivalent C++ types using \p templateParams and \p
/// genericArgs. The converted Clang types are placed into \p templateArgs.
///
/// \p templateArgs must be empty. \p templateParams and \p genericArgs must
/// be equal in size.
///
/// \returns nullptr if successful. If an error occors, returns a list of
/// types that couldn't be converted.
std::unique_ptr<TemplateInstantiationError> getClangTemplateArguments(
const clang::TemplateParameterList *templateParams,
ArrayRef<Type> genericArgs,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/ClangModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ class ClangModuleLoader : public ModuleLoader {
SubstitutionMap subst) = 0;
};

/// Used to describe a template instantiation error.
/// Describes a C++ template instantiation error.
struct TemplateInstantiationError {
/// Generic types that could not be converted to QualTypes using the
/// ClangTypeConverter.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1692,7 +1692,7 @@ ERROR(where_nongeneric_toplevel,none,
"declaration", ())
ERROR(unable_to_convert_generic_swift_types,none,
"could not generate C++ types from the generic Swift types provided. "
"The following Swift type(s) provided to '%0' were unable to be "
"The following Swift type(s) provided to '%0' could not be "
"converted: %1.",
(StringRef, StringRef))

Expand Down
8 changes: 7 additions & 1 deletion lib/AST/ClangTypeConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,12 +860,15 @@ ClangTypeConverter::getClangTemplateArguments(
const clang::TemplateParameterList *templateParams,
ArrayRef<Type> genericArgs,
SmallVectorImpl<clang::TemplateArgument> &templateArgs) {
assert(templateArgs.size() == 0);
assert(genericArgs.size() == templateParams->size());

// Keep track of the types we failed to convert so we can return a useful
// error.
SmallVector<Type, 2> failedTypes;
for (clang::NamedDecl *param : *templateParams) {
// Note: all template parameters must be template type parameters. This is
// verified when we import the clang decl.
// verified when we import the Clang decl.
auto templateParam = cast<clang::TemplateTypeParmDecl>(param);
auto replacement = genericArgs[templateParam->getIndex()];
auto qualType = convert(replacement);
Expand All @@ -878,6 +881,9 @@ ClangTypeConverter::getClangTemplateArguments(
}
if (failedTypes.empty())
return nullptr;
// Clear "templateArgs" to prevent the clients from accidently reading a
// partially converted set of template arguments.
templateArgs.clear();
auto errorInfo = std::make_unique<TemplateInstantiationError>();
llvm::for_each(failedTypes, [&errorInfo](auto type) {
errorInfo->failedTypes.push_back(type);
Expand Down
9 changes: 6 additions & 3 deletions lib/AST/ClangTypeConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ class ClangTypeConverter :
/// Swift declaration.
Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl) const;

/// Translate Swift generic arguments to template arguments.
/// Translate Swift generic arguments to Clang C++ template arguments.
///
/// \returns nullptr if successful. If an error occors, returns a unique_ptr
/// to a `TemplateInstantiationError` with a list of the failed types.
/// \p templateArgs must be empty. \p templateParams and \p genericArgs must
/// be equal in size.
///
/// \returns nullptr if successful. If an error occors, returns a list of
/// types that couldn't be converted.
std::unique_ptr<TemplateInstantiationError> getClangTemplateArguments(
const clang::TemplateParameterList *templateParams,
ArrayRef<Type> genericArgs,
Expand Down
16 changes: 8 additions & 8 deletions test/Interop/Cxx/templates/Inputs/function-templates.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_FUNCTION_TEMPLATES_H
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_FUNCTION_TEMPLATES_H

template <class T> T add(T a, T b) { return a + b; }
template <class T> T addSameTypeParams(T a, T b) { return a + b; }

template <class A, class B> A addTwoTemplates(A a, B b) { return a + b; }
template <class A, class B> A addMixedTypeParams(A a, B b) { return a + b; }

template <class T> T passThrough(T value) { return value; }

template <class T> const T passThroughConst(const T value) { return value; }

void takesString(const char *) {}
template <class T> void expectsString(T str) { takesString(str); }
template <class T> void expectsConstCharPtr(T str) { takesString(str); }

template <long x> void integerTemplate() {}
template <long x = 0> void defaultIntegerTemplate() {}
template <long x> void hasNonTypeTemplateParameter() {}
template <long x = 0> void hasDefaultedNonTypeTemplateParameter() {}

// We cannot yet use this in swift but, make sure we don't crash when parsing
// We cannot yet use this in Swift but, make sure we don't crash when parsing
// it.
template <class R, class T, class U> R returns_template(T a, U b) {
template <class R, class T, class U> R templateParameterReturnType(T a, U b) {
return a + b;
}

// Same here:
template <class T> void cannot_infer_template() {}
template <class T> void cannotInferTemplate() {}

struct HasVariadicMemeber {
void test1(...) {}
Expand Down
4 changes: 2 additions & 2 deletions test/Interop/Cxx/templates/Inputs/member-templates.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct HasMemberTemplates {
template <class T> T add(T a, T b) { return a + b; }
template <class T> T addSameTypeParams(T a, T b) { return a + b; }

template <class T, class U> T addTwoTemplates(T a, U b) { return a + b; }
template <class T, class U> T addMixedTypeParams(T a, U b) { return a + b; }

template <class T, class U> int addAll(int a, T b, U c) { return a + b + c; }

Expand Down
39 changes: 0 additions & 39 deletions test/Interop/Cxx/templates/function-template-errors.swift

This file was deleted.

20 changes: 10 additions & 10 deletions test/Interop/Cxx/templates/function-template-irgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ public func testPassThrough(x: Int32) -> Int32 {
return passThrough(x)
}

// CHECK-LABEL: define {{.*}}i32 @"$s4main19testAddTwoTemplates1xs5Int32VAE_tF"(i32 %0)
// CHECK: [[OUT_VAL:%.*]] = call i32 @{{_Z15addTwoTemplatesIiiET_S0_T0_|"\?\?\$addTwoTemplates@HH@@YAHHH@Z"}}(i32 %0, i32 %0)
// CHECK-LABEL: define {{.*}}i32 @"$s4main22testAddMixedTypeParams1xs5Int32VAE_tF"(i32 %0)
// CHECK: [[OUT_VAL:%.*]] = call i32 @{{_Z18addMixedTypeParamsIiiET_S0_T0_|"\?\?\$addMixedTypeParams@HH@@YAHHH@Z"}}(i32 %0, i32 %0)
// CHECK: ret i32 [[OUT_VAL]]

// CHECK-LABEL: define linkonce_odr {{.*}}i32 @{{_Z15addTwoTemplatesIiiET_S0_T0_|"\?\?\$addTwoTemplates@HH@@YAHHH@Z"}}(i32 %a, i32 %b)
public func testAddTwoTemplates(x: Int32) -> Int32 {
return addTwoTemplates(x, x)
// CHECK-LABEL: define linkonce_odr {{.*}}i32 @{{_Z18addMixedTypeParamsIiiET_S0_T0_|"\?\?\$addMixedTypeParams@HH@@YAHHH@Z"}}(i32 %a, i32 %b)
public func testAddMixedTypeParams(x: Int32) -> Int32 {
return addMixedTypeParams(x, x)
}

// CHECK-LABEL: define {{.*}}i32 @"$s4main7testAdd1xs5Int32VAE_tF"(i32 %0)
// CHECK: [[OUT_VAL:%.*]] = call i32 @{{_Z3addIiET_S0_S0_|"\?\?\$add@H@@YAHHH@Z"}}(i32 %0, i32 %0)
// CHECK-LABEL: define {{.*}}i32 @"$s4main21testAddSameTypeParams1xs5Int32VAE_tF"(i32 %0)
// CHECK: [[OUT_VAL:%.*]] = call i32 @{{_Z17addSameTypeParamsIiET_S0_S0_|"\?\?\$addSameTypeParams@H@@YAHHH@Z"}}(i32 %0, i32 %0)
// CHECK: ret i32 [[OUT_VAL]]

// CHECK-LABEL: define linkonce_odr {{.*}}i32 @{{_Z3addIiET_S0_S0_|"\?\?\$add@H@@YAHHH@Z"}}(i32 %a, i32 %b)
public func testAdd(x: Int32) -> Int32 {
return add(x, x)
// CHECK-LABEL: define linkonce_odr {{.*}}i32 @{{_Z17addSameTypeParamsIiET_S0_S0_|"\?\?\$addSameTypeParams@H@@YAHHH@Z"}}(i32 %a, i32 %b)
public func testAddSameTypeParams(x: Int32) -> Int32 {
return addSameTypeParams(x, x)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=FunctionTemplates -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s

// CHECK: func add<T>(_ a: T, _ b: T) -> T
// CHECK: func addTwoTemplates<A, B>(_ a: A, _ b: B) -> A
// CHECK: func addSameTypeParams<T>(_ a: T, _ b: T) -> T
// CHECK: func addMixedTypeParams<A, B>(_ a: A, _ b: B) -> A
// CHECK: func passThrough<T>(_ value: T) -> T
// CHECK: func passThroughConst<T>(_ value: T) -> T
// CHECK: func returns_template<R, T, U>(_ a: T, _ b: U) -> R
// CHECK: func cannot_infer_template<T>()
// CHECK: func templateParameterReturnType<R, T, U>(_ a: T, _ b: U) -> R
// CHECK: func cannotInferTemplate<T>()

// CHECK: struct HasVariadicMemeber {
// CHECK: @available(*, unavailable, message: "Variadic function is unavailable")
Expand Down
8 changes: 4 additions & 4 deletions test/Interop/Cxx/templates/function-template-silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ import FunctionTemplates
// CHECK: [[PASS_THROUGH_FN:%.*]] = function_ref @{{_Z11passThroughIiET_S0_|\?\?\$passThrough@H@@YAHH@Z}} : $@convention(c) (Int32) -> Int32
// CHECK: [[B:%.*]] = apply [[PASS_THROUGH_FN]](%0) : $@convention(c) (Int32) -> Int32

// CHECK: [[ADD_TWO_FN:%.*]] = function_ref @{{_Z15addTwoTemplatesIiiET_S0_T0_|\?\?\$addTwoTemplates@HH@@YAHHH@Z}} : $@convention(c) (Int32, Int32) -> Int32
// CHECK: [[ADD_TWO_FN:%.*]] = function_ref @{{_Z18addMixedTypeParamsIiiET_S0_T0_|\?\?\$addMixedTypeParams@HH@@YAHHH@Z}} : $@convention(c) (Int32, Int32) -> Int32
// CHECK: [[C:%.*]] = apply [[ADD_TWO_FN]]([[A]], [[B]]) : $@convention(c) (Int32, Int32) -> Int32

// CHECK: [[C_32_ADDR:%.*]] = alloc_stack $Int32
// CHECK: [[C_32:%.*]] = load [[C_32_ADDR]] : $*Int32
// CHECK: [[ADD_FN:%.*]] = function_ref @{{_Z3addIiET_S0_S0_|\?\?\$add@H@@YAHHH@Z}} : $@convention(c) (Int32, Int32) -> Int32
// CHECK: [[ADD_FN:%.*]] = function_ref @{{_Z17addSameTypeParamsIiET_S0_S0_|\?\?\$addSameTypeParams@H@@YAHHH@Z}} : $@convention(c) (Int32, Int32) -> Int32
// CHECK: [[OUT:%.*]] = apply [[ADD_FN]]([[B]], [[C_32]]) : $@convention(c) (Int32, Int32) -> Int32
// CHECK: return [[OUT]] : $Int32

// CHECK-LABEL: end sil function '$s4main4test1xs5Int32VAE_tF'
public func test(x: Int32) -> Int32 {
let a = passThroughConst(Int32(0))
let b = passThrough(x)
let c = addTwoTemplates(a, b)
return add(b, Int32(c))
let c = addMixedTypeParams(a, b)
return addSameTypeParams(b, Int32(c))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// RUN: not %target-typecheck-verify-swift %s -I %S/Inputs -enable-cxx-interop 2>&1 | %FileCheck %s

// README: If you just added support for protocol composition to the
// ClangTypeConverter, please update this test to use a different type that we
// don't support so the error messages here are still tested.


import FunctionTemplates

// Make sure we don't import non-type template parameters.
// CHECK: error: unexpected error produced: cannot find 'hasNonTypeTemplateParameter' in scope
// CHECK: error: unexpected error produced: cannot find 'hasDefaultedNonTypeTemplateParameter' in scope
public func callIntegerTemplates() {
hasNonTypeTemplateParameter()
hasDefaultedNonTypeTemplateParameter()
}

// Use protocol composition to create a type that we cannot (yet) turn into a clang::QualType.
public protocol A { }
public protocol B { }
public protocol C { }

// CHECK: error: unexpected error produced: could not generate C++ types from the generic Swift types provided. The following Swift type(s) provided to 'passThrough' could not be converted: A & B.
public func caller1(x: A & B) -> A & B {
return passThrough(x)
}

// CHECK: error: unexpected error produced: could not generate C++ types from the generic Swift types provided. The following Swift type(s) provided to 'addMixedTypeParams' could not be converted: A & B, A & C.
public func caller2(x: A & B, y: A & C) -> A & B {
return addMixedTypeParams(x, y)
}

// Make sure we emit an error and don't crash when failing to instantiate a function.
// CHECK: error: diagnostic produced elsewhere: no matching function for call to 'takesString'
// CHECK: note: diagnostic produced elsewhere: in instantiation of function template specialization 'expectsConstCharPtr<int>' requested here
// CHECK: note: diagnostic produced elsewhere: candidate function not viable: no known conversion from 'int' to 'const char *' for 1st argument
public func callexpectsConstCharPtr() {
expectsConstCharPtr(0 as Int32)
}
8 changes: 4 additions & 4 deletions test/Interop/Cxx/templates/function-template.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ FunctionTemplateTestSuite.test("passThrough<T> where T == Int") {
expectEqual(42, result)
}

FunctionTemplateTestSuite.test("add<T> where T == Int") {
let result = add(42, 23)
FunctionTemplateTestSuite.test("addSameTypeParams<T> where T == Int") {
let result = addSameTypeParams(42, 23)
expectEqual(65, result)
}

FunctionTemplateTestSuite.test("add<T, U> where T, U == Int") {
let result = addTwoTemplates(42, 23)
FunctionTemplateTestSuite.test("addSameTypeParams<T, U> where T, U == Int") {
let result = addMixedTypeParams(42, 23)
expectEqual(65, result)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=MemberTemplates -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s

// CHECK: struct HasMemberTemplates {
// CHECK: mutating func add<T>(_ a: T, _ b: T) -> T
// CHECK: mutating func addTwoTemplates<T, U>(_ a: T, _ b: U) -> T
// CHECK: mutating func addSameTypeParams<T>(_ a: T, _ b: T) -> T
// CHECK: mutating func addMixedTypeParams<T, U>(_ a: T, _ b: U) -> T
// CHECK: mutating func addAll<T, U>(_ a: Int32, _ b: T, _ c: U) -> Int32
// CHECK: mutating func passThrough<T>(_ val: T) -> T
// CHECK: mutating func passThroughConst<T>(_ val: T) -> T
Expand Down
12 changes: 6 additions & 6 deletions test/Interop/Cxx/templates/member-templates-silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import MemberTemplates

// CHECK-LABEL: sil hidden @$s4main9basicTestyyF : $@convention(thin) () -> ()

// CHECK: [[ADD:%.*]] = function_ref @_ZN18HasMemberTemplates3addIiEET_S1_S1_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32
// CHECK: [[ADD:%.*]] = function_ref @_ZN18HasMemberTemplates3addSameTypeParamsIiEET_S1_S1_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32
// CHECK: apply [[ADD]]({{.*}}) : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32

// CHECK: [[ADD_TWO_TEMPLATES:%.*]] = function_ref @_ZN18HasMemberTemplates15addTwoTemplatesIiiEET_S1_T0_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32 // user: %26
// CHECK: [[ADD_TWO_TEMPLATES:%.*]] = function_ref @_ZN18HasMemberTemplates15addMixedTypeParamsIiiEET_S1_T0_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32 // user: %26
// CHECK: apply [[ADD_TWO_TEMPLATES]]({{.*}}) : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32

// CHECK: [[ADD_ALL:%.*]] = function_ref @_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_ : $@convention(c) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32 // user: %39
Expand All @@ -24,15 +24,15 @@ import MemberTemplates
func basicTest() {
var i: Int32 = 0
var obj = HasMemberTemplates()
obj.add(i, i)
obj.addTwoTemplates(i, i)
obj.addSameTypeParams(i, i)
obj.addMixedTypeParams(i, i)
obj.addAll(i, i, i)
obj.doNothingConstRef(&i)
}

// CHECK-LABEL: sil hidden_external [clang HasMemberTemplates._ZN18HasMemberTemplates3addIiEET_S1_S1_] @_ZN18HasMemberTemplates3addIiEET_S1_S1_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32
// CHECK-LABEL: sil hidden_external [clang HasMemberTemplates._ZN18HasMemberTemplates3addSameTypeParamsIiEET_S1_S1_] @_ZN18HasMemberTemplates3addSameTypeParamsIiEET_S1_S1_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32

// CHECK-LABEL: sil hidden_external [clang HasMemberTemplates._ZN18HasMemberTemplates15addTwoTemplatesIiiEET_S1_T0_] @_ZN18HasMemberTemplates15addTwoTemplatesIiiEET_S1_T0_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32
// CHECK-LABEL: sil hidden_external [clang HasMemberTemplates._ZN18HasMemberTemplates15addMixedTypeParamsIiiEET_S1_T0_] @_ZN18HasMemberTemplates15addMixedTypeParamsIiiEET_S1_T0_ : $@convention(c) (Int32, Int32, @inout HasMemberTemplates) -> Int32

// CHECK-LABEL: sil hidden_external [clang HasMemberTemplates._ZN18HasMemberTemplates6addAllIiiEEiiT_T0_] @_ZN18HasMemberTemplates6addAllIiiEEiiT_T0_ : $@convention(c) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32

Expand Down
4 changes: 2 additions & 2 deletions test/Interop/Cxx/templates/member-templates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ TemplatesTestSuite.test("Set value - IntWrapper") {

TemplatesTestSuite.test("Templated Add") {
var h = HasMemberTemplates()
expectEqual(h.add(2, 1), 3)
expectEqual(h.addTwoTemplates(2, 1), 3)
expectEqual(h.addSameTypeParams(2, 1), 3)
expectEqual(h.addMixedTypeParams(2, 1), 3)
}

runAllTests()