Never return uninhabited values at all
Functions with uninhabited return values are already marked `noreturn`, but we were still generating return instructions for this. When running with `-C passes=lint`, LLVM prints: Unusual: Return statement in function with noreturn attribute The LLVM manual makes a stronger statement about `noreturn` though: > This produces undefined behavior at runtime if the function ever does dynamically return. We now emit an `abort` anywhere that would have tried to return an uninhabited value.
This commit is contained in:
parent
e008e4fde8
commit
c2e0d7f1eb
@ -238,6 +238,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.fn_ty.ret.layout.abi.is_uninhabited() {
|
||||
// Functions with uninhabited return values are marked `noreturn`,
|
||||
// so we should make sure that we never actually do.
|
||||
bx.abort();
|
||||
bx.unreachable();
|
||||
return;
|
||||
}
|
||||
let llval = match self.fn_ty.ret.mode {
|
||||
PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => {
|
||||
bx.ret_void();
|
||||
|
32
src/test/codegen/noreturn-uninhabited.rs
Normal file
32
src/test/codegen/noreturn-uninhabited.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// compile-flags: -g -C no-prepopulate-passes
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum EmptyEnum {}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn empty(x: &EmptyEnum) -> EmptyEnum {
|
||||
// CHECK: @empty({{.*}}) unnamed_addr #0
|
||||
// CHECK-NOT: ret void
|
||||
// CHECK: call void @llvm.trap()
|
||||
// CHECK: unreachable
|
||||
*x
|
||||
}
|
||||
|
||||
pub struct Foo(String, EmptyEnum);
|
||||
|
||||
#[no_mangle]
|
||||
pub fn foo(x: String, y: &EmptyEnum) -> Foo {
|
||||
// CHECK: @foo({{.*}}) unnamed_addr #0
|
||||
// CHECK-NOT: ret %Foo
|
||||
// CHECK: call void @llvm.trap()
|
||||
// CHECK: unreachable
|
||||
Foo(x, *y)
|
||||
}
|
||||
|
||||
// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}}
|
||||
|
||||
// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn
|
||||
// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn
|
Loading…
Reference in New Issue
Block a user