Skip to content

Commit d22821e

Browse files
Merge pull request #31814 from LucianoPAlmeida/SR-12723-conventions
[SR-12723][Sema] Validate function type param representations thick-to-thin conversions
2 parents 8573d70 + da53129 commit d22821e

File tree

2 files changed

+117
-3
lines changed

2 files changed

+117
-3
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,20 +1350,53 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
13501350
return getTypeMatchSuccess();
13511351
}
13521352

1353+
// Determine whether conversion is allowed between two function types
1354+
// based on their representations.
1355+
static bool
1356+
isConversionAllowedBetween(FunctionTypeRepresentation rep1,
1357+
FunctionTypeRepresentation rep2) {
1358+
auto isThin = [](FunctionTypeRepresentation rep) {
1359+
return rep == FunctionTypeRepresentation::CFunctionPointer ||
1360+
rep == FunctionTypeRepresentation::Thin;
1361+
};
1362+
1363+
// Allowing "thin" (c, thin) to "thin" conventions
1364+
if (isThin(rep1) && isThin(rep2))
1365+
return true;
1366+
1367+
// Allowing all to "thick" (swift, block) conventions
1368+
// "thin" (c, thin) to "thick" or "thick" to "thick"
1369+
if (rep2 == FunctionTypeRepresentation::Swift ||
1370+
rep2 == FunctionTypeRepresentation::Block)
1371+
return true;
1372+
1373+
return rep1 == rep2;
1374+
}
1375+
13531376
// Returns 'false' (i.e. no error) if it is legal to match functions with the
13541377
// corresponding function type representations and the given match kind.
13551378
static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
13561379
FunctionTypeRepresentation rep2,
1357-
ConstraintKind kind) {
1380+
ConstraintKind kind,
1381+
ConstraintLocatorBuilder locator) {
13581382
switch (kind) {
13591383
case ConstraintKind::Bind:
13601384
case ConstraintKind::BindParam:
13611385
case ConstraintKind::BindToPointerType:
13621386
case ConstraintKind::Equal:
13631387
return rep1 != rep2;
1388+
1389+
case ConstraintKind::Subtype: {
1390+
auto last = locator.last();
1391+
if (!(last && last->is<LocatorPathElt::FunctionArgument>()))
1392+
return false;
1393+
1394+
// Inverting the result because matchFunctionRepresentations
1395+
// returns false in conversions are allowed.
1396+
return !isConversionAllowedBetween(rep1, rep2);
1397+
}
13641398

13651399
case ConstraintKind::OpaqueUnderlyingType:
1366-
case ConstraintKind::Subtype:
13671400
case ConstraintKind::Conversion:
13681401
case ConstraintKind::BridgingConversion:
13691402
case ConstraintKind::ArgumentConversion:
@@ -1658,7 +1691,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
16581691

16591692
if (matchFunctionRepresentations(func1->getExtInfo().getRepresentation(),
16601693
func2->getExtInfo().getRepresentation(),
1661-
kind)) {
1694+
kind, locator)) {
16621695
return getTypeMatchFailure(locator);
16631696
}
16641697

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// RUN: %target-swift-emit-silgen %s -verify
2+
3+
func SR12723_thin(_: (@convention(thin) () -> Void) -> Void) {}
4+
func SR12723_block(_: (@convention(block) () -> Void) -> Void) {}
5+
func SR12723_c(_: (@convention(c) () -> Void) -> Void) {}
6+
7+
func SR12723_function(_: () -> Void) {}
8+
9+
func context() {
10+
SR12723_c(SR12723_function)
11+
12+
SR12723_block(SR12723_function)
13+
14+
SR12723_thin(SR12723_function)
15+
}
16+
17+
struct SR12723_C {
18+
let function: (@convention(c) () -> Void) -> Void
19+
}
20+
21+
struct SR12723_Thin {
22+
let function: (@convention(thin) () -> Void) -> Void
23+
}
24+
25+
struct SR12723_Block {
26+
let function: (@convention(block) () -> Void) -> Void
27+
}
28+
29+
func proxy(_ f: (() -> Void) -> Void) {
30+
let a = 1
31+
f { print(a) }
32+
}
33+
34+
func cContext() {
35+
let c = SR12723_C { app in app() }
36+
37+
proxy(c.function)
38+
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to expected argument type '(() -> Void) -> Void'}}
39+
40+
let _ : (@convention(block) () -> Void) -> Void = c.function
41+
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to specified type '(@convention(block) () -> Void) -> Void'}}
42+
43+
let _ : (@convention(c) () -> Void) -> Void = c.function // OK
44+
45+
let _ : (@convention(thin) () -> Void) -> Void = c.function // OK
46+
47+
let _ : (() -> Void) -> Void = c.function
48+
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to specified type '(() -> Void) -> Void'}}
49+
50+
}
51+
52+
func thinContext() {
53+
let thin = SR12723_Thin { app in app() }
54+
55+
proxy(thin.function)
56+
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to expected argument type '(() -> Void) -> Void'}}
57+
58+
let _ : (@convention(block) () -> Void) -> Void = thin.function
59+
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to specified type '(@convention(block) () -> Void) -> Void'}}
60+
61+
let _ : (@convention(c) () -> Void) -> Void = thin.function // OK
62+
63+
let _ : (@convention(thin) () -> Void) -> Void = thin.function // OK
64+
65+
let _ : (() -> Void) -> Void = thin.function
66+
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to specified type '(() -> Void) -> Void'}}
67+
}
68+
69+
func blockContext() {
70+
let block = SR12723_Block { app in app() }
71+
72+
proxy(block.function)
73+
74+
let _ : (@convention(block) () -> Void) -> Void = block.function // OK
75+
76+
let _ : (@convention(c) () -> Void) -> Void = block.function // OK
77+
78+
let _ : (@convention(thin) () -> Void) -> Void = block.function // OK
79+
80+
let _ : (() -> Void) -> Void = block.function // OK
81+
}

0 commit comments

Comments
 (0)