Skip to content

Commit a81d356

Browse files
committed
Add tests for function pointers and Obj-C blocks
1 parent 964cfce commit a81d356

File tree

4 files changed

+81
-24
lines changed

4 files changed

+81
-24
lines changed

test/Interop/Cxx/templates/Inputs/function-templates.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,27 @@ template <class T> void expectsConstCharPtr(T str) { takesString(str); }
1515
template <long x> void hasNonTypeTemplateParameter() {}
1616
template <long x = 0> void hasDefaultedNonTypeTemplateParameter() {}
1717

18+
// NOTE: these will cause multi-def linker errors if used in more than one compilation unit
1819
int *intPtr;
19-
int (*functionPtr)(void);
20+
21+
int get42(void) { return 42; }
22+
int (*functionPtrGet42)(void) = &get42;
23+
int (*_Nonnull nonNullFunctionPtrGet42)(void) = &get42;
24+
25+
int tripleInt(int x) { return x * 3; }
26+
int (*functionPtrTripleInt)(int) = &tripleInt;
27+
int (*_Nonnull nonNullFunctionPtrTripleInt)(int) = &tripleInt;
28+
29+
int (^blockReturns111)(void) = ^{ return 111; };
30+
int (^_Nonnull nonNullBlockReturns222)(void) = ^{ return 222; };
31+
32+
int (^blockTripleInt)(int) = ^(int x) { return x * 3; };
33+
int (^_Nonnull nonNullBlockTripleInt)(int) = ^(int x) { return x * 3; };
34+
35+
// These functions construct block literals that capture a local variable, and
36+
// then feed those blocks back to Swift via the given Swift closure (cb).
37+
void getConstantIntBlock(int returnValue, void (^_Nonnull cb)(int (^_Nonnull)(void))) { cb(^{ return returnValue; }); }
38+
int getMultiplyIntBlock(int multiplier, int (^_Nonnull cb)(int (^_Nonnull)(int))) { return cb(^(int x) { return x * multiplier; }); }
2039

2140
// We cannot yet use this in Swift but, make sure we don't crash when parsing
2241
// it.

test/Interop/Cxx/templates/function-template-closures.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ FunctionTemplateClosuresTestSuite.test("callFunctionWithReturn<F, T> where F ==
7979
expectEqual(d.x, 42)
8080
}
8181

82+
FunctionTemplateClosuresTestSuite.test("callFunctionWithPassthrough<F, T> where F == (T) -> T, T == Int") {
83+
expectEqual(callFunctionWithPassthrough({(x: Int) in x}, 42), 42)
84+
expectEqual(callFunctionWithPassthrough({(x: Int) in 24}, 42), 24)
85+
expectEqual(callFunctionWithPassthrough({(x: Int) in x + 42}, 42), 84)
86+
}
87+
8288
FunctionTemplateClosuresTestSuite.test("indirectlyCallFunction<T> where T == () -> ()") {
8389
var value = 42
8490

@@ -99,4 +105,23 @@ FunctionTemplateClosuresTestSuite.test("indirectlyCallFunction<T> where T == ()
99105
expectEqual(value, 24)
100106
}
101107

108+
FunctionTemplateClosuresTestSuite.test("callFunctionWithReturn<F, T> where F == void (^)(int), T == CInt") {
109+
var value: CInt = 0
110+
111+
value = callFunctionWithReturn(blockReturns111!)
112+
expectEqual(value, 111)
113+
114+
value = callFunctionWithReturn(nonNullBlockReturns222)
115+
expectEqual(value, 222)
116+
117+
getConstantIntBlock(333, {cb in value = callFunctionWithReturn(cb) })
118+
expectEqual(value, 333)
119+
}
120+
121+
FunctionTemplateClosuresTestSuite.test("callFunctionWithPassthrough<F, T> where F == int (^)(int), T == CInt") {
122+
expectEqual(callFunctionWithPassthrough(blockTripleInt!, 7), 21)
123+
expectEqual(callFunctionWithPassthrough(nonNullBlockTripleInt, 8), 24)
124+
expectEqual(getMultiplyIntBlock(9, {cb in callFunctionWithPassthrough(cb, 3)}), 27)
125+
}
126+
102127
runAllTests()

test/Interop/Cxx/templates/function-template.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ FunctionTemplateTestSuite.test("constLvalueReferenceToBool<T> where T == Bool")
3939
expectFalse(constLvalueReferenceToBool(false))
4040
}
4141

