diff --git a/Cargo.lock b/Cargo.lock index f0e035c025ed..9fa1daf65461 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "miropt-test-tools", "regex", "rustfix", + "semver", "serde", "serde_json", "tracing", @@ -3203,9 +3204,11 @@ dependencies = [ "rand", "rand_xoshiro", "rustc_data_structures", + "rustc_feature", "rustc_index", "rustc_macros", "rustc_serialize", + "rustc_span", "tracing", ] @@ -3301,6 +3304,7 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_ast", + "rustc_data_structures", "rustc_lexer", "rustc_span", "thin-vec", @@ -3621,6 +3625,7 @@ version = "0.0.0" dependencies = [ "annotate-snippets 0.11.4", "derive_setters", + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -3718,6 +3723,7 @@ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", "rustc_attr", @@ -3745,11 +3751,11 @@ dependencies = [ name = "rustc_hir_pretty" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_hir", "rustc_span", - "rustc_target", ] [[package]] @@ -3906,6 +3912,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3933,6 +3940,7 @@ dependencies = [ name = "rustc_lint_defs" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_error_messages", @@ -3940,7 +3948,6 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", - "rustc_target", "serde", ] @@ -3980,6 +3987,7 @@ dependencies = [ "bitflags 2.6.0", "libloading", "odht", + "rustc_abi", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -3998,7 +4006,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_type_ir", - "snap", "tempfile", "tracing", ] @@ -4048,6 +4055,7 @@ version = "0.0.0" dependencies = [ "either", "itertools", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_ast", @@ -4063,7 +4071,6 @@ dependencies = [ "rustc_pattern_analysis", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", "tracing", ] @@ -4074,6 +4081,7 @@ version = "0.0.0" dependencies = [ "polonius-engine", "regex", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4095,6 +4103,7 @@ version = "0.0.0" dependencies = [ "either", "itertools", + "rustc_abi", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4187,6 +4196,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ + "rustc_abi", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -4213,6 +4223,7 @@ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ "rustc-hash 2.0.0", + "rustc_abi", "rustc_apfloat", "rustc_arena", "rustc_data_structures", @@ -4352,6 +4363,7 @@ dependencies = [ "bitflags 2.6.0", "getopts", "libc", + "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4415,6 +4427,7 @@ version = "0.0.0" dependencies = [ "punycode", "rustc-demangle", + "rustc_abi", "rustc_data_structures", "rustc_errors", "rustc_hir", @@ -4877,12 +4890,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "snap" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" - [[package]] name = "socket2" version = "0.5.7" diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 7448f066d0ac..3acd25e54611 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -9,9 +9,11 @@ bitflags = "2.4.1" rand = { version = "0.8.4", default-features = false, optional = true } rand_xoshiro = { version = "0.6.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_feature = { path = "../rustc_feature", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" # tidy-alphabetical-end @@ -22,8 +24,10 @@ default = ["nightly", "randomize"] # without depending on rustc_data_structures, rustc_macros and rustc_serialize nightly = [ "dep:rustc_data_structures", + "dep:rustc_feature", "dep:rustc_macros", "dep:rustc_serialize", + "dep:rustc_span", "rustc_index/nightly", ] randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 872cae59a4e0..ee63e46e88c1 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -6,9 +6,9 @@ mod abi { #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; -#[cfg(feature = "nightly")] -use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout}; use crate::{Align, HasDataLayout, Size}; +#[cfg(feature = "nightly")] +use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout}; #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -128,11 +128,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - match self.abi { - Abi::Uninhabited => Err(Heterogeneous), + match self.backend_repr { + BackendRepr::Uninhabited => Err(Heterogeneous), // The primitive for this algorithm. - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { let kind = match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => RegKind::Integer, abi::Float(_) => RegKind::Float, @@ -140,7 +140,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { assert!(!self.is_zst()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, @@ -148,7 +148,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). let from_fields_at = @@ -246,7 +246,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(result) } } - Abi::Aggregate { sized: false } => Err(Heterogeneous), + BackendRepr::Memory { sized: false } => Err(Heterogeneous), } } } diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_abi/src/extern_abi/mod.rs similarity index 99% rename from compiler/rustc_target/src/spec/abi/mod.rs rename to compiler/rustc_abi/src/extern_abi/mod.rs index c2095155afaf..f7e41280131f 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_abi/src/extern_abi/mod.rs @@ -7,9 +7,11 @@ use rustc_span::{Span, Symbol}; #[cfg(test)] mod tests; +use ExternAbi as Abi; + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub enum Abi { +pub enum ExternAbi { // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the // hashing tests. These are used in many places, so giving them stable values reduces test // churn. The specific values are meaningless. diff --git a/compiler/rustc_target/src/spec/abi/tests.rs b/compiler/rustc_abi/src/extern_abi/tests.rs similarity index 100% rename from compiler/rustc_target/src/spec/abi/tests.rs rename to compiler/rustc_abi/src/extern_abi/tests.rs diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 141a15b99a3d..e6d66f608dae 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -6,7 +6,7 @@ use rustc_index::Idx; use tracing::debug; use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, + AbiAndPrefAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -28,7 +28,7 @@ where VariantIdx: Idx, F: Deref> + fmt::Debug, { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); // We cannot ignore alignment; that might lead us to entirely discard a variant and // produce an enum that is less aligned than it should be! let is_1zst = fields.iter().all(|f| f.is_1zst()); @@ -125,7 +125,7 @@ impl LayoutCalculator { offsets: [Size::ZERO, b_offset].into(), memory_index: [0, 1].into(), }, - abi: Abi::ScalarPair(a, b), + backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, align, size, @@ -216,7 +216,7 @@ impl LayoutCalculator { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, + backend_repr: BackendRepr::Uninhabited, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -331,7 +331,7 @@ impl LayoutCalculator { if let Ok(common) = common_non_zst_abi_and_align { // Discard valid range information and allow undef - let field_abi = field.abi.to_union(); + let field_abi = field.backend_repr.to_union(); if let Some((common_abi, common_align)) = common { if common_abi != field_abi { @@ -340,7 +340,7 @@ impl LayoutCalculator { } else { // Fields with the same non-Aggregate ABI should also // have the same alignment - if !matches!(common_abi, Abi::Aggregate { .. }) { + if !matches!(common_abi, BackendRepr::Memory { .. }) { assert_eq!( common_align, field.align.abi, "non-Aggregate field with matching ABI but differing alignment" @@ -369,11 +369,11 @@ impl LayoutCalculator { // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. let abi = match common_non_zst_abi_and_align { - Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true }, + Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, Ok(Some((abi, _))) => { if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } } else { abi } @@ -387,7 +387,7 @@ impl LayoutCalculator { Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), - abi, + backend_repr: abi, largest_niche: None, align, size: size.align_to(align.abi), @@ -434,23 +434,23 @@ impl LayoutCalculator { // Already doesn't have any niches Scalar::Union { .. } => {} }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { + match &mut st.backend_repr { + BackendRepr::Uninhabited => {} + BackendRepr::Scalar(scalar) => hide_niches(scalar), + BackendRepr::ScalarPair(a, b) => { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} + BackendRepr::Vector { element, count: _ } => hide_niches(element), + BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; return Ok(st); } let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + match st.backend_repr { + BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => { // Enlarging validity ranges would result in missed // optimizations, *not* wrongly assuming the inner // value is valid. e.g. unions already enlarge validity ranges, @@ -607,8 +607,8 @@ impl LayoutCalculator { } // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; + if !layout.is_uninhabited() { + layout.backend_repr = BackendRepr::Memory { sized: true }; } layout.size += this_offset; @@ -627,26 +627,26 @@ impl LayoutCalculator { let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align; - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited + let abi = if variant_layouts.iter().all(|v| v.is_uninhabited()) { + BackendRepr::Uninhabited } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { + match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { + BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar), + BackendRepr::ScalarPair(first, second) => { // Only the niche is guaranteed to be initialised, // so use union layouts for the other primitive. if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) + BackendRepr::ScalarPair(niche_scalar, second.to_union()) } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + BackendRepr::ScalarPair(first.to_union(), niche_scalar) } } - _ => Abi::Aggregate { sized: true }, + _ => BackendRepr::Memory { sized: true }, } } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let layout = LayoutData { @@ -664,7 +664,7 @@ impl LayoutCalculator { offsets: [niche_offset].into(), memory_index: [0].into(), }, - abi, + backend_repr: abi, largest_niche, size, align, @@ -681,7 +681,7 @@ impl LayoutCalculator { let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { continue; } if discr_type.is_signed() { @@ -833,14 +833,14 @@ impl LayoutCalculator { end: (max as u128 & tag_mask), }, }; - let mut abi = Abi::Aggregate { sized: true }; + let mut abi = BackendRepr::Memory { sized: true }; - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if layout_variants.iter().all(|v| v.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } else if tag.size(dl) == size { // Make sure we only use scalar layout when the enum is entirely its // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); + abi = BackendRepr::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. // That's possible only if we can find a common primitive type for all variants. @@ -864,8 +864,8 @@ impl LayoutCalculator { break; } }; - let prim = match field.abi { - Abi::Scalar(scalar) => { + let prim = match field.backend_repr { + BackendRepr::Scalar(scalar) => { common_prim_initialized_in_all_variants &= matches!(scalar, Scalar::Initialized { .. }); scalar.primitive() @@ -934,7 +934,7 @@ impl LayoutCalculator { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } } @@ -942,12 +942,14 @@ impl LayoutCalculator { // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the // variants to ensure they are consistent. This is because a downcast is // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { for variant in &mut layout_variants { // We only do this for variants with fields; the others are not accessed anyway. // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; + if variant.fields.count() > 0 + && matches!(variant.backend_repr, BackendRepr::Memory { .. }) + { + variant.backend_repr = abi; // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); @@ -970,7 +972,7 @@ impl LayoutCalculator { memory_index: [0].into(), }, largest_niche, - abi, + backend_repr: abi, align, size, max_repr_align, @@ -1252,7 +1254,7 @@ impl LayoutCalculator { } let mut layout_of_single_non_zst_field = None; let sized = unsized_field.is_none(); - let mut abi = Abi::Aggregate { sized }; + let mut abi = BackendRepr::Memory { sized }; let optimize_abi = !repr.inhibit_newtype_abi_optimization(); @@ -1270,16 +1272,16 @@ impl LayoutCalculator { // 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 { - match field.abi { + match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => { - abi = field.abi; + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } if optimize_abi => { + abi = field.backend_repr; } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; + BackendRepr::ScalarPair(..) => { + abi = field.backend_repr; } _ => {} } @@ -1288,8 +1290,8 @@ impl LayoutCalculator { // Two non-ZST fields, and they're both scalars. (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { + match (a.backend_repr, b.backend_repr) { + (BackendRepr::Scalar(a), BackendRepr::Scalar(b)) => { // Order by the memory placement, not source order. let ((i, a), (j, b)) = if offsets[i] < offsets[j] { ((i, a), (j, b)) @@ -1315,7 +1317,7 @@ impl LayoutCalculator { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } _ => {} @@ -1325,8 +1327,8 @@ impl LayoutCalculator { _ => {} } } - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if fields.iter().any(|f| f.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } let unadjusted_abi_align = if repr.transparent() { @@ -1344,7 +1346,7 @@ impl LayoutCalculator { Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, + backend_repr: abi, largest_niche, align, size, diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index e029e1426b21..062447ea03f0 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -83,8 +83,8 @@ impl<'a> Layout<'a> { &self.0.0.variants } - pub fn abi(self) -> Abi { - self.0.0.abi + pub fn backend_repr(self) -> BackendRepr { + self.0.0.backend_repr } pub fn largest_niche(self) -> Option { @@ -114,7 +114,7 @@ impl<'a> Layout<'a> { pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) + && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. })) } } @@ -196,9 +196,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty: TyAbiInterface<'a, C>, C: HasDataLayout, { - match self.abi { - Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), - Abi::Aggregate { .. } => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), + BackendRepr::Memory { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) } else { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b54efa4bb48b..ec758785173b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", doc(rust_logo))] +#![cfg_attr(feature = "nightly", feature(assert_matches))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] @@ -28,8 +29,15 @@ mod layout; #[cfg(test)] mod tests; +#[cfg(feature = "nightly")] +mod extern_abi; + pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; #[cfg(feature = "nightly")] +pub use extern_abi::{ + AbiDisabled, AbiUnsupported, ExternAbi, all_names, enabled_names, is_enabled, is_stable, lookup, +}; +#[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; pub use layout::{LayoutCalculator, LayoutCalculatorError}; @@ -1344,11 +1352,19 @@ impl AddressSpace { pub const DATA: Self = AddressSpace(0); } -/// Describes how values of the type are passed by target ABIs, -/// in terms of categories of C types there are ABI rules for. +/// The way we represent values to the backend +/// +/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI. +/// In reality, this implies little about that, but is mostly used to describe the syntactic form +/// emitted for the backend, as most backends handle SSA values and blobs of memory differently. +/// The psABI may need consideration in doing so, but this enum does not constitute a promise for +/// how the value will be lowered to the calling convention, in itself. +/// +/// Generally, a codegen backend will prefer to handle smaller values as a scalar or short vector, +/// and larger values will usually prefer to be represented as memory. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub enum Abi { +pub enum BackendRepr { Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), @@ -1356,19 +1372,23 @@ pub enum Abi { element: Scalar, count: u64, }, - Aggregate { + // FIXME: I sometimes use memory, sometimes use an IR aggregate! + Memory { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, }, } -impl Abi { +impl BackendRepr { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { match *self { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Aggregate { sized } => !sized, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::Vector { .. } => false, + BackendRepr::Memory { sized } => !sized, } } @@ -1381,7 +1401,7 @@ impl Abi { #[inline] pub fn is_signed(&self) -> bool { match self { - Abi::Scalar(scal) => match scal.primitive() { + BackendRepr::Scalar(scal) => match scal.primitive() { Primitive::Int(_, signed) => signed, _ => false, }, @@ -1392,61 +1412,67 @@ impl Abi { /// Returns `true` if this is an uninhabited type #[inline] pub fn is_uninhabited(&self) -> bool { - matches!(*self, Abi::Uninhabited) + matches!(*self, BackendRepr::Uninhabited) } /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { - matches!(*self, Abi::Scalar(_)) + matches!(*self, BackendRepr::Scalar(_)) } /// Returns `true` if this is a bool #[inline] pub fn is_bool(&self) -> bool { - matches!(*self, Abi::Scalar(s) if s.is_bool()) + matches!(*self, BackendRepr::Scalar(s) if s.is_bool()) } /// Returns the fixed alignment of this ABI, if any is mandated. pub fn inherent_align(&self, cx: &C) -> Option { Some(match *self { - Abi::Scalar(s) => s.align(cx), - Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), - Abi::Vector { element, count } => { + BackendRepr::Scalar(s) => s.align(cx), + BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), + BackendRepr::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Returns the fixed size of this ABI, if any is mandated. pub fn inherent_size(&self, cx: &C) -> Option { Some(match *self { - Abi::Scalar(s) => { + BackendRepr::Scalar(s) => { // No padding in scalars. s.size(cx) } - Abi::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1, s2) => { // May have some padding between the pair. let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) } - Abi::Vector { element, count } => { + BackendRepr::Vector { element, count } => { // No padding in vectors, except possibly for trailing padding // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Discard validity range information and allow undef. pub fn to_union(&self) -> Self { match *self { - Abi::Scalar(s) => Abi::Scalar(s.to_union()), - Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), - Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, - Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()), + BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) + } + BackendRepr::Vector { element, count } => { + BackendRepr::Vector { element: element.to_union(), count } + } + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + BackendRepr::Memory { sized: true } + } } } @@ -1454,12 +1480,12 @@ impl Abi { match (self, other) { // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges. // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). - (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(), + (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(), ( - Abi::Vector { element: element_l, count: count_l }, - Abi::Vector { element: element_r, count: count_r }, + BackendRepr::Vector { element: element_l, count: count_l }, + BackendRepr::Vector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => { + (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() } // Everything else must be strictly identical. @@ -1616,14 +1642,14 @@ pub struct LayoutData { /// must be taken into account. pub variants: Variants, - /// The `abi` defines how this data is passed between functions, and it defines - /// value restrictions via `valid_range`. + /// The `backend_repr` defines how this data will be represented to the codegen backend, + /// and encodes value restrictions via `valid_range`. /// /// Note that this is entirely orthogonal to the recursive structure defined by /// `variants` and `fields`; for example, `ManuallyDrop>` has - /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants` + /// `IrForm::ScalarPair`! So, even with non-`Memory` `backend_repr`, `fields` and `variants` /// have to be taken into account to find all fields of this layout. - pub abi: Abi, + pub backend_repr: BackendRepr, /// The leaf scalar with the largest number of invalid values /// (i.e. outside of its `valid_range`), if it exists. @@ -1646,12 +1672,17 @@ pub struct LayoutData { impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { - match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, + match self.backend_repr { + BackendRepr::Uninhabited | BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } + /// Returns `true` if this is an uninhabited type + pub fn is_uninhabited(&self) -> bool { + self.backend_repr.is_uninhabited() + } + pub fn scalar(cx: &C, scalar: Scalar) -> Self { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); @@ -1659,7 +1690,7 @@ impl LayoutData { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Scalar(scalar), + backend_repr: BackendRepr::Scalar(scalar), largest_niche, size, align, @@ -1681,7 +1712,7 @@ where let LayoutData { size, align, - abi, + backend_repr, fields, largest_niche, variants, @@ -1691,7 +1722,7 @@ where f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", abi) + .field("abi", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) @@ -1727,12 +1758,12 @@ impl LayoutData { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() + self.backend_repr.is_unsized() } #[inline] pub fn is_sized(&self) -> bool { - self.abi.is_sized() + self.backend_repr.is_sized() } /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). @@ -1745,10 +1776,12 @@ impl LayoutData { /// Note that this does *not* imply that the type is irrelevant for layout! It can still have /// non-trivial alignment constraints. You probably want to use `is_1zst` instead. pub fn is_zst(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Uninhabited => self.size.bytes() == 0, - Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { + false + } + BackendRepr::Uninhabited => self.size.bytes() == 0, + BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } @@ -1763,8 +1796,8 @@ impl LayoutData { // 2nd point is quite hard to check though. self.size == other.size && self.is_sized() == other.is_sized() - && self.abi.eq_up_to_validity(&other.abi) - && self.abi.is_bool() == other.abi.is_bool() + && self.backend_repr.eq_up_to_validity(&other.backend_repr) + && self.backend_repr.is_bool() == other.backend_repr.is_bool() && self.align.abi == other.align.abi && self.max_repr_align == other.max_repr_align && self.unadjusted_abi_align == other.unadjusted_abi_align diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8e4f4c8e71a2..ec6ca70ae0a4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2810,6 +2810,8 @@ pub struct ModSpans { /// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// Span of the `extern` keyword. + pub extern_span: Span, /// `unsafe` keyword accepted syntactically for macro DSLs, but not /// semantically by Rust. pub safety: Safety, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2afbd979c302..44bb44cb7288 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -525,7 +525,7 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { } fn walk_foreign_mod(vis: &mut T, foreign_mod: &mut ForeignMod) { - let ForeignMod { safety, abi: _, items } = foreign_mod; + let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; visit_safety(vis, safety); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 1d6abbef06c9..3b9edef06159 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -368,7 +368,7 @@ impl Clone for TokenKind { // a copy. This is faster than the `derive(Clone)` version which has a // separate path for every variant. match self { - Interpolated(nt) => Interpolated(nt.clone()), + Interpolated(nt) => Interpolated(Lrc::clone(nt)), _ => unsafe { std::ptr::read(self) }, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index eb71ec5f4ec9..2f8115441de9 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -366,7 +366,7 @@ impl WalkItemKind for ItemKind { } ModKind::Unloaded => {} }, - ItemKind::ForeignMod(ForeignMod { safety: _, abi: _, items }) => { + ItemKind::ForeignMod(ForeignMod { extern_span: _, safety: _, abi: _, items }) => { walk_list!(visitor, visit_foreign_item, items); } ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 9d2b5690c23d..20d3ce65facc 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -10,17 +10,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { b: &Block, targeted_by_break: bool, ) -> &'hir hir::Block<'hir> { - self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) + let hir_id = self.lower_node_id(b.id); + self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break)) } pub(super) fn lower_block_noalloc( &mut self, + hir_id: hir::HirId, b: &Block, targeted_by_break: bool, ) -> hir::Block<'hir> { let (stmts, expr) = self.lower_stmts(&b.stmts); let rules = self.lower_block_check_mode(&b.rules); - let hir_id = self.lower_node_id(b.id); hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3b85f1737bdd..70c94f4019ae 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -259,10 +259,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); + // Target expr needs to lower `self` path. + this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); this.lower_target_expr(&block) } else { - let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(pat_hir_id, span) + this.generate_arg(param.pat.hir_id, span) }; args.push(arg); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a1a16d0ca263..b7cf2d252dcf 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; @@ -70,8 +71,8 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => (), } - let hir_id = self.lower_node_id(e.id); - self.lower_attrs(hir_id, &e.attrs); + let expr_hir_id = self.lower_node_id(e.id); + self.lower_attrs(expr_hir_id, &e.attrs); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -143,7 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), - LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), + LitKind::ByteStr(Lrc::clone(bytes), StrStyle::Cooked), )); hir::ExprKind::Lit(lit) } @@ -175,18 +176,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::If(cond, then, else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| { - let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); - this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label) - }), - ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| { - hir::ExprKind::Loop( - this.lower_block(body, false), - this.lower_label(*opt_label), - hir::LoopSource::Loop, - this.lower_span(*span), - ) - }), + ExprKind::While(cond, body, opt_label) => { + self.with_loop_scope(expr_hir_id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } + ExprKind::Loop(body, opt_label, span) => { + self.with_loop_scope(expr_hir_id, |this| { + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, + this.lower_span(*span), + ) + }) + } ExprKind::TryBlock(body) => self.lower_expr_try_block(body), ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), @@ -212,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *coroutine_kind, fn_decl, body, @@ -223,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *constness, *movability, fn_decl, @@ -250,8 +258,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Block(blk, opt_label) => { - let opt_label = self.lower_label(*opt_label); - hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) + // Different from loops, label of block resolves to block id rather than + // expr node id. + let block_hir_id = self.lower_node_id(blk.id); + let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); + let hir_block = self.arena.alloc(self.lower_block_noalloc( + block_hir_id, + blk, + opt_label.is_some(), + )); + hir::ExprKind::Block(hir_block, opt_label) } ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( @@ -354,7 +370,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { hir_id, kind, span: self.lower_span(e.span) } + hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) } }) } @@ -504,7 +520,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let if_expr = self.expr(span, if_kind); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); - let opt_label = self.lower_label(opt_label); hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } @@ -512,8 +527,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `try { ; }` into `{ ; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { - self.with_catch_scope(body.id, |this| { - let mut block = this.lower_block_noalloc(body, true); + let body_hir_id = self.lower_node_id(body.id); + self.with_catch_scope(body_hir_id, |this| { + let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block let (try_span, tail_expr) = if let Some(expr) = block.expr.take() { @@ -521,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.mark_span_with_reason( DesugaringKind::TryBlock, expr.span, - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ), expr, ) @@ -529,7 +545,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, this.tcx.sess.source_map().end_point(body.span), - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ); (try_span, this.expr_unit(try_span)) @@ -638,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, self.lower_span(span), - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None); @@ -724,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); self.lower_attrs(inner_hir_id, &[Attribute { kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( @@ -800,13 +816,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let features = match await_kind { FutureKind::Future => None, - FutureKind::AsyncIterator => Some(self.allow_for_await.clone()), + FutureKind::AsyncIterator => Some(Lrc::clone(&self.allow_for_await)), }; let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let expr_hir_id = expr.hir_id; @@ -869,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); - let break_x = self.with_loop_scope(loop_node_id, move |this| { + let break_x = self.with_loop_scope(loop_hir_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); this.arena.alloc(this.expr(gen_future_span, expr_break)) @@ -1101,8 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::CoroutineSource::Closure, ); - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); - this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); + this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); (parameters, expr) }); @@ -1465,8 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } - fn lower_label(&self, opt_label: Option