Skip to content

Commit

Permalink
[cxx-interop] Add support for templated member functions.
Browse files Browse the repository at this point in the history
Essentially applying the same change as for supporting templated
constructors.
  • Loading branch information
zoecarver committed Dec 4, 2020
1 parent 40723a1 commit 24aa9ac
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 3 deletions.
9 changes: 6 additions & 3 deletions lib/Sema/CSApply.cpp
Expand Up @@ -115,10 +115,12 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
auto newFnType = oldFnType->substGenericArgs(subst);
// The constructor type is a function type as follows:
// (CType.Type) -> (Generic) -> CType
// But we only want the result of that function type because that is the
// function type with the generic params that need to be substituted:
// And a method's function type is as follows:
// (inout CType) -> (Generic) -> Void
// In either case, we only want the result of that function type because that
// is the function type with the generic params that need to be substituted:
// (Generic) -> CType
if (isa<ConstructorDecl>(oldDecl))
if (isa<ConstructorDecl>(oldDecl) || oldDecl->isInstanceMember())
newFnType = cast<FunctionType>(newFnType->getResult().getPointer());
SmallVector<ParamDecl *, 4> newParams;
unsigned i = 0;
Expand Down Expand Up @@ -159,6 +161,7 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
/*Async=*/false, oldDecl->hasThrows(), newParamList,
newFnType->getResult(), /*GenericParams=*/nullptr,
oldDecl->getDeclContext(), specialized);
newFnDecl->setSelfAccessKind(cast<FuncDecl>(oldDecl)->getSelfAccessKind());
return ConcreteDeclRef(newFnDecl);
}

Expand Down
31 changes: 31 additions & 0 deletions test/Interop/Cxx/templates/Inputs/member-templates.h
@@ -0,0 +1,31 @@
struct HasMemberTemplates {
template <class T> T add(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> int addAll(int a, T b, U c) { return a + b + c; }

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

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

template <class T> T passThroughOnConst(T val) const { return val; }

template <class T> T passThroughConstOnConst(const T val) const {
return val;
}

template <class T> void doNothingConstRef(const T &val) {}

template <class T> void make42Ref(T &val) {}
};

template <class T> struct TemplateClassWithMemberTemplates {
T value;

template <class U> void setValue(U val) { value = val; }

TemplateClassWithMemberTemplates(T val) : value(val) {}
};

using IntWrapper = TemplateClassWithMemberTemplates<int>;
4 changes: 4 additions & 0 deletions test/Interop/Cxx/templates/Inputs/module.modulemap
Expand Up @@ -61,3 +61,7 @@ module ClassTemplateWithTypedef {
module ClassTemplateInNamespace {
header "class-template-in-namespace.h"
}

module MemberTemplates {
header "member-templates.h"
}
21 changes: 21 additions & 0 deletions test/Interop/Cxx/templates/member-templates-module-interface.swift
@@ -0,0 +1,21 @@
// 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 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
// CHECK: mutating func passThroughOnConst<T>(_ val: T) -> T
// CHECK: mutating func passThroughConstOnConst<T>(_ val: T) -> T
// CHECK: mutating func doNothingConstRef<T>(_ val: UnsafePointer<T>)
// CHECK: mutating func make42Ref<T>(_ val: UnsafeMutablePointer<T>)
// CHECK: }

// CHECK: struct __CxxTemplateInst32TemplateClassWithMemberTemplatesIiE {
// CHECK: var value: Int32
// CHECK: init(_ val: Int32)
// CHECK: mutating func setValue<U>(_ val: U)
// CHECK: }

// CHECK: typealias IntWrapper = __CxxTemplateInst32TemplateClassWithMemberTemplatesIiE
50 changes: 50 additions & 0 deletions test/Interop/Cxx/templates/member-templates-silgen.swift
@@ -0,0 +1,50 @@
// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

// We can't yet call member functions correctly on Windows (SR-13129).
// XFAIL: OS=windows-msvc
// REQUIRES: fixing-after-30630

import MemberTemplates

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

// CHECK: [[ADD:%.*]] = function_ref @_ZN18HasMemberTemplates3addIiEET_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: 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
// CHECK: apply [[ADD_ALL]]({{.*}}) : $@convention(c) (Int32, Int32, Int32, @inout HasMemberTemplates) -> Int32

// CHECK: [[DO_NOTHING:%.*]] = function_ref @_ZN18HasMemberTemplates17doNothingConstRefIiEEvRKT_ : $@convention(c) (UnsafePointer<Int32>, @inout HasMemberTemplates) -> () // user: %48
// CHECK: apply [[DO_NOTHING]]({{.*}}) : $@convention(c) (UnsafePointer<Int32>, @inout HasMemberTemplates) -> ()

// CHECK-LABEL: end sil function '$s4main9basicTestyyF'
func basicTest() {
var i: Int32 = 0
var obj = HasMemberTemplates()
obj.add(i, i)
obj.addTwoTemplates(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._ZN18HasMemberTemplates15addTwoTemplatesIiiEET_S1_T0_] @_ZN18HasMemberTemplates15addTwoTemplatesIiiEET_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

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

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

// CHECK: [[SET_VALUE:%.*]] = function_ref @_ZN32TemplateClassWithMemberTemplatesIiE8setValueIlEEvT_ : $@convention(c) (Int, @inout __CxxTemplateInst32TemplateClassWithMemberTemplatesIiE) -> ()
// CHECK: apply [[SET_VALUE]]({{.*}}) : $@convention(c) (Int, @inout __CxxTemplateInst32TemplateClassWithMemberTemplatesIiE) -> ()

// CHECK-LABEL: end sil function '$s4main12testSetValueyyF'
func testSetValue() {
var w = IntWrapper(11)
w.setValue(42)
}
26 changes: 26 additions & 0 deletions test/Interop/Cxx/templates/member-templates.swift
@@ -0,0 +1,26 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test
//
// We can't yet call member functions correctly on Windows (SR-13129).
// XFAIL: OS=windows-msvc
// REQUIRES: fixing-after-30630

import MemberTemplates
import StdlibUnittest

var TemplatesTestSuite = TestSuite("Member Templates")

TemplatesTestSuite.test("Set value - IntWrapper") {
var w = IntWrapper(11)
w.setValue(42)
expectEqual(w.value, 42)
}

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

runAllTests()

0 comments on commit 24aa9ac

Please sign in to comment.