42+
FunctionTemplateTestSuite.test("callFunctionWithReturn<T, B> where T == C function ptr, B == CInt") {
43+
var value: CInt = 0
44+
45+
value = callFunctionWithReturn(get42)
46+
expectEqual(value, 42)
47+
48+
value = callFunctionWithReturn(functionPtrGet42!)
49+
expectEqual(value, 42)
50+
51+
value = callFunctionWithReturn(nonNullFunctionPtrGet42)
52+
expectEqual(value, 42)
53+
}
54+
55+
FunctionTemplateTestSuite.test("callFunctionWithPassthrough<F, T> where C function ptr, T == CInt") {
56+
expectEqual(callFunctionWithPassthrough(tripleInt, 4), 12)
57+
expectEqual(callFunctionWithPassthrough(functionPtrTripleInt!, 5), 15)
58+
expectEqual(callFunctionWithPassthrough(nonNullFunctionPtrTripleInt, 6), 18)
59+
}
60+
4261
// TODO: Generics, Any, and Protocols should be tested here but need to be
4362
// better supported in ClangTypeConverter first.
4463

test/Interop/Cxx/templates/template-instantiation-irgen.swift

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,8 @@
1111
// SIL for certain template instantiations:
1212
// RUN: %target-swift-emit-ir %s -I %S/Inputs -cxx-interoperability-mode=default -disable-availability-checking | %FileCheck %s
1313
//
14-
// Some instantiations are now forbidden during typechecking (though they do not
15-
// crash), but should probably be allowed. These use "TODO" checks and are
16-
// guarded by CHECK_NO_CRASH:
17-
// RUN: not %target-swift-frontend -typecheck %s -I %S/Inputs -cxx-interoperability-mode=default -disable-availability-checking -D CHECK_NO_CRASH 2>&1 | %FileCheck %s --check-prefix=TODO
18-
//
19-
// Finally, some instantiations still cause Swift compiler crashes. These are
20-
// documented with "FIXME" comments, and aren't tested (yet).
14+
// Some instantiations still cause Swift compiler crashes. These are documented
15+
// with "FIXME" comments.
2116

2217
import FunctionTemplates
2318

@@ -63,22 +58,21 @@ func takesMutPtrToClass(x: UnsafeMutablePointer<CxxClass>) { takesValue(x) }
6358
// FIXME: this crashes because this round-trips to UnsafeMutablePointer<FRT?>
6459
// func takesMutPtrToFRT(x: UnsafeMutablePointer<FRT>) { takesValue(x) }
6560

66-
// FIXME: optional pointers are not yet supported but they should be; this crashes
67-
// func takesCPtr() { takesValue(intPtr) }
68-
func takesDereferencedCPtr() { let swiftPtr = intPtr!; takesValue(swiftPtr) }
61+
func takesCPtr() {
62+
// FIXME: optional pointers are not yet supported but they should be; this crashes
63+
// takesValue(intPtr)
6964

70-
#if CHECK_NO_CRASH
71-
func takesCFnPtr() { takesValue(functionPtr) }
72-
// TODO: error: could not generate C++ types from the generic Swift types provided; the following Swift type(s) provided to 'takesValue' could not be converted: (@convention(c) () -> Int32)?
73-
#endif
65+
// It's fine if we dereference it, though
66+
takesValue(intPtr!)
67+
}
7468

75-
#if CHECK_NO_CRASH
76-
// Uniformly-typed tuples are not yet supported but they should be
77-
func takesBoolTuple() { takesValue((true, false)) }
78-
// TODO: error: could not generate C++ types from the generic Swift types provided; the following Swift type(s) provided to 'takesValue' could not be converted: (Bool, Bool)
79-
func takesIntTuple() { takesValue((42, 0)) }
80-
// TODO: error: could not generate C++ types from the generic Swift types provided; the following Swift type(s) provided to 'takesValue' could not be converted: (Int, Int)
81-
#endif
69+
func takesCFnPtr() {
70+
takesValue(get42) // function symbol
71+
// FIXME: optional pointers are not yet supported but they should be; this crashes
72+
// takesValue(functionPtrGet42)
73+
takesValue(functionPtrGet42!) // dereferenced nullable function pointer
74+
takesValue(nonNullFunctionPtrGet42) // non-null function symbol
75+
}
8276

8377
func takesRecursively() { takesValue(takesRecursively) }
8478
func takesRecursiveClosure() { takesValue({() in takesRecursiveClosure()}) }
@@ -100,7 +94,7 @@ func takesTakesCxxClass() { takesValue(takesCxxClass) }
10094
func takesSwiftClosureReturningFRT() { takesValue({() -> FRT in FRT()}) }
10195

10296
// FIXME: this crashes due to pointer round-tripping
103-
func takesSwiftClosureTakingFRT() { takesValue({(x: FRT) in takesValue(x)}) }
97+
// func takesSwiftClosureTakingFRT() { takesValue({(x: FRT) in takesValue(x)}) }
10498

10599
// FIXME: this crashes due to pointer round-tripping
106-
func takesTakesFRT() { takesValue(takesFRT) }
100+
// func takesTakesFRT() { takesValue(takesFRT) }

0 commit comments

Comments
 (0)