Skip to content

Commit 2ae51ca

Browse files
authored
Merge pull request #24610 from gottesmm/pr-2df2f80b348fecaae23a17b6aa3272de096fd075
[sil] Expand immutable address use verification to in_guaranteed parameters.
2 parents 8625b71 + afe3114 commit 2ae51ca

12 files changed

+164
-42
lines changed

include/swift/SIL/SILFunctionConventions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ class SILFunctionConventions {
322322
SILParameterTypeFunc(silConv)));
323323
}
324324

325+
SILYieldInfo getYieldInfoForOperandIndex(unsigned opIndex) const {
326+
return getYields()[opIndex];
327+
}
328+
325329
//===--------------------------------------------------------------------===//
326330
// SILArgument API, including indirect results and parameters.
327331
//

include/swift/SIL/SILInstruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7031,6 +7031,11 @@ class YieldInst final
70317031
SuccessorListTy getSuccessors() {
70327032
return DestBBs;
70337033
}
7034+
7035+
SILYieldInfo getYieldInfoForOperand(const Operand &op) const;
7036+
7037+
SILArgumentConvention
7038+
getArgumentConventionForOperand(const Operand &op) const;
70347039
};
70357040

70367041
/// BranchInst - An unconditional branch.

lib/SIL/SILInstructions.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,19 @@ YieldInst *YieldInst::create(SILDebugLocation loc,
11531153
return ::new (Buffer) YieldInst(loc, yieldedValues, normalBB, unwindBB);
11541154
}
11551155

