Skip to content

Commit b0c4947

Browse files
authored
Merge pull request #59051 from xedin/rdar-92583588
[TypeChecker] SE-0324: Extend Swift -> C pointer conversions to `inout`
2 parents f62037c + 0a5b3f0 commit b0c4947

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
@@ -263,6 +263,8 @@ enum class ConversionRestrictionKind {
263263
ProtocolMetatypeToProtocolClass,
264264
/// Inout-to-pointer conversion.
265265
InoutToPointer,
266+
/// Converting from `inout` to a C pointer has `PointerToCPointer` semantics.
267+
InoutToCPointer,
266268
/// Array-to-pointer conversion.
267269
ArrayToPointer,
268270
/// String-to-pointer conversion.
@@ -302,8 +304,8 @@ enum class ConversionRestrictionKind {
302304
/// via an implicit Double initializer call passing a CGFloat value.
303305
CGFloatToDouble,
304306
/// Implicit conversion between Swift and C pointers:
305-
// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int>
306-
// - Unsafe[Mutable]Pointer<Int{8, 16, ...}> <-> Unsafe[Mutable]Pointer<UInt{8, 16, ...}>
307+
/// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int>
308+
/// - Unsafe[Mutable]Pointer<Int{8, 16, ...}> <-> Unsafe[Mutable]Pointer<UInt{8, 16, ...}>
307309
PointerToCPointer,
308310
// Convert a pack into a type with an equivalent arity.
309311
// - 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
@@ -6611,7 +6611,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66116611
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false, locator);
66126612
}
66136613

6614-
case ConversionRestrictionKind::InoutToPointer: {
6614+
case ConversionRestrictionKind::InoutToPointer:
6615+
case ConversionRestrictionKind::InoutToCPointer: {
66156616
bool isOptional = false;
66166617
Type unwrappedTy = toType;
66176618
if (Type unwrapped = toType->getOptionalObjectType()) {
@@ -6629,7 +6630,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66296630
result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType));
66306631
return result;
66316632
}
6632-
6633+
66336634
case ConversionRestrictionKind::ArrayToPointer: {
66346635
bool isOptional = false;
66356636
Type unwrappedTy = toType;

lib/Sema/CSDiagnostics.cpp

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

lib/Sema/CSSimplify.cpp

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

@@ -12222,6 +12231,35 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1222212231
case ConversionRestrictionKind::PointerToCPointer:
1222312232
return simplifyPointerToCPointerRestriction(type1, type2, flags, locator);
1222412233

12234+
case ConversionRestrictionKind::InoutToCPointer: {
12235+
SmallVector<Type, 2> optionals;
12236+
12237+
auto ptr2 =
12238+
type2->getDesugaredType()->lookThroughAllOptionalTypes(optionals);
12239+
12240+
increaseScore(SK_ValueToOptional, optionals.size());
12241+
12242+
PointerTypeKind pointerKind;
12243+
(void)ptr2->getAnyPointerElementType(pointerKind);
12244+
12245+
auto baseType1 = type1->getInOutObjectType();
12246+
12247+
Type ptr1;
12248+
// The right-hand size is a raw pointer, so let's use `UnsafeMutablePointer`
12249+
// for the `inout` type.
12250+
if (pointerKind == PTK_UnsafeRawPointer ||
12251+
pointerKind == PTK_UnsafeMutableRawPointer) {
12252+
ptr1 = BoundGenericType::get(Context.getUnsafeMutablePointerDecl(),
12253+
/*parent=*/nullptr, {baseType1});
12254+
} else {
12255+
ptr1 = baseType1->wrapInPointer(pointerKind);
12256+
}
12257+
12258+
assert(ptr1);
12259+
12260+
return simplifyPointerToCPointerRestriction(ptr1, ptr2, flags, locator);
12261+
}
12262+
1222512263
// T < U or T is bridged to V where V < U ===> Array<T> <c Array<U>
1222612264
case ConversionRestrictionKind::ArrayUpcast: {
1222712265
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)