Skip to content

Commit 120b4c9

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 f1f3884 commit 120b4c9

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
@@ -752,6 +752,8 @@ class TypeConverter {
752752

753753
llvm::DenseMap<AbstractClosureExpr *, Optional<AbstractionPattern>>
754754
ClosureAbstractionPatterns;
755+
llvm::DenseMap<SILDeclRef, TypeExpansionContext>
756+
CaptureTypeExpansionContexts;
755757

756758
CanAnyFunctionType makeConstantInterfaceType(SILDeclRef constant);
757759

@@ -1156,6 +1158,7 @@ class TypeConverter {
11561158
/// the abstraction pattern is queried using this function. Once the
11571159
/// abstraction pattern has been asked for, it may not be changed.
11581160
Optional<AbstractionPattern> getConstantAbstractionPattern(SILDeclRef constant);
1161+
TypeExpansionContext getCaptureTypeExpansionContext(SILDeclRef constant);
11591162

11601163
/// Set the preferred abstraction pattern for a closure.
11611164
///
@@ -1165,6 +1168,8 @@ class TypeConverter {
11651168
void setAbstractionPattern(AbstractClosureExpr *closure,
11661169
AbstractionPattern pattern);
11671170

1171+
void setCaptureTypeExpansionContext(SILDeclRef constant,
1172+
SILModule &M);
11681173
private:
11691174
CanType computeLoweredRValueType(TypeExpansionContext context,
11701175
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
@@ -3623,6 +3623,19 @@ TypeConverter::getConstantAbstractionPattern(SILDeclRef constant) {
36233623
return None;
36243624
}
36253625

3626+
TypeExpansionContext
3627+
TypeConverter::getCaptureTypeExpansionContext(SILDeclRef constant) {
3628+
auto found = CaptureTypeExpansionContexts.find(constant);
3629+
if (found != CaptureTypeExpansionContexts.end()) {
3630+
return found->second;
3631+
}
3632+
// Insert a minimal type expansion context into the cache, so that further
3633+
// attempts to change it raise an error.
3634+
auto minimal = TypeExpansionContext::minimal();
3635+
CaptureTypeExpansionContexts.insert({constant, minimal});
3636+
return minimal;
3637+
}
3638+
36263639
void TypeConverter::setAbstractionPattern(AbstractClosureExpr *closure,
36273640
AbstractionPattern pattern) {
36283641
auto existing = ClosureAbstractionPatterns.find(closure);
@@ -3634,6 +3647,31 @@ void TypeConverter::setAbstractionPattern(AbstractClosureExpr *closure,
36343647
}
36353648
}
36363649

3650+
void TypeConverter::setCaptureTypeExpansionContext(SILDeclRef constant,
3651+
SILModule &M) {
3652+
if (!hasLoweredLocalCaptures(constant)) {
3653+
return;
3654+
}
3655+
3656+
TypeExpansionContext context = constant.isSerialized()
3657+
? TypeExpansionContext::minimal()
3658+
: TypeExpansionContext::maximal(constant.getAnyFunctionRef()->getAsDeclContext(),
3659+
M.isWholeModule());
3660+
3661+
auto existing = CaptureTypeExpansionContexts.find(constant);
3662+
if (existing != CaptureTypeExpansionContexts.end()) {
3663+
assert(existing->second == context
3664+
&& "closure shouldn't be emitted with different capture type expansion contexts");
3665+
} else {
3666+
// Lower in the context of the closure. Since the set of captures is a
3667+
// private contract between the closure and its enclosing context, we
3668+
// don't need to keep its capture types opaque.
3669+
// The exception is if it's inlinable, in which case it might get inlined into
3670+
// some place we need to keep opaque types opaque.
3671+
CaptureTypeExpansionContexts.insert({constant, context});
3672+
}
3673+
}
3674+
36373675
static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC,
36383676
SILType Ty,
36393677
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
@@ -1139,6 +1139,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11391139
}
11401140

11411141
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
1142+
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
1143+
11421144
if (afd->getDeclContext()->isLocalContext() &&
11431145
!captureInfo.hasGenericParamCaptures())
11441146
subs = SubstitutionMap();
@@ -1204,6 +1206,9 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12041206
}
12051207

12061208
void visitAbstractClosureExpr(AbstractClosureExpr *e) {
1209+
SILDeclRef constant(e);
1210+
1211+
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
12071212
// Emit the closure body.
12081213
SGF.SGM.emitClosure(e);
12091214

@@ -1216,7 +1221,6 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12161221

12171222
// A directly-called closure can be emitted as a direct call instead of
12181223
// really producing a closure object.
1219-
SILDeclRef constant(e);
12201224

12211225
auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant);
12221226

lib/SILGen/SILGenExpr.cpp

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

25462547
// Emit the closure body.
25472548
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)