Skip to content

Commit 8d669bb

Browse files
Merge pull request #69924 from nate-chandler/opaque-values/20231116/1/resilient_empty_enum_case
[SIL] Addr-only enums have non-none ownership.
2 parents bd61b66 + 98acb40 commit 8d669bb

File tree

5 files changed

+68
-4
lines changed

5 files changed

+68
-4
lines changed

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast)
275275
FORWARDING_OWNERSHIP_INST(Upcast)
276276
FORWARDING_OWNERSHIP_INST(UncheckedValueCast)
277277
FORWARDING_OWNERSHIP_INST(UncheckedEnumData)
278-
FORWARDING_OWNERSHIP_INST(Enum)
279278
FORWARDING_OWNERSHIP_INST(MarkDependence)
280279
// NOTE: init_existential_ref from a reference counting perspective is not
281280
// considered to be "owned" since it doesn't affect reference counts. That being
@@ -296,6 +295,25 @@ FORWARDING_OWNERSHIP_INST(CopyableToMoveOnlyWrapperValue)
296295
FORWARDING_OWNERSHIP_INST(MoveOnlyWrapperToCopyableBox)
297296
#undef FORWARDING_OWNERSHIP_INST
298297

298+
ValueOwnershipKind
299+
ValueOwnershipKindClassifier::visitEnumInst(EnumInst *I) {
300+
if (!I->getModule().useLoweredAddresses() && I->getType().isAddressOnly(*I->getFunction())) {
301+
// During address lowering, an address-only enum instruction will eventually
302+
// be lowered to inject_enum_addr/init_enum_data_addr, initializing a
303+
// non-trivial storage location. So prior to AddressLowering (in opaque
304+
// values mode) such an enum instruction produces a non-trivial value,
305+
// without regard to whether it is in a trivial case. Otherwise, non-trivial
306+
// storage would fail to be destroy_addr'd.
307+
assert(!I->getType().isTrivial(*I->getFunction()));
308+
// An enum instruction is representation changing, so its address-only
309+
// operand must be owned.
310+
return OwnershipKind::Owned;
311+
}
312+
return I->getType().isTrivial(*I->getFunction())
313+
? ValueOwnershipKind(OwnershipKind::None)
314+
: I->getForwardingOwnershipKind();
315+
}
316+
299317
ValueOwnershipKind
300318
ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst(
301319
UncheckedOwnershipConversionInst *I) {

lib/SILGen/SILGenBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ ManagedValue SILGenBuilder::createManagedOptionalNone(SILLocation loc,
681681
if (!type.isAddressOnly(getFunction()) ||
682682
!SGF.silConv.useLoweredAddresses()) {
683683
SILValue noneValue = createOptionalNone(loc, type);
684-
return ManagedValue::forObjectRValueWithoutOwnership(noneValue);
684+
return SGF.emitManagedRValueWithCleanup(noneValue);
685685
}
686686

687687
SILValue tempResult = SGF.emitTemporaryAllocation(loc, type);

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,8 +1028,8 @@ RValue RValueEmitter::visitNilLiteralExpr(NilLiteralExpr *E, SGFContext C) {
10281028

10291029
ManagedValue noneValue;
10301030
if (enumTy.isLoadable(SGF.F) || !SGF.silConv.useLoweredAddresses()) {
1031-
noneValue = ManagedValue::forObjectRValueWithoutOwnership(
1032-
SGF.B.createEnum(E, SILValue(), noneDecl, enumTy));
1031+
auto *e = SGF.B.createEnum(E, SILValue(), noneDecl, enumTy);
1032+
noneValue = SGF.emitManagedRValueWithCleanup(e);
10331033
} else {
10341034
noneValue =
10351035
SGF.B.bufferForExpr(E, enumTy, SGF.getTypeLowering(enumTy), C,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public class ClassEquatable : Equatable {
2+
public static func ==(lhs: ClassEquatable, rhs: ClassEquatable) -> Bool { lhs === rhs }
3+
}
4+
5+
public enum EnumNontrivialWithEmptyCases : Equatable {
6+
case empty
7+
case other
8+
case loaded(ClassEquatable)
9+
}
10+
11+
public enum EnumTrivial : Equatable {
12+
case empty
13+
case other
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -disable-availability-checking -o %t -enable-library-evolution -module-name ResilientLibrary %S/Inputs/opaque_values_silgen_resilient.swift
3+
// RUN: %target-swift-frontend -enable-sil-opaque-values -emit-silgen -disable-availability-checking -I %t %s | %FileCheck %s
4+
5+
import ResilientLibrary
6+
7+
// Verify that an enum instruction producing a trivial is _still_ destroyed if
8+
// (1) the enum instruction's type is non-trivial
9+
// (2) the enum is address-only
10+
// Necessary because such an enum will be lowered to
11+
// init_enum_data_addr/inject_enum_addr and there isn't generally enough
12+
// information to determine whether a destroy_addr is required so it is always
13+
// required.
14+
// CHECK-LABEL: sil [ossa] @produceSomeEmptyNontrivialAddronlyEnumInstance : {{.*}} {
15+
// CHECK: [[EMPTY_CASE:%[^,]+]] = enum $EnumNontrivialWithEmptyCases, #EnumNontrivialWithEmptyCases.empty!enumelt
16+
// CHECK: [[SOME_EMPTY_CASE:%[^,]+]] = enum $Optional<EnumNontrivialWithEmptyCases>, #Optional.some!enumelt, [[EMPTY_CASE]]
17+
// CHECK: destroy_value [[SOME_EMPTY_CASE]]
18+
// CHECK-LABEL: } // end sil function 'produceSomeEmptyNontrivialAddronlyEnumInstance'
19+
@_silgen_name("produceSomeEmptyNontrivialAddronlyEnumInstance")
20+
public func produceSomeEmptyNontrivialAddronlyEnumInstance(_ one: EnumNontrivialWithEmptyCases?) {
21+
if one != .empty {
22+
}
23+
}
24+
25+
// CHECK-LABEL: sil [ossa] @produceNoneEmptyAddronlyEnumInstance : {{.*}} {
26+
// CHECK: [[NONE:%[^,]+]] = enum $Optional<EnumNontrivialWithEmptyCases>, #Optional.none!enumelt
27+
// CHECK: return [[NONE]] : $Optional<EnumNontrivialWithEmptyCases>
28+
// CHECK-LABEL: } // end sil function 'produceNoneEmptyAddronlyEnumInstance'
29+
@_silgen_name("produceNoneEmptyAddronlyEnumInstance")
30+
public func produceNoneEmptyAddronlyEnumInstance() -> EnumNontrivialWithEmptyCases? {
31+
return .none
32+
}

0 commit comments

Comments
 (0)