From 4f008e06c33e1ef729bce839c0899154e71902b0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Mar 2022 13:46:56 +1100 Subject: [PATCH] Clarify `Layout` interning. `Layout` is another type that is sometimes interned, sometimes not, and we always use references to refer to it so we can't take any advantage of the uniqueness properties for hashing or equality checks. This commit renames `Layout` as `LayoutS`, and then introduces a new `Layout` that is a newtype around an `Interned`. It also interns more layouts than before. Previously layouts within layouts (via the `variants` field) were never interned, but now they are. Hence the lifetime on the new `Layout` type. Unlike other interned types, these ones are in `rustc_target` instead of `rustc_middle`. This reflects the existing structure of the code, which does layout-specific stuff in `rustc_target` while `TyAndLayout` is generic over the `Ty`, allowing the type-specific stuff to occur in `rustc_middle`. The commit also adds a `HashStable` impl for `Interned`, which was needed. It hashes the contents, unlike the `Hash` impl which hashes the pointer. --- .../src/abi/comments.rs | 10 +- .../src/intrinsics/mod.rs | 2 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 8 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 14 +-- .../src/debuginfo/type_names.rs | 2 +- compiler/rustc_data_structures/src/intern.rs | 10 ++ compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/layout.rs | 103 +++++++++++------- .../src/uninhabited_enum_branching.rs | 2 +- compiler/rustc_target/src/abi/mod.rs | 76 +++++++++++-- compiler/rustc_target/src/lib.rs | 9 +- src/librustdoc/html/render/print_item.rs | 10 +- .../src/transmute/transmute_undefined_repr.rs | 2 +- 17 files changed, 177 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 5fbaed7283a..37d2679c10d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -82,8 +82,14 @@ pub(super) fn add_local_place_comments<'tcx>( return; } let TyAndLayout { ty, layout } = place.layout(); - let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } = - layout; + let rustc_target::abi::LayoutS { + size, + align, + abi: _, + variants: _, + fields: _, + largest_niche: _, + } = layout.0.0; let (kind, extra) = match *place.inner() { CPlaceInner::Var(place_local, var) => { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4dfb13476c2..6489b96be4b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1070,7 +1070,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value { }; raw_eq, (v lhs_ref, v rhs_ref) { - let size = fx.layout_of(substs.type_at(0)).layout.size; + let size = fx.layout_of(substs.type_at(0)).layout.size(); // FIXME add and use emit_small_memcmp let is_eq_value = if size == Size::ZERO { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 572ac559d09..ef213f56369 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -272,20 +272,20 @@ fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'t use rustc_target::abi::Abi::*; let tp_ty = substs.type_at(0); let layout = self.layout_of(tp_ty).layout; - let _use_integer_compare = match layout.abi { + let _use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. - layout.size <= self.data_layout().pointer_size * 2 + layout.size() <= self.data_layout().pointer_size * 2 } }; let a = args[0].immediate(); let b = args[1].immediate(); - if layout.size.bytes() == 0 { + if layout.size().bytes() == 0 { self.const_bool(true) } /*else if use_integer_compare { @@ -301,7 +301,7 @@ fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'t let void_ptr_type = self.context.new_type::<*const ()>(); let a_ptr = self.bitcast(a, void_ptr_type); let b_ptr = self.bitcast(b, void_ptr_type); - let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type); + let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type); let builtin = self.context.get_builtin_function("memcmp"); let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e7c13e793d9..7f804ab5e63 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -300,34 +300,34 @@ fn codegen_intrinsic_call( use abi::Abi::*; let tp_ty = substs.type_at(0); let layout = self.layout_of(tp_ty).layout; - let use_integer_compare = match layout.abi { + let use_integer_compare = match layout.abi() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, Aggregate { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. - layout.size <= self.data_layout().pointer_size * 2 + layout.size() <= self.data_layout().pointer_size * 2 } }; let a = args[0].immediate(); let b = args[1].immediate(); - if layout.size.bytes() == 0 { + if layout.size().bytes() == 0 { self.const_bool(true) } else if use_integer_compare { - let integer_ty = self.type_ix(layout.size.bits()); + let integer_ty = self.type_ix(layout.size().bits()); let ptr_ty = self.type_ptr_to(integer_ty); let a_ptr = self.bitcast(a, ptr_ty); - let a_val = self.load(integer_ty, a_ptr, layout.align.abi); + let a_val = self.load(integer_ty, a_ptr, layout.align().abi); let b_ptr = self.bitcast(b, ptr_ty); - let b_val = self.load(integer_ty, b_ptr, layout.align.abi); + let b_val = self.load(integer_ty, b_ptr, layout.align().abi); self.icmp(IntPredicate::IntEQ, a_val, b_val) } else { let i8p_ty = self.type_i8p(); let a_ptr = self.bitcast(a, i8p_ty); let b_ptr = self.bitcast(b, i8p_ty); - let n = self.const_usize(layout.size.bytes()); + let n = self.const_usize(layout.size().bytes()); let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]); self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 37e84046901..62a297937d4 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -427,7 +427,7 @@ fn msvc_enum_fallback<'tcx>( // calculate the range of values for the dataful variant let dataful_discriminant_range = - dataful_variant_layout.largest_niche.unwrap().scalar.valid_range; + dataful_variant_layout.largest_niche().unwrap().scalar.valid_range; let min = dataful_discriminant_range.start; let min = tag.value.size(&tcx).truncate(min); diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index f0e3f83e848..7a320b10b60 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -1,3 +1,4 @@ +use crate::stable_hasher::{HashStable, StableHasher}; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::ops::Deref; @@ -98,5 +99,14 @@ fn hash(&self, s: &mut H) { } } +impl HashStable for Interned<'_, T> +where + T: HashStable, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.0.hash_stable(hcx, hasher); + } +} + #[cfg(test)] mod tests; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 72b8d8bb297..b6b73ba4539 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2861,8 +2861,8 @@ fn structurally_same_type_impl<'tcx>( let compare_layouts = |a, b| -> Result> { debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &cx.layout_of(a)?.layout.abi; - let b_layout = &cx.layout_of(b)?.layout.abi; + let a_layout = &cx.layout_of(a)?.layout.abi(); + let b_layout = &cx.layout_of(b)?.layout.abi(); debug!( "comparing layouts: {:?} == {:?} = {}", a_layout, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index c0bf64387ff..0d5e1e7f551 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1349,7 +1349,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants) .map(|(variant, variant_layout)| { // Subtract the size of the enum tag. - let bytes = variant_layout.size.bytes().saturating_sub(tag_size); + let bytes = variant_layout.size().bytes().saturating_sub(tag_size); debug!("- variant `{}` is {} bytes large", variant.ident, bytes); bytes diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 7cdcb6a4ab3..f4bc28f4da1 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -392,7 +392,7 @@ fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize { .layout; // In both stdcall and fastcall, we always round up the argument size to the // nearest multiple of 4 bytes. - (layout.size.bytes_usize() + 3) & !3 + (layout.size().bytes_usize() + 3) & !3 }) .sum() } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index c4e6734aa0f..825dc79129d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -6,7 +6,7 @@ macro_rules! arena_types { ($macro:path) => ( $macro!([ - [] layout: rustc_target::abi::Layout, + [] layout: rustc_target::abi::LayoutS<'tcx>, [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>, // AdtDef are interned and compared by address [decode] adt_def: rustc_middle::ty::AdtDef, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b48b6e3a820..99dd4ab1bf5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -56,7 +56,7 @@ use rustc_span::source_map::{MultiSpan, SourceMap}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::TypeFlags; @@ -114,7 +114,7 @@ pub struct CtxtInterners<'tcx> { const_: InternedSet<'tcx, ConstS<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>, - layout: InternedSet<'tcx, Layout>, + layout: InternedSet<'tcx, LayoutS<'tcx>>, adt_def: InternedSet<'tcx, AdtDef>, } @@ -2146,6 +2146,7 @@ pub fn $method(self, v: $ty) -> $ret_ty { region: mk_region(RegionKind): Region -> Region<'tcx>, const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>, const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, + layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>, } macro_rules! direct_interners_old { @@ -2186,7 +2187,6 @@ pub fn $method(self, v: $ty) -> &'tcx $ty { // FIXME: eventually these should all be converted to `direct_interners`. direct_interners_old! { - layout: intern_layout(Layout), adt_def: intern_adt_def(AdtDef), } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 7495449da4c..23664640aae 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,6 +5,7 @@ use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; use rustc_ast as ast; use rustc_attr as attr; +use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; @@ -302,7 +303,7 @@ fn invert_mapping(map: &[u32]) -> Vec { } impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { - fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout { + fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> { let dl = self.data_layout(); let b_align = b.value.align(dl); let align = a.value.align(dl).max(b_align).max(dl.aggregate_align); @@ -316,7 +317,7 @@ fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout { .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); - Layout { + LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO, b_offset], @@ -335,7 +336,7 @@ fn univariant_uninterned( fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind: StructKind, - ) -> Result> { + ) -> Result, LayoutError<'tcx>> { let dl = self.data_layout(); let pack = repr.pack; if pack.is_some() && repr.align.is_some() { @@ -503,8 +504,20 @@ fn univariant_uninterned( // Two non-ZST fields, and they're both scalars. ( - Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })), - Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })), + Some(( + i, + &TyAndLayout { + layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)), + .. + }, + )), + Some(( + j, + &TyAndLayout { + layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)), + .. + }, + )), None, ) => { // Order by the memory placement, not source order. @@ -537,7 +550,7 @@ fn univariant_uninterned( abi = Abi::Uninhabited; } - Ok(Layout { + Ok(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, abi, @@ -547,7 +560,7 @@ fn univariant_uninterned( }) } - fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { + fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result, LayoutError<'tcx>> { let tcx = self.tcx; let param_env = self.param_env; let dl = self.data_layout(); @@ -556,7 +569,8 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' assert!(size.bits() <= 128); Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } } }; - let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value))); + let scalar = + |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value))); let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| { Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?)) @@ -565,11 +579,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' Ok(match *ty.kind() { // Basic scalars. - ty::Bool => tcx.intern_layout(Layout::scalar( + ty::Bool => tcx.intern_layout(LayoutS::scalar( self, Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } }, )), - ty::Char => tcx.intern_layout(Layout::scalar( + ty::Char => tcx.intern_layout(LayoutS::scalar( self, Scalar { value: Int(I32, false), @@ -585,11 +599,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' ty::FnPtr(_) => { let mut ptr = scalar_unit(Pointer); ptr.valid_range = ptr.valid_range.with_start(1); - tcx.intern_layout(Layout::scalar(self, ptr)) + tcx.intern_layout(LayoutS::scalar(self, ptr)) } // The never type. - ty::Never => tcx.intern_layout(Layout { + ty::Never => tcx.intern_layout(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Uninhabited, @@ -607,13 +621,13 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' let pointee = tcx.normalize_erasing_regions(param_env, pointee); if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { - return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr))); + return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr))); } let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); let metadata = match unsized_part.kind() { ty::Foreign(..) => { - return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr))); + return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr))); } ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Dynamic(..) => { @@ -651,7 +665,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' let largest_niche = if count != 0 { element.largest_niche } else { None }; - tcx.intern_layout(Layout { + tcx.intern_layout(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Array { stride: element.size, count }, abi, @@ -662,7 +676,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' } ty::Slice(element) => { let element = self.layout_of(element)?; - tcx.intern_layout(Layout { + tcx.intern_layout(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Array { stride: element.size, count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -671,7 +685,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' size: Size::ZERO, }) } - ty::Str => tcx.intern_layout(Layout { + ty::Str => tcx.intern_layout(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, abi: Abi::Aggregate { sized: false }, @@ -775,7 +789,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' // Extract the number of elements from the layout of the array field: let Ok(TyAndLayout { - layout: Layout { fields: FieldsShape::Array { count, .. }, .. }, + layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)), .. }) = self.layout_of(f0_ty) else { return Err(LayoutError::Unknown(ty)); @@ -825,7 +839,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' FieldsShape::Array { stride: e_ly.size, count: e_len } }; - tcx.intern_layout(Layout { + tcx.intern_layout(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields, abi: Abi::Vector { element: e_abi, count: e_len }, @@ -905,7 +919,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' align = align.min(AbiAndPrefAlign::new(pack)); } - return Ok(tcx.intern_layout(Layout { + return Ok(tcx.intern_layout(LayoutS { variants: Variants::Single { index }, fields: FieldsShape::Union( NonZeroUsize::new(variants[index].len()) @@ -1100,17 +1114,17 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' align = align.max(st.align); - Ok(st) + Ok(tcx.intern_layout(st)) }) .collect::, _>>()?; - let offset = st[i].fields.offset(field_index) + niche.offset; - let size = st[i].size; + let offset = st[i].fields().offset(field_index) + niche.offset; + let size = st[i].size(); - let abi = if st.iter().all(|v| v.abi.is_uninhabited()) { + let abi = if st.iter().all(|v| v.abi().is_uninhabited()) { Abi::Uninhabited } else { - match st[i].abi { + match st[i].abi() { Abi::Scalar(_) => Abi::Scalar(niche_scalar), Abi::ScalarPair(first, second) => { // We need to use scalar_unit to reset the @@ -1130,7 +1144,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' let largest_niche = Niche::from_scalar(dl, offset, niche_scalar); - niche_filling_layout = Some(Layout { + niche_filling_layout = Some(LayoutS { variants: Variants::Multiple { tag: niche_scalar, tag_encoding: TagEncoding::Niche { @@ -1377,7 +1391,10 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<' let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let tagged_layout = Layout { + let layout_variants = + layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect(); + + let tagged_layout = LayoutS { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, @@ -1563,7 +1580,7 @@ fn generator_layout( ty: Ty<'tcx>, def_id: hir::def_id::DefId, substs: SubstsRef<'tcx>, - ) -> Result<&'tcx Layout, LayoutError<'tcx>> { + ) -> Result, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = self.tcx; let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs); @@ -1586,7 +1603,7 @@ fn generator_layout( value: Primitive::Int(discr_int, false), valid_range: WrappingRange { start: 0, end: max_discr }, }; - let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag)); + let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag)); let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout }; let promoted_layouts = ineligible_locals @@ -1722,20 +1739,20 @@ fn generator_layout( size = size.max(variant.size); align = align.max(variant.align); - Ok(variant) + Ok(tcx.intern_layout(variant)) }) .collect::, _>>()?; size = size.align_to(align.abi); - let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited()) - { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; + let abi = + if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) { + Abi::Uninhabited + } else { + Abi::Aggregate { sized: true } + }; - let layout = tcx.intern_layout(Layout { + let layout = tcx.intern_layout(LayoutS { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, @@ -2250,7 +2267,7 @@ fn ty_and_layout_for_variant( ty::Adt(def, _) => def.variants[variant_index].fields.len(), _ => bug!(), }; - tcx.intern_layout(Layout { + tcx.intern_layout(LayoutS { variants: Variants::Single { index: variant_index }, fields: match NonZeroUsize::new(fields) { Some(fields) => FieldsShape::Union(fields), @@ -2263,10 +2280,10 @@ fn ty_and_layout_for_variant( }) } - Variants::Multiple { ref variants, .. } => &variants[variant_index], + Variants::Multiple { ref variants, .. } => variants[variant_index], }; - assert_eq!(layout.variants, Variants::Single { index: variant_index }); + assert_eq!(*layout.variants(), Variants::Single { index: variant_index }); TyAndLayout { ty: this.ty, layout } } @@ -2284,8 +2301,10 @@ fn field_ty_or_layout<'tcx>( ) -> TyMaybeWithLayout<'tcx> { let tcx = cx.tcx(); let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> { - let layout = Layout::scalar(cx, tag); - TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) } + TyAndLayout { + layout: tcx.intern_layout(LayoutS::scalar(cx, tag)), + ty: tag.value.to_ty(tcx), + } }; match *this.ty.kind() { diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index 7133724d07d..bd196f11879 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>( Variants::Multiple { variants, .. } => variants .iter_enumerated() .filter_map(|(idx, layout)| { - (layout.abi != Abi::Uninhabited) + (layout.abi() != Abi::Uninhabited) .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) }) .collect(), diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 4ef86371298..fb5e0272cc3 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -10,6 +10,7 @@ use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; use std::str::FromStr; +use rustc_data_structures::intern::Interned; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable_Generic; use rustc_serialize::json::{Json, ToJson}; @@ -1024,7 +1025,7 @@ pub struct VariantIdx { } #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum Variants { +pub enum Variants<'a> { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, @@ -1038,7 +1039,7 @@ pub enum Variants { tag: Scalar, tag_encoding: TagEncoding, tag_field: usize, - variants: IndexVec, + variants: IndexVec>, }, } @@ -1146,8 +1147,8 @@ pub fn reserve(&self, cx: &C, count: u128) -> Option<(u128, Sc } } -#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub struct Layout { +#[derive(PartialEq, Eq, Hash, HashStable_Generic)] +pub struct LayoutS<'a> { /// Says where the fields are located within the layout. pub fields: FieldsShape, @@ -1158,7 +1159,7 @@ pub struct Layout { /// /// To access all fields of this layout, both `fields` and the fields of the active variant /// must be taken into account. - pub variants: Variants, + pub variants: Variants<'a>, /// The `abi` defines how this data is passed between functions, and it defines /// value restrictions via `valid_range`. @@ -1177,12 +1178,12 @@ pub struct Layout { pub size: Size, } -impl Layout { +impl<'a> LayoutS<'a> { pub fn scalar(cx: &C, scalar: Scalar) -> Self { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.value.size(cx); let align = scalar.value.align(cx); - Layout { + LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, abi: Abi::Scalar(scalar), @@ -1193,6 +1194,59 @@ pub fn scalar(cx: &C, scalar: Scalar) -> Self { } } +impl<'a> fmt::Debug for LayoutS<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This is how `Layout` used to print before it become + // `Interned`. We print it like this to avoid having to update + // expected output in a lot of tests. + f.debug_struct("Layout") + .field("fields", &self.fields) + .field("variants", &self.variants) + .field("abi", &self.abi) + .field("largest_niche", &self.largest_niche) + .field("align", &self.align) + .field("size", &self.size) + .finish() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>); + +impl<'a> fmt::Debug for Layout<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // See comment on `::fmt` above. + self.0.0.fmt(f) + } +} + +impl<'a> Layout<'a> { + pub fn fields(self) -> &'a FieldsShape { + &self.0.0.fields + } + + pub fn variants(self) -> &'a Variants<'a> { + &self.0.0.variants + } + + pub fn abi(self) -> Abi { + self.0.0.abi + } + + pub fn largest_niche(self) -> Option { + self.0.0.largest_niche + } + + pub fn align(self) -> AbiAndPrefAlign { + self.0.0.align + } + + pub fn size(self) -> Size { + self.0.0.size + } +} + /// The layout of a type, alongside the type itself. /// Provides various type traversal APIs (e.g., recursing into fields). /// @@ -1203,13 +1257,13 @@ pub fn scalar(cx: &C, scalar: Scalar) -> Self { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)] pub struct TyAndLayout<'a, Ty> { pub ty: Ty, - pub layout: &'a Layout, + pub layout: Layout<'a>, } impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { - type Target = &'a Layout; - fn deref(&self) -> &&'a Layout { - &self.layout + type Target = &'a LayoutS<'a>; + fn deref(&self) -> &&'a LayoutS<'a> { + &self.layout.0.0 } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 2919743e499..e9ef71ede51 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -8,13 +8,14 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(bool_to_option)] -#![feature(let_else)] -#![feature(nll)] -#![feature(never_type)] #![feature(associated_type_bounds)] +#![feature(bool_to_option)] #![feature(exhaustive_patterns)] +#![feature(let_else)] #![feature(min_specialization)] +#![feature(never_type)] +#![feature(nll)] +#![feature(rustc_attrs)] #![feature(step_trait)] use std::iter::FromIterator; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e84dc6c7240..68644a017a4 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1710,11 +1710,11 @@ struct update syntax will not work.", } fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { - fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) { - if layout.abi.is_unsized() { + fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) { + if layout.abi().is_unsized() { write!(w, "(unsized)"); } else { - let bytes = layout.size.bytes() - tag_size; + let bytes = layout.size().bytes() - tag_size; write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },); } } @@ -1744,7 +1744,7 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) { write_size_of_layout(w, ty_layout.layout, 0); writeln!(w, "

"); if let Variants::Multiple { variants, tag, tag_encoding, .. } = - &ty_layout.layout.variants + &ty_layout.layout.variants() { if !variants.is_empty() { w.write_str( @@ -1767,7 +1767,7 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) { for (index, layout) in variants.iter_enumerated() { let name = adt.variants[index].name; write!(w, "
  • {name}: ", name = name); - write_size_of_layout(w, layout, tag_size); + write_size_of_layout(w, *layout, tag_size); writeln!(w, "
  • "); } w.write_str(""); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 05eadab3e6c..81076776ed3 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -326,7 +326,7 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty); if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); then { - layout.layout.size.bytes() == 0 + layout.layout.size().bytes() == 0 } else { false }