Skip to content

Commit 6c8d8fe

Browse files
authored
Rollup merge of rust-lang#59639 - cuviper:ignore-uninhabited, r=sanxiyn
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 mark such return values with a new `IgnoreMode::Uninhabited`, and emit an `abort` anywhere that would have returned. Fixes rust-lang#48227 cc rust-lang#7463 rust-lang#48229 r? @eddyb
2 parents 9274fba + fb575c0 commit 6c8d8fe

File tree

5 files changed

+49
-3
lines changed

5 files changed

+49
-3
lines changed

src/librustc_codegen_llvm/abi.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,11 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
518518
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
519519
let is_return = arg_idx.is_none();
520520
let mut arg = mk_arg_type(ty, arg_idx);
521-
if arg.layout.is_zst() {
521+
if is_return && arg.layout.abi.is_uninhabited() {
522+
// Functions with uninhabited return values are marked `noreturn`,
523+
// so we don't actually need to do anything with the value.
524+
arg.mode = PassMode::Ignore(IgnoreMode::Uninhabited);
525+
} else if arg.layout.is_zst() {
522526
// For some forsaken reason, x86_64-pc-windows-gnu
523527
// doesn't ignore zero-sized struct arguments.
524528
// The same is true for s390x-unknown-linux-gnu
@@ -677,7 +681,8 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
677681
);
678682

679683
let llreturn_ty = match self.ret.mode {
680-
PassMode::Ignore(IgnoreMode::Zst) => cx.type_void(),
684+
PassMode::Ignore(IgnoreMode::Zst)
685+
| PassMode::Ignore(IgnoreMode::Uninhabited) => cx.type_void(),
681686
PassMode::Ignore(IgnoreMode::CVarArgs) =>
682687
bug!("`va_list` should never be a return type"),
683688
PassMode::Direct(_) | PassMode::Pair(..) => {

src/librustc_codegen_ssa/mir/block.rs

+6
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,12 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
244244
return;
245245
}
246246

247+
PassMode::Ignore(IgnoreMode::Uninhabited) => {
248+
bx.abort();
249+
bx.unreachable();
250+
return;
251+
}
252+
247253
PassMode::Ignore(IgnoreMode::CVarArgs) => {
248254
bug!("C-variadic arguments should never be the return type");
249255
}

src/librustc_codegen_ssa/mir/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,8 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
521521
PassMode::Ignore(IgnoreMode::Zst) => {
522522
return local(OperandRef::new_zst(bx, arg.layout));
523523
}
524-
PassMode::Ignore(IgnoreMode::CVarArgs) => {}
524+
PassMode::Ignore(IgnoreMode::CVarArgs)
525+
| PassMode::Ignore(IgnoreMode::Uninhabited) => {}
525526
PassMode::Direct(_) => {
526527
let llarg = bx.get_param(llarg_idx);
527528
bx.set_value_name(llarg, &name);

src/librustc_target/abi/call/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub enum IgnoreMode {
2929
CVarArgs,
3030
/// A zero-sized type.
3131
Zst,
32+
/// An uninhabited type.
33+
Uninhabited,
3234
}
3335

3436
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+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)