Skip to content

Commit cca5a6e

Browse files
committed
[SILGen] Emit block after unreachable when emitting if/switch expressions
When emitting the underlying `switch` statement for a `switch` expression, we emit an `unreachable` if the subject is uninhabited. Statement emission code can handle this, but expression emission expects an RValue to handed back. To remedy this, emit an unreachable block that we can emit the rest of the expression emission code into. The SILOptimizer will then drop this unreachable block.
1 parent dcb3b9b commit cca5a6e

File tree

3 files changed

+112
-2
lines changed

3 files changed

+112
-2
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,11 +2174,26 @@ RValue RValueEmitter::visitEnumIsCaseExpr(EnumIsCaseExpr *E,
21742174

21752175
RValue RValueEmitter::visitSingleValueStmtExpr(SingleValueStmtExpr *E,
21762176
SGFContext C) {
2177+
auto emitStmt = [&]() {
2178+
SGF.emitStmt(E->getStmt());
2179+
2180+
// A switch of an uninhabited value gets emitted as an unreachable. In that
2181+
// case we need to emit a block to emit the rest of the expression code
2182+
// into. This block will be unreachable, so will be eliminated by the
2183+
// SILOptimizer. This is easier than handling unreachability throughout
2184+
// expression emission, as eventually SingleValueStmtExprs ought to be able
2185+
// to appear in arbitrary expression position. The rest of the emission
2186+
// will reference the uninitialized temporary variable, but that's fine
2187+
// because it'll be eliminated.
2188+
if (!SGF.B.hasValidInsertionPoint())
2189+
SGF.B.emitBlock(SGF.createBasicBlock());
2190+
};
2191+
21772192
// A void SingleValueStmtExpr either only has Void expression branches, or
21782193
// we've decided that it should have purely statement semantics. In either
21792194
// case, we can just emit the statement as-is, and produce the void rvalue.
21802195
if (E->getType()->isVoid()) {
2181-
SGF.emitStmt(E->getStmt());
2196+
emitStmt();
21822197
return SGF.emitEmptyTupleRValue(E, C);
21832198
}
21842199
auto &lowering = SGF.getTypeLowering(E->getType());
@@ -2201,7 +2216,7 @@ RValue RValueEmitter::visitSingleValueStmtExpr(SingleValueStmtExpr *E,
22012216
// Push the initialization for branches of the statement to initialize into.
22022217
SGF.SingleValueStmtInitStack.push_back(std::move(initInfo));
22032218
SWIFT_DEFER { SGF.SingleValueStmtInitStack.pop_back(); };
2204-
SGF.emitStmt(E->getStmt());
2219+
emitStmt();
22052220
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
22062221
}
22072222

test/SILGen/if_expr.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,11 @@ struct TestLValues {
500500
opt![keyPath: kp] = if .random() { 1 } else { throw Err() }
501501
}
502502
}
503+
504+
func testNever1() -> Never {
505+
if case let x = fatalError() { x } else { fatalError() }
506+
}
507+
508+
func testNever2() -> Never {
509+
if .random() { fatalError() } else { fatalError() }
510+
}

test/SILGen/switch_expr.swift

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,90 @@ func exprPatternInClosure() {
616616
}
617617
}
618618
}
619+
620+
func testNeverSwitch1() {
621+
let x = switch fatalError() {}
622+
return x
623+
}
624+
625+
func testNeverSwitch2() -> Never {
626+
let x = switch fatalError() {
627+
case let x: x
628+
}
629+
return x
630+
}
631+
632+
func testNeverSwitch3() -> Int {
633+
let x = switch fatalError() {
634+
case fatalError(): 0
635+
case _ where .random(): 1
636+
default: 2
637+
}
638+
return x
639+
}
640+
641+
func testNeverSwitch4() {
642+
let x: Void
643+
x = switch fatalError() {}
644+
return x
645+
}
646+
647+
func testNeverSwitch5() -> Never {
648+
let x: Never
649+
x = switch fatalError() {
650+
case let x: x
651+
}
652+
return x
653+
}
654+
655+
func testNeverSwitch6() -> Int {
656+
let x: Int
657+
x = switch fatalError() {
658+
case fatalError(): 0
659+
case _ where .random(): 1
660+
default: 2
661+
}
662+
return x
663+
}
664+
665+
func testNeverSwitch7() {
666+
let _ = switch fatalError() {}
667+
let _ = switch fatalError() { case let x: x }
668+
let _ = switch fatalError() { default: "" }
669+
}
670+
671+
func testNeverSwitch8() {
672+
let _ = switch fatalError() { default: C() }
673+
}
674+
675+
func testNeverSwitch9() {
676+
let i = switch Bool.random() {
677+
case true:
678+
switch fatalError() {}
679+
case false:
680+
switch fatalError() {}
681+
}
682+
return i
683+
}
684+
685+
func testNeverSwitch10() -> Never {
686+
switch fatalError() {}
687+
}
688+
689+
func testNeverSwitch11() {
690+
return switch fatalError() {}
691+
}
692+
693+
func testNeverSwitch12() -> Never {
694+
return switch fatalError() { case let x: x }
695+
}
696+
697+
func testNeverSwitch13() {
698+
return switch fatalError() { case let x: x }
699+
}
700+
701+
extension Never {
702+
init(value: Self) {
703+
self = switch value { case let v: v }
704+
}
705+
}

0 commit comments

Comments
 (0)