about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2021-08-10 18:34:13 +0000
committerManish Goregaokar <manishsmail@gmail.com>2021-08-12 09:44:16 -0700
commitfd116c806aaa59fabd2ab72398d35fc665e8226e (patch)
tree3b83acaf50233c52e2bcbf39216cf8fafd886db2
parentae90dcf0207c57c3034f00b07048d63f8b2363c8 (diff)
downloadrust-fd116c806aaa59fabd2ab72398d35fc665e8226e.tar.gz
rust-fd116c806aaa59fabd2ab72398d35fc665e8226e.zip
Add c_enum_min_bits to target spec
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs24
-rw-r--r--compiler/rustc_target/src/abi/mod.rs17
-rw-r--r--compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs12
-rw-r--r--src/test/ui/layout/thumb-enum.rs34
-rw-r--r--src/test/ui/layout/thumb-enum.stderr442
6 files changed, 515 insertions, 16 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 423f3faf21f..3caca313ffd 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 9a24edf1a42..8ef6e142cae 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<Self, String> {
+        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 e0097ee220a..27d306c41b7 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 9c957cba6cc..e5987511c97 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<Abi>,
+
+    /// 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<u32>) => ( {
                 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<Abi>)?;
+        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 00000000000..3b43b1b83fa
--- /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 00000000000..898a61b904d
--- /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
+