Skip to content

Commit 95f551e

Browse files
committed
Fix LowerAggregateInstrs to avoid lowering move-only types
Fixes rdar://109849028 ([move-only] LowerAggregateInstrs eliminates struct deinitialization)
1 parent 56fca83 commit 95f551e

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,21 @@ static llvm::cl::opt<bool> EnableExpandAll("sil-lower-agg-instrs-expand-all",
4343
// Utility
4444
//===----------------------------------------------------------------------===//
4545

46+
/// Expansion of struct-with-deinit is illegal because it drops the deinit. For
47+
/// now, simply avoid all move-only AST types.
48+
static bool canExpandType(SILType type) {
49+
return type.isPureMoveOnly();
50+
}
51+
4652
/// We only expand if we are not in ownership and shouldExpand is true. The
4753
/// reason why is that this was originally done to help the low level ARC
4854
/// optimizer. To the high level ARC optimizer, this is just noise and
4955
/// unnecessary IR. At the same time for testing purposes, we want to provide a
5056
/// way even with ownership enabled to expand so we can check correctness.
5157
static bool shouldExpandShim(SILFunction *fn, SILType type) {
58+
if (!canExpandType(type))
59+
return false;
60+
5261
return EnableExpandAll ||
5362
(!fn->hasOwnership() && shouldExpand(fn->getModule(), type));
5463
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all -lower-aggregate-instrs %s | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
7+
struct S : ~Copyable {
8+
deinit {}
9+
}
10+
struct S2 : ~Copyable {
11+
var s1 = S()
12+
var s2 = S()
13+
}
14+
15+
// Test that a struct-with-deinit is not expanded. Doing so would
16+
// forget the deinit.
17+
//
18+
// public func testDeinitTwo() {
19+
// var s = S2()
20+
// }
21+
//
22+
// CHECK-LABEL: sil @testDeinitTwo : $@convention(thin) () -> () {
23+
// CHECK: release_value %{{.*}} : $S2
24+
// CHECK-LABEL: } // end sil function 'testDeinitTwo'
25+
sil @testDeinitTwo : $@convention(thin) () -> () {
26+
bb0:
27+
%0 = struct $S ()
28+
%1 = struct $S2 (%0 : $S, %0 : $S)
29+
release_value %1 : $S2
30+
%5 = tuple ()
31+
return %5 : $()
32+
}

0 commit comments

Comments
 (0)