Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2606,19 +2606,31 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E,
}

RValue RValueEmitter::visitUnreachableExpr(UnreachableExpr *E, SGFContext C) {
// Emit the expression, followed by an unreachable. To produce a value of
// arbitrary type, we emit a temporary allocation, with the use of the
// allocation in the unreachable block. The SILOptimizer will eliminate both
// the unreachable block and unused allocation.
// Emit the expression, followed by an unreachable.
SGF.emitIgnoredExpr(E->getSubExpr());
SGF.B.createUnreachable(E);

// Continue code generation in a block with no predecessors.
// Whatever code is emitted here is guaranteed to be removed by SIL passes.
SGF.B.emitBlock(SGF.createBasicBlock());

// Since the type is uninhabited, use a SILUndef of so that we can return
// some sort of RValue from this API.
auto &lowering = SGF.getTypeLowering(E->getType());
auto resultAddr = SGF.emitTemporaryAllocation(E, lowering.getLoweredType());
auto loweredTy = lowering.getLoweredType();
auto undef = SILUndef::get(SGF.F, loweredTy);

SGF.B.createUnreachable(E);
SGF.B.emitBlock(SGF.createBasicBlock());
// Create an alloc initialized with contents from the undefined addr type.
// It seems pack addresses do not satisfy isPlusOneOrTrivial, so we need an
// actual allocation.
if (loweredTy.isAddress()) {
auto resultAddr = SGF.emitTemporaryAllocation(E, loweredTy);
SGF.emitSemanticStore(E, undef, resultAddr, lowering, IsInitialization);
return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
}

return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(resultAddr));
// Otherwise, if it's not an address, just emit the undef value itself.
return RValue(SGF, E, ManagedValue::forRValueWithoutOwnership(undef));
}

VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
Expand Down
20 changes: 20 additions & 0 deletions test/SILGen/unreachable_expr.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all | %FileCheck %s --check-prefixes CHECK,REG
// RUN: %target-swift-emit-silgen %s -verify -sil-verify-all -enable-sil-opaque-values | %FileCheck %s --check-prefixes CHECK,OV

// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}uninhabited_generic{{.*}}
// CHECK: [[NEVER:%[^,]+]] = apply {{.*}} -> Never
// CHECK-NEXT: ignored_use [[NEVER]]
// CHECK-NEXT: unreachable
//
// CHECK: bb1:
// CHECK-NOT: Preds

// Without opaque values, take from an undef address,
// through a temporary alloc, to eventually the out-parameter %0
// REG-NEXT: [[BOGUS_ALLOC:%.*]] = alloc_stack $T
// REG-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
// REG-NEXT: copy_addr [take] [[BOGUS_ALLOC]] to [init] %0

// With opaque values, simply return the undef value
// OV-NEXT: return undef : $T
func uninhabited_generic<T>() -> T { fatalError("todo") }
10 changes: 10 additions & 0 deletions test/SILGen/variadic-generic-tuples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ func convertVoidPayloads() {
convertPayloads(as: Void.self)
}

// CHECK-LABEL: sil{{.*}} [ossa] @{{.*}}convertPayloads{{.*}} :
// CHECK: ignored_use {{.*}}
// CHECK-NEXT: unreachable
//
// CHECK: bb1:
// CHECK-NOT: Preds
// CHECK: [[BOGUS_ALLOC:%.*]] = alloc_stack $(repeat each Value)
// CHECK-NEXT: copy_addr [take] undef to [init] [[BOGUS_ALLOC]]
//
// CHECK: = tuple_pack_element_addr {{.*}} of [[BOGUS_ALLOC]]
func convertPayloads<each Value>(as valueTypes: repeat (each Value).Type) -> (repeat each Value) {
fatalError()
}