Skip to content

Commit f8b3541

Browse files
committed
SILGen: Capture address-only lets with the in_guaranteed convention.
Fixes rdar://problem/40828667. If we capture a `let` as inout_aliasable, then definite initialization mistakes capture of the `let` from a defer closure as an inappropriate inout use.
1 parent 812e945 commit f8b3541

File tree

5 files changed

+65
-16
lines changed

5 files changed

+65
-16
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,8 +1925,12 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
19251925

19261926
// There are variables without storage, such as "struct { func foo() {}
19271927
// }". Emit them as constant 0.
1928-
if (isa<llvm::UndefValue>(Piece))
1929-
Piece = llvm::ConstantInt::get(IGM.Int64Ty, 0);
1928+
if (isa<llvm::UndefValue>(Piece)) {
1929+
auto undefSize = IGM.DataLayout.getTypeSizeInBits(Piece->getType());
1930+
1931+
Piece = llvm::ConstantInt::get(
1932+
llvm::IntegerType::get(IGM.getLLVMContext(), undefSize), 0);
1933+
}
19301934

19311935
if (IsPiece) {
19321936
// Advance the offset and align it for the next piece.

lib/SIL/SILFunctionType.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,9 +881,16 @@ lowerCaptureContextParameters(SILModule &M, AnyFunctionRef function,
881881
case CaptureKind::StorageAddress: {
882882
// Non-escaping lvalues are captured as the address of the value.
883883
SILType ty = loweredTy.getAddressType();
884+
885+
ParameterConvention convention
886+
= ParameterConvention::Indirect_InoutAliasable;
887+
888+
if (auto var = dyn_cast<VarDecl>(VD))
889+
if (var->isLet())
890+
convention = ParameterConvention::Indirect_In_Guaranteed;
891+
884892
auto param =
885-
SILParameterInfo(ty.getASTType(),
886-
ParameterConvention::Indirect_InoutAliasable);
893+
SILParameterInfo(ty.getASTType(), convention);
887894
inputs.push_back(param);
888895
break;
889896
}

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,17 @@ SingleValueInstruction *CallSiteDescriptor::getClosure() const {
285285
return CInfo->Closure;
286286
}
287287

288-
static bool isNonInoutIndirectSILArgument(SILValue Arg,
288+
static bool isConsumingIndirectSILArgumentConvention(SILArgumentConvention ArgConvention) {
289+
return ArgConvention.isIndirectConvention() &&
290+
ArgConvention != SILArgumentConvention::Indirect_In_Guaranteed &&
291+
ArgConvention != SILArgumentConvention::Indirect_Inout &&
292+
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable;
293+
}
294+
295+
static bool isConsumingIndirectSILArgument(SILValue Arg,
289296
SILArgumentConvention ArgConvention) {
290-
return !Arg->getType().isObject() && ArgConvention.isIndirectConvention() &&
291-
ArgConvention != SILArgumentConvention::Indirect_Inout &&
292-
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable;
297+
return !Arg->getType().isObject()
298+
&& isConsumingIndirectSILArgumentConvention(ArgConvention);
293299
}
294300

295301
/// Update the callsite to pass in the correct arguments.
@@ -332,12 +338,12 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc,
332338

333339
// Non-inout indirect arguments are not supported yet.
334340
assert(ArgTy.isObject() ||
335-
!isNonInoutIndirectSILArgument(Arg, ArgConvention));
341+
!isConsumingIndirectSILArgument(Arg, ArgConvention));
336342

337343
// If argument is not an object and it is an inout parameter,
338344
// continue...
339345
if (!ArgTy.isObject() &&
340-
!isNonInoutIndirectSILArgument(Arg, ArgConvention)) {
346+
!isConsumingIndirectSILArgument(Arg, ArgConvention)) {
341347
NewArgs.push_back(Arg);
342348
++ClosureArgIdx;
343349
continue;
@@ -472,7 +478,7 @@ void CallSiteDescriptor::extendArgumentLifetime(
472478
SILBuilderWithScope Builder(getClosure());
473479

474480
// Indirect non-inout arguments are not supported yet.
475-
assert(!isNonInoutIndirectSILArgument(Arg, ArgConvention));
481+
assert(!isConsumingIndirectSILArgument(Arg, ArgConvention));
476482

477483
if (ArgTy.isObject()) {
478484
Builder.createRetainValue(getClosure()->getLoc(), Arg,
@@ -534,8 +540,7 @@ static bool isSupportedClosure(const SILInstruction *Closure) {
534540
}
535541
auto ArgConvention =
536542
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
537-
if (ArgConvention != SILArgumentConvention::Indirect_Inout &&
538-
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable)
543+
if (isConsumingIndirectSILArgumentConvention(ArgConvention))
539544
return false;
540545
++ClosureArgIdx;
541546
}
@@ -601,7 +606,8 @@ ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc,
601606
ParamConv = PInfo.getConvention();
602607
assert(!SILModuleConventions(M).useLoweredAddresses()
603608
|| ParamConv == ParameterConvention::Indirect_Inout
604-
|| ParamConv == ParameterConvention::Indirect_InoutAliasable);
609+
|| ParamConv == ParameterConvention::Indirect_InoutAliasable
610+
|| ParamConv == ParameterConvention::Indirect_In_Guaranteed);
605611
} else {
606612
ParamConv = ClosedOverFunConv.getSILType(PInfo).isTrivial(M)
607613
? ParameterConvention::Direct_Unowned

test/SILGen/generic_closures.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ class NestedGeneric<U> {
144144

145145
// CHECK: sil hidden @$S16generic_closures018nested_closure_in_A0yxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T
146146
// CHECK: function_ref [[OUTER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_]]
147-
// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T
147+
// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@in_guaranteed T) -> @out T
148148
// CHECK: function_ref [[INNER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_xyXEfU_]]
149-
// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T {
149+
// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
150150
func nested_closure_in_generic<T>(_ x:T) -> T {
151151
return { { x }() }()
152152
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify %s
2+
3+
func foo<T>(a: Bool, t: T) {
4+
let x: T
5+
defer { print(x) }
6+
7+
x = t
8+
return
9+
}
10+
11+
func bar<T>(a: Bool, t: T) {
12+
let x: T // expected-note {{defined here}}
13+
defer { print(x) } //expected-error{{constant 'x' used before being initialized}}
14+
15+
if a {
16+
x = t
17+
return
18+
}
19+
}
20+
21+
func bas<T>(a: Bool, t: T) {
22+
let x: T
23+
defer { print(x) }
24+
25+
if a {
26+
x = t
27+
return
28+
}
29+
30+
x = t
31+
}
32+

0 commit comments

Comments
 (0)