Skip to content

Commit 75c5fc5

Browse files
committed
[SILGen] Emit unreachable for uninhabited if/switch expr branches
If we have an uninhabited branch, emit it as an ignored expr followed by an unreachable. Previously we would omit the unreachable and rely on the SILOptimizer to infer it, but we ought to just emit it here. Also check `isUninhabited()` instead of `isStructurallyUninhabited` since this better matches what we allow in Sema. For tuples of uninhabited values, we can do a regular initialization without issue.
1 parent 4002cc8 commit 75c5fc5

File tree

3 files changed

+150
-2
lines changed

3 files changed

+150
-2
lines changed

lib/SILGen/SILGenStmt.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -827,9 +827,20 @@ void StmtEmitter::visitYieldStmt(YieldStmt *S) {
827827

828828
void StmtEmitter::visitThenStmt(ThenStmt *S) {
829829
auto *E = S->getResult();
830-
auto init = SGF.getSingleValueStmtInit(E);
831830

832-
if (init && !E->getType()->isStructurallyUninhabited()) {
831+
// If we have an uninhabited type, we may not be able to use it for
832+
// initialization, since we allow the conversion of Never to any other type.
833+
// Instead, emit an ignored expression with an unreachable.
834+
if (E->getType()->isUninhabited()) {
835+
SGF.emitIgnoredExpr(E);
836+
SGF.B.createUnreachable(E);
837+
return;
838+
}
839+
840+
// Retrieve the initialization for the parent SingleValueStmtExpr. If we don't
841+
// have an init, we don't care about the result, emit an ignored expr. This is
842+
// the case if e.g the result is being converted to Void.
843+
if (auto init = SGF.getSingleValueStmtInit(E)) {
833844
SGF.emitExprInto(E, init.get());
834845
} else {
835846
SGF.emitIgnoredExpr(E);

test/SILGen/if_expr.swift

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,73 @@ func testNever2() -> Never {
509509
if .random() { fatalError() } else { fatalError() }
510510
}
511511

512+
func testNever3() -> Int {
513+
if .random() {
514+
fatalError()
515+
} else {
516+
0
517+
}
518+
}
519+
// CHECK-LABEL: sil hidden [ossa] @$s7if_expr10testNever3SiyF : $@convention(thin) () -> Int
520+
// CHECK: [[RESULT_STORAGE:%[0-9]+]] = alloc_stack $Int
521+
// CHECK: cond_br {{%[0-9]+}}, [[BB_TRUE:bb[0-9]+]], [[BB_FALSE:bb[0-9]+]]
522+
//
523+
// CHECK: [[BB_TRUE]]:
524+
// CHECK: function_ref fatalError(_:file:line:)
525+
// CHECK: unreachable
526+
//
527+
// CHECK: [[BB_FALSE]]:
528+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*Int
529+
// CHECK: store {{%[0-9]+}} to [trivial] [[RESULT]] : $*Int
530+
// CHECK: [[RET:%[0-9]+]] = load [trivial] [[RESULT_STORAGE]] : $*Int
531+
// CHECK: dealloc_stack [[RESULT_STORAGE]] : $*Int
532+
// CHECK: return [[RET]]
533+
534+
func never() -> Never { fatalError() }
535+
536+
func testNever4() -> Int {
537+
if .random() {
538+
never()
539+
} else {
540+
0
541+
}
542+
}
543+
544+
func neverTuple() -> (Never, Int) { fatalError() }
545+
546+
func testNever5() -> (Never, Int) {
547+
if .random() {
548+
neverTuple()
549+
} else {
550+
(never(), 0)
551+
}
552+
}
553+
// CHECK-LABEL: sil hidden [ossa] @$s7if_expr10testNever5s5NeverO_SityF : $@convention(thin) () -> (Never, Int)
554+
// CHECK: [[RESULT_STORAGE:%[0-9]+]] = alloc_stack $(Never, Int)
555+
// CHECK: cond_br {{%[0-9]+}}, [[BB_TRUE:bb[0-9]+]], [[BB_FALSE:bb[0-9]+]]
556+
//
557+
// CHECK: [[BB_TRUE]]:
558+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*(Never, Int)
559+
// CHECK: [[ELT_0:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 0
560+
// CHECK: [[ELT_1:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 1
561+
// CHECK: ([[RET_0:%[0-9]+]], [[RET_1:%[0-9]+]]) = destructure_tuple {{%[0-9]+}} : $(Never, Int)
562+
// CHECK: store [[RET_0]] to [trivial] [[ELT_0]] : $*Never
563+
// CHECK: store [[RET_1]] to [trivial] [[ELT_1]] : $*Int
564+
// CHECK: br [[BB_EXIT:bb[0-9]+]]
565+
//
566+
// CHECK: [[BB_FALSE]]:
567+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*(Never, Int)
568+
// CHECK: [[ELT_0:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 0
569+
// CHECK: [[ELT_1:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 1
570+
// CHECK: store {{%[0-9]+}} to [trivial] [[ELT_0]] : $*Never
571+
// CHECK: store {{%[0-9]+}} to [trivial] [[ELT_1]] : $*Int
572+
// CHECK: br [[BB_EXIT:bb[0-9]+]]
573+
//
574+
// CHECK: [[BB_EXIT]]:
575+
// CHECK: dealloc_stack [[RESULT_STORAGE]] : $*(Never, Int)
576+
// CHECK: [[RET:%[0-9]+]] = tuple ({{%[0-9]+}} : $Never, {{%[0-9]+}} : $Int)
577+
// CHECK: return [[RET]]
578+
512579
func testCaptureList() -> Int {
513580
let fn = { [x = if .random() { 0 } else { 1 }] in x }
514581
return fn()

test/SILGen/switch_expr.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,76 @@ extension Never {
708708
}
709709
}
710710

711+
func testNever5() -> Int {
712+
switch Bool.random() {
713+
case true:
714+
fatalError()
715+
case false:
716+
0
717+
}
718+
}
719+
// CHECK-LABEL: sil hidden [ossa] @$s11switch_expr10testNever5SiyF : $@convention(thin) () -> Int
720+
// CHECK: [[RESULT_STORAGE:%[0-9]+]] = alloc_stack $Int
721+
// CHECK: switch_value {{.*}}, case {{%[0-9]+}}: [[BB_TRUE:bb[0-9]+]], case {{%[0-9]+}}: [[BB_FALSE:bb[0-9]+]]
722+
//
723+
// CHECK: [[BB_TRUE]]:
724+
// CHECK: function_ref fatalError(_:file:line:)
725+
// CHECK: unreachable
726+
//
727+
// CHECK: [[BB_FALSE]]:
728+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*Int
729+
// CHECK: store {{%[0-9]+}} to [trivial] [[RESULT]] : $*Int
730+
// CHECK: [[RET:%[0-9]+]] = load [trivial] [[RESULT_STORAGE]] : $*Int
731+
// CHECK: dealloc_stack [[RESULT_STORAGE]] : $*Int
732+
// CHECK: return [[RET]]
733+
734+
func never() -> Never { fatalError() }
735+
736+
func testNever6() -> Int {
737+
switch Bool.random() {
738+
case true:
739+
never()
740+
case false:
741+
0
742+
}
743+
}
744+
745+
func neverTuple() -> (Never, Int) { fatalError() }
746+
747+
func testNever7() -> (Never, Int) {
748+
switch Bool.random() {
749+
case true:
750+
neverTuple()
751+
case false:
752+
(never(), 0)
753+
}
754+
}
755+
// CHECK-LABEL: sil hidden [ossa] @$s11switch_expr10testNever7s5NeverO_SityF : $@convention(thin) () -> (Never, Int)
756+
// CHECK: [[RESULT_STORAGE:%[0-9]+]] = alloc_stack $(Never, Int)
757+
// CHECK: switch_value {{.*}}, case {{%[0-9]+}}: [[BB_TRUE:bb[0-9]+]], case {{%[0-9]+}}: [[BB_FALSE:bb[0-9]+]]
758+
//
759+
// CHECK: [[BB_TRUE]]:
760+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*(Never, Int)
761+
// CHECK: [[ELT_0:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 0
762+
// CHECK: [[ELT_1:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 1
763+
// CHECK: ([[RET_0:%[0-9]+]], [[RET_1:%[0-9]+]]) = destructure_tuple {{%[0-9]+}} : $(Never, Int)
764+
// CHECK: store [[RET_0]] to [trivial] [[ELT_0]] : $*Never
765+
// CHECK: store [[RET_1]] to [trivial] [[ELT_1]] : $*Int
766+
// CHECK: br [[BB_EXIT:bb[0-9]+]]
767+
//
768+
// CHECK: [[BB_FALSE]]:
769+
// CHECK: [[RESULT:%[0-9]+]] = mark_uninitialized [var] [[RESULT_STORAGE]] : $*(Never, Int)
770+
// CHECK: [[ELT_0:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 0
771+
// CHECK: [[ELT_1:%[0-9]+]] = tuple_element_addr [[RESULT]] : $*(Never, Int), 1
772+
// CHECK: store {{%[0-9]+}} to [trivial] [[ELT_0]] : $*Never
773+
// CHECK: store {{%[0-9]+}} to [trivial] [[ELT_1]] : $*Int
774+
// CHECK: br [[BB_EXIT:bb[0-9]+]]
775+
//
776+
// CHECK: [[BB_EXIT]]:
777+
// CHECK: dealloc_stack [[RESULT_STORAGE]] : $*(Never, Int)
778+
// CHECK: [[RET:%[0-9]+]] = tuple ({{%[0-9]+}} : $Never, {{%[0-9]+}} : $Int)
779+
// CHECK: return [[RET]]
780+
711781
func testCaptureList() -> Int {
712782
let fn = { [x = switch Bool.random() { case true: 0 case false: 1 }] in x }
713783
return fn()

0 commit comments

Comments
 (0)