Skip to content

Commit 41dc6e2

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 2f7b42c commit 41dc6e2

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
@@ -833,9 +833,20 @@ void StmtEmitter::visitYieldStmt(YieldStmt *S) {
833833

834834
void StmtEmitter::visitThenStmt(ThenStmt *S) {
835835
auto *E = S->getResult();
836-
auto init = SGF.getSingleValueStmtInit(E);
837836

838-
if (init && !E->getType()->isStructurallyUninhabited()) {
837+
// If we have an uninhabited type, we may not be able to use it for
838+
// initialization, since we allow the conversion of Never to any other type.
839+
// Instead, emit an ignored expression with an unreachable.
840+
if (E->getType()->isUninhabited()) {
841+
SGF.emitIgnoredExpr(E);
842+
SGF.B.createUnreachable(E);
843+
return;
844+
}
845+
846+
// Retrieve the initialization for the parent SingleValueStmtExpr. If we don't
847+
// have an init, we don't care about the result, emit an ignored expr. This is
848+
// the case if e.g the result is being converted to Void.
849+
if (auto init = SGF.getSingleValueStmtInit(E)) {
839850
SGF.emitExprInto(E, init.get());
840851
} else {
841852
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)