Skip to content

Commit 4e4518c

Browse files
authored
Merge pull request #65195 from gottesmm/release/5.9/101651138/107974302/104395115
[5.9] Batched cherry-picks
2 parents c7e066b + d7533df commit 4e4518c

9 files changed

+578
-2
lines changed

lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ TypeSubElementCount::TypeSubElementCount(SILType type, SILModule &mod,
6969
numElements += TypeSubElementCount(
7070
type.getFieldType(fieldDecl, mod, context), mod, context);
7171
number = numElements;
72+
73+
// If we do not have any elements, just set our size to 1.
74+
if (numElements == 0)
75+
number = 1;
76+
7277
return;
7378
}
7479

lib/SILGen/SILGenConstructor.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,22 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
631631
if (!isDelegating) {
632632
auto *typeDC = ctor->getDeclContext();
633633
auto *nominal = typeDC->getSelfNominalTypeDecl();
634-
emitMemberInitializers(ctor, selfDecl, nominal);
634+
635+
// If we have an empty move only struct, then we will not initialize it with
636+
// any member initializers, breaking SIL. So in that case, just construct a
637+
// SIL struct value and initialize the memory with that.
638+
//
639+
// DISCUSSION: This only happens with noncopyable types since the memory
640+
// lifetime checker doesn't seem to process trivial locations. But empty
641+
// move only structs are non-trivial, so we need to handle this here.
642+
if (isa<StructDecl>(nominal) && nominal->isMoveOnly() &&
643+
nominal->getStoredProperties().empty()) {
644+
auto *si = B.createStruct(ctor, lowering.getLoweredType(), {});
645+
B.emitStoreValueOperation(ctor, si, selfLV.getLValueAddress(),
646+
StoreOwnershipQualifier::Init);
647+
} else {
648+
emitMemberInitializers(ctor, selfDecl, nominal);
649+
}
635650
}
636651

637652
emitProfilerIncrement(ctor->getTypecheckedBody());

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ checkForDestructureThroughDeinit(MarkMustCheckInst *rootAddress, Operand *use,
13331333
// cannot contain non-copyable types and that our parent root type must be
13341334
// an enum, tuple, or struct.
13351335
if (auto *nom = iterType.getNominalOrBoundGenericNominal()) {
1336-
if (mod.lookUpMoveOnlyDeinitFunction(nom)) {
1336+
if (nom->getValueTypeDestructor()) {
13371337
// If we find one, emit an error since we are going to have to extract
13381338
// through the deinit. Emit a nice error saying what it is. Since we
13391339
// are emitting an error, we do a bit more work and construct the

lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,4 +774,6 @@ void DiagnosticEmitter::emitCannotDestructureDeinitNominalError(
774774
}
775775
diagnose(astContext, consumingUser,
776776
diag::sil_moveonlychecker_consuming_use_here);
777+
astContext.Diags.diagnose(deinitedNominal->getValueTypeDestructor(),
778+
diag::sil_moveonlychecker_deinit_here);
777779
}

test/Interpreter/moveonly.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,17 @@ Tests.test("deinit not called in init when assigned") {
8989
}
9090
expectEqual(0, FD2.count)
9191
}
92+
93+
Tests.test("empty struct") {
94+
@_moveOnly
95+
struct EmptyStruct {
96+
func doSomething() {}
97+
var value: Bool { false }
98+
}
99+
100+
let e = EmptyStruct()
101+
e.doSomething()
102+
if e.value {
103+
let _ = consume e
104+
}
105+
}

test/SILGen/moveonly.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,3 +779,27 @@ func checkMarkMustCheckOnCaptured(x: __owned FD) {
779779
func clodger<T>(_: () -> T) {}
780780
clodger({ consumeVal(x) })
781781
}
782+
783+
//////////////////
784+
// Empty Struct //
785+
//////////////////
786+
787+
@_moveOnly
788+
struct EmptyStruct {
789+
// Make sure we explicitly initialize empty struct as appropriate despite the
790+
// fact we do not have any fields.
791+
//
792+
// CHECK-LABEL: sil hidden [ossa] @$s8moveonly11EmptyStructVACycfC : $@convention(method) (@thin EmptyStruct.Type) -> @owned EmptyStruct {
793+
// CHECK: [[BOX:%.*]] = alloc_box ${ var EmptyStruct }, var, name "self"
794+
// CHECK: [[MARKED_UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]]
795+
// CHECK: [[PROJECT:%.*]] = project_box [[MARKED_UNINIT]]
796+
// CHECK: [[STRUCT:%.*]] = struct $EmptyStruct ()
797+
// CHECK: store [[STRUCT]] to [init] [[PROJECT]]
798+
// CHECK: [[MV_CHECK:%.*]] = mark_must_check [assignable_but_not_consumable] [[PROJECT]]
799+
// CHECK: [[LOADED_VALUE:%.*]] = load [copy] [[MV_CHECK]]
800+
// CHECK: destroy_value [[MARKED_UNINIT]]
801+
// CHECK: return [[LOADED_VALUE]]
802+
// CHECK: } // end sil function '$s8moveonly11EmptyStructVACycfC'
803+
init() {
804+
}
805+
}

test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ struct DeinitStruct {
5959
var fifth: MoveOnlyKlass
6060

6161
deinit {}
62+
// expected-note @-1 {{deinit declared here}}
63+
// expected-note @-2 {{deinit declared here}}
64+
// expected-note @-3 {{deinit declared here}}
65+
// expected-note @-4 {{deinit declared here}}
66+
// expected-note @-5 {{deinit declared here}}
67+
// expected-note @-6 {{deinit declared here}}
68+
// expected-note @-7 {{deinit declared here}}
69+
// expected-note @-8 {{deinit declared here}}
70+
// expected-note @-9 {{deinit declared here}}
71+
// expected-note @-10 {{deinit declared here}}
6272
}
6373

6474
func testConsumeCopyable(_ x: consuming DeinitStruct) {

0 commit comments

Comments
 (0)