Skip to content

Commit 3411a56

Browse files
authored
Rollup merge of rust-lang#59639 - cuviper:ignore-uninhabited, r=eddyb
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
2 parents 1b9fdbf + c2e0d7f commit 3411a56

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

src/librustc_codegen_ssa/mir/block.rs

+7
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
238238
}
239239
}
240240
}
241+
if self.fn_ty.ret.layout.abi.is_uninhabited() {
242+
// Functions with uninhabited return values are marked `noreturn`,
243+
// so we should make sure that we never actually do.
244+
bx.abort();
245+
bx.unreachable();
246+
return;
247+
}
241248
let llval = match self.fn_ty.ret.mode {
242249
PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => {
243250
bx.ret_void();
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// compile-flags: -g -C no-prepopulate-passes
2+
// ignore-tidy-linelength
3+
4+
#![crate_type = "lib"]
5+
6+
#[derive(Clone, Copy)]
7+
pub enum EmptyEnum {}
8+
9+
#[no_mangle]
10+
pub fn empty(x: &EmptyEnum) -> EmptyEnum {
11+
// CHECK: @empty({{.*}}) unnamed_addr #0
12+
// CHECK-NOT: ret void
13+
// CHECK: call void @llvm.trap()
14+
// CHECK: unreachable
15+
*x
16+
}
17+
18+
pub struct Foo(String, EmptyEnum);
19+
20+
#[no_mangle]
21+
pub fn foo(x: String, y: &EmptyEnum) -> Foo {
22+
// CHECK: @foo({{.*}}) unnamed_addr #0
23+
// CHECK-NOT: ret %Foo
24+
// CHECK: call void @llvm.trap()
25+
// CHECK: unreachable
26+
Foo(x, *y)
27+
}
28+
29+
// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}}
30+
31+
// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn
32+
// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn

0 commit comments

Comments
 (0)