Skip to content

Commit

Permalink
Rollup merge of rust-lang#59639 - cuviper:ignore-uninhabited, r=eddyb
Browse files Browse the repository at this point in the history
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.

Fixes rust-lang#48227
cc rust-lang#7463 rust-lang#48229

r? @eddyb
  • Loading branch information
Centril committed Apr 4, 2019
2 parents 56328a5 + c2e0d7f commit 05c31ba
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/librustc_codegen_ssa/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
32 changes: 32 additions & 0 deletions src/test/codegen/noreturn-uninhabited.rs
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 05c31ba

Please sign in to comment.