]> git.lizzy.rs Git - rust.git/commitdiff
Clarify `Layout` interning.
authorNicholas Nethercote <n.nethercote@gmail.com>
Fri, 4 Mar 2022 02:46:56 +0000 (13:46 +1100)
committerNicholas Nethercote <n.nethercote@gmail.com>
Mon, 7 Mar 2022 02:41:47 +0000 (13:41 +1100)
`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<LayoutS>`. 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.

17 files changed:
compiler/rustc_codegen_cranelift/src/abi/comments.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_data_structures/src/intern.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/lib.rs
src/librustdoc/html/render/print_item.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs

index 5fbaed7283a6781400a2ca0628cc731ae49edb8e..37d2679c10d70af2f21316bf404ecbd29eecf4a8 100644 (file)
@@ -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) => {
index 4dfb13476c287f7bbe06692b3025f9547097db60..6489b96be4b2d037e212ba7b650c7adfab7bd02f 100644 (file)
@@ -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 {
index 572ac559d09dfb89fb5842cab86c7903d900dae7..ef213f5636907811ad4c0354e1e99153f5dfe287 100644 (file)
@@ -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))
index e7c13e793d92e3150cca00f3d9b8f33243d73989..7f804ab5e6347aad8a5e9a4809420c65990b77c5 100644 (file)
@@ -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))
                 }
index 37e84046901f695ee1533b906ea63ed225bc736d..62a297937d40c66c2856fa5746f67f6123e64cb2 100644 (file)
@@ -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);
index f0e3f83e8489cfeadf925b0abd7ebfdfdfb87325..7a320b10b60300460fc3efe19811798742efb599 100644 (file)
@@ -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<H: Hasher>(&self, s: &mut H) {
     }
 }
 
+impl<T, CTX> HashStable<CTX> for Interned<'_, T>
+where
+    T: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.0.hash_stable(hcx, hasher);
+    }
+}
+
 #[cfg(test)]
 mod tests;
index 72b8d8bb297a6b8a486814726ddf34851b73ac31..b6b73ba45391ea1d3d19e3b999bdbf634b8855e6 100644 (file)
@@ -2861,8 +2861,8 @@ fn structurally_same_type_impl<'tcx>(
 
                 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
                     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,
index c0bf64387ff376ab77bad579e4802c70bcc7779e..0d5e1e7f5513cc25dce49be4dd462b85cb906d5f 100644 (file)
@@ -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
index 7cdcb6a4ab302604c30cb4fb95c1f1937cc56610..f4bc28f4da19914ee396fcb465356c030160e3da 100644 (file)
@@ -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()
     }
index c4e6734aa0fa71efa23fc2c361a991e462889b35..825dc79129d267a2eb7342432c112106c8d85360 100644 (file)
@@ -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,
index b48b6e3a820c523ae67391fee45ac60c0dc95402..99dd4ab1bf5fd8e14d620c27f5b441fdfd97a3aa 100644 (file)
@@ -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<ty::BoundVariableKind>>,
-    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),
 }
 
index 7495449da4c4f78abee054894d03aadd3f7eee9e..23664640aaef0f8987c7b82121bb7675359a769c 100644 (file)
@@ -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<u32> {
 }
 
 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<Layout, LayoutError<'tcx>> {
+    ) -> Result<LayoutS<'tcx>, 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<Layout<'tcx>, 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::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
-                            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<Layout<'tcx>, 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::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
         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() {
index 7133724d07d95c6639b922ce61ab40cd8fb3ebbf..bd196f1187966db729fe37b77b544bfa79e6b621 100644 (file)
@@ -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(),
index 4ef863712983f802b793c2f87c717e08c5e39cfc..fb5e0272cc359c36e5273fa685b17eb45fcdc966 100644 (file)
@@ -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<VariantIdx, Layout>,
+        variants: IndexVec<VariantIdx, Layout<'a>>,
     },
 }
 
@@ -1146,8 +1147,8 @@ pub fn reserve<C: HasDataLayout>(&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<C: HasDataLayout>(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<C: HasDataLayout>(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<LayoutS>`. 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 `<LayoutS as Debug>::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<Niche> {
+        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<C: HasDataLayout>(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
     }
 }
 
index 2919743e4996fa12e9d65f7f2df4a5da3b5a7b8c..e9ef71ede51821469a6d3840fc8b26ef055de3b5 100644 (file)
@@ -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;
index e84dc6c72409f6ee2bc98089a3ad6144a8e77503..68644a017a4004001188eaf3c697e99dd1f9a0ac 100644 (file)
@@ -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, "</p>");
             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, "<li><code>{name}</code>: ", name = name);
-                        write_size_of_layout(w, layout, tag_size);
+                        write_size_of_layout(w, *layout, tag_size);
                         writeln!(w, "</li>");
                     }
                     w.write_str("</ul>");
index 05eadab3e6ccdcc500f881b62668bbc1a53a2a08..81076776ed3d333ad00dc1271fa17ff199a6fc70 100644 (file)
@@ -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
         }