Skip to content

Commit 2b6da60

Browse files
committed
SILGen: Add asserts that bridged types are loadable
Bridging thunks don't yet support bridging address-only types, but ideally they should, so that we can bridge Objective-C types to resilient value types. This came up while I was adding @_fixed_layout declarations in the standard library. To make this easier to figure out in the future, add the asserts to the bridging logic for now. Also, to avoid hitting the asserts when we emit a reference to a C function with an incompatible type, don't emit the foreign function at all until we determine that the ABI conversion is safe.
1 parent 86d4c45 commit 2b6da60

File tree

3 files changed

+76
-30
lines changed

3 files changed

+76
-30
lines changed

lib/SIL/TypeLowering.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,12 @@ TypeConverter::getTypeLoweringForUncachedLoweredType(TypeKey key) {
16201620
CanGenericSignature(),
16211621
ResilienceExpansion::Minimal,
16221622
key.isDependent()).visit(contextType);
1623+
1624+
if (key.OrigType.isForeign()) {
1625+
assert(theInfo->isLoadable() && "Cannot lower address-only type with "
1626+
"foreign abstraction pattern");
1627+
}
1628+
16231629
insert(key, theInfo);
16241630
return *theInfo;
16251631
}

lib/SILGen/SILGenBridging.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ static ManagedValue emitNativeToCBridgedValue(SILGenFunction &gen,
419419
SILLocation loc,
420420
ManagedValue v,
421421
SILType bridgedTy) {
422+
assert(v.getType().isLoadable(gen.F.getModule()) &&
423+
"Cannot bridge address-only types");
424+
422425
CanType loweredBridgedTy = bridgedTy.getSwiftRValueType();
423426
CanType loweredNativeTy = v.getType().getSwiftRValueType();
424427
if (loweredNativeTy == loweredBridgedTy)
@@ -556,6 +559,9 @@ static ManagedValue emitCBridgedToNativeValue(SILGenFunction &gen,
556559
SILLocation loc,
557560
ManagedValue v,
558561
SILType nativeTy) {
562+
assert(nativeTy.isLoadable(gen.F.getModule()) &&
563+
"Cannot bridge address-only types");
564+
559565
CanType loweredNativeTy = nativeTy.getSwiftRValueType();
560566
CanType loweredBridgedTy = v.getType().getSwiftRValueType();
561567
if (loweredNativeTy == loweredBridgedTy)
@@ -797,7 +803,7 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &gen,
797803
assert(bridgedArgs.size() + unsigned(foreignError.hasValue())
798804
== objcFnTy->getParameters().size() &&
799805
"objc inputs don't match number of arguments?!");
800-
assert(bridgedArgs.size() == swiftFnTy->getNumSILArguments() &&
806+
assert(bridgedArgs.size() == swiftFnTy->getParameters().size() &&
801807
"swift inputs don't match number of arguments?!");
802808
assert((foreignErrorSlot || !foreignError) &&
803809
"didn't find foreign error slot");

lib/SILGen/SILGenExpr.cpp

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,29 +1121,46 @@ RValue RValueEmitter::visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E,
11211121

11221122
static ManagedValue convertCFunctionSignature(SILGenFunction &SGF,
11231123
FunctionConversionExpr *e,
1124-
ManagedValue result) {
1124+
SILType loweredResultTy,
1125+
llvm::function_ref<ManagedValue ()> fnEmitter) {
11251126
SILType loweredDestTy = SGF.getLoweredType(e->getType());
1126-
1127-
if (result.getType() == loweredDestTy)
1128-
return result;
1127+
ManagedValue result;
11291128

11301129
// We're converting between C function pointer types. They better be
11311130
// ABI-compatible, since we can't emit a thunk.
1132-
if (SGF.SGM.Types.checkForABIDifferences(result.getSwiftType(),
1133-
loweredDestTy.getSwiftRValueType())
1134-
== TypeConverter::ABIDifference::NeedsThunk) {
1131+
switch (SGF.SGM.Types.checkForABIDifferences(
1132+
loweredResultTy.getSwiftRValueType(),
1133+
loweredDestTy.getSwiftRValueType())) {
1134+
case TypeConverter::ABIDifference::Trivial:
1135+
result = fnEmitter();
1136+
assert(result.getType() == loweredResultTy);
1137+
1138+
if (loweredResultTy != loweredDestTy) {
1139+
result = ManagedValue::forUnmanaged(
1140+
SGF.B.createConvertFunction(e, result.getUnmanagedValue(),
1141+
loweredDestTy));
1142+
}
1143+
1144+
break;
1145+
1146+
case TypeConverter::ABIDifference::NeedsThunk:
1147+
// Note: in this case, we don't call the emitter at all -- doing so
1148+
// just runs the risk of tripping up asserts in SILGenBridging.cpp
11351149
SGF.SGM.diagnose(e, diag::unsupported_c_function_pointer_conversion,
11361150
e->getSubExpr()->getType(), e->getType());
1137-
return SGF.emitUndef(e, loweredDestTy);
1151+
result = SGF.emitUndef(e, loweredDestTy);
1152+
break;
1153+
1154+
case TypeConverter::ABIDifference::ThinToThick:
1155+
llvm_unreachable("Cannot have thin to thick conversion here");
11381156
}
11391157

1140-
return ManagedValue::forUnmanaged(
1141-
SGF.B.createConvertFunction(e, result.getUnmanagedValue(),
1142-
loweredDestTy));
1158+
return result;
11431159
}
11441160

1145-
static RValue emitCFunctionPointer(SILGenFunction &gen,
1146-
FunctionConversionExpr *conversionExpr) {
1161+
static
1162+
ManagedValue emitCFunctionPointer(SILGenFunction &gen,
1163+
FunctionConversionExpr *conversionExpr) {
11471164
auto expr = conversionExpr->getSubExpr();
11481165

11491166
// Look through base-ignored exprs to get to the function ref.
@@ -1180,13 +1197,18 @@ static RValue emitCFunctionPointer(SILGenFunction &gen,
11801197
}
11811198

11821199
// Produce a reference to the C-compatible entry point for the function.
1183-
SILDeclRef cEntryPoint(loc, ResilienceExpansion::Minimal,
1184-
/*uncurryLevel*/ 0,
1185-
/*foreign*/ true);
1186-
SILValue cRef = gen.emitGlobalFunctionRef(expr, cEntryPoint);
1187-
ManagedValue result = convertCFunctionSignature(gen, conversionExpr,
1188-
ManagedValue::forUnmanaged(cRef));
1189-
return RValue(gen, conversionExpr, result);
1200+
SILDeclRef constant(loc, ResilienceExpansion::Minimal,
1201+
/*uncurryLevel*/ 0,
1202+
/*foreign*/ true);
1203+
SILConstantInfo constantInfo = gen.getConstantInfo(constant);
1204+
1205+
return convertCFunctionSignature(
1206+
gen, conversionExpr,
1207+
constantInfo.getSILType(),
1208+
[&]() -> ManagedValue {
1209+
SILValue cRef = gen.emitGlobalFunctionRef(expr, constant);
1210+
return ManagedValue::forUnmanaged(cRef);
1211+
});
11901212
}
11911213

11921214
// Change the representation without changing the signature or
@@ -1271,15 +1293,27 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
12711293
cast<FunctionType>(e->getType()->getCanonicalType());
12721294

12731295
if (destRepTy->getRepresentation() == FunctionTypeRepresentation::CFunctionPointer) {
1274-
// A "conversion" of a DeclRef a C function pointer is done by referencing
1275-
// the thunk (or original C function) with the C calling convention.
1276-
if (srcRepTy->getRepresentation() != FunctionTypeRepresentation::CFunctionPointer)
1277-
return emitCFunctionPointer(SGF, e);
1278-
1279-
// Ok, we're converting a C function pointer value to another C function
1280-
// pointer.
1281-
auto result = SGF.emitRValueAsSingleValue(e->getSubExpr());
1282-
return RValue(SGF, e, convertCFunctionSignature(SGF, e, result));
1296+
ManagedValue result;
1297+
1298+
if (srcRepTy->getRepresentation() != FunctionTypeRepresentation::CFunctionPointer) {
1299+
// A "conversion" of a DeclRef a C function pointer is done by referencing
1300+
// the thunk (or original C function) with the C calling convention.
1301+
result = emitCFunctionPointer(SGF, e);
1302+
} else {
1303+
// Ok, we're converting a C function pointer value to another C function
1304+
// pointer.
1305+
1306+
// Emit the C function pointer
1307+
result = SGF.emitRValueAsSingleValue(e->getSubExpr());
1308+
1309+
// Possibly bitcast the C function pointer to account for ABI-compatible
1310+
// parameter and result type conversions
1311+
result = convertCFunctionSignature(SGF, e, result.getType(),
1312+
[&]() -> ManagedValue {
1313+
return result;
1314+
});
1315+
}
1316+
return RValue(SGF, e, result);
12831317
}
12841318

12851319
// Break the conversion into three stages:

0 commit comments

Comments
 (0)