Skip to content

Commit 38839fc

Browse files
authored
Merge pull request #59084 from xedin/rdar-92583588-5.7
[5.7][TypeChecker] SE-0324: Extend Swift -> C pointer conversions to `inout`
2 parents eefb3a6 + b5a475a commit 38839fc

File tree

8 files changed

+83
-6
lines changed

8 files changed

+83
-6
lines changed

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ enum class ConversionRestrictionKind {
264264
ProtocolMetatypeToProtocolClass,
265265
/// Inout-to-pointer conversion.
266266
InoutToPointer,
267+
/// Converting from `inout` to a C pointer has `PointerToCPointer` semantics.
268+
InoutToCPointer,
267269
/// Array-to-pointer conversion.
268270
ArrayToPointer,
269271
/// String-to-pointer conversion.
@@ -303,8 +305,8 @@ enum class ConversionRestrictionKind {
303305
/// via an implicit Double initializer call passing a CGFloat value.
304306
CGFloatToDouble,
305307
/// Implicit conversion between Swift and C pointers:
306-
// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int>
307-
// - Unsafe[Mutable]Pointer<Int{8, 16, ...}> <-> Unsafe[Mutable]Pointer<UInt{8, 16, ...}>
308+
/// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int>
309+
/// - Unsafe[Mutable]Pointer<Int{8, 16, ...}> <-> Unsafe[Mutable]Pointer<UInt{8, 16, ...}>
308310
PointerToCPointer,
309311
// Convert a pack into a type with an equivalent arity.
310312
// - If the arity of the pack is 1, drops the pack structure <T> => T

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6646,7 +6646,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66466646
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false, locator);
66476647
}
66486648

6649-
case ConversionRestrictionKind::InoutToPointer: {
6649+
case ConversionRestrictionKind::InoutToPointer:
6650+
case ConversionRestrictionKind::InoutToCPointer: {
66506651
bool isOptional = false;
66516652
Type unwrappedTy = toType;
66526653
if (Type unwrapped = toType->getOptionalObjectType()) {
@@ -6664,7 +6665,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66646665
result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType));
66656666
return result;
66666667
}
6667-
6668+
66686669
case ConversionRestrictionKind::ArrayToPointer: {
66696670
bool isOptional = false;
66706671
Type unwrappedTy = toType;

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6897,6 +6897,7 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const {
68976897
break;
68986898
}
68996899
case ConversionRestrictionKind::InoutToPointer:
6900+
case ConversionRestrictionKind::InoutToCPointer:
69006901
// For an arbitrary inout-to-pointer, we can suggest
69016902
// withUnsafe[Mutable][Bytes/Pointer].
69026903
if (auto alternative = getAlternativeKind())

lib/Sema/CSSimplify.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6591,9 +6591,18 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
65916591
// Only try an inout-to-pointer conversion if we know it's not
65926592
// an array being converted to a raw pointer type. Such
65936593
// conversions can only use array-to-pointer.
6594-
if (!baseIsArray || !isRawPointerKind(pointerKind))
6594+
if (!baseIsArray || !isRawPointerKind(pointerKind)) {
65956595
conversionsOrFixes.push_back(
65966596
ConversionRestrictionKind::InoutToPointer);
6597+
6598+
// If regular inout-to-pointer conversion doesn't work,
6599+
// let's try C pointer conversion that has special semantics
6600+
// for imported declarations.
6601+
if (isArgumentOfImportedDecl(locator)) {
6602+
conversionsOrFixes.push_back(
6603+
ConversionRestrictionKind::InoutToCPointer);
6604+
}
6605+
}
65976606
}
65986607
}
65996608

@@ -12211,6 +12220,35 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1221112220
case ConversionRestrictionKind::PointerToCPointer:
1221212221
return simplifyPointerToCPointerRestriction(type1, type2, flags, locator);
1221312222

