From fd116c806aaa59fabd2ab72398d35fc665e8226e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 10 Aug 2021 18:34:13 +0000 Subject: [PATCH] Add c_enum_min_bits to target spec --- compiler/rustc_middle/src/ty/layout.rs | 24 +- compiler/rustc_target/src/abi/mod.rs | 17 + .../src/spec/hexagon_unknown_linux_musl.rs | 2 + compiler/rustc_target/src/spec/mod.rs | 12 + src/test/ui/layout/thumb-enum.rs | 34 ++ src/test/ui/layout/thumb-enum.stderr | 442 ++++++++++++++++++ 6 files changed, 515 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/layout/thumb-enum.rs create mode 100644 src/test/ui/layout/thumb-enum.stderr diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 423f3faf21fff..3caca313ffddd 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -112,9 +112,6 @@ impl IntegerExt for Integer { let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128)); let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); - let mut min_from_extern = None; - let min_default = I8; - if let Some(ity) = repr.int { let discr = Integer::from_attr(&tcx, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; @@ -128,19 +125,14 @@ impl IntegerExt for Integer { return (discr, ity.is_signed()); } - if repr.c() { - match &tcx.sess.target.arch[..] { - "hexagon" => min_from_extern = Some(I8), - // WARNING: the ARM EABI has two variants; the one corresponding - // to `at_least == I32` appears to be used on Linux and NetBSD, - // but some systems may use the variant corresponding to no - // lower bound. However, we don't run on those yet...? - "arm" => min_from_extern = Some(I32), - _ => min_from_extern = Some(I32), - } - } - - let at_least = min_from_extern.unwrap_or(min_default); + let at_least = if repr.c() { + // This is usually I32, however it can be different on some platforms, + // notably hexagon and arm-none/thumb-none + tcx.data_layout().c_enum_min_size + } else { + // repr(Rust) enums try to be as small as possible + I8 + }; // If there are no negative values, we can use the unsigned fit. if min >= 0 { diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 9a24edf1a42cb..8ef6e142caecf 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -36,6 +36,9 @@ pub struct TargetDataLayout { pub vector_align: Vec<(Size, AbiAndPrefAlign)>, pub instruction_address_space: AddressSpace, + + /// Minimum size of #[repr(C)] enums (default I32 bits) + pub c_enum_min_size: Integer, } impl Default for TargetDataLayout { @@ -60,6 +63,7 @@ impl Default for TargetDataLayout { (Size::from_bits(128), AbiAndPrefAlign::new(align(128))), ], instruction_address_space: AddressSpace::DATA, + c_enum_min_size: Integer::I32, } } } @@ -173,6 +177,8 @@ impl TargetDataLayout { )); } + dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?; + Ok(dl) } @@ -610,6 +616,17 @@ impl Integer { } I8 } + + fn from_size(size: Size) -> Result { + match size.bits() { + 8 => Ok(Integer::I8), + 16 => Ok(Integer::I16), + 32 => Ok(Integer::I32), + 64 => Ok(Integer::I64), + 128 => Ok(Integer::I128), + _ => Err(format!("rust does not support integers with {} bits", size.bits())), + } + } } /// Fundamental unit of memory access and layout. diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs index e0097ee220a46..27d306c41b795 100644 --- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs @@ -13,6 +13,8 @@ pub fn target() -> Target { base.dynamic_linking = true; base.executables = true; + base.c_enum_min_bits = 8; + Target { llvm_target: "hexagon-unknown-linux-musl".to_string(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 9c957cba6cc09..e5987511c9737 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1335,6 +1335,9 @@ pub struct TargetOptions { /// If present it's a default value to use for adjusting the C ABI. pub default_adjusted_cabi: Option, + + /// Minimum number of bits in #[repr(C)] enum. Defaults to 32. + pub c_enum_min_bits: u64, } impl Default for TargetOptions { @@ -1439,6 +1442,7 @@ impl Default for TargetOptions { split_debuginfo: SplitDebuginfo::Off, supported_sanitizers: SanitizerSet::empty(), default_adjusted_cabi: None, + c_enum_min_bits: 32, } } } @@ -1603,6 +1607,12 @@ impl Target { base.$key_name = s; } } ); + ($key_name:ident, u64) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) { + base.$key_name = s; + } + } ); ($key_name:ident, Option) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) { @@ -2016,6 +2026,7 @@ impl Target { key!(split_debuginfo, SplitDebuginfo)?; key!(supported_sanitizers, SanitizerSet)?; key!(default_adjusted_cabi, Option)?; + key!(c_enum_min_bits, u64); if base.is_builtin { // This can cause unfortunate ICEs later down the line. @@ -2254,6 +2265,7 @@ impl ToJson for Target { target_option_val!(has_thumb_interworking); target_option_val!(split_debuginfo); target_option_val!(supported_sanitizers); + target_option_val!(c_enum_min_bits); if let Some(abi) = self.default_adjusted_cabi { d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json()); diff --git a/src/test/ui/layout/thumb-enum.rs b/src/test/ui/layout/thumb-enum.rs new file mode 100644 index 0000000000000..3b43b1b83fa6e --- /dev/null +++ b/src/test/ui/layout/thumb-enum.rs @@ -0,0 +1,34 @@ +// compile-flags: --target thumbv8m.main-none-eabihf +// needs-llvm-components: arm +// +// Verify that thumb targets implement the repr(C) for enums correctly. +// +// See #87917 +#![feature(never_type, rustc_attrs, no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang="sized"] +trait Sized {} + +#[rustc_layout(debug)] +#[repr(C)] +enum A { Apple } //~ ERROR: layout_of + +#[rustc_layout(debug)] +#[repr(C)] +enum B { Banana = 255, } //~ ERROR: layout_of + +#[rustc_layout(debug)] +#[repr(C)] +enum C { Chaenomeles = 256, } //~ ERROR: layout_of + +#[rustc_layout(debug)] +#[repr(C)] +enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of + +const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator! + +#[rustc_layout(debug)] +#[repr(C)] +enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of diff --git a/src/test/ui/layout/thumb-enum.stderr b/src/test/ui/layout/thumb-enum.stderr new file mode 100644 index 0000000000000..898a61b904db5 --- /dev/null +++ b/src/test/ui/layout/thumb-enum.stderr @@ -0,0 +1,442 @@ +error: layout_of(A) = Layout { + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Scalar { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 0, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 1, + }, + }, + ], + }, + abi: Scalar( + Scalar { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 0, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 1, + }, +} + --> $DIR/thumb-enum.rs:16:1 + | +LL | enum A { Apple } + | ^^^^^^^^^^^^^^^^ + +error: layout_of(B) = Layout { + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Scalar { + value: Int( + I8, + false, + ), + valid_range: 255..=255, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 0, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 1, + }, + }, + ], + }, + abi: Scalar( + Scalar { + value: Int( + I8, + false, + ), + valid_range: 255..=255, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Int( + I8, + false, + ), + valid_range: 255..=255, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 0, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 1, + }, +} + --> $DIR/thumb-enum.rs:20:1 + | +LL | enum B { Banana = 255, } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: layout_of(C) = Layout { + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Scalar { + value: Int( + I16, + false, + ), + valid_range: 256..=256, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 1, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 2, + }, + }, + ], + }, + abi: Scalar( + Scalar { + value: Int( + I16, + false, + ), + valid_range: 256..=256, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Int( + I16, + false, + ), + valid_range: 256..=256, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 1, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 2, + }, +} + --> $DIR/thumb-enum.rs:24:1 + | +LL | enum C { Chaenomeles = 256, } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: layout_of(P) = Layout { + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Scalar { + value: Int( + I32, + false, + ), + valid_range: 268435456..=268435456, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 2, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 4, + }, + }, + ], + }, + abi: Scalar( + Scalar { + value: Int( + I32, + false, + ), + valid_range: 268435456..=268435456, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Int( + I32, + false, + ), + valid_range: 268435456..=268435456, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 2, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 4, + }, +} + --> $DIR/thumb-enum.rs:28:1 + | +LL | enum P { Peach = 0x1000_0000isize, } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: layout_of(T) = Layout { + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Scalar { + value: Int( + I32, + true, + ), + valid_range: 2164260864..=2164260864, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 2, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 4, + }, + }, + ], + }, + abi: Scalar( + Scalar { + value: Int( + I32, + true, + ), + valid_range: 2164260864..=2164260864, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Int( + I32, + true, + ), + valid_range: 2164260864..=2164260864, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 2, + }, + pref: Align { + pow2: 2, + }, + }, + size: Size { + raw: 4, + }, +} + --> $DIR/thumb-enum.rs:34:1 + | +LL | enum T { Tangerine = TANGERINE as isize } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors +