Skip to content

Commit a9fdb7a

Browse files
committed
[CSSimplify] Detect and diagnose Swift -> C pointer conversion failures
Detect and diagnose situations when Swift -> C pointer conversion is unsupported due to method not being imported from C header.
1 parent 25762c2 commit a9fdb7a

File tree

3 files changed

+76
-24
lines changed

3 files changed

+76
-24
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5894,7 +5894,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
58945894
//
58955895
// Do some light verification before recording restriction to
58965896
// avoid allocating constraints for obviously invalid cases.
5897-
if (type1IsPointer && !type1IsOptional && !type2IsOptional) {
5897+
if (type1IsPointer && !type1IsOptional && !type2IsOptional &&
5898+
(shouldAttemptFixes() || isArgumentOfImportedDecl(locator))) {
58985899
// UnsafeRawPointer -> UnsafePointer<[U]Int8>
58995900
if (type1PointerKind == PTK_UnsafeRawPointer &&
59005901
pointerKind == PTK_UnsafePointer) {
@@ -11384,42 +11385,59 @@ ConstraintSystem::SolutionKind
1138411385
ConstraintSystem::simplifyPointerToCPointerRestriction(
1138511386
Type type1, Type type2, TypeMatchOptions flags,
1138611387
ConstraintLocatorBuilder locator) {
11387-
// If this is not an imported function, let's not proceed with this
11388-
// conversion.
11389-
if (!isArgumentOfImportedDecl(locator)) {
11390-
return SolutionKind::Error;
11391-
}
11388+
bool inCorrectPosition = isArgumentOfImportedDecl(locator);
11389+
11390+
if (inCorrectPosition) {
11391+
// Make sure that solutions with implicit pointer conversions
11392+
// are always worse than the ones without them.
11393+
increaseScore(SK_ImplicitValueConversion);
11394+
} else {
11395+
// If this is not an imported function, let's not proceed with
11396+
// the conversion, unless in diagnostic mode.
11397+
if (!shouldAttemptFixes())
11398+
return SolutionKind::Error;
1139211399

11393-
// Make sure that solutions with implicit pointer conversions
11394-
// are always worse than the ones without them.
11395-
increaseScore(SK_ImplicitValueConversion);
11400+
// Let's attempt to convert the types and record a tailored
11401+
// fix if that succeeds.
11402+
}
1139611403

1139711404
auto &ctx = getASTContext();
1139811405

1139911406
PointerTypeKind swiftPtrKind, cPtrKind;
1140011407

11401-
auto swiftPtr =
11402-
type1->lookThroughAllOptionalTypes()->getAnyPointerElementType(
11403-
swiftPtrKind);
11408+
auto swiftPtr = type1->getAnyPointerElementType(swiftPtrKind);
11409+
auto cPtr = type2->getAnyPointerElementType(cPtrKind);
11410+
11411+
assert(swiftPtr);
11412+
assert(cPtr);
11413+
11414+
auto markSupported = [&]() -> SolutionKind {
11415+
if (inCorrectPosition)
11416+
return SolutionKind::Solved;
1140411417

11405-
auto cPtr =
11406-
type2->lookThroughAllOptionalTypes()->getAnyPointerElementType(cPtrKind);
11418+
// If conversion cannot be allowed on account of declaration,
11419+
// let's add a tailored fix.
11420+
auto *fix = AllowSwiftToCPointerConversion::create(
11421+
*this, getConstraintLocator(locator));
11422+
11423+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
11424+
};
1140711425

1140811426
// Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int8>
1140911427
if (swiftPtrKind == PTK_UnsafeRawPointer ||
1141011428
swiftPtrKind == PTK_UnsafeMutableRawPointer) {
1141111429
// Since it's a C pointer on parameter side it would always
1141211430
// be fully resolved.
1141311431
if (cPtr->isInt8() || cPtr->isUInt8())
11414-
return SolutionKind::Solved;
11432+
return markSupported();
1141511433
} else {
1141611434
// Unsafe[Mutable]Pointer<T> -> Unsafe[Mutable]Pointer<[U]Int8>
1141711435
if (cPtr->isInt8() || cPtr->isUInt8()) {
1141811436
// <T> can default to the type of C pointer.
1141911437
addConstraint(
1142011438
ConstraintKind::Defaultable, swiftPtr, cPtr,
1142111439
locator.withPathElement(LocatorPathElt::GenericArgument(0)));
11422-
return SolutionKind::Solved;
11440+
return markSupported();
1142311441
}
1142411442

1142511443
auto elementLoc =
@@ -11432,42 +11450,50 @@ ConstraintSystem::simplifyPointerToCPointerRestriction(
1143211450
addConstraint(ConstraintKind::Equal, cPtr,
1143311451
swiftPtr->isUInt() ? ctx.getIntType() : ctx.getUIntType(),
1143411452
elementLoc);
11435-
return SolutionKind::Solved;
11453+
return markSupported();
1143611454
}
1143711455

1143811456
if (swiftPtr->isInt8() || swiftPtr->isUInt8()) {
1143911457
addConstraint(ConstraintKind::Equal, cPtr,
1144011458
swiftPtr->isUInt8() ? ctx.getInt8Type()
1144111459
: ctx.getUInt8Type(),
1144211460
elementLoc);
11443-
return SolutionKind::Solved;
11461+
return markSupported();
1144411462
}
1144511463

1144611464
if (swiftPtr->isInt16() || swiftPtr->isUInt16()) {
1144711465
addConstraint(ConstraintKind::Equal, cPtr,
1144811466
swiftPtr->isUInt16() ? ctx.getInt16Type()
1144911467
: ctx.getUInt16Type(),
1145011468
elementLoc);
11451-
return SolutionKind::Solved;
11469+
return markSupported();
1145211470
}
1145311471

1145411472
if (swiftPtr->isInt32() || swiftPtr->isUInt32()) {
1145511473
addConstraint(ConstraintKind::Equal, cPtr,
1145611474
swiftPtr->isUInt32() ? ctx.getInt32Type()
1145711475
: ctx.getUInt32Type(),
1145811476
elementLoc);
11459-
return SolutionKind::Solved;
11477+
return markSupported();
1146011478
}
1146111479

1146211480
if (swiftPtr->isInt64() || swiftPtr->isUInt64()) {
1146311481
addConstraint(ConstraintKind::Equal, cPtr,
1146411482
swiftPtr->isUInt64() ? ctx.getInt64Type()
1146511483
: ctx.getUInt64Type(),
1146611484
elementLoc);
11467-
return SolutionKind::Solved;
11485+
return markSupported();
1146811486
}
1146911487
}
1147011488

11489+
// If the conversion is unsupported, let's record a generic argument mismatch.
11490+
if (shouldAttemptFixes() && !inCorrectPosition) {
11491+
auto *fix = AllowArgumentMismatch::create(*this, type1, type2,
11492+
getConstraintLocator(locator));
11493+
return recordFix(fix, /*impact=*/2) ? SolutionKind::Error
11494+
: SolutionKind::Solved;
11495+
}
11496+
1147111497
return SolutionKind::Error;
1147211498
}
1147311499

test/Constraints/swift_to_c_pointer_conversions.swift.gyb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,29 @@ func test_overloaded_ref_is_not_ambiguous() {
243243
const_char_ptr_func(overloaded_func()) // Ok
244244
const_opt_char_ptr_func(overloaded_func()) // Ok
245245
}
246+
247+
func test_tailored_diagnostic(ptr: UnsafeRawPointer, tptr: UnsafePointer<Int8>) {
248+
func swift_uint8_func(_: UnsafePointer<UInt8>) {}
249+
func swift_int8_func(_: UnsafePointer<Int8>) {}
250+
func opt_arg_func(_: UnsafePointer<Int8>?) {}
251+
252+
swift_uint8_func(ptr)
253+
// expected-error@-1 {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<UInt8>' because local function 'swift_uint8_func' was not imported from C header}}
254+
swift_uint8_func(tptr)
255+
// expected-error@-1 {{cannot convert value of type 'UnsafePointer<Int8>' to expected argument type 'UnsafePointer<UInt8>' because local function 'swift_uint8_func' was not imported from C header}}
256+
257+
swift_int8_func(ptr)
258+
// expected-error@-1 {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int8>' because local function 'swift_int8_func' was not imported from C header}}
259+
swift_int8_func(tptr) // Ok
260+
261+
opt_arg_func(ptr)
262+
// expected-error@-1 {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int8>?' because local function 'opt_arg_func' was not imported from C header}}
263+
opt_arg_func(tptr) // Ok
264+
265+
let optrS8: UnsafePointer<Int8>? = nil
266+
let optrU8: UnsafePointer<UInt8>? = nil
267+
268+
opt_arg_func(optrS8) // Ok
269+
opt_arg_func(optrU8)
270+
// expected-error@-1 {{cannot convert value of type 'UnsafePointer<UInt8>?' to expected argument type 'UnsafePointer<Int8>?' because local function 'opt_arg_func' was not imported from C header}}
271+
}

test/stdlib/UnsafePointerDiagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ func unsafePointerConversionAvailability(
7979
_ = UnsafeMutablePointer<Int>(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
8080
_ = UnsafeMutablePointer<Int>(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
8181
_ = UnsafeMutablePointer<Int>(orp) // expected-error {{cannot convert value of type 'UnsafeRawPointer?' to expected argument type 'UnsafeMutablePointer<Int>'}}
82-
_ = UnsafeMutablePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer?' to expected argument type 'UnsafeMutablePointer<Int>'}}
82+
_ = UnsafeMutablePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafeMutablePointer<Int>'}}
8383

8484
_ = UnsafePointer<Int>(rp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int>'}}
8585
_ = UnsafePointer<Int>(mrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafePointer<Int>'}}
86-
_ = UnsafePointer<Int>(orp) // expected-error {{cannot convert value of type 'UnsafeRawPointer?' to expected argument type 'UnsafePointer<Int>'}}
87-
_ = UnsafePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer?' to expected argument type 'UnsafePointer<Int>'}}
86+
_ = UnsafePointer<Int>(orp) // expected-error {{cannot convert value of type 'UnsafeRawPointer' to expected argument type 'UnsafePointer<Int>'}}
87+
_ = UnsafePointer<Int>(omrp) // expected-error {{cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'UnsafePointer<Int>'}}
8888

8989
_ = UnsafePointer<Int>(ups) // expected-error {{cannot convert value of type 'UnsafePointer<String>' to expected argument type 'UnsafePointer<Int>'}}
9090
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('String' and 'Int') are expected to be equal}}

0 commit comments

Comments
 (0)