Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions compiler/rustc_target/src/callconv/x86_win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(
// - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667
if t.abi_return_struct_as_int || opts.reg_struct_return {
match fn_abi.ret.layout.size.bytes() {
1 => fn_abi.ret.cast_to(Reg::i8()),
2 => fn_abi.ret.cast_to(Reg::i16()),
4 => fn_abi.ret.cast_to(Reg::i32()),
8 => fn_abi.ret.cast_to(Reg::i64()),
1 => fn_abi.ret.cast_to_maybe_noundef(Reg::i8(), cx),
2 => fn_abi.ret.cast_to_maybe_noundef(Reg::i16(), cx),
4 => fn_abi.ret.cast_to_maybe_noundef(Reg::i32(), cx),
8 => fn_abi.ret.cast_to_maybe_noundef(Reg::i64(), cx),
_ => fn_abi.ret.make_indirect(),
}
} else {
Expand Down
95 changes: 95 additions & 0 deletions tests/codegen-llvm/abi-noundef-cast-win32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Checks that small aggregates returned as an integer under the Win32 (MSVC) ABI
// (`abi_return_struct_as_int`) carry `noundef` when the layout is provably free of
// uninit bytes, and omit it when the layout may contain uninit bytes (padding or a
// union).
//
// See <https://github.com/rust-lang/rust/issues/123183>.

//@ add-minicore
//@ compile-flags: --target i686-pc-windows-msvc -Cno-prepopulate-passes -Copt-level=3
//@ needs-llvm-components: x86

#![feature(no_core, lang_items)]
#![no_core]
#![crate_type = "lib"]

extern crate minicore;
use minicore::*;

// Fully-defined layouts, one per integer register size (i8/i16/i32/i64).

#[repr(C)]
pub struct OneU8 {
x: u8,
}

#[repr(C)]
pub struct TwoU8 {
x: u8,
y: u8,
}

#[repr(C)]
pub struct TwoU16 {
x: u16,
y: u16,
}

#[repr(C)]
pub struct TwoU32 {
x: u32,
y: u32,
}

// Layouts that may contain uninit bytes.

// Tail padding: `u8` at offset 4 leaves bytes 5..8 uninit.
#[repr(C)]
pub struct Padded {
x: u32,
y: u8,
}

#[repr(C)]
pub union U {
x: u32,
y: u32,
}

// CHECK: define noundef i8 @ret_one_u8()
#[no_mangle]
pub extern "C" fn ret_one_u8() -> OneU8 {
OneU8 { x: 1 }
}

// CHECK: define noundef i16 @ret_two_u8()
#[no_mangle]
pub extern "C" fn ret_two_u8() -> TwoU8 {
TwoU8 { x: 1, y: 2 }
}

// CHECK: define noundef i32 @ret_two_u16()
#[no_mangle]
pub extern "C" fn ret_two_u16() -> TwoU16 {
TwoU16 { x: 1, y: 2 }
}

// CHECK: define noundef i64 @ret_two_u32()
#[no_mangle]
pub extern "C" fn ret_two_u32() -> TwoU32 {
TwoU32 { x: 1, y: 2 }
}

// Tail padding -> no `noundef`.
// CHECK: define i64 @ret_padded()
#[no_mangle]
pub extern "C" fn ret_padded() -> Padded {
Padded { x: 1, y: 2 }
}

// Union -> no `noundef`.
// CHECK: define i32 @ret_union()
#[no_mangle]
pub extern "C" fn ret_union() -> U {
U { x: 1 }
}
Loading