12223+
case ConversionRestrictionKind::InoutToCPointer: {
12224+
SmallVector<Type, 2> optionals;
12225+
12226+
auto ptr2 =
12227+
type2->getDesugaredType()->lookThroughAllOptionalTypes(optionals);
12228+
12229+
increaseScore(SK_ValueToOptional, optionals.size());
12230+
12231+
PointerTypeKind pointerKind;
12232+
(void)ptr2->getAnyPointerElementType(pointerKind);
12233+
12234+
auto baseType1 = type1->getInOutObjectType();
12235+
12236+
Type ptr1;
12237+
// The right-hand size is a raw pointer, so let's use `UnsafeMutablePointer`
12238+
// for the `inout` type.
12239+
if (pointerKind == PTK_UnsafeRawPointer ||
12240+
pointerKind == PTK_UnsafeMutableRawPointer) {
12241+
ptr1 = BoundGenericType::get(Context.getUnsafeMutablePointerDecl(),
12242+
/*parent=*/nullptr, {baseType1});
12243+
} else {
12244+
ptr1 = baseType1->wrapInPointer(pointerKind);
12245+
}
12246+
12247+
assert(ptr1);
12248+
12249+
return simplifyPointerToCPointerRestriction(ptr1, ptr2, flags, locator);
12250+
}
12251+
1221412252
// T < U or T is bridged to V where V < U ===> Array<T> <c Array<U>
1221512253
case ConversionRestrictionKind::ArrayUpcast: {
1221612254
Type baseType1 = *isArrayType(type1);

lib/Sema/Constraint.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
612612
return "[string-to-pointer]";
613613
case ConversionRestrictionKind::InoutToPointer:
614614
return "[inout-to-pointer]";
615+
case ConversionRestrictionKind::InoutToCPointer:
616+
return "[inout-to-c-pointer]";
615617
case ConversionRestrictionKind::PointerToPointer:
616618
return "[pointer-to-pointer]";
617619
case ConversionRestrictionKind::PointerToCPointer:

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5719,7 +5719,8 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
57195719
case ConversionRestrictionKind::StringToPointer:
57205720
// Always ephemeral.
57215721
return ConversionEphemeralness::Ephemeral;
5722-
case ConversionRestrictionKind::InoutToPointer: {
5722+
case ConversionRestrictionKind::InoutToPointer:
5723+
case ConversionRestrictionKind::InoutToCPointer: {
57235724

57245725
// Ephemeral, except if the expression is a reference to a global or
57255726
// static stored variable, or a directly accessed stored property on such a

test/Constraints/Inputs/c_pointer_conversions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
#include "stdint.h"
44

5+
void void_ptr_func(void * _Nonnull buffer);
6+
void const_void_ptr_func(const void * _Nonnull buffer);
7+
void opt_void_ptr_func(void * _Nullable buffer);
8+
void const_opt_void_ptr_func(const void * _Nullable buffer);
9+
510
void char_ptr_func(char * _Nonnull buffer);
611
void const_char_ptr_func(const char * _Nonnull buffer);
712

test/Constraints/swift_to_c_pointer_conversions.swift.gyb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,30 @@ func test_tailored_diagnostic(ptr: UnsafeRawPointer, tptr: UnsafePointer<Int8>)
269269
opt_arg_func(optrU8)
270270
// 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}}
271271
}
272+
273+
func test_inout_to_pointer_conversion() {
274+
% for Size in ['16', '32', '64']:
275+
var x${Size}: Int${Size} = 0
276+
277+
void_ptr_func(&x${Size}) // Ok
278+
const_void_ptr_func(&x${Size}) // Ok
279+
opt_void_ptr_func(&x${Size}) // Ok
280+
281+
char_ptr_func(&x${Size}) // Ok
282+
opt_char_ptr_func(&x${Size}) // Ok
283+
284+
const_char_ptr_func(&x${Size}) // Ok
285+
const_opt_char_ptr_func(&x${Size}) // Ok
286+
287+
int_${Size}_ptr_func(&x${Size}) // Ok
288+
uint_${Size}_ptr_func(&x${Size}) // Ok
289+
290+
opt_int_${Size}_ptr_func(&x${Size}) // Ok
291+
opt_uint_${Size}_ptr_func(&x${Size}) // Ok
292+
293+
const_int_${Size}_ptr_func(&x${Size}) // OK
294+
const_uint_${Size}_ptr_func(&x${Size}) // OK
295+
const_opt_int_${Size}_ptr_func(&x${Size}) // OK
296+
const_opt_uint_${Size}_ptr_func(&x${Size}) // OK
297+
% end
298+
}

0 commit comments

Comments
 (0)