mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #31814 from LucianoPAlmeida/SR-12723-conventions
[SR-12723][Sema] Validate function type param representations thick-to-thin conversions
This commit is contained in:
@@ -1350,20 +1350,53 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
|||||||
return getTypeMatchSuccess();
|
return getTypeMatchSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine whether conversion is allowed between two function types
|
||||||
|
// based on their representations.
|
||||||
|
static bool
|
||||||
|
isConversionAllowedBetween(FunctionTypeRepresentation rep1,
|
||||||
|
FunctionTypeRepresentation rep2) {
|
||||||
|
auto isThin = [](FunctionTypeRepresentation rep) {
|
||||||
|
return rep == FunctionTypeRepresentation::CFunctionPointer ||
|
||||||
|
rep == FunctionTypeRepresentation::Thin;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allowing "thin" (c, thin) to "thin" conventions
|
||||||
|
if (isThin(rep1) && isThin(rep2))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Allowing all to "thick" (swift, block) conventions
|
||||||
|
// "thin" (c, thin) to "thick" or "thick" to "thick"
|
||||||
|
if (rep2 == FunctionTypeRepresentation::Swift ||
|
||||||
|
rep2 == FunctionTypeRepresentation::Block)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return rep1 == rep2;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns 'false' (i.e. no error) if it is legal to match functions with the
|
// Returns 'false' (i.e. no error) if it is legal to match functions with the
|
||||||
// corresponding function type representations and the given match kind.
|
// corresponding function type representations and the given match kind.
|
||||||
static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
|
static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
|
||||||
FunctionTypeRepresentation rep2,
|
FunctionTypeRepresentation rep2,
|
||||||
ConstraintKind kind) {
|
ConstraintKind kind,
|
||||||
|
ConstraintLocatorBuilder locator) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case ConstraintKind::Bind:
|
case ConstraintKind::Bind:
|
||||||
case ConstraintKind::BindParam:
|
case ConstraintKind::BindParam:
|
||||||
case ConstraintKind::BindToPointerType:
|
case ConstraintKind::BindToPointerType:
|
||||||
case ConstraintKind::Equal:
|
case ConstraintKind::Equal:
|
||||||
return rep1 != rep2;
|
return rep1 != rep2;
|
||||||
|
|
||||||
|
case ConstraintKind::Subtype: {
|
||||||
|
auto last = locator.last();
|
||||||
|
if (!(last && last->is<LocatorPathElt::FunctionArgument>()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Inverting the result because matchFunctionRepresentations
|
||||||
|
// returns false in conversions are allowed.
|
||||||
|
return !isConversionAllowedBetween(rep1, rep2);
|
||||||
|
}
|
||||||
|
|
||||||
case ConstraintKind::OpaqueUnderlyingType:
|
case ConstraintKind::OpaqueUnderlyingType:
|
||||||
case ConstraintKind::Subtype:
|
|
||||||
case ConstraintKind::Conversion:
|
case ConstraintKind::Conversion:
|
||||||
case ConstraintKind::BridgingConversion:
|
case ConstraintKind::BridgingConversion:
|
||||||
case ConstraintKind::ArgumentConversion:
|
case ConstraintKind::ArgumentConversion:
|
||||||
@@ -1658,7 +1691,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
|||||||
|
|
||||||
if (matchFunctionRepresentations(func1->getExtInfo().getRepresentation(),
|
if (matchFunctionRepresentations(func1->getExtInfo().getRepresentation(),
|
||||||
func2->getExtInfo().getRepresentation(),
|
func2->getExtInfo().getRepresentation(),
|
||||||
kind)) {
|
kind, locator)) {
|
||||||
return getTypeMatchFailure(locator);
|
return getTypeMatchFailure(locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
validation-test/compiler_crashers_2_fixed/sr12723.swift
Normal file
81
validation-test/compiler_crashers_2_fixed/sr12723.swift
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// RUN: %target-swift-emit-silgen %s -verify
|
||||||
|
|
||||||
|
func SR12723_thin(_: (@convention(thin) () -> Void) -> Void) {}
|
||||||
|
func SR12723_block(_: (@convention(block) () -> Void) -> Void) {}
|
||||||
|
func SR12723_c(_: (@convention(c) () -> Void) -> Void) {}
|
||||||
|
|
||||||
|
func SR12723_function(_: () -> Void) {}
|
||||||
|
|
||||||
|
func context() {
|
||||||
|
SR12723_c(SR12723_function)
|
||||||
|
|
||||||
|
SR12723_block(SR12723_function)
|
||||||
|
|
||||||
|
SR12723_thin(SR12723_function)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SR12723_C {
|
||||||
|
let function: (@convention(c) () -> Void) -> Void
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SR12723_Thin {
|
||||||
|
let function: (@convention(thin) () -> Void) -> Void
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SR12723_Block {
|
||||||
|
let function: (@convention(block) () -> Void) -> Void
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxy(_ f: (() -> Void) -> Void) {
|
||||||
|
let a = 1
|
||||||
|
f { print(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func cContext() {
|
||||||
|
let c = SR12723_C { app in app() }
|
||||||
|
|
||||||
|
proxy(c.function)
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to expected argument type '(() -> Void) -> Void'}}
|
||||||
|
|
||||||
|
let _ : (@convention(block) () -> Void) -> Void = c.function
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to specified type '(@convention(block) () -> Void) -> Void'}}
|
||||||
|
|
||||||
|
let _ : (@convention(c) () -> Void) -> Void = c.function // OK
|
||||||
|
|
||||||
|
let _ : (@convention(thin) () -> Void) -> Void = c.function // OK
|
||||||
|
|
||||||
|
let _ : (() -> Void) -> Void = c.function
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(c) () -> Void) -> Void' to specified type '(() -> Void) -> Void'}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func thinContext() {
|
||||||
|
let thin = SR12723_Thin { app in app() }
|
||||||
|
|
||||||
|
proxy(thin.function)
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to expected argument type '(() -> Void) -> Void'}}
|
||||||
|
|
||||||
|
let _ : (@convention(block) () -> Void) -> Void = thin.function
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to specified type '(@convention(block) () -> Void) -> Void'}}
|
||||||
|
|
||||||
|
let _ : (@convention(c) () -> Void) -> Void = thin.function // OK
|
||||||
|
|
||||||
|
let _ : (@convention(thin) () -> Void) -> Void = thin.function // OK
|
||||||
|
|
||||||
|
let _ : (() -> Void) -> Void = thin.function
|
||||||
|
// expected-error@-1 {{cannot convert value of type '(@convention(thin) () -> Void) -> Void' to specified type '(() -> Void) -> Void'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockContext() {
|
||||||
|
let block = SR12723_Block { app in app() }
|
||||||
|
|
||||||
|
proxy(block.function)
|
||||||
|
|
||||||
|
let _ : (@convention(block) () -> Void) -> Void = block.function // OK
|
||||||
|
|
||||||
|
let _ : (@convention(c) () -> Void) -> Void = block.function // OK
|
||||||
|
|
||||||
|
let _ : (@convention(thin) () -> Void) -> Void = block.function // OK
|
||||||
|
|
||||||
|
let _ : (() -> Void) -> Void = block.function // OK
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user