diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index bac5c9066f1f6..ef8c88355f62d 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; -use stable_mir::abi::{FnAbi, Layout, LayoutShape}; +use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions}; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{BinOp, Body, Place, UnOp}; @@ -397,6 +397,13 @@ impl<'tcx> SmirCtxt<'tcx> { tables.tcx.is_lang_item(def_id, LangItem::CStr) } + /// Returns the representation options for this ADT + pub fn adt_repr(&self, def: AdtDef) -> ReprOptions { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).repr().stable(&mut *tables) + } + /// Retrieve the function signature for the given generic arguments. pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 7ccc785a40026..28ff84ff35be2 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -5,9 +5,9 @@ use rustc_middle::ty; use rustc_target::callconv::{self, Conv}; use stable_mir::abi::{ - AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, - LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, - WrappingRange, + AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, + IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar, + TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange, }; use stable_mir::opaque; use stable_mir::target::MachineSize as Size; @@ -303,3 +303,42 @@ impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { WrappingRange { start: self.start, end: self.end } } } + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags { + type T = ReprFlags; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + ReprFlags { + is_simd: self.intersects(Self::IS_SIMD), + is_c: self.intersects(Self::IS_C), + is_transparent: self.intersects(Self::IS_TRANSPARENT), + is_linear: self.intersects(Self::IS_LINEAR), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType { + type T = IntegerType; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::IntegerType::Pointer(signed) => IntegerType::Pointer { is_signed: *signed }, + rustc_abi::IntegerType::Fixed(integer, signed) => { + IntegerType::Fixed { length: integer.stable(tables), is_signed: *signed } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions { + type T = ReprOptions; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + ReprOptions { + int: self.int.map(|int| int.stable(tables)), + align: self.align.map(|align| align.stable(tables)), + pack: self.pack.map(|pack| pack.stable(tables)), + flags: self.flags.stable(tables), + } + } +} diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs index 3842cb7e653e8..347c6ed16a245 100644 --- a/compiler/rustc_smir/src/stable_mir/abi.rs +++ b/compiler/rustc_smir/src/stable_mir/abi.rs @@ -455,3 +455,38 @@ pub enum CallConvention { RiscvInterrupt, } + +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprFlags { + pub is_simd: bool, + pub is_c: bool, + pub is_transparent: bool, + pub is_linear: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub enum IntegerType { + /// Pointer-sized integer type, i.e. `isize` and `usize`. + Pointer { + /// Signedness. e.g. `true` for `isize` + is_signed: bool, + }, + /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. + Fixed { + /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`. + length: IntegerLength, + /// Signedness. e.g. `false` for `u8` + is_signed: bool, + }, +} + +/// Representation options provided by the user +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprOptions { + pub int: Option, + pub align: Option, + pub pack: Option, + pub flags: ReprFlags, +} diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index bb35e23a72884..3967ad13eebdc 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs @@ -6,7 +6,7 @@ use std::cell::Cell; use rustc_smir::context::SmirCtxt; -use stable_mir::abi::{FnAbi, Layout, LayoutShape}; +use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions}; use stable_mir::crate_def::Attribute; use stable_mir::mir::alloc::{AllocId, GlobalAlloc}; use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef}; @@ -200,6 +200,11 @@ impl<'tcx> SmirInterface<'tcx> { self.cx.adt_is_cstr(def) } + /// Returns the representation options for this ADT + pub(crate) fn adt_repr(&self, def: AdtDef) -> ReprOptions { + self.cx.adt_repr(def) + } + /// Retrieve the function signature for the given generic arguments. pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { self.cx.fn_sig(def, args) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index e331e5934716a..4461b4ae1250c 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -9,6 +9,7 @@ use stable_mir::mir::mono::StaticDef; use stable_mir::target::MachineInfo; use stable_mir::{Filename, Opaque}; +use super::abi::ReprOptions; use super::mir::{Body, Mutability, Safety}; use super::{DefId, Error, Symbol, with}; use crate::stable_mir; @@ -818,6 +819,10 @@ impl AdtDef { pub fn variant(&self, idx: VariantIdx) -> Option { (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) } + + pub fn repr(&self) -> ReprOptions { + with(|cx| cx.adt_repr(*self)) + } } /// Definition of a variant, which can be either a struct / union field or an enum variant. diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 71edf813a7be2..15ef583709b03 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -21,10 +21,13 @@ use stable_mir::abi::{ ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi, VariantsShape, }; +use stable_mir::mir::MirVisitor; use stable_mir::mir::mono::Instance; use stable_mir::target::MachineInfo; +use stable_mir::ty::{AdtDef, RigidTy, Ty, TyKind}; use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind}; use std::assert_matches::assert_matches; +use std::collections::HashSet; use std::convert::TryFrom; use std::io::Write; use std::ops::ControlFlow; @@ -67,6 +70,17 @@ fn test_stable_mir() -> ControlFlow<()> { assert!(ptr_variadic_fn_abi.c_variadic); assert_eq!(ptr_variadic_fn_abi.args.len(), 1); + let entry = stable_mir::entry_fn().unwrap(); + let main_fn = Instance::try_from(entry).unwrap(); + let mut visitor = AdtDefVisitor::default(); + visitor.visit_body(&main_fn.body().unwrap()); + let AdtDefVisitor { adt_defs } = visitor; + assert_eq!(adt_defs.len(), 1); + + // Test ADT representation options + let repr_c_struct = adt_defs.iter().find(|def| def.trimmed_name() == "ReprCStruct").unwrap(); + assert!(repr_c_struct.repr().flags.is_c); + ControlFlow::Continue(()) } @@ -138,6 +152,20 @@ fn get_item<'a>( items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1) } +#[derive(Default)] +struct AdtDefVisitor { + adt_defs: HashSet, +} + +impl MirVisitor for AdtDefVisitor { + fn visit_ty(&mut self, ty: &Ty, _location: stable_mir::mir::visit::Location) { + if let TyKind::RigidTy(RigidTy::Adt(adt, _)) = ty.kind() { + self.adt_defs.insert(adt); + } + self.super_ty(ty) + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. /// Then it will create a `StableMir` using custom arguments and then @@ -147,7 +175,7 @@ fn main() { generate_input(&path).unwrap(); let args = &[ "rustc".to_string(), - "--crate-type=lib".to_string(), + "-Cpanic=abort".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), path.to_string(), @@ -185,6 +213,13 @@ fn generate_input(path: &str) -> std::io::Result<()> { // We only care about the signature. todo!() }} + + fn main() {{ + #[repr(C)] + struct ReprCStruct; + + let _s = ReprCStruct; + }} "# )?; Ok(())