1156+
SILYieldInfo YieldInst::getYieldInfoForOperand(const Operand &op) const {
1157+
// We expect op to be our operand.
1158+
assert(op.getUser() == this);
1159+
auto conv = getFunction()->getConventions();
1160+
return conv.getYieldInfoForOperandIndex(op.getOperandNumber());
1161+
}
1162+
1163+
SILArgumentConvention
1164+
YieldInst::getArgumentConventionForOperand(const Operand &op) const {
1165+
auto conv = getYieldInfoForOperand(op).getConvention();
1166+
return SILArgumentConvention(conv);
1167+
}
1168+
11561169
BranchInst *BranchInst::create(SILDebugLocation Loc, SILBasicBlock *DestBB,
11571170
SILFunction &F) {
11581171
return create(Loc, DestBB, {}, F);

lib/SIL/SILVerifier.cpp

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,7 @@ void verifyKeyPathComponent(SILModule &M,
416416
struct ImmutableAddressUseVerifier {
417417
SmallVector<Operand *, 32> worklist;
418418

419-
bool isConsumingOrMutatingApplyUse(Operand *use) {
420-
ApplySite apply(use->getUser());
421-
assert(apply && "Not an apply instruction kind");
422-
auto conv = apply.getArgumentConvention(*use);
419+
bool isConsumingOrMutatingArgumentConvention(SILArgumentConvention conv) {
423420
switch (conv) {
424421
case SILArgumentConvention::Indirect_In_Guaranteed:
425422
return false;
@@ -448,10 +445,24 @@ struct ImmutableAddressUseVerifier {
448445
return true; // return something "conservative".
449446
}
450447
llvm_unreachable("covered switch isn't covered?!");
451-
};
448+
}
452449

453-
/// A "copy_addr %src [take] to *" is consuming on "%src".
454-
/// A "copy_addr * to * %dst" is mutating on "%dst".
450+
bool isConsumingOrMutatingApplyUse(Operand *use) {
451+
ApplySite apply(use->getUser());
452+
assert(apply && "Not an apply instruction kind");
453+
auto conv = apply.getArgumentConvention(*use);
454+
return isConsumingOrMutatingArgumentConvention(conv);
455+
}
456+
457+
bool isConsumingOrMutatingYieldUse(Operand *use) {
458+
// For now, just say that it is non-consuming for now.
459+
auto *yield = cast<YieldInst>(use->getUser());
460+
auto conv = yield->getArgumentConventionForOperand(*use);
461+
return isConsumingOrMutatingArgumentConvention(conv);
462+
}
463+
464+
// A "copy_addr %src [take] to *" is consuming on "%src".
465+
// A "copy_addr * to * %dst" is mutating on "%dst".
455466
bool isConsumingOrMutatingCopyAddrUse(Operand *use) {
456467
auto *copyAddr = cast<CopyAddrInst>(use->getUser());
457468
if (copyAddr->getDest() == use->get())
@@ -462,37 +473,56 @@ struct ImmutableAddressUseVerifier {
462473
}
463474

464475
bool isCastToNonConsuming(UncheckedAddrCastInst *i) {
465-
for (auto *use : i->getUses()) {
476+
// Check if any of our uses are consuming. If none of them are consuming, we
477+
// are good to go.
478+
return llvm::none_of(i->getUses(), [&](Operand *use) -> bool {
466479
auto *inst = use->getUser();
467480
switch (inst->getKind()) {
481+
default:
482+
return false;
468483
case SILInstructionKind::ApplyInst:
469484
case SILInstructionKind::TryApplyInst:
470485
case SILInstructionKind::PartialApplyInst:
471-
if (isConsumingOrMutatingApplyUse(use))
472-
return false;
473-
continue;
474-
default:
475-
continue;
486+
case SILInstructionKind::BeginApplyInst:
487+
return isConsumingOrMutatingApplyUse(use);
476488
}
477-
}
478-
return true;
489+
});
479490
}
480491

481492
bool isMutatingOrConsuming(SILValue address) {
482-
for (auto *use : address->getUses()) {
493+
copy(address->getUses(), std::back_inserter(worklist));
494+
while (!worklist.empty()) {
495+
auto *use = worklist.pop_back_val();
483496
auto *inst = use->getUser();
484497
if (inst->isTypeDependentOperand(*use))
485498
continue;
486499
switch (inst->getKind()) {
487500
case SILInstructionKind::MarkDependenceInst:
501+
case SILInstructionKind::LoadBorrowInst:
502+
case SILInstructionKind::DebugValueAddrInst:
503+
case SILInstructionKind::ExistentialMetatypeInst:
504+
case SILInstructionKind::ValueMetatypeInst:
505+
case SILInstructionKind::FixLifetimeInst:
506+
case SILInstructionKind::KeyPathInst:
507+
case SILInstructionKind::SwitchEnumAddrInst:
508+
break;
509+
case SILInstructionKind::AddressToPointerInst:
510+
// We assume that the user is attempting to do something unsafe since we
511+
// are converting to a raw pointer. So just ignore this use.
512+
//
513+
// TODO: Can we do better?
488514
break;
489515
case SILInstructionKind::ApplyInst:
490516
case SILInstructionKind::TryApplyInst:
491517
case SILInstructionKind::PartialApplyInst:
518+
case SILInstructionKind::BeginApplyInst:
492519
if (isConsumingOrMutatingApplyUse(use))
493520
return true;
494-
else
495-
break;
521+
break;
522+
case SILInstructionKind::YieldInst:
523+
if (isConsumingOrMutatingYieldUse(use))
524+
return true;
525+
break;
496526
case SILInstructionKind::CopyAddrInst:
497527
if (isConsumingOrMutatingCopyAddrUse(use))
498528
return true;
@@ -519,11 +549,32 @@ struct ImmutableAddressUseVerifier {
519549
break;
520550
case SILInstructionKind::LoadInst:
521551
// A 'non-taking' value load is harmless.
522-
return cast<LoadInst>(inst)->getOwnershipQualifier() ==
523-
LoadOwnershipQualifier::Take;
552+
if (cast<LoadInst>(inst)->getOwnershipQualifier() ==
553+
LoadOwnershipQualifier::Take)
554+
return true;
524555
break;
525-
case SILInstructionKind::DebugValueAddrInst:
526-
// Harmless use.
556+
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
557+
case SILInstructionKind::Load##Name##Inst: \
558+
if (cast<Load##Name##Inst>(inst)->isTake()) \
559+
return true; \
560+
break;
561+
#include "swift/AST/ReferenceStorage.def"
562+
case SILInstructionKind::OpenExistentialAddrInst:
563+
// If we have a mutable use, return true. Otherwise fallthrough since we
564+
// want to look through immutable uses.
565+
if (cast<OpenExistentialAddrInst>(inst)->getAccessKind() !=
566+
OpenedExistentialAccess::Immutable)
567+
return true;
568+
LLVM_FALLTHROUGH;
569+
case SILInstructionKind::StructElementAddrInst:
570+
case SILInstructionKind::TupleElementAddrInst:
571+
case SILInstructionKind::IndexAddrInst:
572+
case SILInstructionKind::TailAddrInst:
573+
case SILInstructionKind::IndexRawPointerInst:
574+
// Add these to our worklist.
575+
for (auto result : inst->getResults()) {
576+
copy(result->getUses(), std::back_inserter(worklist));
577+
}
527578
break;
528579
default:
529580
llvm_unreachable("Unhandled unexpected instruction");
@@ -840,7 +891,19 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
840891
|| arg->getParent()->getSinglePredecessorBlock(),
841892
"Non-branch terminator must have a unique successor.");
842893
}
894+
return;
843895
}
896+
897+
// If we are not in lowered SIL and have an in_guaranteed function argument,
898+
// verify that we do not mutate or consume it.
899+
auto *fArg = cast<SILFunctionArgument>(arg);
900+
if (fArg->getModule().getStage() == SILStage::Lowered ||
901+
!fArg->getType().isAddress() ||
902+
!fArg->hasConvention(SILArgumentConvention::Indirect_In_Guaranteed))
903+
return;
904+
905+
require(!ImmutableAddressUseVerifier().isMutatingOrConsuming(fArg),
906+
"Found mutating or consuming use of an in_guaranteed parameter?!");
844907
}
845908

846909
void visitSILInstruction(SILInstruction *I) {

lib/SILGen/SILGenPoly.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,9 +1116,13 @@ namespace {
11161116

11171117
// Load if necessary.
11181118
if (elt.getType().isAddress()) {
1119+
// This code assumes that we have each element at +1. So, if we do
1120+
// not have a cleanup, we emit a load [copy]. This can occur if we
1121+
// are translating in_guaranteed parameters.
1122+
IsTake_t isTakeVal = elt.isPlusZero() ? IsNotTake : IsTake;
11191123
elt = SGF.emitLoad(Loc, elt.forward(SGF),
1120-
SGF.getTypeLowering(elt.getType()),
1121-
SGFContext(), IsTake);
1124+
SGF.getTypeLowering(elt.getType()), SGFContext(),
1125+
isTakeVal);
11221126
}
11231127
}
11241128

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -813,11 +813,12 @@ static bool canReplaceCopiedArg(FullApplySite Apply, SILValue Arg,
813813
if (!IEA)
814814
return false;
815815

816-
// If the witness method mutates Arg, we cannot replace Arg with
817-
// the source of a copy. Otherwise the call would modify another value than
818-
// the original argument.
816+
// If the witness method does not take the value as guaranteed, we cannot
817+
// replace Arg with the source of a copy. Otherwise the call would modify
818+
// another value than the original argument (in the case of indirect mutating)
819+
// or create a use-after-free (in the case of indirect consuming).
819820
auto origConv = Apply.getOrigCalleeConv();
820-
if (origConv.getParamInfoForSILArg(ArgIdx).isIndirectMutating())
821+
if (!origConv.getParamInfoForSILArg(ArgIdx).isIndirectInGuaranteed())
821822
return false;
822823

823824
auto *DT = DA->get(Apply.getFunction());

test/SILOptimizer/escape_analysis.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ bb0(%0: $*Int32, %1: $*Int32):
362362
// CHECK-NEXT: Arg %1 Esc: A, Succ: (%1.1)
363363
// CHECK-NEXT: Con %1.1 Esc: A, Succ:
364364
// CHECK-NEXT: End
365-
sil @copy_addr_take_content : $@convention(thin) (@in_guaranteed Int32) -> @out Int32 {
365+
sil @copy_addr_take_content : $@convention(thin) (@in Int32) -> @out Int32 {
366366
bb0(%0: $*Int32, %1: $*Int32):
367367
copy_addr [take] %1 to [initialization] %0 : $*Int32
368368
%2 = tuple()
@@ -375,7 +375,7 @@ bb0(%0: $*Int32, %1: $*Int32):
375375
// CHECK-NEXT: Arg %1 Esc: G, Succ: (%1.1)
376376
// CHECK-NEXT: Con %1.1 Esc: G, Succ:
377377
// CHECK-NEXT: End
378-
sil @copy_addr_noinit_content : $@convention(thin) (@in_guaranteed Int32) -> @out Int32 {
378+
sil @copy_addr_noinit_content : $@convention(thin) (@in Int32) -> @out Int32 {
379379
bb0(%0: $*Int32, %1: $*Int32):
380380
copy_addr [take] %1 to %0 : $*Int32
381381
%2 = tuple()

test/SILOptimizer/performance_inliner.sil

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -sil-combine | %FileCheck %s
32

43
sil_stage canonical
@@ -907,7 +906,6 @@ bb1(%6 : $()):
907906

908907
bb2:
909908
strong_release %2 : $@callee_owned () -> (@out T, @error Error)
910-
destroy_addr %1 : $*T
911909
%10 = tuple ()
912910
return %10 : $()
913911

test/SILOptimizer/predictable_deadalloc_elim.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,11 @@ bb3:
212212
}
213213

214214
// We should not promote this due to this being an assign to %2.
215-
// CHECK-LABEL: sil @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
215+
// CHECK-LABEL: sil @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
216216
// CHECK: alloc_stack
217217
// CHECK: copy_addr
218218
// CHECK: } // end sil function 'simple_diamond_with_assign'
219-
sil @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
219+
sil @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
220220
bb0(%0 : $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
221221
%2 = alloc_stack $Builtin.NativeObject
222222
store %0 to %2 : $*Builtin.NativeObject
@@ -241,11 +241,11 @@ bb3:
241241
// this test shows that we /tried/ and failed with the available value test
242242
// instead of failing earlier due to the copy_addr being an assign since we
243243
// explode the copy_addr.
244-
// CHECK-LABEL: sil @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
244+
// CHECK-LABEL: sil @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
245245
// CHECK: alloc_stack
246246
// CHECK-NOT: copy_addr
247247
// CHECK: } // end sil function 'simple_diamond_with_assign_remove'
248-
sil @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
248+
sil @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
249249
bb0(%0 : $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
250250
%2 = alloc_stack $Builtin.NativeObject
251251
store %0 to %2 : $*Builtin.NativeObject

test/SILOptimizer/predictable_deadalloc_elim_ownership.sil

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,11 @@ bb3:
227227
}
228228

229229
// We should not promote this due to this being an assign to %2.
230-
// CHECK-LABEL: sil [ossa] @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
230+
// CHECK-LABEL: sil [ossa] @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
231231
// CHECK: alloc_stack
232232
// CHECK: copy_addr
233233
// CHECK: } // end sil function 'simple_diamond_with_assign'
234-
sil [ossa] @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
234+
sil [ossa] @simple_diamond_with_assign : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
235235
bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
236236
%2 = alloc_stack $Builtin.NativeObject
237237
store %0 to [init] %2 : $*Builtin.NativeObject
@@ -256,11 +256,12 @@ bb3:
256256
// this test shows that we /tried/ and failed with the available value test
257257
// instead of failing earlier due to the copy_addr being an assign since we
258258
// explode the copy_addr.
259-
// CHECK-LABEL: sil [ossa] @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
259+
//
260+
// CHECK-LABEL: sil [ossa] @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
260261
// CHECK: alloc_stack
261262
// CHECK-NOT: copy_addr
262263
// CHECK: } // end sil function 'simple_diamond_with_assign_remove'
263-
sil [ossa] @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in_guaranteed Builtin.NativeObject) -> () {
264+
sil [ossa] @simple_diamond_with_assign_remove : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
264265
bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
265266
%2 = alloc_stack $Builtin.NativeObject
266267
store %0 to [init] %2 : $*Builtin.NativeObject

test/SILOptimizer/sil_combine_concrete_existential.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,3 +499,36 @@ bb0(%0 : $Array<Int>):
499499
%25 = tuple ()
500500
return %25 : $()
501501
}
502+
503+
struct InGuaranteedArgTestNativeObjectWrapper {
504+
var i: Builtin.NativeObject
505+
}
506+
507+
protocol InGuaranteedArgTestProtocol {}
508+
extension InGuaranteedArgTestNativeObjectWrapper : InGuaranteedArgTestProtocol {}
509+
510+
sil @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
511+
512+
// The current transformation is not smart enough to remove the
513+
// destroy_addr. Simply substituting the copy source for the apply argument
514+
// would introduce a use-after-free. = (.
515+
//
516+
// CHECK-LABEL: sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
517+
// CHECK: apply {{%.*}}<@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol>
518+
// CHECK: } // end sil function 'in_guaranteed_arg_test_caller'
519+
sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
520+
bb0(%0 : $*τ_0_0):
521+
%1 = alloc_stack $InGuaranteedArgTestProtocol
522+
%2 = init_existential_addr %1 : $*InGuaranteedArgTestProtocol, $τ_0_0
523+
copy_addr [take] %0 to [initialization] %2 : $*τ_0_0
524+
%3 = function_ref @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
525+
%4 = alloc_stack $InGuaranteedArgTestProtocol
526+
copy_addr %1 to [initialization] %4 : $*InGuaranteedArgTestProtocol
527+
%5 = open_existential_addr mutable_access %4 : $*InGuaranteedArgTestProtocol to $*@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol
528+
apply %3<@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD") InGuaranteedArgTestProtocol>(%5) : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
529+
dealloc_stack %4 : $*InGuaranteedArgTestProtocol
530+
destroy_addr %1 : $*InGuaranteedArgTestProtocol
531+
dealloc_stack %1 : $*InGuaranteedArgTestProtocol
532+
%9999 = tuple()
533+
return %9999 : $()
534+
}

test/SILOptimizer/sil_combiner_concrete_prop_all_args.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ bb0(%0 : $*SomeNoClass):
178178
sil hidden [signature_optimized_thunk] [always_inline] @$s21existential_transform12wrap_foo_ncp1as5Int32VAA19SomeNoClassProtocol_p_tF : $@convention(thin) (@in_guaranteed SomeNoClassProtocol) -> Int32 {
179179
bb0(%0 : $*SomeNoClassProtocol):
180180
%1 = function_ref @$s21existential_transform12wrap_foo_ncp1as5Int32VAA19SomeNoClassProtocol_p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocol> (@in_guaranteed τ_0_0) -> Int32
181-
%2 = open_existential_addr mutable_access %0 : $*SomeNoClassProtocol to $*@opened("CC97FCD6-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocol
181+
%2 = open_existential_addr immutable_access %0 : $*SomeNoClassProtocol to $*@opened("CC97FCD6-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocol
182182
%3 = apply %1<@opened("CC97FCD6-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocol>(%2) : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocol> (@in_guaranteed τ_0_0) -> Int32
183183
return %3 : $Int32
184184
} // end sil function '$s21existential_transform12wrap_foo_ncp1as5Int32VAA19SomeNoClassProtocol_p_tF'
@@ -302,7 +302,7 @@ bb0(%0 : $*SomeNoClassComp):
302302
sil hidden [signature_optimized_thunk] [always_inline] @$s21existential_transform25wrap_no_foo_bar_comp_ncpc1as5Int32VAA23SomeNoClassProtocolComp_AA0j5OtherklmN0p_tF : $@convention(thin) (@in_guaranteed SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp) -> Int32 {
303303
bb0(%0 : $*SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp):
304304
%1 = function_ref @$s21existential_transform25wrap_no_foo_bar_comp_ncpc1as5Int32VAA23SomeNoClassProtocolComp_AA0j5OtherklmN0p_tFTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocolComp, τ_0_0 : SomeOtherNoClassProtocolComp> (@in_guaranteed τ_0_0) -> Int32
305-
%2 = open_existential_addr mutable_access %0 : $*SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp to $*@opened("CC983642-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp
305+
%2 = open_existential_addr immutable_access %0 : $*SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp to $*@opened("CC983642-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp
306306
%3 = apply %1<@opened("CC983642-AC7C-11E8-B742-D0817AD4059B") SomeNoClassProtocolComp & SomeOtherNoClassProtocolComp>(%2) : $@convention(thin) <τ_0_0 where τ_0_0 : SomeNoClassProtocolComp, τ_0_0 : SomeOtherNoClassProtocolComp> (@in_guaranteed τ_0_0) -> Int32
307307
return %3 : $Int32
308308
} // end sil function '$s21existential_transform25wrap_no_foo_bar_comp_ncpc1as5Int32VAA23SomeNoClassProtocolComp_AA0j5OtherklmN0p_tF'

0 commit comments

Comments
 (0)