From 0becc89d4a75d14571b02fb34ec1e3a45c9fb9dc Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 31 Oct 2022 20:38:40 -0700 Subject: [PATCH 01/26] rustc_target: Add alignment to indirectly-passed by-value types, correcting the alignment of `byval` on x86 in the process. Commit 88e4d2c2918428d55e34cd57c11279ea839c8822 from five years ago removed support for alignment on indirectly-passed arguments because of problems with the `i686-pc-windows-msvc` target. Unfortunately, the `memcpy` optimizations I recently added to LLVM 16 depend on this to forward `memcpy`s. This commit attempts to fix the problems with `byval` parameters on that target and now correctly adds the `align` attribute. The problem is summarized in [this comment] by @eddyb. Briefly, 32-bit x86 has special alignment rules for `byval` parameters: for the most part, their alignment is forced to 4. This is not well-documented anywhere but in the Clang source. I looked at the logic in Clang `TargetInfo.cpp` and tried to replicate it here. The relevant methods in that file are `X86_32ABIInfo::getIndirectResult()` and `X86_32ABIInfo::getTypeStackAlignInBytes()`. The `align` parameter attribute for `byval` parameters in LLVM must match the platform ABI, or miscompilations will occur. Note that this doesn't use the approach suggested by eddyb, because I felt it was overkill to store the alignment in `on_stack` when special handling is really only needed for 32-bit x86. As a side effect, this should fix #80127, because it will make the `align` parameter attribute for `byval` parameters match the platform ABI on LLVM x86-64. [this comment]: https://github.com/rust-lang/rust/pull/80822#issuecomment-829985417 --- compiler/rustc_target/src/abi/call/m68k.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 19 ++++-- compiler/rustc_target/src/abi/call/wasm.rs | 2 +- compiler/rustc_target/src/abi/call/x86.rs | 35 +++++++++-- compiler/rustc_target/src/abi/call/x86_64.rs | 2 +- tests/codegen/align-byval.rs | 56 +++++++++++++++++ tests/codegen/function-arguments-noopt.rs | 4 +- tests/codegen/function-arguments.rs | 4 +- .../extern-fn-explicit-align/Makefile | 5 ++ .../run-make/extern-fn-explicit-align/test.c | 35 +++++++++++ .../run-make/extern-fn-explicit-align/test.rs | 61 +++++++++++++++++++ 11 files changed, 208 insertions(+), 17 deletions(-) create mode 100644 tests/codegen/align-byval.rs create mode 100644 tests/run-make/extern-fn-explicit-align/Makefile create mode 100644 tests/run-make/extern-fn-explicit-align/test.c create mode 100644 tests/run-make/extern-fn-explicit-align/test.rs diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/abi/call/m68k.rs index c1e0f54af5f1e..1d4649ed8678e 100644 --- a/compiler/rustc_target/src/abi/call/m68k.rs +++ b/compiler/rustc_target/src/abi/call/m68k.rs @@ -10,7 +10,7 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { if arg.layout.is_aggregate() { - arg.make_indirect_byval(); + arg.make_indirect_byval(None); } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index c4abf6f4b5e49..c4984936cac1a 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -494,9 +494,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { .set(ArgAttribute::NonNull) .set(ArgAttribute::NoUndef); attrs.pointee_size = layout.size; - // FIXME(eddyb) We should be doing this, but at least on - // i686-pc-windows-msvc, it results in wrong stack offsets. - // attrs.pointee_align = Some(layout.align.abi); + attrs.pointee_align = Some(layout.align.abi); let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new()); @@ -513,11 +511,19 @@ impl<'a, Ty> ArgAbi<'a, Ty> { self.mode = Self::indirect_pass_mode(&self.layout); } - pub fn make_indirect_byval(&mut self) { + pub fn make_indirect_byval(&mut self, byval_align: Option) { self.make_indirect(); match self.mode { - PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => { + PassMode::Indirect { ref mut attrs, extra_attrs: _, ref mut on_stack } => { *on_stack = true; + + // Some platforms, like 32-bit x86, change the alignment of the type when passing + // `byval`. Account for that. + if let Some(byval_align) = byval_align { + // On all targets with byval align this is currently true, so let's assert it. + debug_assert!(byval_align >= Align::from_bytes(4).unwrap()); + attrs.pointee_align = Some(byval_align); + } } _ => unreachable!(), } @@ -644,7 +650,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { { if abi == spec::abi::Abi::X86Interrupt { if let Some(arg) = self.args.first_mut() { - arg.make_indirect_byval(); + // FIXME(pcwalton): This probably should use the x86 `byval` ABI... + arg.make_indirect_byval(None); } return Ok(()); } diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs index 44427ee5317c1..0eb2309ecb28b 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/abi/call/wasm.rs @@ -36,7 +36,7 @@ where { arg.extend_integer_width_to(32); if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) { - arg.make_indirect_byval(); + arg.make_indirect_byval(None); } } diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 7c26335dcf4cd..58c0717b7d1b3 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{HasDataLayout, TyAbiInterface}; +use crate::abi::{Align, HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; #[derive(PartialEq)] @@ -53,11 +53,38 @@ where if arg.is_ignore() { continue; } - if arg.layout.is_aggregate() { - arg.make_indirect_byval(); - } else { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); + continue; } + + // We need to compute the alignment of the `byval` argument. The rules can be found in + // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized here, + // they are: + // + // 1. If the natural alignment of the type is less than or equal to 4, the alignment is 4. + // + // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. + // (This doesn't matter here because we ensure we have an aggregate with the check above.) + // + // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector type + // is 16. + // + // 4. If none of these conditions are true, the alignment is 4. + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + let byval_align = if arg.layout.align.abi < align_4 { + align_4 + } else if t.is_like_osx && arg.layout.align.abi >= align_16 { + // FIXME(pcwalton): This is dubious--we should actually be looking inside the type to + // determine if it contains SIMD vector values--but I think it's fine? + align_16 + } else { + align_4 + }; + + arg.make_indirect_byval(Some(byval_align)); } if flavor == Flavor::FastcallOrVectorcall { diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index b1aefaf050727..d1efe97769925 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -213,7 +213,7 @@ where match cls_or_mem { Err(Memory) => { if is_arg { - arg.make_indirect_byval(); + arg.make_indirect_byval(None); } else { // `sret` parameter thus one less integer register available arg.make_indirect(); diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs new file mode 100644 index 0000000000000..35b3b1adc2cdc --- /dev/null +++ b/tests/codegen/align-byval.rs @@ -0,0 +1,56 @@ +// ignore-x86 +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mips64 +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// +// Tests that `byval` alignment is properly specified (#80127). +// The only targets that use `byval` are m68k, wasm, x86-64, and x86. Note that +// x86 has special rules (see #103830), and it's therefore ignored here. + +#[repr(C)] +#[repr(align(16))] +struct Foo { + a: [i32; 16], +} + +extern "C" { + // CHECK: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + fn f(foo: Foo); +} + +pub fn main() { + unsafe { f(Foo { a: [1; 16] }) } +} diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs index 35f31eba3b11e..f99cc8fb41563 100644 --- a/tests/codegen/function-arguments-noopt.rs +++ b/tests/codegen/function-arguments-noopt.rs @@ -42,7 +42,7 @@ pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 { f(x) } -// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %x) +// CHECK: void @struct_({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %x) #[no_mangle] pub fn struct_(x: S) -> S { x @@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S { // CHECK-LABEL: @struct_call #[no_mangle] pub fn struct_call(x: S, f: fn(S) -> S) -> S { - // CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %{{.+}}) + // CHECK: call void %f({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %{{.+}}) f(x) } diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index ccf4a5de327e2..2f047f1031100 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -142,7 +142,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) { pub fn notunpin_borrow(_: &NotUnpin) { } -// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly dereferenceable(32) %_1) +// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly align 4 dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) { } @@ -188,7 +188,7 @@ pub fn notunpin_box(x: Box) -> Box { x } -// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) align 4 dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { diff --git a/tests/run-make/extern-fn-explicit-align/Makefile b/tests/run-make/extern-fn-explicit-align/Makefile new file mode 100644 index 0000000000000..4f5d026f213f2 --- /dev/null +++ b/tests/run-make/extern-fn-explicit-align/Makefile @@ -0,0 +1,5 @@ +include ../tools.mk + +all: $(call NATIVE_STATICLIB,test) + $(RUSTC) test.rs + $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c new file mode 100644 index 0000000000000..a015fc9aaf606 --- /dev/null +++ b/tests/run-make/extern-fn-explicit-align/test.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +struct TwoU64s +{ + uint64_t a; + uint64_t b; +} __attribute__((aligned(16))); + +struct BoolAndU32 +{ + bool a; + uint32_t b; +}; + +int32_t many_args( + void *a, + void *b, + const char *c, + uint64_t d, + bool e, + struct BoolAndU32 f, + void *g, + struct TwoU64s h, + void *i, + void *j, + void *k, + void *l, + const char *m) +{ + assert(strcmp(m, "Hello world") == 0); + return 0; +} diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs new file mode 100644 index 0000000000000..ba6cc87bd1857 --- /dev/null +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -0,0 +1,61 @@ +// Issue #80127: Passing structs via FFI should work with explicit alignment. + +use std::ffi::CString; +use std::ptr::null_mut; + +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +#[repr(align(16))] +pub struct TwoU64s { + pub a: u64, + pub b: u64, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BoolAndU32 { + pub a: bool, + pub b: u32, +} + +#[link(name = "test", kind = "static")] +extern "C" { + fn many_args( + a: *mut (), + b: *mut (), + c: *const i8, + d: u64, + e: bool, + f: BoolAndU32, + g: *mut (), + h: TwoU64s, + i: *mut (), + j: *mut (), + k: *mut (), + l: *mut (), + m: *const i8, + ) -> i32; +} + +fn main() { + let two_u64s = TwoU64s { a: 1, b: 2 }; + let bool_and_u32 = BoolAndU32 { a: true, b: 3 }; + let string = CString::new("Hello world").unwrap(); + unsafe { + many_args( + null_mut(), + null_mut(), + null_mut(), + 4, + true, + bool_and_u32, + null_mut(), + two_u64s, + null_mut(), + null_mut(), + null_mut(), + null_mut(), + string.as_ptr(), + ); + } +} From 102292655b896135be2970cc9b47b26ec3edea55 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 13 May 2023 21:54:54 -0400 Subject: [PATCH 02/26] align-byval test: use revisions to test different targets --- tests/codegen/align-byval.rs | 75 +++++++++++++++++------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 35b3b1adc2cdc..4315c3371e19f 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -1,56 +1,51 @@ -// ignore-x86 -// ignore-aarch64 -// ignore-aarch64_be -// ignore-arm -// ignore-armeb -// ignore-avr -// ignore-bpfel -// ignore-bpfeb -// ignore-hexagon -// ignore-mips -// ignore-mips64 -// ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-powerpc -// ignore-r600 -// ignore-amdgcn -// ignore-sparc -// ignore-sparcv9 -// ignore-sparcel -// ignore-s390x -// ignore-tce -// ignore-thumb -// ignore-thumbeb -// ignore-xcore -// ignore-nvptx -// ignore-nvptx64 -// ignore-le32 -// ignore-le64 -// ignore-amdil -// ignore-amdil64 -// ignore-hsail -// ignore-hsail64 -// ignore-spir -// ignore-spir64 -// ignore-kalimba -// ignore-shave -// +// revisions:m68k wasm x86_64-linux x86_64-windows + +//[m68k] compile-flags: --target m68k-unknown-linux-gnu +//[m68k] needs-llvm-components: m68k +//[wasm] compile-flags: --target wasm32-unknown-emscripten +//[wasm] needs-llvm-components: webassembly +//[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64-linux] needs-llvm-components: x86 +//[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc +//[x86_64-windows] needs-llvm-components: x86 + // Tests that `byval` alignment is properly specified (#80127). // The only targets that use `byval` are m68k, wasm, x86-64, and x86. Note that // x86 has special rules (see #103830), and it's therefore ignored here. +// Note also that Windows mandates a by-ref ABI here, so it does not use byval. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } + +impl Copy for i32 {} +impl Copy for i64 {} #[repr(C)] #[repr(align(16))] struct Foo { a: [i32; 16], + b: i8 } extern "C" { - // CHECK: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + // m68k: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + + // wasm: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + + // x86_64-linux: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + + // x86_64-windows: declare void @f( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 16{{.*}}) fn f(foo: Foo); } pub fn main() { - unsafe { f(Foo { a: [1; 16] }) } + unsafe { f(Foo { a: [1; 16], b: 2 }) } } From be1d4e3e0b97ac07d6a76356a8714c0eaa39610b Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 13 May 2023 22:00:37 -0400 Subject: [PATCH 03/26] update array-map test for removed alloca --- tests/codegen/array-map.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs index 24f3f43d07874..4d218e6a951b2 100644 --- a/tests/codegen/array-map.rs +++ b/tests/codegen/array-map.rs @@ -30,7 +30,6 @@ pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] { pub fn long_integer_map(x: [u32; 512]) -> [u32; 512] { // CHECK: start: // CHECK-NEXT: alloca [512 x i32] - // CHECK-NEXT: alloca %"core::mem::manually_drop::ManuallyDrop<[u32; 512]>" // CHECK-NOT: alloca // CHECK: mul <{{[0-9]+}} x i32> // CHECK: add <{{[0-9]+}} x i32> From a07eb0abbd24e21716d476d7c363270c907f5d2e Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 15 May 2023 00:49:12 -0400 Subject: [PATCH 04/26] implement vector-containing aggregate alignment for x86 darwin --- compiler/rustc_target/src/abi/call/x86.rs | 82 ++++++++++++++--------- tests/codegen/align-byval-vector.rs | 58 ++++++++++++++++ 2 files changed, 109 insertions(+), 31 deletions(-) create mode 100644 tests/codegen/align-byval-vector.rs diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 58c0717b7d1b3..d2c604fafa682 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{Align, HasDataLayout, TyAbiInterface}; +use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; #[derive(PartialEq)] @@ -53,38 +53,58 @@ where if arg.is_ignore() { continue; } - if !arg.layout.is_aggregate() { - arg.extend_integer_width_to(32); - continue; - } - // We need to compute the alignment of the `byval` argument. The rules can be found in - // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized here, - // they are: - // - // 1. If the natural alignment of the type is less than or equal to 4, the alignment is 4. - // - // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. - // (This doesn't matter here because we ensure we have an aggregate with the check above.) - // - // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector type - // is 16. - // - // 4. If none of these conditions are true, the alignment is 4. - let t = cx.target_spec(); - let align_4 = Align::from_bytes(4).unwrap(); - let align_16 = Align::from_bytes(16).unwrap(); - let byval_align = if arg.layout.align.abi < align_4 { - align_4 - } else if t.is_like_osx && arg.layout.align.abi >= align_16 { - // FIXME(pcwalton): This is dubious--we should actually be looking inside the type to - // determine if it contains SIMD vector values--but I think it's fine? - align_16 - } else { - align_4 - }; + if arg.layout.is_aggregate() { + // We need to compute the alignment of the `byval` argument. The rules can be found in + // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized + // here, they are: + // + // 1. If the natural alignment of the type is <= 4, the alignment is 4. + // + // 2. Otherwise, on Linux, the alignment of any vector type is the natural alignment. + // This doesn't matter here because we only pass aggregates via `byval`, not vectors. + // + // 3. Otherwise, on Apple platforms, the alignment of anything that contains a vector + // type is 16. + // + // 4. If none of these conditions are true, the alignment is 4. + + fn contains_vector<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool + where + Ty: TyAbiInterface<'a, C> + Copy, + { + match layout.abi { + Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false, + Abi::Vector { .. } => true, + Abi::Aggregate { .. } => { + for i in 0..layout.fields.count() { + if contains_vector(cx, layout.field(cx, i)) { + return true; + } + } + false + } + } + } - arg.make_indirect_byval(Some(byval_align)); + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + let byval_align = if arg.layout.align.abi < align_4 { + // (1.) + align_4 + } else if t.is_like_osx && contains_vector(cx, arg.layout) { + // (3.) + align_16 + } else { + // (4.) + align_4 + }; + + arg.make_indirect_byval(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } } if flavor == Flavor::FastcallOrVectorcall { diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs new file mode 100644 index 0000000000000..3c8be659671be --- /dev/null +++ b/tests/codegen/align-byval-vector.rs @@ -0,0 +1,58 @@ +// revisions:x86-linux x86-darwin + +//[x86-linux] compile-flags: --target i686-unknown-linux-gnu +//[x86-linux] needs-llvm-components: x86 +//[x86-darwin] compile-flags: --target i686-apple-darwin +//[x86-darwin] needs-llvm-components: x86 + +// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin. + +#![feature(no_core, lang_items, repr_simd, simd_ffi)] +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![allow(non_camel_case_types)] + +#[lang = "sized"] +trait Sized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} + +#[repr(simd)] +pub struct i32x4(i32, i32, i32, i32); + +#[repr(C)] +pub struct Foo { + a: i32x4, + b: i8, +} + +// This tests that we recursively check for vector types, not just at the top level. +#[repr(C)] +pub struct DoubleFoo { + one: Foo, + two: Foo, +} + +extern "C" { + // x86-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}}) + // x86-darwin: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + fn f(foo: Foo); + + // x86-linux: declare void @g({{.*}}byval(%DoubleFoo) align 4{{.*}}) + // x86-darwin: declare void @g({{.*}}byval(%DoubleFoo) align 16{{.*}}) + fn g(foo: DoubleFoo); +} + +pub fn main() { + unsafe { f(Foo { a: i32x4(1, 2, 3, 4), b: 0 }) } + + unsafe { + g(DoubleFoo { + one: Foo { a: i32x4(1, 2, 3, 4), b: 0 }, + two: Foo { a: i32x4(1, 2, 3, 4), b: 0 }, + }) + } +} From 0f7d3337d62927fb6211ce2200c4e0700169e674 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 15 May 2023 17:52:43 -0400 Subject: [PATCH 05/26] add ignore-cross-compile to run-make/extern-fn-explicit-align From the test logs, other extern-fn-* tests have this: [run-make] tests/run-make/extern-fn-with-packed-struct ... ignored, ignored when cross-compiling [run-make] tests/run-make/extern-fn-with-union ... ignored, ignored when cross-compiling [run-make] tests/run-make/extern-multiple-copies ... ignored, ignored when cross-compiling [run-make] tests/run-make/extern-multiple-copies2 ... ignored, ignored when cross-compiling [run-make] tests/run-make/extern-overrides-distribution ... ignored, ignored when cross-compiling [run-make] tests/run-make/extra-filename-with-temp-outputs ... ignored, ignored when cross-compiling [run-make] tests/run-make/extern-fn-explicit-align ... FAILED --- tests/run-make/extern-fn-explicit-align/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/extern-fn-explicit-align/Makefile b/tests/run-make/extern-fn-explicit-align/Makefile index 4f5d026f213f2..3cbbf3839969f 100644 --- a/tests/run-make/extern-fn-explicit-align/Makefile +++ b/tests/run-make/extern-fn-explicit-align/Makefile @@ -1,3 +1,4 @@ +# ignore-cross-compile include ../tools.mk all: $(call NATIVE_STATICLIB,test) From fdaaf86cc03421dc96d755bc9e6c5984b124028d Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Tue, 16 May 2023 20:25:15 -0400 Subject: [PATCH 06/26] add align attr to addr-of-mutate test --- tests/codegen/addr-of-mutate.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs index bea1aad235242..6dfc182501510 100644 --- a/tests/codegen/addr-of-mutate.rs +++ b/tests/codegen/addr-of-mutate.rs @@ -6,7 +6,7 @@ // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. // See . -// CHECK: i8 @foo(ptr noalias nocapture noundef dereferenceable(128) %x) +// CHECK: i8 @foo(ptr noalias nocapture noundef align 1 dereferenceable(128) %x) #[no_mangle] pub fn foo(x: [u8; 128]) -> u8 { let ptr = core::ptr::addr_of!(x).cast_mut(); @@ -16,7 +16,7 @@ pub fn foo(x: [u8; 128]) -> u8 { x[0] } -// CHECK: i1 @second(ptr noalias nocapture noundef dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @second(ptr noalias nocapture noundef align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); @@ -25,7 +25,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { } // If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr noalias nocapture noundef readonly dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @third(ptr noalias nocapture noundef readonly align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); From 84ff2e3d1cf8a2fb55ff639e635b5ab3b8283428 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Wed, 17 May 2023 08:31:35 -0400 Subject: [PATCH 07/26] extern-fn-explicit-align test: use ffi::c_char instead of i8 --- tests/run-make/extern-fn-explicit-align/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index ba6cc87bd1857..cda6777a42f80 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -1,6 +1,6 @@ // Issue #80127: Passing structs via FFI should work with explicit alignment. -use std::ffi::CString; +use std::ffi::{CString, c_char}; use std::ptr::null_mut; #[derive(Clone, Copy, Debug, PartialEq)] @@ -23,7 +23,7 @@ extern "C" { fn many_args( a: *mut (), b: *mut (), - c: *const i8, + c: *const c_char, d: u64, e: bool, f: BoolAndU32, @@ -33,7 +33,7 @@ extern "C" { j: *mut (), k: *mut (), l: *mut (), - m: *const i8, + m: *const c_char, ) -> i32; } From 5f4472e45101dae008f375f6a2a3162500e6bc21 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Thu, 18 May 2023 17:53:03 -0400 Subject: [PATCH 08/26] extern-fn-explicit-align test: add MSVC compatible alignment attribute --- tests/run-make/extern-fn-explicit-align/test.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c index a015fc9aaf606..154b63ff45b39 100644 --- a/tests/run-make/extern-fn-explicit-align/test.c +++ b/tests/run-make/extern-fn-explicit-align/test.c @@ -3,11 +3,20 @@ #include #include +#ifdef _MSC_VER +__declspec(align(16)) struct TwoU64s { uint64_t a; uint64_t b; -} __attribute__((aligned(16))); +}; +#else +struct __attribute__((aligned(16))) TwoU64s +{ + uint64_t a; + uint64_t b; +}; +#endif struct BoolAndU32 { From bc9d26aee6d2c67374cf9961b25a227d5d18d6c0 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 01:24:33 -0400 Subject: [PATCH 09/26] extern-fn-explicit-align test: cleanup --- tests/run-make/extern-fn-explicit-align/test.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index cda6777a42f80..4621c36c4942a 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -1,9 +1,9 @@ // Issue #80127: Passing structs via FFI should work with explicit alignment. -use std::ffi::{CString, c_char}; +use std::ffi::{CStr, c_char}; use std::ptr::null_mut; -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Copy, Clone)] #[repr(C)] #[repr(align(16))] pub struct TwoU64s { @@ -12,7 +12,7 @@ pub struct TwoU64s { } #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Copy, Clone)] pub struct BoolAndU32 { pub a: bool, pub b: u32, @@ -37,10 +37,12 @@ extern "C" { ) -> i32; } +const STRING: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello world\0") }; + fn main() { let two_u64s = TwoU64s { a: 1, b: 2 }; let bool_and_u32 = BoolAndU32 { a: true, b: 3 }; - let string = CString::new("Hello world").unwrap(); + let string = STRING; unsafe { many_args( null_mut(), From 08d18929fbd343cd46e8a8216c0c8d67f9763216 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 01:30:59 -0400 Subject: [PATCH 10/26] align-byval test: add x86 x86 Windows also should not use byval since the struct is overaligned, see https://reviews.llvm.org/D72114 --- tests/codegen/align-byval.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 4315c3371e19f..1470e7bf782a2 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -1,4 +1,4 @@ -// revisions:m68k wasm x86_64-linux x86_64-windows +// revisions:m68k wasm x86_64-linux x86_64-windows i686-linux i686-windows //[m68k] compile-flags: --target m68k-unknown-linux-gnu //[m68k] needs-llvm-components: m68k @@ -8,10 +8,13 @@ //[x86_64-linux] needs-llvm-components: x86 //[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc //[x86_64-windows] needs-llvm-components: x86 +//[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//[i686-linux] needs-llvm-components: x86 +//[i686-windows] compile-flags: --target i686-pc-windows-msvc +//[i686-windows] needs-llvm-components: x86 // Tests that `byval` alignment is properly specified (#80127). -// The only targets that use `byval` are m68k, wasm, x86-64, and x86. Note that -// x86 has special rules (see #103830), and it's therefore ignored here. +// The only targets that use `byval` are m68k, wasm, x86-64, and x86. // Note also that Windows mandates a by-ref ABI here, so it does not use byval. #![feature(no_core, lang_items)] @@ -43,6 +46,12 @@ extern "C" { // x86_64-windows: declare void @f( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 16{{.*}}) + + // i686-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}}) + + // i686-windows: declare void @f( + // i686-windows-NOT: byval + // i686-windows-SAME: align 16{{.*}}) fn f(foo: Foo); } From 8ec90f6f14a5c2c8cc454e78f87b7fc6347fe2f8 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 15:32:37 -0400 Subject: [PATCH 11/26] align-byval test: add cases distinguishing natural vs forced/requested alignment --- tests/codegen/align-byval.rs | 72 +++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 1470e7bf782a2..10ded42bd666d 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -29,32 +29,84 @@ impl Copy for i32 {} impl Copy for i64 {} +// on i686-windows, this should be passed on stack using `byval` +#[repr(C)] +pub struct NaturalAlign8 { + a: i64, + b: i64, + c: i64 +} + +// on i686-windows, this should be passed by reference (because the alignment is requested/forced), +// even though it has the exact same layout as `NaturalAlign8` (!!!) +#[repr(C)] +#[repr(align(8))] +pub struct ForceAlign8 { + a: i64, + b: i64, + c: i64 +} + #[repr(C)] #[repr(align(16))] -struct Foo { +pub struct ForceAlign16 { a: [i32; 16], b: i8 } extern "C" { - // m68k: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + // m68k: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + + // wasm: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}}) + + // x86_64-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}}) + + // x86_64-windows: declare void @natural_align_8( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 8{{.*}}) + + // i686-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + + // i686-windows: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) + fn natural_align_8(x: NaturalAlign8); + + // m68k: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + + // wasm: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + + // x86_64-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}}) + + // x86_64-windows: declare void @force_align_8( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 8{{.*}}) + + // i686-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 4{{.*}}) + + // i686-windows: declare void @force_align_8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn force_align_8(y: ForceAlign8); + + // m68k: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) - // wasm: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + // wasm: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) - // x86_64-linux: declare void @f({{.*}}byval(%Foo) align 16{{.*}}) + // x86_64-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) - // x86_64-windows: declare void @f( + // x86_64-windows: declare void @force_align_16( // x86_64-windows-NOT: byval // x86_64-windows-SAME: align 16{{.*}}) - // i686-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}}) + // i686-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 4{{.*}}) - // i686-windows: declare void @f( + // i686-windows: declare void @force_align_16( // i686-windows-NOT: byval // i686-windows-SAME: align 16{{.*}}) - fn f(foo: Foo); + fn force_align_16(z: ForceAlign16); } -pub fn main() { - unsafe { f(Foo { a: [1; 16], b: 2 }) } +pub unsafe fn main(x: NaturalAlign8, y: ForceAlign8, z: ForceAlign16) { + natural_align_8(x); + force_align_8(y); + force_align_16(z); } From 7089321c6deabb3c25cf0ec829ca209f77b8ee5a Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 15:33:20 -0400 Subject: [PATCH 12/26] extern-fn-struct-passing-abi test: ensure we don't start passing struct with natural alignment > 8 by reference --- .../extern-fn-struct-passing-abi/test.c | 36 +++++++++++++++++++ .../extern-fn-struct-passing-abi/test.rs | 17 +++++++++ 2 files changed, 53 insertions(+) diff --git a/tests/run-make/extern-fn-struct-passing-abi/test.c b/tests/run-make/extern-fn-struct-passing-abi/test.c index 136b07129e1df..2cff776d86ce6 100644 --- a/tests/run-make/extern-fn-struct-passing-abi/test.c +++ b/tests/run-make/extern-fn-struct-passing-abi/test.c @@ -28,6 +28,14 @@ struct Huge { int32_t e; }; +struct Huge64 { + int64_t a; + int64_t b; + int64_t c; + int64_t d; + int64_t e; +}; + struct FloatPoint { double x; double y; @@ -152,6 +160,21 @@ void byval_rect_with_many_huge(struct Huge a, struct Huge b, struct Huge c, assert(g.d == 420); } +// System V x86_64 ABI: +// a, b, d, e, f should be byval pointer (on the stack) +// g passed via register (fixes #41375) +// +// i686-windows ABI: +// a, b, d, e, f, g should be byval pointer +void byval_rect_with_many_huge64(struct Huge64 a, struct Huge64 b, struct Huge64 c, + struct Huge64 d, struct Huge64 e, struct Huge64 f, + struct Rect g) { + assert(g.a == 1234); + assert(g.b == 4567); + assert(g.c == 7890); + assert(g.d == 4209); +} + // System V x86_64 & Win64 ABI: // a, b should be in registers // s should be split across 2 integer registers @@ -279,6 +302,19 @@ struct Huge huge_struct(struct Huge s) { return s; } +// System V x86_64 & i686-windows ABI: +// s should be byval pointer +// return should in a hidden sret pointer +struct Huge64 huge64_struct(struct Huge64 s) { + assert(s.a == 1234); + assert(s.b == 1335); + assert(s.c == 1436); + assert(s.d == 1537); + assert(s.e == 1638); + + return s; +} + // System V x86_64 ABI: // p should be in registers // return should be in registers diff --git a/tests/run-make/extern-fn-struct-passing-abi/test.rs b/tests/run-make/extern-fn-struct-passing-abi/test.rs index afe0f52ef0b28..d58254301cc8f 100644 --- a/tests/run-make/extern-fn-struct-passing-abi/test.rs +++ b/tests/run-make/extern-fn-struct-passing-abi/test.rs @@ -36,6 +36,16 @@ struct Huge { e: i32, } +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct Huge64 { + a: i64, + b: i64, + c: i64, + d: i64, + e: i64, +} + #[derive(Clone, Copy, Debug, PartialEq)] #[repr(C)] struct FloatPoint { @@ -79,6 +89,8 @@ extern "C" { fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect); + fn byval_rect_with_many_huge64(a: Huge64, b: Huge64, c: Huge64, d: Huge64, e: Huge64, f: Huge64, g: Rect); + fn split_rect(a: i32, b: i32, s: Rect); fn split_rect_floats(a: f32, b: f32, s: FloatRect); @@ -95,6 +107,8 @@ extern "C" { fn huge_struct(s: Huge) -> Huge; + fn huge64_struct(s: Huge64) -> Huge64; + fn float_point(p: FloatPoint) -> FloatPoint; fn float_one(f: FloatOne) -> FloatOne; @@ -107,6 +121,7 @@ fn main() { let t = BiggerRect { s: s, a: 27834, b: 7657 }; let u = FloatRect { a: 3489, b: 3490, c: 8. }; let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 }; + let w = Huge64 { a: 1234, b: 1335, c: 1436, d: 1537, e: 1638 }; let p = FloatPoint { x: 5., y: -3. }; let f1 = FloatOne { x: 7. }; let i = IntOdd { a: 1, b: 2, c: 3 }; @@ -117,12 +132,14 @@ fn main() { byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u); byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s); byval_rect_with_many_huge(v, v, v, v, v, v, Rect { a: 123, b: 456, c: 789, d: 420 }); + byval_rect_with_many_huge64(w, w, w, w, w, w, Rect { a: 1234, b: 4567, c: 7890, d: 4209 }); split_rect(1, 2, s); split_rect_floats(1., 2., u); split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s); split_and_byval_rect(1, 2, 3, s, s); split_rect(1, 2, s); assert_eq!(huge_struct(v), v); + assert_eq!(huge64_struct(w), w); assert_eq!(split_ret_byval_struct(1, 2, s), s); assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t); assert_eq!(sret_split_struct(1, 2, s), t); From ed317e4a479b4bacf102188445d03fabfb81a2c5 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 16:11:09 -0400 Subject: [PATCH 13/26] i686-windows: pass arguments with requested alignment > 4 indirectly --- compiler/rustc_middle/src/ty/layout.rs | 9 ++++++ compiler/rustc_target/src/abi/call/x86.rs | 29 ++++++++++++++++--- compiler/rustc_target/src/abi/mod.rs | 8 +++++ compiler/rustc_target/src/lib.rs | 1 + .../extern-fn-struct-passing-abi/test.rs | 6 +++- 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d95b05ef75408..dc116e616fa68 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1104,6 +1104,15 @@ where fn is_unit(this: TyAndLayout<'tcx>) -> bool { matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0) } + + fn repr_options(this: TyAndLayout<'tcx>) -> ReprOptions { + match *this.ty.kind() { + ty::Adt(def, ..) => def.repr(), + _ => { + bug!("TyAndLayout::repr_options({:?}): not applicable", this) + } + } + } } /// Calculates whether a function's ABI can unwind or not. diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index d2c604fafa682..dd52b3cb52096 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -54,7 +54,31 @@ where continue; } - if arg.layout.is_aggregate() { + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 + // See https://reviews.llvm.org/D72114 for Clang behavior + + let t = cx.target_spec(); + let align_4 = Align::from_bytes(4).unwrap(); + let align_16 = Align::from_bytes(16).unwrap(); + + if t.is_like_msvc + && arg.layout.is_adt() + && let Some(requested_align) = arg.layout.repr_options().align + && requested_align > align_4 + { + // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. + // Summarized here: + // - Arguments with _requested_ alignment > 4 are passed indirectly. + // - For backwards compatibility, arguments with natural alignment > 4 are still passed + // on stack (via `byval`). For example, this includes `double`, `int64_t`, + // and structs containing them, provided they lack an explicit alignment attribute. + assert!(arg.layout.align.abi >= requested_align, + "abi alignment {:?} less than requested alignment {:?}", + arg.layout.align.abi, + requested_align + ); + arg.make_indirect(); + } else if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized // here, they are: @@ -87,9 +111,6 @@ where } } - let t = cx.target_spec(); - let align_4 = Align::from_bytes(4).unwrap(); - let align_16 = Align::from_bytes(16).unwrap(); let byval_align = if arg.layout.align.abi < align_4 { // (1.) align_4 diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 589cd3cf96b3e..aecf8b339f0e0 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized { fn is_never(this: TyAndLayout<'a, Self>) -> bool; fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; fn is_unit(this: TyAndLayout<'a, Self>) -> bool; + fn repr_options(this: TyAndLayout<'a, Self>) -> ReprOptions; } impl<'a, Ty> TyAndLayout<'a, Ty> { @@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_unit(self) } + pub fn repr_options(self) -> ReprOptions + where + Ty: TyAbiInterface<'a, C>, + { + Ty::repr_options(self) + } + pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index a7b54766bc623..3307244a21729 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -12,6 +12,7 @@ #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(iter_intersperse)] +#![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/tests/run-make/extern-fn-struct-passing-abi/test.rs b/tests/run-make/extern-fn-struct-passing-abi/test.rs index d58254301cc8f..99e079f98a872 100644 --- a/tests/run-make/extern-fn-struct-passing-abi/test.rs +++ b/tests/run-make/extern-fn-struct-passing-abi/test.rs @@ -89,7 +89,11 @@ extern "C" { fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect); - fn byval_rect_with_many_huge64(a: Huge64, b: Huge64, c: Huge64, d: Huge64, e: Huge64, f: Huge64, g: Rect); + fn byval_rect_with_many_huge64( + a: Huge64, b: Huge64, c: Huge64, + d: Huge64, e: Huge64, f: Huge64, + g: Rect, + ); fn split_rect(a: i32, b: i32, s: Rect); From 209ed071bab1cad917c825c55f3a83feb72cd664 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 20 May 2023 16:54:12 -0400 Subject: [PATCH 14/26] align-byval test: add cases for <= align 4 --- tests/codegen/align-byval.rs | 52 ++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 10ded42bd666d..03641b00c5f7d 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -29,6 +29,19 @@ impl Copy for i32 {} impl Copy for i64 {} +#[repr(C)] +pub struct NaturalAlign2 { + a: [i16; 16], + b: i16, +} + +#[repr(C)] +#[repr(align(4))] +pub struct ForceAlign4 { + a: [i8; 16], + b: i8, +} + // on i686-windows, this should be passed on stack using `byval` #[repr(C)] pub struct NaturalAlign8 { @@ -37,7 +50,7 @@ pub struct NaturalAlign8 { c: i64 } -// on i686-windows, this should be passed by reference (because the alignment is requested/forced), +// on i686-windows, this is passed by reference (because alignment is >4 and requested/forced), // even though it has the exact same layout as `NaturalAlign8` (!!!) #[repr(C)] #[repr(align(8))] @@ -55,6 +68,36 @@ pub struct ForceAlign16 { } extern "C" { + // m68k: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + + // wasm: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + + // x86_64-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) + + // x86_64-windows: declare void @natural_align_2( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 2{{.*}}) + + // i686-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) + + // i686-windows: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) + fn natural_align_2(a: NaturalAlign2); + + // m68k: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + + // wasm: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + + // x86_64-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + + // x86_64-windows: declare void @force_align_4( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 4{{.*}}) + + // i686-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + + // i686-windows: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) + fn force_align_4(b: ForceAlign4); + // m68k: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) // wasm: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}}) @@ -105,7 +148,12 @@ extern "C" { fn force_align_16(z: ForceAlign16); } -pub unsafe fn main(x: NaturalAlign8, y: ForceAlign8, z: ForceAlign16) { +pub unsafe fn main( + a: NaturalAlign2, b: ForceAlign4, + x: NaturalAlign8, y: ForceAlign8, z: ForceAlign16 +) { + natural_align_2(a); + force_align_4(b); natural_align_8(x); force_align_8(y); force_align_16(z); From 0e76446a9ff834b402c352b495cc1bb30c30d3cb Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sat, 10 Jun 2023 22:16:11 -0400 Subject: [PATCH 15/26] ensure byval allocas are sufficiently aligned --- compiler/rustc_codegen_ssa/src/mir/block.rs | 68 ++++++++---- compiler/rustc_codegen_ssa/src/mir/place.rs | 12 +- tests/codegen/align-byval.rs | 116 +++++++++++++++++--- 3 files changed, 157 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 9d1b3ce82661a..07e21225a6f21 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -23,6 +23,8 @@ use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; +use std::cmp; + // Indicates if we are in the middle of merging a BB's successor into it. This // can happen when BB jumps directly to its successor and the successor has no // other predecessors. @@ -1360,36 +1362,58 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Force by-ref if we have to load through a cast pointer. let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => match arg.mode { - PassMode::Indirect { .. } | PassMode::Cast(..) => { + PassMode::Indirect { attrs, .. } => { + // Indirect argument may have higher alignment requirements than the type's alignment. + // This can happen, e.g. when passing types with <4 byte alignment on the stack on x86. + let required_align = match attrs.pointee_align { + Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), + None => arg.layout.align.abi, + }; + let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); + op.val.store(bx, scratch); + (scratch.llval, scratch.align, true) + } + PassMode::Cast(..) => { let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) } _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), }, - Ref(llval, _, align) => { - if arg.is_indirect() && align < arg.layout.align.abi { - // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I - // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't - // have scary latent bugs around. - - let scratch = PlaceRef::alloca(bx, arg.layout); - base::memcpy_ty( - bx, - scratch.llval, - scratch.align, - llval, - align, - op.layout, - MemFlags::empty(), - ); - (scratch.llval, scratch.align, true) - } else { - (llval, align, true) + Ref(llval, _, align) => match arg.mode { + PassMode::Indirect { attrs, .. } => { + let required_align = match attrs.pointee_align { + Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), + None => arg.layout.align.abi, + }; + if align < required_align { + // For `foo(packed.large_field)`, and types with <4 byte alignment on x86, + // alignment requirements may be higher than the type's alignment, so copy + // to a higher-aligned alloca. + let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); + base::memcpy_ty( + bx, + scratch.llval, + scratch.align, + llval, + align, + op.layout, + MemFlags::empty(), + ); + (scratch.llval, scratch.align, true) + } else { + (llval, align, true) + } } - } + _ => (llval, align, true), + }, ZeroSized => match arg.mode { - PassMode::Indirect { .. } => { + PassMode::Indirect { on_stack, .. } => { + if on_stack { + // It doesn't seem like any target can have `byval` ZSTs, so this assert + // is here to replace a would-be untested codepath. + bug!("ZST {op:?} passed on stack with abi {arg:?}"); + } // Though `extern "Rust"` doesn't pass ZSTs, some ABIs pass // a pointer for `repr(C)` structs even when empty, so get // one from an `alloca` (which can be left uninitialized). diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index ab493ae5c1fc0..90eab55f76e76 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -47,10 +47,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn alloca>( bx: &mut Bx, layout: TyAndLayout<'tcx>, + ) -> Self { + Self::alloca_aligned(bx, layout, layout.align.abi) + } + + pub fn alloca_aligned>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + align: Align, ) -> Self { assert!(layout.is_sized(), "tried to statically allocate unsized place"); - let tmp = bx.alloca(bx.cx().backend_type(layout), layout.align.abi); - Self::new_sized(tmp, layout) + let tmp = bx.alloca(bx.cx().backend_type(layout), align); + Self::new_sized_aligned(tmp, layout, align) } /// Returns a place for an indirect reference to an unsized place. diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 03641b00c5f7d..6a9f7fae6a818 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // revisions:m68k wasm x86_64-linux x86_64-windows i686-linux i686-windows //[m68k] compile-flags: --target m68k-unknown-linux-gnu @@ -29,6 +30,16 @@ impl Copy for i32 {} impl Copy for i64 {} +// This struct can be represented as a pair, so it exercises the OperandValue::Pair +// codepath in `codegen_argument`. +#[repr(C)] +pub struct NaturalAlign1 { + a: i8, + b: i8, +} + +// This struct cannot be represented as an immediate, so it exercises the OperandValue::Ref +// codepath in `codegen_argument`. #[repr(C)] pub struct NaturalAlign2 { a: [i16; 16], @@ -67,7 +78,93 @@ pub struct ForceAlign16 { b: i8 } +// CHECK-LABEL: @call_na1 +#[no_mangle] +pub unsafe fn call_na1(x: NaturalAlign1) { + // CHECK: start: + + // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1 + // m68k: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]]) + + // wasm: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1 + // wasm: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]]) + + // x86_64-linux: call void @natural_align_1(i16 + + // x86_64-windows: call void @natural_align_1(i16 + + // i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4 + // i686-linux: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]]) + + // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4 + // i686-windows: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]]) + natural_align_1(x); +} + +// CHECK-LABEL: @call_na2 +#[no_mangle] +pub unsafe fn call_na2(x: NaturalAlign2) { + // CHECK: start: + + // m68k-NEXT: call void @natural_align_2 + // wasm-NEXT: call void @natural_align_2 + // x86_64-linux-NEXT: call void @natural_align_2 + // x86_64-windows-NEXT: call void @natural_align_2 + + // i686-linux: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4 + // i686-linux: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]]) + + // i686-windows: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4 + // i686-windows: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]]) + natural_align_2(x); +} + +// CHECK-LABEL: @call_fa4 +#[no_mangle] +pub unsafe fn call_fa4(x: ForceAlign4) { + // CHECK: start: + // CHECK-NEXT: call void @force_align_4 + force_align_4(x); +} + +// CHECK-LABEL: @call_na8 +#[no_mangle] +pub unsafe fn call_na8(x: NaturalAlign8) { + // CHECK: start: + // CHECK-NEXT: call void @natural_align_8 + natural_align_8(x); +} + +// CHECK-LABEL: @call_fa8 +#[no_mangle] +pub unsafe fn call_fa8(x: ForceAlign8) { + // CHECK: start: + // CHECK-NEXT: call void @force_align_8 + force_align_8(x); +} + +// CHECK-LABEL: @call_fa16 +#[no_mangle] +pub unsafe fn call_fa16(x: ForceAlign16) { + // CHECK: start: + // CHECK-NEXT: call void @force_align_16 + force_align_16(x); +} + extern "C" { + // m68k: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}}) + + // wasm: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}}) + + // x86_64-linux: declare void @natural_align_1(i16) + + // x86_64-windows: declare void @natural_align_1(i16) + + // i686-linux: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}}) + + // i686-windows: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}}) + fn natural_align_1(x: NaturalAlign1); + // m68k: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) // wasm: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}}) @@ -81,7 +178,7 @@ extern "C" { // i686-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) // i686-windows: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}}) - fn natural_align_2(a: NaturalAlign2); + fn natural_align_2(x: NaturalAlign2); // m68k: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) @@ -96,7 +193,7 @@ extern "C" { // i686-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) // i686-windows: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}}) - fn force_align_4(b: ForceAlign4); + fn force_align_4(x: ForceAlign4); // m68k: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}}) @@ -128,7 +225,7 @@ extern "C" { // i686-windows: declare void @force_align_8( // i686-windows-NOT: byval // i686-windows-SAME: align 8{{.*}}) - fn force_align_8(y: ForceAlign8); + fn force_align_8(x: ForceAlign8); // m68k: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) @@ -145,16 +242,5 @@ extern "C" { // i686-windows: declare void @force_align_16( // i686-windows-NOT: byval // i686-windows-SAME: align 16{{.*}}) - fn force_align_16(z: ForceAlign16); -} - -pub unsafe fn main( - a: NaturalAlign2, b: ForceAlign4, - x: NaturalAlign8, y: ForceAlign8, z: ForceAlign16 -) { - natural_align_2(a); - force_align_4(b); - natural_align_8(x); - force_align_8(y); - force_align_16(z); + fn force_align_16(x: ForceAlign16); } From f704396c0e26fd6de1cfb4e03e1749e9829a11ea Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 13:40:47 -0400 Subject: [PATCH 16/26] align-byval test: add cases for lower requested alignment, wrapped, and repr(transparent) --- tests/codegen/align-byval.rs | 103 ++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 6a9f7fae6a818..2c64230bfd0b8 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -53,7 +53,7 @@ pub struct ForceAlign4 { b: i8, } -// on i686-windows, this should be passed on stack using `byval` +// On i686-windows, this is passed on stack using `byval` #[repr(C)] pub struct NaturalAlign8 { a: i64, @@ -61,8 +61,8 @@ pub struct NaturalAlign8 { c: i64 } -// on i686-windows, this is passed by reference (because alignment is >4 and requested/forced), -// even though it has the exact same layout as `NaturalAlign8` (!!!) +// On i686-windows, this is passed by reference (because alignment is >4 and requested/forced), +// even though it has the exact same layout as `NaturalAlign8`! #[repr(C)] #[repr(align(8))] pub struct ForceAlign8 { @@ -71,6 +71,30 @@ pub struct ForceAlign8 { c: i64 } +// On i686-windows, this is passed by reference because alignment is requested, +// even though the requested alignment is less than the natural alignment. +#[repr(C)] +#[repr(align(1))] +pub struct LowerFA8 { + a: i64, + b: i64, + c: i64 +} + +// On i686-windows, this is passed on stack again, because the wrapper struct does not have +// requested/forced alignment. +#[repr(C)] +pub struct WrappedFA8 { + a: ForceAlign8 +} + +// On i686-windows, this has the same ABI as ForceAlign8, i.e. passed by reference. +#[repr(transparent)] +pub struct TransparentFA8 { + _0: (), + a: ForceAlign8 +} + #[repr(C)] #[repr(align(16))] pub struct ForceAlign16 { @@ -143,6 +167,30 @@ pub unsafe fn call_fa8(x: ForceAlign8) { force_align_8(x); } +// CHECK-LABEL: @call_lfa8 +#[no_mangle] +pub unsafe fn call_lfa8(x: LowerFA8) { + // CHECK: start: + // CHECK-NEXT: call void @lower_fa8 + lower_fa8(x); +} + +// CHECK-LABEL: @call_wfa8 +#[no_mangle] +pub unsafe fn call_wfa8(x: WrappedFA8) { + // CHECK: start: + // CHECK-NEXT: call void @wrapped_fa8 + wrapped_fa8(x); +} + +// CHECK-LABEL: @call_tfa8 +#[no_mangle] +pub unsafe fn call_tfa8(x: TransparentFA8) { + // CHECK: start: + // CHECK-NEXT: call void @transparent_fa8 + transparent_fa8(x); +} + // CHECK-LABEL: @call_fa16 #[no_mangle] pub unsafe fn call_fa16(x: ForceAlign16) { @@ -227,6 +275,55 @@ extern "C" { // i686-windows-SAME: align 8{{.*}}) fn force_align_8(x: ForceAlign8); + // m68k: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) + + // wasm: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}}) + + // x86_64-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}}) + + // x86_64-windows: declare void @lower_fa8( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 8{{.*}}) + + // i686-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) + + // i686-windows: declare void @lower_fa8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn lower_fa8(x: LowerFA8); + + // m68k: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + + // wasm: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + + // x86_64-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) + + // x86_64-windows: declare void @wrapped_fa8( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 8{{.*}}) + + // i686-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}}) + + // i686-windows: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}}) + fn wrapped_fa8(x: WrappedFA8); + + // m68k: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + + // wasm: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + + // x86_64-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) + + // x86_64-windows: declare void @transparent_fa8( + // x86_64-windows-NOT: byval + // x86_64-windows-SAME: align 8{{.*}}) + + // i686-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 4{{.*}}) + + // i686-windows: declare void @transparent_fa8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) + fn transparent_fa8(x: TransparentFA8); + // m68k: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) // wasm: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}}) From 65d11b5c6562c57d61bf0db88736da06b8b77423 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 13:41:46 -0400 Subject: [PATCH 17/26] extern-fn-explicit-align test: add wrapped and lower requested alignment, improve assertions --- .../run-make/extern-fn-explicit-align/test.c | 48 +++++++++++++++++-- .../run-make/extern-fn-explicit-align/test.rs | 36 ++++++++++---- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c index 154b63ff45b39..292e7a822b594 100644 --- a/tests/run-make/extern-fn-explicit-align/test.c +++ b/tests/run-make/extern-fn-explicit-align/test.c @@ -3,6 +3,12 @@ #include #include +struct BoolAndU32 +{ + bool a; + uint32_t b; +}; + #ifdef _MSC_VER __declspec(align(16)) struct TwoU64s @@ -18,12 +24,28 @@ struct __attribute__((aligned(16))) TwoU64s }; #endif -struct BoolAndU32 +struct WrappedU64s { - bool a; - uint32_t b; + struct TwoU64s a; }; +#ifdef _MSC_VER +__declspec(align(1)) +struct LowerAlign +{ + uint64_t a; + uint64_t b; +}; +#else +struct __attribute__((aligned(1))) LowerAlign +{ + uint64_t a; + uint64_t b; +}; +#endif + + + int32_t many_args( void *a, void *b, @@ -34,11 +56,27 @@ int32_t many_args( void *g, struct TwoU64s h, void *i, - void *j, + struct WrappedU64s j, void *k, - void *l, + struct LowerAlign l, const char *m) { + assert(!a); + assert(!b); + assert(!c); + assert(d == 42); + assert(e); + assert(f.a); + assert(f.b == 1337); + assert(!g); + assert(h.a == 1); + assert(h.b == 2); + assert(!i); + assert(j.a.a == 3); + assert(j.a.b == 4); + assert(!k); + assert(l.a == 5); + assert(l.b == 6); assert(strcmp(m, "Hello world") == 0); return 0; } diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index 4621c36c4942a..c5b3e24048ee1 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -3,6 +3,13 @@ use std::ffi::{CStr, c_char}; use std::ptr::null_mut; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct BoolAndU32 { + pub a: bool, + pub b: u32, +} + #[derive(Copy, Clone)] #[repr(C)] #[repr(align(16))] @@ -11,11 +18,20 @@ pub struct TwoU64s { pub b: u64, } +#[derive(Copy, Clone)] #[repr(C)] +pub struct WrappedU64s { + pub a: TwoU64s +} + #[derive(Copy, Clone)] -pub struct BoolAndU32 { - pub a: bool, - pub b: u32, +#[repr(C)] +// Even though requesting align 1 can never change the alignment, it still affects the ABI +// on some platforms like i686-windows. +#[repr(align(1))] +pub struct LowerAlign { + pub a: u64, + pub b: u64, } #[link(name = "test", kind = "static")] @@ -30,9 +46,9 @@ extern "C" { g: *mut (), h: TwoU64s, i: *mut (), - j: *mut (), + j: WrappedU64s, k: *mut (), - l: *mut (), + l: LowerAlign, m: *const c_char, ) -> i32; } @@ -40,23 +56,25 @@ extern "C" { const STRING: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello world\0") }; fn main() { + let bool_and_u32 = BoolAndU32 { a: true, b: 1337 }; let two_u64s = TwoU64s { a: 1, b: 2 }; - let bool_and_u32 = BoolAndU32 { a: true, b: 3 }; + let wrapped = WrappedU64s { a: TwoU64s { a: 3, b: 4 } }; + let lower = LowerAlign { a: 5, b: 6 }; let string = STRING; unsafe { many_args( null_mut(), null_mut(), null_mut(), - 4, + 42, true, bool_and_u32, null_mut(), two_u64s, null_mut(), + wrapped, null_mut(), - null_mut(), - null_mut(), + lower, string.as_ptr(), ); } From 00b3eca0dfab4ccebbfb6614b83235cc82f9245f Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 13:43:49 -0400 Subject: [PATCH 18/26] move has_repr to layout, handle repr(transparent) properly --- compiler/rustc_abi/src/layout.rs | 14 ++++++++++++++ compiler/rustc_abi/src/lib.rs | 13 ++++++++++++- compiler/rustc_middle/src/ty/layout.rs | 10 +--------- compiler/rustc_target/src/abi/call/x86.rs | 9 ++------- compiler/rustc_target/src/abi/mod.rs | 8 -------- compiler/rustc_ty_utils/src/layout.rs | 5 +++++ 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index f6875d895d302..efae34e95df25 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -40,6 +40,7 @@ pub trait LayoutCalculator { largest_niche, align, size, + has_repr_align: false, } } @@ -122,6 +123,7 @@ pub trait LayoutCalculator { largest_niche: None, align: dl.i8_align, size: Size::ZERO, + has_repr_align: false, } } @@ -422,6 +424,7 @@ pub trait LayoutCalculator { largest_niche, size, align, + has_repr_align: repr.align.is_some(), }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -691,6 +694,7 @@ pub trait LayoutCalculator { abi, align, size, + has_repr_align: repr.align.is_some(), }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -809,6 +813,7 @@ pub trait LayoutCalculator { largest_niche: None, align, size: size.align_to(align.abi), + has_repr_align: repr.align.is_some(), }) } } @@ -1036,6 +1041,7 @@ fn univariant( inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect() }; let size = min_size.align_to(align.abi); + let mut layout_of_single_non_zst_field = None; let mut abi = Abi::Aggregate { sized }; // Unpack newtype ABIs and find scalar pairs. if sized && size.bytes() > 0 { @@ -1045,6 +1051,8 @@ fn univariant( match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { // We have exactly one non-ZST field. (Some((i, field)), None, None) => { + layout_of_single_non_zst_field = Some(field); + // Field fills the struct and it has a scalar or scalar pair ABI. if offsets[i].bytes() == 0 && align.abi == field.align().abi && size == field.size() { @@ -1102,6 +1110,11 @@ fn univariant( if fields.iter().any(|f| f.abi().is_uninhabited()) { abi = Abi::Uninhabited; } + + let has_repr_align = repr.align.is_some() + || repr.transparent() + && layout_of_single_non_zst_field.map_or(false, |l| l.has_repr_align()); + Some(LayoutS { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Arbitrary { offsets, memory_index }, @@ -1109,6 +1122,7 @@ fn univariant( largest_niche, align, size, + has_repr_align, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index e1b9987f57816..4cf6289ae008e 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1531,6 +1531,11 @@ pub struct LayoutS { pub align: AbiAndPrefAlign, pub size: Size, + + /// True if the alignment was explicitly requested with `repr(align)`. + /// Only used on i686-windows, where the argument passing ABI is different when alignment is + /// requested, even if the requested alignment is equal to or less than the natural alignment. + pub has_repr_align: bool, } impl LayoutS { @@ -1545,6 +1550,7 @@ impl LayoutS { largest_niche, size, align, + has_repr_align: false, } } } @@ -1554,7 +1560,7 @@ impl fmt::Debug for LayoutS { // This is how `Layout` used to print before it become // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { size, align, abi, fields, largest_niche, variants } = self; + let LayoutS { size, align, abi, fields, largest_niche, variants, has_repr_align } = self; f.debug_struct("Layout") .field("size", size) .field("align", align) @@ -1562,6 +1568,7 @@ impl fmt::Debug for LayoutS { .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) + .field("has_repr_align", has_repr_align) .finish() } } @@ -1602,6 +1609,10 @@ impl<'a> Layout<'a> { self.0.0.size } + pub fn has_repr_align(self) -> bool { + self.0.0.has_repr_align + } + /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. /// /// Currently, that means that the type is pointer-sized, pointer-aligned, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dc116e616fa68..cdf9cd8c809c4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -755,6 +755,7 @@ where largest_niche: None, align: tcx.data_layout.i8_align, size: Size::ZERO, + has_repr_align: false, }) } @@ -1104,15 +1105,6 @@ where fn is_unit(this: TyAndLayout<'tcx>) -> bool { matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0) } - - fn repr_options(this: TyAndLayout<'tcx>) -> ReprOptions { - match *this.ty.kind() { - ty::Adt(def, ..) => def.repr(), - _ => { - bug!("TyAndLayout::repr_options({:?}): not applicable", this) - } - } - } } /// Calculates whether a function's ABI can unwind or not. diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index dd52b3cb52096..9d3f9413afd90 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -63,8 +63,8 @@ where if t.is_like_msvc && arg.layout.is_adt() - && let Some(requested_align) = arg.layout.repr_options().align - && requested_align > align_4 + && arg.layout.has_repr_align + && arg.layout.align.abi > align_4 { // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. // Summarized here: @@ -72,11 +72,6 @@ where // - For backwards compatibility, arguments with natural alignment > 4 are still passed // on stack (via `byval`). For example, this includes `double`, `int64_t`, // and structs containing them, provided they lack an explicit alignment attribute. - assert!(arg.layout.align.abi >= requested_align, - "abi alignment {:?} less than requested alignment {:?}", - arg.layout.align.abi, - requested_align - ); arg.make_indirect(); } else if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index aecf8b339f0e0..589cd3cf96b3e 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -55,7 +55,6 @@ pub trait TyAbiInterface<'a, C>: Sized { fn is_never(this: TyAndLayout<'a, Self>) -> bool; fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; fn is_unit(this: TyAndLayout<'a, Self>) -> bool; - fn repr_options(this: TyAndLayout<'a, Self>) -> ReprOptions; } impl<'a, Ty> TyAndLayout<'a, Ty> { @@ -126,13 +125,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_unit(self) } - pub fn repr_options(self) -> ReprOptions - where - Ty: TyAbiInterface<'a, C>, - { - Ty::repr_options(self) - } - pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index b67cd96a7347c..f693263ac958a 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -258,6 +258,7 @@ fn layout_of_uncached<'tcx>( largest_niche, align: element.align, size, + has_repr_align: false, }) } ty::Slice(element) => { @@ -269,6 +270,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: element.align, size: Size::ZERO, + has_repr_align: false, }) } ty::Str => tcx.mk_layout(LayoutS { @@ -278,6 +280,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: dl.i8_align, size: Size::ZERO, + has_repr_align: false, }), // Odd unit types. @@ -431,6 +434,7 @@ fn layout_of_uncached<'tcx>( largest_niche: e_ly.largest_niche, size, align, + has_repr_align: false, }) } @@ -879,6 +883,7 @@ fn generator_layout<'tcx>( largest_niche: prefix.largest_niche, size, align, + has_repr_align: false, }); debug!("generator layout ({:?}): {:#?}", ty, layout); Ok(layout) From 4c1dbc3aec35daca455c9ba7e440651bcf16069a Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 13:47:35 -0400 Subject: [PATCH 19/26] bless layout tests for has_repr_align in debug output --- tests/ui/layout/debug.stderr | 18 ++++++++++++++++++ tests/ui/layout/hexagon-enum.stderr | 10 ++++++++++ ...8-scalarpair-payload-might-be-uninit.stderr | 17 +++++++++++++++++ .../layout/issue-96185-overaligned-enum.stderr | 6 ++++++ tests/ui/layout/thumb-enum.stderr | 10 ++++++++++ .../layout/zero-sized-array-enum-niche.stderr | 13 +++++++++++++ 6 files changed, 74 insertions(+) diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index b9fa1b299e969..4f27eaae8d8e0 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -53,6 +53,7 @@ error: layout_of(E) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(12 bytes), @@ -77,9 +78,11 @@ error: layout_of(E) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/debug.rs:7:1 | @@ -124,6 +127,7 @@ error: layout_of(S) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:10:1 | @@ -146,6 +150,7 @@ error: layout_of(U) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:13:1 | @@ -237,6 +242,7 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(8 bytes), @@ -272,9 +278,11 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/debug.rs:16:1 | @@ -301,6 +309,7 @@ error: layout_of(i32) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:19:1 | @@ -323,6 +332,7 @@ error: layout_of(V) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:22:1 | @@ -345,6 +355,7 @@ error: layout_of(W) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:28:1 | @@ -367,6 +378,7 @@ error: layout_of(Y) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:34:1 | @@ -389,6 +401,7 @@ error: layout_of(P1) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:41:1 | @@ -411,6 +424,7 @@ error: layout_of(P2) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:45:1 | @@ -433,6 +447,7 @@ error: layout_of(P3) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:53:1 | @@ -455,6 +470,7 @@ error: layout_of(P4) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:57:1 | @@ -482,6 +498,7 @@ error: layout_of(P5) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:61:1 | @@ -509,6 +526,7 @@ error: layout_of(std::mem::MaybeUninit) = Layout { variants: Single { index: 0, }, + has_repr_align: false, } --> $DIR/debug.rs:64:1 | diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index d850dd69c96e3..08c4e547ff23c 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -59,9 +59,11 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/hexagon-enum.rs:16:1 | @@ -129,9 +131,11 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/hexagon-enum.rs:20:1 | @@ -199,9 +203,11 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/hexagon-enum.rs:24:1 | @@ -269,9 +275,11 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/hexagon-enum.rs:28:1 | @@ -339,9 +347,11 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/hexagon-enum.rs:34:1 | diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 8c7c915350f19..5fae4d9a6a51e 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -81,6 +81,7 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(1 bytes), @@ -99,9 +100,11 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 | @@ -193,6 +196,7 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(2 bytes), @@ -228,9 +232,11 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 | @@ -320,6 +326,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(2 bytes), @@ -354,9 +361,11 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 | @@ -462,6 +471,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(0 bytes), @@ -480,6 +490,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, Layout { size: Size(0 bytes), @@ -498,9 +509,11 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 2, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 | @@ -606,6 +619,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(0 bytes), @@ -624,6 +638,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, Layout { size: Size(0 bytes), @@ -642,9 +657,11 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 2, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 | diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index de6177c8dfc4d..fe1d4392b673d 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -53,6 +53,7 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 0, }, + has_repr_align: true, }, Layout { size: Size(8 bytes), @@ -71,9 +72,11 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 1, }, + has_repr_align: true, }, ], }, + has_repr_align: true, } --> $DIR/issue-96185-overaligned-enum.rs:8:1 | @@ -141,6 +144,7 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 0, }, + has_repr_align: true, }, Layout { size: Size(1 bytes), @@ -159,9 +163,11 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 1, }, + has_repr_align: true, }, ], }, + has_repr_align: true, } --> $DIR/issue-96185-overaligned-enum.rs:16:1 | diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 227bd950b6666..7aca1aa462e3a 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -59,9 +59,11 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/thumb-enum.rs:16:1 | @@ -129,9 +131,11 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/thumb-enum.rs:20:1 | @@ -199,9 +203,11 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/thumb-enum.rs:24:1 | @@ -269,9 +275,11 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/thumb-enum.rs:28:1 | @@ -339,9 +347,11 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/thumb-enum.rs:34:1 | diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index a3e82070e0f52..8342d64b6fe6d 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -57,6 +57,7 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(2 bytes), @@ -88,9 +89,11 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/zero-sized-array-enum-niche.rs:13:1 | @@ -156,6 +159,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(4 bytes), @@ -178,6 +182,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, Layout { size: Size(2 bytes), @@ -209,9 +214,11 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 2, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/zero-sized-array-enum-niche.rs:21:1 | @@ -277,6 +284,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(3 bytes), @@ -308,9 +316,11 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/zero-sized-array-enum-niche.rs:37:1 | @@ -380,6 +390,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 0, }, + has_repr_align: false, }, Layout { size: Size(2 bytes), @@ -411,9 +422,11 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 1, }, + has_repr_align: false, }, ], }, + has_repr_align: false, } --> $DIR/zero-sized-array-enum-niche.rs:44:1 | From 2591c30eaf30425812f42beb47bd2615a533e961 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 14:00:33 -0400 Subject: [PATCH 20/26] cg_clif: add has_repr_align --- compiler/rustc_codegen_cranelift/src/abi/comments.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 364503fd3639a..f1ada7b72190c 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -83,6 +83,7 @@ pub(super) fn add_local_place_comments<'tcx>( let rustc_target::abi::LayoutS { size, align, + has_repr_align: _, abi: _, variants: _, fields: _, From 7e933b4e26947b04da70589110dacbdb2461e27d Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 11 Jun 2023 17:05:26 -0400 Subject: [PATCH 21/26] repr(align) <= 4 should still be byval --- compiler/rustc_abi/src/layout.rs | 18 +++++----- compiler/rustc_abi/src/lib.rs | 16 ++++----- .../src/abi/comments.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_target/src/abi/call/x86.rs | 8 +++-- compiler/rustc_ty_utils/src/layout.rs | 10 +++--- tests/codegen/align-byval.rs | 11 +++--- tests/ui/layout/debug.stderr | 36 +++++++++---------- tests/ui/layout/hexagon-enum.stderr | 20 +++++------ ...-scalarpair-payload-might-be-uninit.stderr | 34 +++++++++--------- .../issue-96185-overaligned-enum.stderr | 24 +++++++++---- tests/ui/layout/thumb-enum.stderr | 20 +++++------ .../layout/zero-sized-array-enum-niche.stderr | 26 +++++++------- 13 files changed, 120 insertions(+), 107 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index efae34e95df25..ff811be3c8139 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -40,7 +40,7 @@ pub trait LayoutCalculator { largest_niche, align, size, - has_repr_align: false, + repr_align: None, } } @@ -123,7 +123,7 @@ pub trait LayoutCalculator { largest_niche: None, align: dl.i8_align, size: Size::ZERO, - has_repr_align: false, + repr_align: None, } } @@ -424,7 +424,7 @@ pub trait LayoutCalculator { largest_niche, size, align, - has_repr_align: repr.align.is_some(), + repr_align: repr.align, }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -694,7 +694,7 @@ pub trait LayoutCalculator { abi, align, size, - has_repr_align: repr.align.is_some(), + repr_align: repr.align, }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -813,7 +813,7 @@ pub trait LayoutCalculator { largest_niche: None, align, size: size.align_to(align.abi), - has_repr_align: repr.align.is_some(), + repr_align: repr.align, }) } } @@ -1111,9 +1111,9 @@ fn univariant( abi = Abi::Uninhabited; } - let has_repr_align = repr.align.is_some() - || repr.transparent() - && layout_of_single_non_zst_field.map_or(false, |l| l.has_repr_align()); + let repr_align = repr.align.or_else(|| { + if repr.transparent() { layout_of_single_non_zst_field?.repr_align() } else { None } + }); Some(LayoutS { variants: Variants::Single { index: FIRST_VARIANT }, @@ -1122,7 +1122,7 @@ fn univariant( largest_niche, align, size, - has_repr_align, + repr_align, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 4cf6289ae008e..b1577add4d024 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1532,10 +1532,10 @@ pub struct LayoutS { pub align: AbiAndPrefAlign, pub size: Size, - /// True if the alignment was explicitly requested with `repr(align)`. + /// The alignment explicitly requested with `repr(align)`. /// Only used on i686-windows, where the argument passing ABI is different when alignment is - /// requested, even if the requested alignment is equal to or less than the natural alignment. - pub has_repr_align: bool, + /// requested, even if the requested alignment is equal to the natural alignment. + pub repr_align: Option, } impl LayoutS { @@ -1550,7 +1550,7 @@ impl LayoutS { largest_niche, size, align, - has_repr_align: false, + repr_align: None, } } } @@ -1560,7 +1560,7 @@ impl fmt::Debug for LayoutS { // This is how `Layout` used to print before it become // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { size, align, abi, fields, largest_niche, variants, has_repr_align } = self; + let LayoutS { size, align, abi, fields, largest_niche, variants, repr_align } = self; f.debug_struct("Layout") .field("size", size) .field("align", align) @@ -1568,7 +1568,7 @@ impl fmt::Debug for LayoutS { .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) - .field("has_repr_align", has_repr_align) + .field("repr_align", repr_align) .finish() } } @@ -1609,8 +1609,8 @@ impl<'a> Layout<'a> { self.0.0.size } - pub fn has_repr_align(self) -> bool { - self.0.0.has_repr_align + pub fn repr_align(self) -> Option { + self.0.0.repr_align } /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index f1ada7b72190c..97f8452a46814 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -83,7 +83,7 @@ pub(super) fn add_local_place_comments<'tcx>( let rustc_target::abi::LayoutS { size, align, - has_repr_align: _, + repr_align: _, abi: _, variants: _, fields: _, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cdf9cd8c809c4..ffebbab04a6c2 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -755,7 +755,7 @@ where largest_niche: None, align: tcx.data_layout.i8_align, size: Size::ZERO, - has_repr_align: false, + repr_align: None, }) } diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 9d3f9413afd90..e429215106573 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -63,8 +63,8 @@ where if t.is_like_msvc && arg.layout.is_adt() - && arg.layout.has_repr_align - && arg.layout.align.abi > align_4 + && let Some(repr_align) = arg.layout.repr_align + && repr_align > align_4 { // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. // Summarized here: @@ -72,6 +72,10 @@ where // - For backwards compatibility, arguments with natural alignment > 4 are still passed // on stack (via `byval`). For example, this includes `double`, `int64_t`, // and structs containing them, provided they lack an explicit alignment attribute. + assert!(arg.layout.align.abi >= repr_align, + "abi alignment {:?} less than requested alignment {repr_align:?}", + arg.layout.align.abi, + ); arg.make_indirect(); } else if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f693263ac958a..4fbc6b9400f87 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -258,7 +258,7 @@ fn layout_of_uncached<'tcx>( largest_niche, align: element.align, size, - has_repr_align: false, + repr_align: None, }) } ty::Slice(element) => { @@ -270,7 +270,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: element.align, size: Size::ZERO, - has_repr_align: false, + repr_align: None, }) } ty::Str => tcx.mk_layout(LayoutS { @@ -280,7 +280,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: dl.i8_align, size: Size::ZERO, - has_repr_align: false, + repr_align: None, }), // Odd unit types. @@ -434,7 +434,7 @@ fn layout_of_uncached<'tcx>( largest_niche: e_ly.largest_niche, size, align, - has_repr_align: false, + repr_align: None, }) } @@ -883,7 +883,7 @@ fn generator_layout<'tcx>( largest_niche: prefix.largest_niche, size, align, - has_repr_align: false, + repr_align: None, }); debug!("generator layout ({:?}): {:#?}", ty, layout); Ok(layout) diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index 2c64230bfd0b8..fc5f795bf6726 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -71,17 +71,16 @@ pub struct ForceAlign8 { c: i64 } -// On i686-windows, this is passed by reference because alignment is requested, -// even though the requested alignment is less than the natural alignment. +// On i686-windows, this is passed on stack, because requested alignment is <=4. #[repr(C)] -#[repr(align(1))] +#[repr(align(4))] pub struct LowerFA8 { a: i64, b: i64, c: i64 } -// On i686-windows, this is passed on stack again, because the wrapper struct does not have +// On i686-windows, this is passed on stack, because the wrapper struct does not have // requested/forced alignment. #[repr(C)] pub struct WrappedFA8 { @@ -287,9 +286,7 @@ extern "C" { // i686-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) - // i686-windows: declare void @lower_fa8( - // i686-windows-NOT: byval - // i686-windows-SAME: align 8{{.*}}) + // i686-windows: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}}) fn lower_fa8(x: LowerFA8); // m68k: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}}) diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 4f27eaae8d8e0..99022fb11b5b3 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -53,7 +53,7 @@ error: layout_of(E) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(12 bytes), @@ -78,11 +78,11 @@ error: layout_of(E) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:7:1 | @@ -127,7 +127,7 @@ error: layout_of(S) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:10:1 | @@ -150,7 +150,7 @@ error: layout_of(U) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:13:1 | @@ -242,7 +242,7 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(8 bytes), @@ -278,11 +278,11 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:16:1 | @@ -309,7 +309,7 @@ error: layout_of(i32) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:19:1 | @@ -332,7 +332,7 @@ error: layout_of(V) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:22:1 | @@ -355,7 +355,7 @@ error: layout_of(W) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:28:1 | @@ -378,7 +378,7 @@ error: layout_of(Y) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:34:1 | @@ -401,7 +401,7 @@ error: layout_of(P1) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:41:1 | @@ -424,7 +424,7 @@ error: layout_of(P2) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:45:1 | @@ -447,7 +447,7 @@ error: layout_of(P3) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:53:1 | @@ -470,7 +470,7 @@ error: layout_of(P4) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:57:1 | @@ -498,7 +498,7 @@ error: layout_of(P5) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:61:1 | @@ -526,7 +526,7 @@ error: layout_of(std::mem::MaybeUninit) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, } --> $DIR/debug.rs:64:1 | diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index 08c4e547ff23c..a907853585da7 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -59,11 +59,11 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/hexagon-enum.rs:16:1 | @@ -131,11 +131,11 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/hexagon-enum.rs:20:1 | @@ -203,11 +203,11 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/hexagon-enum.rs:24:1 | @@ -275,11 +275,11 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/hexagon-enum.rs:28:1 | @@ -347,11 +347,11 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/hexagon-enum.rs:34:1 | diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 5fae4d9a6a51e..2db6ab9bc899b 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -81,7 +81,7 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(1 bytes), @@ -100,11 +100,11 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 | @@ -196,7 +196,7 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(2 bytes), @@ -232,11 +232,11 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 | @@ -326,7 +326,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(2 bytes), @@ -361,11 +361,11 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 | @@ -471,7 +471,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(0 bytes), @@ -490,7 +490,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(0 bytes), @@ -509,11 +509,11 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 2, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 | @@ -619,7 +619,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(0 bytes), @@ -638,7 +638,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(0 bytes), @@ -657,11 +657,11 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 2, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 | diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index fe1d4392b673d..3a0ad07347dda 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -53,7 +53,9 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 0, }, - has_repr_align: true, + repr_align: Some( + Align(8 bytes), + ), }, Layout { size: Size(8 bytes), @@ -72,11 +74,15 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 1, }, - has_repr_align: true, + repr_align: Some( + Align(8 bytes), + ), }, ], }, - has_repr_align: true, + repr_align: Some( + Align(8 bytes), + ), } --> $DIR/issue-96185-overaligned-enum.rs:8:1 | @@ -144,7 +150,9 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 0, }, - has_repr_align: true, + repr_align: Some( + Align(1 bytes), + ), }, Layout { size: Size(1 bytes), @@ -163,11 +171,15 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 1, }, - has_repr_align: true, + repr_align: Some( + Align(1 bytes), + ), }, ], }, - has_repr_align: true, + repr_align: Some( + Align(1 bytes), + ), } --> $DIR/issue-96185-overaligned-enum.rs:16:1 | diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 7aca1aa462e3a..27bba72fcfe6d 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -59,11 +59,11 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/thumb-enum.rs:16:1 | @@ -131,11 +131,11 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/thumb-enum.rs:20:1 | @@ -203,11 +203,11 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/thumb-enum.rs:24:1 | @@ -275,11 +275,11 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/thumb-enum.rs:28:1 | @@ -347,11 +347,11 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/thumb-enum.rs:34:1 | diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 8342d64b6fe6d..a9a242943babe 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -57,7 +57,7 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(2 bytes), @@ -89,11 +89,11 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/zero-sized-array-enum-niche.rs:13:1 | @@ -159,7 +159,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(4 bytes), @@ -182,7 +182,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(2 bytes), @@ -214,11 +214,11 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 2, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/zero-sized-array-enum-niche.rs:21:1 | @@ -284,7 +284,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(3 bytes), @@ -316,11 +316,11 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/zero-sized-array-enum-niche.rs:37:1 | @@ -390,7 +390,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 0, }, - has_repr_align: false, + repr_align: None, }, Layout { size: Size(2 bytes), @@ -422,11 +422,11 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 1, }, - has_repr_align: false, + repr_align: None, }, ], }, - has_repr_align: false, + repr_align: None, } --> $DIR/zero-sized-array-enum-niche.rs:44:1 | From d1e764cb3bc961a4395164a36c4e0cfd57e681a1 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Wed, 14 Jun 2023 22:39:11 -0400 Subject: [PATCH 22/26] aarch64-linux: properly handle 128bit aligned aggregates --- compiler/rustc_abi/src/layout.rs | 57 ++++++- compiler/rustc_abi/src/lib.rs | 22 ++- compiler/rustc_middle/src/ty/layout.rs | 1 + compiler/rustc_target/src/abi/call/aarch64.rs | 70 ++++---- compiler/rustc_target/src/abi/call/mod.rs | 10 +- compiler/rustc_ty_utils/src/layout.rs | 5 + tests/codegen/aarch64-struct-align-128.rs | 150 ++++++++++++++++++ .../run-make/extern-fn-explicit-align/test.c | 15 +- .../run-make/extern-fn-explicit-align/test.rs | 14 +- tests/ui/layout/debug.stderr | 18 +++ tests/ui/layout/hexagon-enum.stderr | 10 ++ ...-scalarpair-payload-might-be-uninit.stderr | 17 ++ .../issue-96185-overaligned-enum.stderr | 6 + tests/ui/layout/thumb-enum.stderr | 10 ++ .../layout/zero-sized-array-enum-niche.stderr | 13 ++ 15 files changed, 370 insertions(+), 48 deletions(-) create mode 100644 tests/codegen/aarch64-struct-align-128.rs diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index ff811be3c8139..75c64aabfbb1b 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -41,6 +41,7 @@ pub trait LayoutCalculator { align, size, repr_align: None, + unadjusted_abi_align: align.abi, } } @@ -124,6 +125,7 @@ pub trait LayoutCalculator { align: dl.i8_align, size: Size::ZERO, repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, } } @@ -291,6 +293,8 @@ pub trait LayoutCalculator { } let mut align = dl.aggregate_align; + let mut unadjusted_abi_align = align.abi; + let mut variant_layouts = variants .iter_enumerated() .map(|(j, v)| { @@ -298,6 +302,7 @@ pub trait LayoutCalculator { st.variants = Variants::Single { index: j }; align = align.max(st.align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Some(st) }) @@ -425,6 +430,7 @@ pub trait LayoutCalculator { size, align, repr_align: repr.align, + unadjusted_abi_align, }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -459,6 +465,8 @@ pub trait LayoutCalculator { let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); let mut align = dl.aggregate_align; + let mut unadjusted_abi_align = align.abi; + let mut size = Size::ZERO; // We're interested in the smallest alignment, so start large. @@ -501,6 +509,7 @@ pub trait LayoutCalculator { } size = cmp::max(size, st.size); align = align.max(st.align); + unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Some(st) }) .collect::>>()?; @@ -695,6 +704,7 @@ pub trait LayoutCalculator { align, size, repr_align: repr.align, + unadjusted_abi_align, }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -735,10 +745,6 @@ pub trait LayoutCalculator { let dl = dl.borrow(); let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - if let Some(repr_align) = repr.align { - align = align.max(AbiAndPrefAlign::new(repr_align)); - } - // If all the non-ZST fields have the same ABI and union ABI optimizations aren't // disabled, we can use that common ABI for the union as a whole. struct AbiMismatch; @@ -791,6 +797,14 @@ pub trait LayoutCalculator { if let Some(pack) = repr.pack { align = align.min(AbiAndPrefAlign::new(pack)); } + // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). + // See documentation on `LayoutS::unadjusted_abi_align`. + let unadjusted_abi_align = align.abi; + if let Some(repr_align) = repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); + } + // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate. + let align = align; // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. @@ -814,6 +828,7 @@ pub trait LayoutCalculator { align, size: size.align_to(align.abi), repr_align: repr.align, + unadjusted_abi_align, }) } } @@ -1023,9 +1038,16 @@ fn univariant( offset = offset.checked_add(field.size(), dl)?; } + + // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). + // See documentation on `LayoutS::unadjusted_abi_align`. + let unadjusted_abi_align = align.abi; if let Some(repr_align) = repr.align { align = align.max(AbiAndPrefAlign::new(repr_align)); } + // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. + let align = align; + debug!("univariant min_size: {:?}", offset); let min_size = offset; // As stated above, inverse_memory_index holds field indices by increasing offset. @@ -1111,9 +1133,29 @@ fn univariant( abi = Abi::Uninhabited; } - let repr_align = repr.align.or_else(|| { - if repr.transparent() { layout_of_single_non_zst_field?.repr_align() } else { None } - }); + let (repr_align, unadjusted_abi_align) = if repr.transparent() { + match layout_of_single_non_zst_field { + Some(l) => (l.repr_align(), l.unadjusted_abi_align()), + None => { + // `repr(transparent)` with all ZST fields. + // + // Using `None` for `repr_align` here is technically incorrect, since one of + // the ZSTs could have `repr(align(1))`. It's an interesting question, if you have + // `#{repr(transparent)] struct Foo((), ZstWithReprAlign1)`, which of those ZSTs' + // ABIs is forwarded by `repr(transparent)`? The answer to that question determines + // whether we should use `None` or `Some(align 1)` here. Thanksfully, two things + // together mean this doesn't matter: + // - You're not allowed to have a `repr(transparent)` struct that contains + // `repr(align)` > 1 ZSTs. See error E0691. + // - MSVC never treats requested align 1 differently from natural align 1. + // (And the `repr_align` field is only used on i686-windows, see `LayoutS` docs.) + // So just use `None` for now. + (None, align.abi) + } + } + } else { + (repr.align, unadjusted_abi_align) + }; Some(LayoutS { variants: Variants::Single { index: FIRST_VARIANT }, @@ -1123,6 +1165,7 @@ fn univariant( align, size, repr_align, + unadjusted_abi_align, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b1577add4d024..b2138dcefae6b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1536,6 +1536,11 @@ pub struct LayoutS { /// Only used on i686-windows, where the argument passing ABI is different when alignment is /// requested, even if the requested alignment is equal to the natural alignment. pub repr_align: Option, + + /// The alignment the type would have, ignoring any `repr(align)` but including `repr(packed)`. + /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment + /// in some cases. + pub unadjusted_abi_align: Align, } impl LayoutS { @@ -1551,6 +1556,7 @@ impl LayoutS { size, align, repr_align: None, + unadjusted_abi_align: align.abi, } } } @@ -1560,7 +1566,16 @@ impl fmt::Debug for LayoutS { // This is how `Layout` used to print before it become // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. - let LayoutS { size, align, abi, fields, largest_niche, variants, repr_align } = self; + let LayoutS { + size, + align, + abi, + fields, + largest_niche, + variants, + repr_align, + unadjusted_abi_align, + } = self; f.debug_struct("Layout") .field("size", size) .field("align", align) @@ -1569,6 +1584,7 @@ impl fmt::Debug for LayoutS { .field("largest_niche", largest_niche) .field("variants", variants) .field("repr_align", repr_align) + .field("unadjusted_abi_align", unadjusted_abi_align) .finish() } } @@ -1613,6 +1629,10 @@ impl<'a> Layout<'a> { self.0.0.repr_align } + pub fn unadjusted_abi_align(self) -> Align { + self.0.0.unadjusted_abi_align + } + /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. /// /// Currently, that means that the type is pointer-sized, pointer-aligned, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ffebbab04a6c2..843ea64fc29ee 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -756,6 +756,7 @@ where align: tcx.data_layout.i8_align, size: Size::ZERO, repr_align: None, + unadjusted_abi_align: tcx.data_layout.i8_align.abi, }) } diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index a84988fa75c6d..b4c7b0f120f91 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -1,25 +1,15 @@ use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{HasDataLayout, TyAbiInterface}; -/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the -/// `ParamExtension` policy specifies how a uM value should be treated when -/// passed via register or stack-slot of width N. See also rust-lang/rust#97463. +/// Indicates the variant of the AArch64 ABI we are compiling for. +/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI. +/// +/// Corresponds to Clang's `AArch64ABIInfo::ABIKind`. #[derive(Copy, Clone, PartialEq)] -pub enum ParamExtension { - /// Indicates that when passing an i8/i16, either as a function argument or - /// as a return value, it must be sign-extended to 32 bits, and likewise a - /// u8/u16 must be zero-extended to 32-bits. (This variant is here to - /// accommodate Apple's deviation from the usual AArch64 ABI as defined by - /// ARM.) - /// - /// See also: - ExtendTo32Bits, - - /// Indicates that no sign- nor zero-extension is performed: if a value of - /// type with bitwidth M is passed as function argument or return value, - /// then M bits are copied into the least significant M bits, and the - /// remaining bits of the register (or word of memory) are untouched. - NoExtension, +pub enum AbiKind { + AAPCS, + DarwinPCS, + Win64, } fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option @@ -45,15 +35,17 @@ where }) } -fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) +fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !ret.layout.is_aggregate() { - match param_policy { - ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32), - ParamExtension::NoExtension => {} + if kind == AbiKind::DarwinPCS { + // On Darwin, when returning an i8/i16, it must be sign-extended to 32 bits, + // and likewise a u8/u16 must be zero-extended to 32-bits. + // See also: + ret.extend_integer_width_to(32) } return; } @@ -70,15 +62,17 @@ where ret.make_indirect(); } -fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_aggregate() { - match param_policy { - ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32), - ParamExtension::NoExtension => {} + if kind == AbiKind::DarwinPCS { + // On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits, + // and likewise a u8/u16 must be zero-extended to 32-bits. + // See also: + arg.extend_integer_width_to(32); } return; } @@ -87,27 +81,39 @@ where return; } let size = arg.layout.size; - let bits = size.bits(); - if bits <= 128 { - arg.cast_to(Uniform { unit: Reg::i64(), total: size }); + let align = if kind == AbiKind::AAPCS { + // When passing small aggregates by value, the AAPCS ABI mandates using the unadjusted + // alignment of the type (not including `repr(align)`). + // This matches behavior of `AArch64ABIInfo::classifyArgumentType` in Clang. + // See: + arg.layout.unadjusted_abi_align + } else { + arg.layout.align.abi + }; + if size.bits() <= 128 { + if align.bits() == 128 { + arg.cast_to(Uniform { unit: Reg::i128(), total: size }); + } else { + arg.cast_to(Uniform { unit: Reg::i64(), total: size }); + } return; } arg.make_indirect(); } -pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension) +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !fn_abi.ret.is_ignore() { - classify_ret(cx, &mut fn_abi.ret, param_policy); + classify_ret(cx, &mut fn_abi.ret, kind); } for arg in fn_abi.args.iter_mut() { if arg.is_ignore() { continue; } - classify_arg(cx, arg, param_policy); + classify_arg(cx, arg, kind); } } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index c4984936cac1a..03e7b3e7b402f 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -679,12 +679,14 @@ impl<'a, Ty> FnAbi<'a, Ty> { } }, "aarch64" => { - let param_policy = if cx.target_spec().is_like_osx { - aarch64::ParamExtension::ExtendTo32Bits + let kind = if cx.target_spec().is_like_osx { + aarch64::AbiKind::DarwinPCS + } else if cx.target_spec().is_like_windows { + aarch64::AbiKind::Win64 } else { - aarch64::ParamExtension::NoExtension + aarch64::AbiKind::AAPCS }; - aarch64::compute_abi_info(cx, self, param_policy) + aarch64::compute_abi_info(cx, self, kind) } "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 4fbc6b9400f87..b8ab8baeeddb4 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -259,6 +259,7 @@ fn layout_of_uncached<'tcx>( align: element.align, size, repr_align: None, + unadjusted_abi_align: element.align.abi, }) } ty::Slice(element) => { @@ -271,6 +272,7 @@ fn layout_of_uncached<'tcx>( align: element.align, size: Size::ZERO, repr_align: None, + unadjusted_abi_align: element.align.abi, }) } ty::Str => tcx.mk_layout(LayoutS { @@ -281,6 +283,7 @@ fn layout_of_uncached<'tcx>( align: dl.i8_align, size: Size::ZERO, repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, }), // Odd unit types. @@ -435,6 +438,7 @@ fn layout_of_uncached<'tcx>( size, align, repr_align: None, + unadjusted_abi_align: align.abi, }) } @@ -884,6 +888,7 @@ fn generator_layout<'tcx>( size, align, repr_align: None, + unadjusted_abi_align: align.abi, }); debug!("generator layout ({:?}): {:#?}", ty, layout); Ok(layout) diff --git a/tests/codegen/aarch64-struct-align-128.rs b/tests/codegen/aarch64-struct-align-128.rs new file mode 100644 index 0000000000000..bf34717786d48 --- /dev/null +++ b/tests/codegen/aarch64-struct-align-128.rs @@ -0,0 +1,150 @@ +// Test that structs aligned to 128 bits are passed with the correct ABI on aarch64. + +// revisions:linux darwin windows +//[linux] compile-flags: --target aarch64-unknown-linux-gnu +//[darwin] compile-flags: --target aarch64-apple-darwin +//[windows] compile-flags: --target aarch64-pc-windows-msvc +//[linux] needs-llvm-components: aarch64 +//[darwin] needs-llvm-components: aarch64 +//[windows] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + + + +// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct Align8 { + pub a: u64, + pub b: u64, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct Transparent8 { + a: Align8 +} + +// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct Wrapped8 { + a: Align8, +} + +extern "C" { + // linux: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) + // darwin: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) + // windows: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) + fn test_8(a: Align8, b: Transparent8, c: Wrapped8); +} + + + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +// EXCEPT on Linux, where there's a special case to use its unadjusted alignment, +// making it the same as `Align8`, so it's be passed as `[i64 x 2]`. +#[repr(C)] +#[repr(align(16))] +pub struct Align16 { + pub a: u64, + pub b: u64, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct Transparent16 { + a: Align16 +} + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +// On Linux, the "unadjustedness" doesn't recurse into fields, so this is passed as `i128`. +#[repr(C)] +pub struct Wrapped16 { + pub a: Align16, +} + +extern "C" { + // linux: declare void @test_16([2 x i64], [2 x i64], i128) + // darwin: declare void @test_16(i128, i128, i128) + // windows: declare void @test_16(i128, i128, i128) + fn test_16(a: Align16, b: Transparent16, c: Wrapped16); +} + + + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +#[repr(C)] +pub struct I128 { + pub a: i128, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct TransparentI128 { + a: I128 +} + +// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits. +#[repr(C)] +pub struct WrappedI128 { + pub a: I128 +} + +extern "C" { + // linux: declare void @test_i128(i128, i128, i128) + // darwin: declare void @test_i128(i128, i128, i128) + // windows: declare void @test_i128(i128, i128, i128) + fn test_i128(a: I128, b: TransparentI128, c: WrappedI128); +} + + + +// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +// Note that the Linux special case does not apply, because packing is not considered "adjustment". +#[repr(C)] +#[repr(packed)] +pub struct Packed { + pub a: i128, +} + +// repr(transparent), so same as above. +#[repr(transparent)] +pub struct TransparentPacked { + a: Packed +} + +// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits. +#[repr(C)] +pub struct WrappedPacked { + pub a: Packed +} + +extern "C" { + // linux: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) + // darwin: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) + // windows: declare void @test_packed([2 x i64], [2 x i64], [2 x i64]) + fn test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked); +} + + + +pub unsafe fn main( + a1: Align8, a2: Transparent8, a3: Wrapped8, + b1: Align16, b2: Transparent16, b3: Wrapped16, + c1: I128, c2: TransparentI128, c3: WrappedI128, + d1: Packed, d2: TransparentPacked, d3: WrappedPacked, +) { + test_8(a1, a2, a3); + test_16(b1, b2, b3); + test_i128(c1, c2, c3); + test_packed(d1, d2, d3); +} diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c index 292e7a822b594..8d20864326b40 100644 --- a/tests/run-make/extern-fn-explicit-align/test.c +++ b/tests/run-make/extern-fn-explicit-align/test.c @@ -44,7 +44,12 @@ struct __attribute__((aligned(1))) LowerAlign }; #endif - +#pragma pack(push, 1) +struct Packed +{ + __uint128_t a; +}; +#pragma pack(pop) int32_t many_args( void *a, @@ -59,7 +64,9 @@ int32_t many_args( struct WrappedU64s j, void *k, struct LowerAlign l, - const char *m) + void *m, + struct Packed n, + const char *o) { assert(!a); assert(!b); @@ -77,6 +84,8 @@ int32_t many_args( assert(!k); assert(l.a == 5); assert(l.b == 6); - assert(strcmp(m, "Hello world") == 0); + assert(!m); + assert(n.a == 7); + assert(strcmp(o, "Hello world") == 0); return 0; } diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index c5b3e24048ee1..56c6437dad2a7 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -34,6 +34,13 @@ pub struct LowerAlign { pub b: u64, } +#[derive(Copy, Clone)] +#[repr(C)] +#[repr(packed)] +pub struct Packed { + pub a: u128 +} + #[link(name = "test", kind = "static")] extern "C" { fn many_args( @@ -49,7 +56,9 @@ extern "C" { j: WrappedU64s, k: *mut (), l: LowerAlign, - m: *const c_char, + m: *mut (), + n: Packed, + o: *const c_char, ) -> i32; } @@ -60,6 +69,7 @@ fn main() { let two_u64s = TwoU64s { a: 1, b: 2 }; let wrapped = WrappedU64s { a: TwoU64s { a: 3, b: 4 } }; let lower = LowerAlign { a: 5, b: 6 }; + let packed = Packed { a: 7 }; let string = STRING; unsafe { many_args( @@ -75,6 +85,8 @@ fn main() { wrapped, null_mut(), lower, + null_mut(), + packed, string.as_ptr(), ); } diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 99022fb11b5b3..1bf89d0dcb39d 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -54,6 +54,7 @@ error: layout_of(E) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(12 bytes), @@ -79,10 +80,12 @@ error: layout_of(E) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:7:1 | @@ -128,6 +131,7 @@ error: layout_of(S) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:10:1 | @@ -151,6 +155,7 @@ error: layout_of(U) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:13:1 | @@ -243,6 +248,7 @@ error: layout_of(std::result::Result) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, Layout { size: Size(8 bytes), @@ -279,10 +285,12 @@ error: layout_of(std::result::Result) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:16:1 | @@ -310,6 +318,7 @@ error: layout_of(i32) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:19:1 | @@ -333,6 +342,7 @@ error: layout_of(V) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:22:1 | @@ -356,6 +366,7 @@ error: layout_of(W) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:28:1 | @@ -379,6 +390,7 @@ error: layout_of(Y) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:34:1 | @@ -402,6 +414,7 @@ error: layout_of(P1) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:41:1 | @@ -425,6 +438,7 @@ error: layout_of(P2) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:45:1 | @@ -448,6 +462,7 @@ error: layout_of(P3) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:53:1 | @@ -471,6 +486,7 @@ error: layout_of(P4) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:57:1 | @@ -499,6 +515,7 @@ error: layout_of(P5) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:61:1 | @@ -527,6 +544,7 @@ error: layout_of(std::mem::MaybeUninit) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:64:1 | diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index a907853585da7..acc97672d3c72 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -60,10 +60,12 @@ error: layout_of(A) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/hexagon-enum.rs:16:1 | @@ -132,10 +134,12 @@ error: layout_of(B) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/hexagon-enum.rs:20:1 | @@ -204,10 +208,12 @@ error: layout_of(C) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), } --> $DIR/hexagon-enum.rs:24:1 | @@ -276,10 +282,12 @@ error: layout_of(P) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/hexagon-enum.rs:28:1 | @@ -348,10 +356,12 @@ error: layout_of(T) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/hexagon-enum.rs:34:1 | diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 2db6ab9bc899b..6e013af199dc9 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -82,6 +82,7 @@ error: layout_of(MissingPayloadField) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(1 bytes), @@ -101,10 +102,12 @@ error: layout_of(MissingPayloadField) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 | @@ -197,6 +200,7 @@ error: layout_of(CommonPayloadField) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(2 bytes), @@ -233,10 +237,12 @@ error: layout_of(CommonPayloadField) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 | @@ -327,6 +333,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(2 bytes), @@ -362,10 +369,12 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 | @@ -472,6 +481,7 @@ error: layout_of(NicheFirst) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(0 bytes), @@ -491,6 +501,7 @@ error: layout_of(NicheFirst) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(0 bytes), @@ -510,10 +521,12 @@ error: layout_of(NicheFirst) = Layout { index: 2, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 | @@ -620,6 +633,7 @@ error: layout_of(NicheSecond) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(0 bytes), @@ -639,6 +653,7 @@ error: layout_of(NicheSecond) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(0 bytes), @@ -658,10 +673,12 @@ error: layout_of(NicheSecond) = Layout { index: 2, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 | diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index 3a0ad07347dda..ef6cc79eedb05 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -56,6 +56,7 @@ error: layout_of(Aligned1) = Layout { repr_align: Some( Align(8 bytes), ), + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(8 bytes), @@ -77,12 +78,14 @@ error: layout_of(Aligned1) = Layout { repr_align: Some( Align(8 bytes), ), + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: Some( Align(8 bytes), ), + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96185-overaligned-enum.rs:8:1 | @@ -153,6 +156,7 @@ error: layout_of(Aligned2) = Layout { repr_align: Some( Align(1 bytes), ), + unadjusted_abi_align: Align(1 bytes), }, Layout { size: Size(1 bytes), @@ -174,12 +178,14 @@ error: layout_of(Aligned2) = Layout { repr_align: Some( Align(1 bytes), ), + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: Some( Align(1 bytes), ), + unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96185-overaligned-enum.rs:16:1 | diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 27bba72fcfe6d..c1837b0e47e73 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -60,10 +60,12 @@ error: layout_of(A) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/thumb-enum.rs:16:1 | @@ -132,10 +134,12 @@ error: layout_of(B) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), } --> $DIR/thumb-enum.rs:20:1 | @@ -204,10 +208,12 @@ error: layout_of(C) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), } --> $DIR/thumb-enum.rs:24:1 | @@ -276,10 +282,12 @@ error: layout_of(P) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/thumb-enum.rs:28:1 | @@ -348,10 +356,12 @@ error: layout_of(T) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/thumb-enum.rs:34:1 | diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index a9a242943babe..02bf9d496bc2f 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -58,6 +58,7 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, Layout { size: Size(2 bytes), @@ -90,10 +91,12 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:13:1 | @@ -160,6 +163,7 @@ error: layout_of(MultipleAlignments) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(2 bytes), }, Layout { size: Size(4 bytes), @@ -183,6 +187,7 @@ error: layout_of(MultipleAlignments) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, Layout { size: Size(2 bytes), @@ -215,10 +220,12 @@ error: layout_of(MultipleAlignments) = Layout { index: 2, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:21:1 | @@ -285,6 +292,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, Layout { size: Size(3 bytes), @@ -317,10 +325,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:37:1 | @@ -391,6 +401,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { index: 0, }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), }, Layout { size: Size(2 bytes), @@ -423,10 +434,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { index: 1, }, repr_align: None, + unadjusted_abi_align: Align(1 bytes), }, ], }, repr_align: None, + unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:44:1 | From c858d345b3028c7c1b66f36291baea9ce52cad5f Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Wed, 14 Jun 2023 22:51:44 -0400 Subject: [PATCH 23/26] cg_clif: just ignore all the unused LayoutS fields --- compiler/rustc_codegen_cranelift/src/abi/comments.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 97f8452a46814..ade6968de2bb6 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -80,15 +80,7 @@ pub(super) fn add_local_place_comments<'tcx>( return; } let TyAndLayout { ty, layout } = place.layout(); - let rustc_target::abi::LayoutS { - size, - align, - repr_align: _, - abi: _, - variants: _, - fields: _, - largest_niche: _, - } = layout.0.0; + let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0; let (kind, extra) = place.debug_comment(); From ecf2390fb0791f5f96507c11ed1f3b331f5e8b73 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Thu, 13 Jul 2023 00:54:11 -0400 Subject: [PATCH 24/26] extern fn-explicit-align test: don't use uint128_t ...which seems not to be available on some platforms. Or maybe it is under a different name but I don't want to deal with that Instead, use two u64s. This isn't exactly the same, but we already have some coverage of the packed u128 case in another test, so it's not essential to have it here. --- tests/run-make/extern-fn-explicit-align/test.c | 4 +++- tests/run-make/extern-fn-explicit-align/test.rs | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c index 8d20864326b40..a3db3442aafea 100644 --- a/tests/run-make/extern-fn-explicit-align/test.c +++ b/tests/run-make/extern-fn-explicit-align/test.c @@ -47,7 +47,8 @@ struct __attribute__((aligned(1))) LowerAlign #pragma pack(push, 1) struct Packed { - __uint128_t a; + uint64_t a; + uint64_t b; }; #pragma pack(pop) @@ -86,6 +87,7 @@ int32_t many_args( assert(l.b == 6); assert(!m); assert(n.a == 7); + assert(n.b == 8); assert(strcmp(o, "Hello world") == 0); return 0; } diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index 56c6437dad2a7..ad06d92ac9680 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -38,7 +38,8 @@ pub struct LowerAlign { #[repr(C)] #[repr(packed)] pub struct Packed { - pub a: u128 + pub a: u64, + pub b: u64, } #[link(name = "test", kind = "static")] @@ -69,7 +70,7 @@ fn main() { let two_u64s = TwoU64s { a: 1, b: 2 }; let wrapped = WrappedU64s { a: TwoU64s { a: 3, b: 4 } }; let lower = LowerAlign { a: 5, b: 6 }; - let packed = Packed { a: 7 }; + let packed = Packed { a: 7, b: 8 }; let string = STRING; unsafe { many_args( From f297f3200ffe3cb921a04c6b4eea944a72207eb4 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Fri, 14 Jul 2023 16:22:29 -0400 Subject: [PATCH 25/26] extern-fn-explicit-align test: remove unnecessary derives --- tests/run-make/extern-fn-explicit-align/test.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs index ad06d92ac9680..846622de3cd10 100644 --- a/tests/run-make/extern-fn-explicit-align/test.rs +++ b/tests/run-make/extern-fn-explicit-align/test.rs @@ -3,14 +3,12 @@ use std::ffi::{CStr, c_char}; use std::ptr::null_mut; -#[derive(Copy, Clone)] #[repr(C)] pub struct BoolAndU32 { pub a: bool, pub b: u32, } -#[derive(Copy, Clone)] #[repr(C)] #[repr(align(16))] pub struct TwoU64s { @@ -18,13 +16,11 @@ pub struct TwoU64s { pub b: u64, } -#[derive(Copy, Clone)] #[repr(C)] pub struct WrappedU64s { pub a: TwoU64s } -#[derive(Copy, Clone)] #[repr(C)] // Even though requesting align 1 can never change the alignment, it still affects the ABI // on some platforms like i686-windows. @@ -34,7 +30,6 @@ pub struct LowerAlign { pub b: u64, } -#[derive(Copy, Clone)] #[repr(C)] #[repr(packed)] pub struct Packed { From 2daacf5af965090b885287f1d40e13ff5db724cf Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Fri, 14 Jul 2023 17:48:13 -0400 Subject: [PATCH 26/26] i686-windows: make requested alignment > 4 special case apply transitively --- compiler/rustc_abi/src/layout.rs | 40 +++++++++---------- compiler/rustc_abi/src/lib.rs | 14 +++---- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_target/src/abi/call/x86.rs | 8 ++-- compiler/rustc_ty_utils/src/layout.rs | 10 ++--- tests/codegen/align-byval.rs | 6 ++- tests/ui/layout/debug.stderr | 36 ++++++++--------- tests/ui/layout/hexagon-enum.stderr | 20 +++++----- ...-scalarpair-payload-might-be-uninit.stderr | 34 ++++++++-------- .../issue-96185-overaligned-enum.stderr | 12 +++--- tests/ui/layout/thumb-enum.stderr | 20 +++++----- .../layout/zero-sized-array-enum-niche.stderr | 26 ++++++------ 12 files changed, 113 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 75c64aabfbb1b..aea88641f82b1 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -40,7 +40,7 @@ pub trait LayoutCalculator { largest_niche, align, size, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: align.abi, } } @@ -124,7 +124,7 @@ pub trait LayoutCalculator { largest_niche: None, align: dl.i8_align, size: Size::ZERO, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, } } @@ -293,6 +293,7 @@ pub trait LayoutCalculator { } let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align.abi; let mut variant_layouts = variants @@ -302,6 +303,7 @@ pub trait LayoutCalculator { st.variants = Variants::Single { index: j }; align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Some(st) @@ -429,7 +431,7 @@ pub trait LayoutCalculator { largest_niche, size, align, - repr_align: repr.align, + max_repr_align, unadjusted_abi_align, }; @@ -465,6 +467,7 @@ pub trait LayoutCalculator { let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max); let mut align = dl.aggregate_align; + let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align.abi; let mut size = Size::ZERO; @@ -509,6 +512,7 @@ pub trait LayoutCalculator { } size = cmp::max(size, st.size); align = align.max(st.align); + max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Some(st) }) @@ -703,7 +707,7 @@ pub trait LayoutCalculator { abi, align, size, - repr_align: repr.align, + max_repr_align, unadjusted_abi_align, }; @@ -744,6 +748,7 @@ pub trait LayoutCalculator { let dl = self.current_data_layout(); let dl = dl.borrow(); let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; + let mut max_repr_align = repr.align; // If all the non-ZST fields have the same ABI and union ABI optimizations aren't // disabled, we can use that common ABI for the union as a whole. @@ -761,6 +766,7 @@ pub trait LayoutCalculator { assert!(field.0.is_sized()); align = align.max(field.align()); + max_repr_align = max_repr_align.max(field.max_repr_align()); size = cmp::max(size, field.size()); if field.0.is_zst() { @@ -827,7 +833,7 @@ pub trait LayoutCalculator { largest_niche: None, align, size: size.align_to(align.abi), - repr_align: repr.align, + max_repr_align, unadjusted_abi_align, }) } @@ -849,6 +855,7 @@ fn univariant( ) -> Option { let pack = repr.pack; let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; + let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec = fields.indices().collect(); let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize && fields.len() > 1 { @@ -1017,6 +1024,7 @@ fn univariant( }; offset = offset.align_to(field_align.abi); align = align.max(field_align); + max_repr_align = max_repr_align.max(field.max_repr_align()); debug!("univariant offset: {:?} field: {:#?}", offset, field); offsets[i] = offset; @@ -1133,28 +1141,16 @@ fn univariant( abi = Abi::Uninhabited; } - let (repr_align, unadjusted_abi_align) = if repr.transparent() { + let unadjusted_abi_align = if repr.transparent() { match layout_of_single_non_zst_field { - Some(l) => (l.repr_align(), l.unadjusted_abi_align()), + Some(l) => l.unadjusted_abi_align(), None => { // `repr(transparent)` with all ZST fields. - // - // Using `None` for `repr_align` here is technically incorrect, since one of - // the ZSTs could have `repr(align(1))`. It's an interesting question, if you have - // `#{repr(transparent)] struct Foo((), ZstWithReprAlign1)`, which of those ZSTs' - // ABIs is forwarded by `repr(transparent)`? The answer to that question determines - // whether we should use `None` or `Some(align 1)` here. Thanksfully, two things - // together mean this doesn't matter: - // - You're not allowed to have a `repr(transparent)` struct that contains - // `repr(align)` > 1 ZSTs. See error E0691. - // - MSVC never treats requested align 1 differently from natural align 1. - // (And the `repr_align` field is only used on i686-windows, see `LayoutS` docs.) - // So just use `None` for now. - (None, align.abi) + align.abi } } } else { - (repr.align, unadjusted_abi_align) + unadjusted_abi_align }; Some(LayoutS { @@ -1164,7 +1160,7 @@ fn univariant( largest_niche, align, size, - repr_align, + max_repr_align, unadjusted_abi_align, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b2138dcefae6b..ef0c763ac2038 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1532,10 +1532,10 @@ pub struct LayoutS { pub align: AbiAndPrefAlign, pub size: Size, - /// The alignment explicitly requested with `repr(align)`. + /// The largest alignment explicitly requested with `repr(align)` on this type or any field. /// Only used on i686-windows, where the argument passing ABI is different when alignment is /// requested, even if the requested alignment is equal to the natural alignment. - pub repr_align: Option, + pub max_repr_align: Option, /// The alignment the type would have, ignoring any `repr(align)` but including `repr(packed)`. /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment @@ -1555,7 +1555,7 @@ impl LayoutS { largest_niche, size, align, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: align.abi, } } @@ -1573,7 +1573,7 @@ impl fmt::Debug for LayoutS { fields, largest_niche, variants, - repr_align, + max_repr_align, unadjusted_abi_align, } = self; f.debug_struct("Layout") @@ -1583,7 +1583,7 @@ impl fmt::Debug for LayoutS { .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) - .field("repr_align", repr_align) + .field("max_repr_align", max_repr_align) .field("unadjusted_abi_align", unadjusted_abi_align) .finish() } @@ -1625,8 +1625,8 @@ impl<'a> Layout<'a> { self.0.0.size } - pub fn repr_align(self) -> Option { - self.0.0.repr_align + pub fn max_repr_align(self) -> Option { + self.0.0.max_repr_align } pub fn unadjusted_abi_align(self) -> Align { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 843ea64fc29ee..f8c56e5abb802 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -755,7 +755,7 @@ where largest_niche: None, align: tcx.data_layout.i8_align, size: Size::ZERO, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: tcx.data_layout.i8_align.abi, }) } diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index e429215106573..b738c3133d95e 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -63,8 +63,8 @@ where if t.is_like_msvc && arg.layout.is_adt() - && let Some(repr_align) = arg.layout.repr_align - && repr_align > align_4 + && let Some(max_repr_align) = arg.layout.max_repr_align + && max_repr_align > align_4 { // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. // Summarized here: @@ -72,8 +72,8 @@ where // - For backwards compatibility, arguments with natural alignment > 4 are still passed // on stack (via `byval`). For example, this includes `double`, `int64_t`, // and structs containing them, provided they lack an explicit alignment attribute. - assert!(arg.layout.align.abi >= repr_align, - "abi alignment {:?} less than requested alignment {repr_align:?}", + assert!(arg.layout.align.abi >= max_repr_align, + "abi alignment {:?} less than requested alignment {max_repr_align:?}", arg.layout.align.abi, ); arg.make_indirect(); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index b8ab8baeeddb4..74b484bd85ac5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -258,7 +258,7 @@ fn layout_of_uncached<'tcx>( largest_niche, align: element.align, size, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: element.align.abi, }) } @@ -271,7 +271,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: element.align, size: Size::ZERO, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: element.align.abi, }) } @@ -282,7 +282,7 @@ fn layout_of_uncached<'tcx>( largest_niche: None, align: dl.i8_align, size: Size::ZERO, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, }), @@ -437,7 +437,7 @@ fn layout_of_uncached<'tcx>( largest_niche: e_ly.largest_niche, size, align, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: align.abi, }) } @@ -887,7 +887,7 @@ fn generator_layout<'tcx>( largest_niche: prefix.largest_niche, size, align, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: align.abi, }); debug!("generator layout ({:?}): {:#?}", ty, layout); diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs index fc5f795bf6726..e2446e02ef44c 100644 --- a/tests/codegen/align-byval.rs +++ b/tests/codegen/align-byval.rs @@ -80,7 +80,7 @@ pub struct LowerFA8 { c: i64 } -// On i686-windows, this is passed on stack, because the wrapper struct does not have +// On i686-windows, this is passed by reference, because it contains a field with // requested/forced alignment. #[repr(C)] pub struct WrappedFA8 { @@ -301,7 +301,9 @@ extern "C" { // i686-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}}) - // i686-windows: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}}) + // i686-windows: declare void @wrapped_fa8( + // i686-windows-NOT: byval + // i686-windows-SAME: align 8{{.*}}) fn wrapped_fa8(x: WrappedFA8); // m68k: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}}) diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 1bf89d0dcb39d..eeffb3c5f6476 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -53,7 +53,7 @@ error: layout_of(E) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -79,12 +79,12 @@ error: layout_of(E) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:7:1 @@ -130,7 +130,7 @@ error: layout_of(S) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:10:1 @@ -154,7 +154,7 @@ error: layout_of(U) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:13:1 @@ -247,7 +247,7 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, Layout { @@ -284,12 +284,12 @@ error: layout_of(std::result::Result) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:16:1 @@ -317,7 +317,7 @@ error: layout_of(i32) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/debug.rs:19:1 @@ -341,7 +341,7 @@ error: layout_of(V) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:22:1 @@ -365,7 +365,7 @@ error: layout_of(W) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:28:1 @@ -389,7 +389,7 @@ error: layout_of(Y) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } --> $DIR/debug.rs:34:1 @@ -413,7 +413,7 @@ error: layout_of(P1) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:41:1 @@ -437,7 +437,7 @@ error: layout_of(P2) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:45:1 @@ -461,7 +461,7 @@ error: layout_of(P3) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:53:1 @@ -485,7 +485,7 @@ error: layout_of(P4) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:57:1 @@ -514,7 +514,7 @@ error: layout_of(P5) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:61:1 @@ -543,7 +543,7 @@ error: layout_of(std::mem::MaybeUninit) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/debug.rs:64:1 diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index acc97672d3c72..a2ad4a1ab58ad 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -59,12 +59,12 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/hexagon-enum.rs:16:1 @@ -133,12 +133,12 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/hexagon-enum.rs:20:1 @@ -207,12 +207,12 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } --> $DIR/hexagon-enum.rs:24:1 @@ -281,12 +281,12 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/hexagon-enum.rs:28:1 @@ -355,12 +355,12 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/hexagon-enum.rs:34:1 diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 6e013af199dc9..d3ba1a295b1bc 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -81,7 +81,7 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -101,12 +101,12 @@ error: layout_of(MissingPayloadField) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 @@ -199,7 +199,7 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -236,12 +236,12 @@ error: layout_of(CommonPayloadField) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 @@ -332,7 +332,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -368,12 +368,12 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 @@ -480,7 +480,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -500,7 +500,7 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -520,12 +520,12 @@ error: layout_of(NicheFirst) = Layout { variants: Single { index: 2, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 @@ -632,7 +632,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -652,7 +652,7 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, Layout { @@ -672,12 +672,12 @@ error: layout_of(NicheSecond) = Layout { variants: Single { index: 2, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index ef6cc79eedb05..c539eb453d915 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -53,7 +53,7 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 0, }, - repr_align: Some( + max_repr_align: Some( Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), @@ -75,14 +75,14 @@ error: layout_of(Aligned1) = Layout { variants: Single { index: 1, }, - repr_align: Some( + max_repr_align: Some( Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: Some( + max_repr_align: Some( Align(8 bytes), ), unadjusted_abi_align: Align(1 bytes), @@ -153,7 +153,7 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 0, }, - repr_align: Some( + max_repr_align: Some( Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), @@ -175,14 +175,14 @@ error: layout_of(Aligned2) = Layout { variants: Single { index: 1, }, - repr_align: Some( + max_repr_align: Some( Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: Some( + max_repr_align: Some( Align(1 bytes), ), unadjusted_abi_align: Align(1 bytes), diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index c1837b0e47e73..6f6ab49820676 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -59,12 +59,12 @@ error: layout_of(A) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/thumb-enum.rs:16:1 @@ -133,12 +133,12 @@ error: layout_of(B) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), } --> $DIR/thumb-enum.rs:20:1 @@ -207,12 +207,12 @@ error: layout_of(C) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), } --> $DIR/thumb-enum.rs:24:1 @@ -281,12 +281,12 @@ error: layout_of(P) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/thumb-enum.rs:28:1 @@ -355,12 +355,12 @@ error: layout_of(T) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/thumb-enum.rs:34:1 diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 02bf9d496bc2f..df9f1cc8d1057 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -57,7 +57,7 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, Layout { @@ -90,12 +90,12 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:13:1 @@ -162,7 +162,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(2 bytes), }, Layout { @@ -186,7 +186,7 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, Layout { @@ -219,12 +219,12 @@ error: layout_of(MultipleAlignments) = Layout { variants: Single { index: 2, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:21:1 @@ -291,7 +291,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, Layout { @@ -324,12 +324,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:37:1 @@ -400,7 +400,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 0, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), }, Layout { @@ -433,12 +433,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { variants: Single { index: 1, }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(1 bytes), }, ], }, - repr_align: None, + max_repr_align: None, unadjusted_abi_align: Align(4 bytes), } --> $DIR/zero-sized-array-enum-niche.rs:44:1