From 7f6d47314bde7b8c49651bcb3802f0994d531a34 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 1 May 2018 00:13:14 +0100 Subject: [PATCH 1/3] Correct initial field alignment for repr(C)/repr(int) --- src/librustc/ty/layout.rs | 8 ++++-- src/test/run-pass/repr_c_int_align.rs | 39 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/repr_c_int_align.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 53dde3e6903..a319b341ebb 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -940,11 +940,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // We increase the size of the discriminant to avoid LLVM copying // padding when it doesn't need to. This normally causes unaligned // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and + // bigger integer size, LLVM can be sure about its contents and // won't be so conservative. // Use the initial field alignment - let mut ity = Integer::for_abi_align(dl, start_align).unwrap_or(min_ity); + let mut ity = if def.repr.c() || def.repr.int.is_some() { + min_ity + } else { + Integer::for_abi_align(dl, start_align).unwrap_or(min_ity) + }; // If the alignment is not larger than the chosen discriminant size, // don't use the alignment as the final size. diff --git a/src/test/run-pass/repr_c_int_align.rs b/src/test/run-pass/repr_c_int_align.rs new file mode 100644 index 00000000000..32d015c3ca2 --- /dev/null +++ b/src/test/run-pass/repr_c_int_align.rs @@ -0,0 +1,39 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![allow(dead_code)] + +#[repr(C, u8)] +enum ReprCu8 { + A(u16), + B, +} + +#[repr(C)] +struct ReprC { + tag: u8, + padding: u8, + payload: u16, +} + +fn main() { + let r1 = ReprC { tag: 0, padding: 0, payload: 0 }; + let r2 = ReprC { tag: 0, padding: 1, payload: 1 }; + + let t1: &ReprCu8 = unsafe { std::mem::transmute(&r1) }; + let t2: &ReprCu8 = unsafe { std::mem::transmute(&r2) }; + + match (t1, t2) { + (ReprCu8::A(_), ReprCu8::A(_)) => (), + _ => assert!(false) + }; +} From 4da1f71e4be9f9105f504f9a303d05b69ab8971d Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 1 May 2018 18:52:27 +0100 Subject: [PATCH 2/3] Add repr(u8) to the test --- src/test/run-pass/repr_c_int_align.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/run-pass/repr_c_int_align.rs b/src/test/run-pass/repr_c_int_align.rs index 32d015c3ca2..af4eb615302 100644 --- a/src/test/run-pass/repr_c_int_align.rs +++ b/src/test/run-pass/repr_c_int_align.rs @@ -18,6 +18,12 @@ enum ReprCu8 { B, } +#[repr(u8)] +enum Repru8 { + A(u16), + B, +} + #[repr(C)] struct ReprC { tag: u8, @@ -26,6 +32,7 @@ struct ReprC { } fn main() { + // Test `repr(C, u8)`. let r1 = ReprC { tag: 0, padding: 0, payload: 0 }; let r2 = ReprC { tag: 0, padding: 1, payload: 1 }; @@ -36,4 +43,13 @@ fn main() { (ReprCu8::A(_), ReprCu8::A(_)) => (), _ => assert!(false) }; + + // Test `repr(u8)`. + let t1: &Repru8 = unsafe { std::mem::transmute(&r1) }; + let t2: &Repru8 = unsafe { std::mem::transmute(&r2) }; + + match (t1, t2) { + (Repru8::A(_), Repru8::A(_)) => (), + _ => assert!(false) + }; } From 2d0d73ea5a004158e07ec6169b517c7ca6cbe3b0 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 1 May 2018 20:25:30 +0100 Subject: [PATCH 3/3] Add a print_types_sizes regression test --- src/test/ui/print_type_sizes/repr_int_c.rs | 35 +++++++++++++++++++ .../ui/print_type_sizes/repr_int_c.stdout | 12 +++++++ 2 files changed, 47 insertions(+) create mode 100644 src/test/ui/print_type_sizes/repr_int_c.rs create mode 100644 src/test/ui/print_type_sizes/repr_int_c.stdout diff --git a/src/test/ui/print_type_sizes/repr_int_c.rs b/src/test/ui/print_type_sizes/repr_int_c.rs new file mode 100644 index 00000000000..04bb2ab26f3 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr_int_c.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes +// compile-pass + +// This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)` +// variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug). + +#![feature(start)] +#![allow(dead_code)] + +#[repr(C, u8)] +enum ReprCu8 { + A(u16), + B, +} + +#[repr(u8)] +enum Repru8 { + A(u16), + B, +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + 0 +} diff --git a/src/test/ui/print_type_sizes/repr_int_c.stdout b/src/test/ui/print_type_sizes/repr_int_c.stdout new file mode 100644 index 00000000000..254b3c7a853 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr_int_c.stdout @@ -0,0 +1,12 @@ +print-type-size type: `ReprCu8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 1 bytes +print-type-size type: `Repru8`: 4 bytes, alignment: 2 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 3 bytes +print-type-size padding: 1 bytes +print-type-size field `.0`: 2 bytes, alignment: 2 bytes +print-type-size variant `B`: 0 bytes