Skip to content

Commit 6b6a557

Browse files
committed
SILGen: Carry WMO of type lowering context to closure captures.
TypeConverter doesn't know by itself what SILModule it's currently lowering on behalf of, so the existing code forming the TypeExpansionContext for opaque types incorrectly set the isWholeModule flag to always false. This created a miscompile when a public API contained a closure that captured a value involving private types from another file in the same module because of mismatched type expansion contexts inside and outside the closure. Fixes rdar://93821679
1 parent 53e8e7b commit 6b6a557

File tree

9 files changed

+93
-9
lines changed

9 files changed

+93
-9
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,8 @@ class TypeConverter {
776776

777777
llvm::DenseMap<AbstractClosureExpr *, Optional<AbstractionPattern>>
778778
ClosureAbstractionPatterns;
779+
llvm::DenseMap<SILDeclRef, TypeExpansionContext>
780+
CaptureTypeExpansionContexts;
779781

780782
CanAnyFunctionType makeConstantInterfaceType(SILDeclRef constant);
781783

@@ -1180,6 +1182,7 @@ class TypeConverter {
11801182
/// the abstraction pattern is queried using this function. Once the
11811183
/// abstraction pattern has been asked for, it may not be changed.
11821184
Optional<AbstractionPattern> getConstantAbstractionPattern(SILDeclRef constant);
1185+
TypeExpansionContext getCaptureTypeExpansionContext(SILDeclRef constant);
11831186

11841187
/// Set the preferred abstraction pattern for a closure.
11851188
///
@@ -1189,6 +1192,8 @@ class TypeConverter {
11891192
void setAbstractionPattern(AbstractClosureExpr *closure,
11901193
AbstractionPattern pattern);
11911194

1195+
void setCaptureTypeExpansionContext(SILDeclRef constant,
1196+
SILModule &M);
11921197
private:
11931198
CanType computeLoweredRValueType(TypeExpansionContext context,
11941199
AbstractionPattern origType,

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,13 +2078,9 @@ static CanSILFunctionType getSILFunctionType(
20782078
// Lower in the context of the closure. Since the set of captures is a
20792079
// private contract between the closure and its enclosing context, we
20802080
// don't need to keep its capture types opaque.
2081-
auto expansion = TypeExpansionContext::maximal(
2082-
constant->getAnyFunctionRef()->getAsDeclContext(), false);
2083-
// ...unless it's inlinable, in which case it might get inlined into
2084-
// some place we need to keep opaque types opaque.
2085-
if (constant->isSerialized())
2086-
expansion = TypeExpansionContext::minimal();
2087-
lowerCaptureContextParameters(TC, *constant, genericSig, expansion, inputs);
2081+
lowerCaptureContextParameters(TC, *constant, genericSig,
2082+
TC.getCaptureTypeExpansionContext(*constant),
2083+
inputs);
20882084
}
20892085

20902086
auto calleeConvention = ParameterConvention::Direct_Unowned;

lib/SIL/IR/TypeLowering.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3634,6 +3634,19 @@ TypeConverter::getConstantAbstractionPattern(SILDeclRef constant) {
36343634
return None;
36353635
}
36363636

3637+
TypeExpansionContext
3638+
TypeConverter::getCaptureTypeExpansionContext(SILDeclRef constant) {
3639+
auto found = CaptureTypeExpansionContexts.find(constant);
3640+
if (found != CaptureTypeExpansionContexts.end()) {
3641+
return found->second;
3642+
}
3643+
// Insert a minimal type expansion context into the cache, so that further
3644+
// attempts to change it raise an error.
3645+
auto minimal = TypeExpansionContext::minimal();
3646+
CaptureTypeExpansionContexts.insert({constant, minimal});
3647+
return minimal;
3648+
}
3649+
36373650
void TypeConverter::setAbstractionPattern(AbstractClosureExpr *closure,
36383651
AbstractionPattern pattern) {
36393652
auto existing = ClosureAbstractionPatterns.find(closure);
@@ -3645,6 +3658,31 @@ void TypeConverter::setAbstractionPattern(AbstractClosureExpr *closure,
36453658
}
36463659
}
36473660

3661+
void TypeConverter::setCaptureTypeExpansionContext(SILDeclRef constant,
3662+
SILModule &M) {
3663+
if (!hasLoweredLocalCaptures(constant)) {
3664+
return;
3665+
}
3666+
3667+
TypeExpansionContext context = constant.isSerialized()
3668+
? TypeExpansionContext::minimal()
3669+
: TypeExpansionContext::maximal(constant.getAnyFunctionRef()->getAsDeclContext(),
3670+
M.isWholeModule());
3671+
3672+
auto existing = CaptureTypeExpansionContexts.find(constant);
3673+
if (existing != CaptureTypeExpansionContexts.end()) {
3674+
assert(existing->second == context
3675+
&& "closure shouldn't be emitted with different capture type expansion contexts");
3676+
} else {
3677+
// Lower in the context of the closure. Since the set of captures is a
3678+
// private contract between the closure and its enclosing context, we
3679+
// don't need to keep its capture types opaque.
3680+
// The exception is if it's inlinable, in which case it might get inlined into
3681+
// some place we need to keep opaque types opaque.
3682+
CaptureTypeExpansionContexts.insert({constant, context});
3683+
}
3684+
}
3685+
36483686
static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC,
36493687
SILType Ty,
36503688
TypeExpansionContext expansion) {

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,8 @@ void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {
14211421
}
14221422

14231423
void SILGenModule::emitFunction(FuncDecl *fd) {
1424+
Types.setCaptureTypeExpansionContext(SILDeclRef(fd), M);
1425+
14241426
SILDeclRef::Loc decl = fd;
14251427

14261428
emitAbstractFuncDecl(fd);

lib/SILGen/SILGenApply.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11421142
}
11431143

11441144
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
1145+
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
1146+
11451147
if (afd->getDeclContext()->isLocalContext() &&
11461148
!captureInfo.hasGenericParamCaptures())
11471149
subs = SubstitutionMap();
@@ -1207,6 +1209,9 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12071209
}
12081210

12091211
void visitAbstractClosureExpr(AbstractClosureExpr *e) {
1212+
SILDeclRef constant(e);
1213+
1214+
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
12101215
// Emit the closure body.
12111216
SGF.SGM.emitClosure(e);
12121217

@@ -1219,7 +1224,6 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12191224

12201225
// A directly-called closure can be emitted as a direct call instead of
12211226
// really producing a closure object.
1222-
SILDeclRef constant(e);
12231227

12241228
auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant);
12251229

lib/SILGen/SILGenExpr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2541,6 +2541,7 @@ RValue RValueEmitter::visitAbstractClosureExpr(AbstractClosureExpr *e,
25412541
if (auto contextOrigType = C.getAbstractionPattern()) {
25422542
SGF.SGM.Types.setAbstractionPattern(e, *contextOrigType);
25432543
}
2544+
SGF.SGM.Types.setCaptureTypeExpansionContext(SILDeclRef(e), SGF.SGM.M);
25442545

25452546
// Emit the closure body.
25462547
SGF.SGM.emitClosure(e);

lib/SILGen/SILGenFunction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,8 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
441441
SubstitutionMap subs,
442442
bool alreadyConverted) {
443443
auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(constant);
444-
444+
SGM.Types.setCaptureTypeExpansionContext(constant, SGM.M);
445+
445446
auto constantInfo = getConstantInfo(getTypeExpansionContext(), constant);
446447
SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo);
447448
SILType functionTy = functionRef->getType();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
public protocol P {}
3+
4+
struct PImpl: P {}
5+
6+
public struct Wrapper<T: P, U>: P {
7+
public init(value: T, extra: U) {}
8+
}
9+
10+
private struct Burrito {}
11+
12+
extension P {
13+
@inlinable
14+
public func wrapped<U>(extra: U) -> Wrapper<Self, U> {
15+
return Wrapper(value: self, extra: extra)
16+
}
17+
18+
public func burritoed() -> some P {
19+
return wrapped(extra: Burrito())
20+
}
21+
}
22+
23+
public class Butz<T: P> {
24+
init(_: T) {}
25+
}
26+
27+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-emit-silgen -disable-availability-checking -verify -wmo %s %S/Inputs/opaque_result_type_captured_wmo_2.swift
2+
func foo(s: String?) {
3+
let x = PImpl()
4+
.burritoed()
5+
.wrapped(extra: 1)
6+
7+
let butz = Butz(x)
8+
9+
s.map { print("\($0) \(butz)") }
10+
}

0 commit comments

Comments
 (0)