Skip to content

Commit 5556848

Browse files
authored
Merge pull request #65774 from gottesmm/release/5.9/rdar108993297
[5.9][move-only] Ensure that if we have an allocation that isn't fully initialized (and DI errors on it as such), the move checkers do not run on the allocation.
2 parents 830ea2d + c82a034 commit 5556848

File tree

4 files changed

+106
-8
lines changed

4 files changed

+106
-8
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#define DEBUG_TYPE "definite-init"
14+
1415
#include "DIMemoryUseCollector.h"
1516
#include "swift/AST/DiagnosticEngine.h"
1617
#include "swift/AST/DiagnosticsSIL.h"
1718
#include "swift/AST/Expr.h"
1819
#include "swift/AST/Stmt.h"
1920
#include "swift/ClangImporter/ClangModule.h"
2021
#include "swift/SIL/BasicBlockBits.h"
22+
#include "swift/AST/SemanticAttrs.h"
2123
#include "swift/SIL/BasicBlockData.h"
2224
#include "swift/SIL/InstructionUtils.h"
2325
#include "swift/SIL/MemAccessUtils.h"
@@ -1140,7 +1142,15 @@ void LifetimeChecker::doIt() {
11401142
}
11411143

11421144
// If we emitted an error, there is no reason to proceed with load promotion.
1143-
if (!EmittedErrorLocs.empty()) return;
1145+
if (!EmittedErrorLocs.empty()) {
1146+
// Since we failed DI, for now, turn off the move checker on the entire
1147+
// function. With time, we should be able to allow for move checker checks
1148+
// to be emitted on unrelated allocations, but given where we are this is a
1149+
// good enough fix.
1150+
TheMemory.getFunction().addSemanticsAttr(
1151+
semantics::NO_MOVEONLY_DIAGNOSTICS);
1152+
return;
1153+
}
11441154

11451155
// If the memory object has nontrivial type, then any destroy/release of the
11461156
// memory object will destruct the memory. If the memory (or some element

test/SILOptimizer/definite_init_markuninitialized_rootself.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ bb0(%0 : @owned $RootClassWithIVars, %1 : $Int):
5050
return %3 : $RootClassWithIVars
5151
}
5252

53-
// CHECK-LABEL: sil [ossa] @rootclass_test2
53+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @rootclass_test2
5454
sil [ossa] @rootclass_test2 : $@convention(method) (@owned RootClassWithIVars, Int) -> @owned RootClassWithIVars {
5555
bb0(%0 : @owned $RootClassWithIVars, %1 : $Int):
5656
%3 = mark_uninitialized [rootself] %0 : $RootClassWithIVars
@@ -74,7 +74,7 @@ bb0(%0 : @owned $RootClassWithIVars, %1 : $Int):
7474
return %3 : $RootClassWithIVars // expected-error {{return from initializer without initializing all stored properties}}
7575
}
7676

77-
// CHECK-LABEL: sil [ossa] @rootclass_test3
77+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @rootclass_test3
7878
sil [ossa] @rootclass_test3 : $@convention(method) (@owned RootClassWithIVars, Int) -> @owned RootClassWithIVars {
7979
bb0(%0 : @owned $RootClassWithIVars, %1 : $Int):
8080
%3 = mark_uninitialized [rootself] %0 : $RootClassWithIVars

test/SILOptimizer/definite_init_markuninitialized_var.sil

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Swift
1111
sil @takes_Int_inout : $@convention(thin) (@inout Int) -> ()
1212
sil @makesInt : $@convention(thin) () -> Int
1313

14-
// CHECK-LABEL: sil [ossa] @use_before_init
14+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @use_before_init
1515
sil [ossa] @use_before_init : $@convention(thin) () -> Int {
1616
bb0:
1717
%0 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
@@ -85,7 +85,7 @@ bb0:
8585
return %5 : $Int
8686
}
8787

88-
// CHECK-LABEL: sil [ossa] @tuple_elements1
88+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @tuple_elements1
8989
sil [ossa] @tuple_elements1 : $@convention(thin) (Int) -> () {
9090
bb0(%0 : $Int):
9191
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Int)>
@@ -101,7 +101,7 @@ bb0(%0 : $Int):
101101
return %99 : $()
102102
}
103103

104-
// CHECK-LABEL: sil [ossa] @tuple_elements2
104+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @tuple_elements2
105105
sil [ossa] @tuple_elements2 : $@convention(thin) (Int) -> (Int, Int) {
106106
bb0(%0 : $Int):
107107
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Int)>
@@ -130,7 +130,7 @@ bb0(%0 : $*T, %1 : $*T):
130130
return %9 : $()
131131
}
132132

133-
// CHECK-LABEL: sil [ossa] @copy_addr2
133+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @copy_addr2
134134
sil [ossa] @copy_addr2 : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
135135
bb0(%0 : $*T, %1 : $*T):
136136
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
@@ -145,7 +145,7 @@ bb0(%0 : $*T, %1 : $*T):
145145
sil [ossa] @takes_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
146146
sil [ossa] @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
147147

148-
// CHECK-LABEL: sil [ossa] @closure_test
148+
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @closure_test
149149
sil [ossa] @closure_test : $@convention(thin) () -> () {
150150
bb0:
151151
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy %s
2+
3+
// This testStruct specifically testStructs how DI and the move checkers interact with each other
4+
5+
func testStructSimpleNoInit() {
6+
struct M: ~Copyable {
7+
private let i: Int // expected-note {{'self.i' not initialized}}
8+
9+
// No initialization. Should get DI error and no crash.
10+
init() {
11+
} // expected-error {{return from initializer without initializing all stored properties}}
12+
}
13+
}
14+
15+
func testStructSimplePartialInit() {
16+
struct M: ~Copyable {
17+
private let i: Int
18+
private let i2: Int // expected-note {{'self.i2' not initialized}}
19+
20+
init() {
21+
i = 5
22+
} // expected-error {{return from initializer without initializing all stored properties}}
23+
}
24+
}
25+
26+
func testStructSimplePartialInit2() {
27+
struct M: ~Copyable {
28+
private let i: Int = 5
29+
private let i2: Int // expected-note {{'self.i2' not initialized}}
30+
31+
init() {
32+
} // expected-error {{return from initializer without initializing all stored properties}}
33+
}
34+
}
35+
36+
func testStructGenericNoInit() {
37+
struct M<T>: ~Copyable {
38+
private let i: T // expected-note {{'self.i' not initialized}}
39+
40+
init() {
41+
} // expected-error {{return from initializer without initializing all stored properties}}
42+
}
43+
}
44+
45+
func testStructGenericPartialInit() {
46+
struct M<T>: ~Copyable {
47+
private let i: T
48+
private let i2: T // expected-note {{'self.i2' not initialized}}
49+
50+
init(_ t: T) {
51+
self.i = t
52+
} // expected-error {{return from initializer without initializing all stored properties}}
53+
}
54+
}
55+
56+
func testEnumNoInit() {
57+
enum E : ~Copyable {
58+
case first
59+
case second
60+
61+
init() {
62+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
63+
}
64+
}
65+
66+
func testEnumNoInitWithPayload() {
67+
@_moveOnly struct Empty {}
68+
69+
enum E : ~Copyable {
70+
case first(Empty)
71+
case second
72+
73+
init() {
74+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
75+
}
76+
}
77+
78+
func testEnumNoInitWithGenericPayload() {
79+
@_moveOnly struct Empty {}
80+
81+
enum E<T> : ~Copyable {
82+
case first(Empty)
83+
case second(T)
84+
85+
init() {
86+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
87+
}
88+
}

0 commit comments

Comments
 (0)