Skip to content

Commit b946fa4

Browse files
committed
Fix codegen of uninhabited PassMode::Indirect return types.
Add codegen test for uninhabited PassMode::Indirect return types.
1 parent 2a9336c commit b946fa4

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+7-21
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange};
44
use rustc_ast as ast;
55
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
66
use rustc_hir::lang_items::LangItem;
7-
use rustc_middle::mir::{
8-
self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason,
9-
};
7+
use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason};
108
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
119
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1210
use rustc_middle::ty::{self, Instance, Ty};
@@ -942,7 +940,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
942940
&fn_abi.ret,
943941
&mut llargs,
944942
Some(intrinsic),
945-
target,
946943
);
947944
let dest = match ret_dest {
948945
_ if fn_abi.ret.is_indirect() => llargs[0],
@@ -998,19 +995,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
998995
};
999996

1000997
let mut llargs = Vec::with_capacity(arg_count);
1001-
let destination = target.as_ref().map(|&target| {
1002-
(
1003-
self.make_return_dest(
1004-
bx,
1005-
destination,
1006-
&fn_abi.ret,
1007-
&mut llargs,
1008-
None,
1009-
Some(target),
1010-
),
1011-
target,
1012-
)
1013-
});
998+
999+
// We still need to call `make_return_dest` even if there's no `target`, since
1000+
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
1001+
// and `make_return_dest` adds the return-place indirect pointer to `llargs`.
1002+
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None);
1003+
let destination = target.map(|target| (return_dest, target));
10141004

10151005
// Split the rust-call tupled arguments off.
10161006
let (first_args, untuple) = if abi == ExternAbi::RustCall && !args.is_empty() {
@@ -1813,11 +1803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
18131803
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
18141804
llargs: &mut Vec<Bx::Value>,
18151805
intrinsic: Option<ty::IntrinsicDef>,
1816-
target: Option<BasicBlock>,
18171806
) -> ReturnDest<'tcx, Bx::Value> {
1818-
if target.is_none() {
1819-
return ReturnDest::Nothing;
1820-
}
18211807
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
18221808
if fn_ret.is_ignore() {
18231809
return ReturnDest::Nothing;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// See https://github.com/rust-lang/rust/issues/135802
2+
3+
#![crate_type = "lib"]
4+
5+
enum Void {}
6+
7+
// Should be ABI-compatible with T, but wasn't prior to the PR adding this test.
8+
#[repr(transparent)]
9+
struct NoReturn<T>(T, Void);
10+
11+
// Returned by invisible reference (in most ABIs)
12+
#[allow(dead_code)]
13+
struct Large(u64, u64, u64);
14+
15+
extern "Rust" {
16+
fn opaque() -> NoReturn<Large>;
17+
fn opaque_with_arg(rsi: u32) -> NoReturn<Large>;
18+
}
19+
20+
// CHECK-LABEL: @test_uninhabited_ret_by_ref
21+
#[no_mangle]
22+
pub fn test_uninhabited_ret_by_ref() {
23+
// CHECK: %_1 = alloca [24 x i8], align {{8|4}}
24+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_1)
25+
// CHECK-NEXT: call void @opaque(ptr noalias nocapture noundef nonnull sret([24 x i8]) align {{8|4}} dereferenceable(24) %_1) #2
26+
// CHECK-NEXT: unreachable
27+
unsafe {
28+
opaque();
29+
}
30+
}
31+
32+
// CHECK-LABEL: @test_uninhabited_ret_by_ref_with_arg
33+
#[no_mangle]
34+
pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) {
35+
// CHECK: %_2 = alloca [24 x i8], align {{8|4}}
36+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_2)
37+
// CHECK-NEXT: call void @opaque_with_arg(ptr noalias nocapture noundef nonnull sret([24 x i8]) align {{8|4}} dereferenceable(24) %_2, i32 noundef %rsi) #2
38+
// CHECK-NEXT: unreachable
39+
unsafe {
40+
opaque_with_arg(rsi);
41+
}
42+
}

0 commit comments

Comments
 (0)