From 15955b9b1038f504ea7e87aacd481a2cc98e29dc Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Mon, 24 Dec 2018 17:52:50 +0100 Subject: [PATCH 1/7] Move pointee_info_at to TyLayoutMethods. The original implementation is still present at librustc_codegen_llvm/abi.rs, should be removed later to prevent code duplication. --- src/librustc/ty/layout.rs | 128 +++++++++++++++++++++++++++++++++ src/librustc_target/abi/mod.rs | 27 +++++++ 2 files changed, 155 insertions(+) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f4506c8e81976..5ec256cab7bc1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -22,6 +22,8 @@ use std::iter; use std::mem; use std::ops::Bound; +use hir; + use ich::StableHashingContext; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -1497,6 +1499,7 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> { pub trait MaybeResult { fn from_ok(x: T) -> Self; fn map_same T>(self, f: F) -> Self; + fn ok(self) -> Option; } impl MaybeResult for T { @@ -1506,6 +1509,9 @@ impl MaybeResult for T { fn map_same T>(self, f: F) -> Self { f(self) } + fn ok(self) -> Option { + Some(self) + } } impl MaybeResult for Result { @@ -1515,6 +1521,9 @@ impl MaybeResult for Result { fn map_same T>(self, f: F) -> Self { self.map(f) } + fn ok(self) -> Option { + self.ok() + } } pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; @@ -1762,6 +1771,125 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } }) } + + fn pointee_info_at(this: TyLayout<'tcx>, cx: &C, offset: Size + ) -> Option { + let mut result = None; + match this.ty.sty { + ty::RawPtr(mt) if offset.bytes() == 0 => { + result = cx.layout_of(mt.ty).ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + }); + } + + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let tcx = cx.tcx(); + let is_freeze = ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP); + let kind = match mt { + hir::MutImmutable => if is_freeze { + PointerKind::Frozen + } else { + PointerKind::Shared + }, + hir::MutMutable => { + // Previously we would only emit noalias annotations for LLVM >= 6 or in + // panic=abort mode. That was deemed right, as prior versions had many bugs + // in conjunction with unwinding, but later versions didn’t seem to have + // said issues. See issue #31681. + // + // Alas, later on we encountered a case where noalias would generate wrong + // code altogether even with recent versions of LLVM in *safe* code with no + // unwinding involved. See #54462. + // + // For now, do not enable mutable_noalias by default at all, while the + // issue is being figured out. + let mutable_noalias = tcx.sess.opts.debugging_opts.mutable_noalias + .unwrap_or(false); + if mutable_noalias { + PointerKind::UniqueBorrowed + } else { + PointerKind::Shared + } + } + }; + + result = cx.layout_of(ty).ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: Some(kind), + }); + } + + _ => { + let mut data_variant = match this.variants { + Variants::NicheFilling { dataful_variant, .. } => { + // Only the niche itthis is always initialized, + // so only check for a pointer at its offset. + // + // If the niche is a pointer, it's either valid + // (according to its type), or null (which the + // niche field's scalar validity range encodes). + // This allows using `dereferenceable_or_null` + // for e.g., `Option<&T>`, and this will continue + // to work as long as we don't start using more + // niches than just null (e.g., the first page + // of the address space, or unaligned pointers). + if this.fields.offset(0) == offset { + Some(this.for_variant(cx, dataful_variant)) + } else { + None + } + } + _ => Some(this) + }; + + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let FieldPlacement::Union(_) = variant.fields { + data_variant = None; + } + } + + if let Some(variant) = data_variant { + let ptr_end = offset + Pointer.size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + result = field.ok() + .and_then(|field| { + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + Self::pointee_info_at(field, cx, offset - field_start) + } else { + None + } + }); + if result.is_some() { + break; + } + } + } + } + + // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + if let Some(ref mut pointee) = result { + if let ty::Adt(def, _) = this.ty.sty { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } + } + } + } + } + + result + } + } struct Niche { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 5912da9d3aa2f..eb360965cee30 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -913,6 +913,28 @@ pub trait LayoutOf { fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout; } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PointerKind { + /// Most general case, we know no restrictions to tell LLVM. + Shared, + + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. + Frozen, + + /// `&mut T`, when we know `noalias` is safe for LLVM. + UniqueBorrowed, + + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. + UniqueOwned +} + +#[derive(Copy, Clone)] +pub struct PointeeInfo { + pub size: Size, + pub align: Align, + pub safe: Option, +} + pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { fn for_variant( this: TyLayout<'a, Self>, @@ -920,6 +942,11 @@ pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { variant_index: VariantIdx, ) -> TyLayout<'a, Self>; fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout; + fn pointee_info_at( + this: TyLayout<'a, Self>, + cx: &C, + offset: Size + ) -> Option; } impl<'a, Ty> TyLayout<'a, Ty> { From 659ffb249d8b014664c6bb5a38eb1c8ad0d39841 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 28 Dec 2018 12:23:23 +0100 Subject: [PATCH 2/7] Fix typo in src/librustc/ty/layout.rs Co-Authored-By: wildarch --- src/librustc/ty/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5ec256cab7bc1..f91e552fa5b81 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1827,7 +1827,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> _ => { let mut data_variant = match this.variants { Variants::NicheFilling { dataful_variant, .. } => { - // Only the niche itthis is always initialized, + // Only the niche in this is always initialized, // so only check for a pointer at its offset. // // If the niche is a pointer, it's either valid From 3d3d64f0d37309a79ad0b5bcb6cc233f24029d14 Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Fri, 28 Dec 2018 12:52:31 +0100 Subject: [PATCH 3/7] Return instead of collecting to mut result. --- src/librustc/ty/layout.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f91e552fa5b81..10aa155cfd997 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1772,17 +1772,19 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> }) } - fn pointee_info_at(this: TyLayout<'tcx>, cx: &C, offset: Size + fn pointee_info_at( + this: TyLayout<'tcx>, + cx: &C, + offset: Size, ) -> Option { - let mut result = None; match this.ty.sty { ty::RawPtr(mt) if offset.bytes() == 0 => { - result = cx.layout_of(mt.ty).ok() + cx.layout_of(mt.ty).ok() .map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: None, - }); + }) } ty::Ref(_, ty, mt) if offset.bytes() == 0 => { @@ -1816,12 +1818,12 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } }; - result = cx.layout_of(ty).ok() + cx.layout_of(ty).ok() .map(|layout| PointeeInfo { size: layout.size, align: layout.align.abi, safe: Some(kind), - }); + }) } _ => { @@ -1854,6 +1856,8 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } } + let mut result = None; + if let Some(variant) = data_variant { let ptr_end = offset + Pointer.size(cx); for i in 0..variant.fields.count() { @@ -1884,10 +1888,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } } } + + result } } - - result } } From e08d9cf059f94409abeaa197463c5238259eb66c Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Fri, 28 Dec 2018 13:15:39 +0100 Subject: [PATCH 4/7] Remove old pointee_info_at body. --- src/librustc_codegen_llvm/abi.rs | 4 +- src/librustc_codegen_llvm/context.rs | 3 +- src/librustc_codegen_llvm/type_of.rs | 132 +-------------------------- 3 files changed, 6 insertions(+), 133 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 8c4f7a58dab40..5047ea9e56107 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -15,7 +15,7 @@ use context::CodegenCx; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; use type_::Type; -use type_of::{LayoutLlvmExt, PointerKind}; +use type_of::{LayoutLlvmExt}; use value::Value; use rustc_target::abi::call::ArgType; @@ -23,7 +23,7 @@ use rustc_codegen_ssa::traits::*; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi}; use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout; +use rustc::ty::layout::{self, PointerKind}; use libc::c_uint; diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index b75cd8f68b368..aebce5b5c8579 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -18,7 +18,6 @@ use value::Value; use monomorphize::partitioning::CodegenUnit; use type_::Type; -use type_of::PointeeInfo; use rustc_codegen_ssa::traits::*; use libc::c_uint; @@ -27,7 +26,7 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc::mir::mono::Stats; use rustc::session::config::{self, DebugInfo}; use rustc::session::Session; -use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx}; +use rustc::ty::layout::{LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use rustc_target::spec::{HasTargetSpec, Target}; diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 52b560c662540..519cac27373c7 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -10,10 +10,9 @@ use abi::{FnType, FnTypeExt}; use common::*; -use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; -use rustc_target::abi::FloatTy; +use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout}; +use rustc_target::abi::{FloatTy, TyLayoutMethods}; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_codegen_ssa::traits::*; use type_::Type; @@ -179,28 +178,6 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum PointerKind { - /// Most general case, we know no restrictions to tell LLVM. - Shared, - - /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. - Frozen, - - /// `&mut T`, when we know `noalias` is safe for LLVM. - UniqueBorrowed, - - /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. - UniqueOwned -} - -#[derive(Copy, Clone)] -pub struct PointeeInfo { - pub size: Size, - pub align: Align, - pub safe: Option, -} - pub trait LayoutLlvmExt<'tcx> { fn is_llvm_immediate(&self) -> bool; fn is_llvm_scalar_pair<'a>(&self) -> bool; @@ -411,110 +388,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { return pointee; } - let mut result = None; - match self.ty.sty { - ty::RawPtr(mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(mt.ty); - result = Some(PointeeInfo { - size, - align, - safe: None - }); - } - - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(ty); - - let kind = match mt { - hir::MutImmutable => if cx.type_is_freeze(ty) { - PointerKind::Frozen - } else { - PointerKind::Shared - }, - hir::MutMutable => { - // Previously we would only emit noalias annotations for LLVM >= 6 or in - // panic=abort mode. That was deemed right, as prior versions had many bugs - // in conjunction with unwinding, but later versions didn’t seem to have - // said issues. See issue #31681. - // - // Alas, later on we encountered a case where noalias would generate wrong - // code altogether even with recent versions of LLVM in *safe* code with no - // unwinding involved. See #54462. - // - // For now, do not enable mutable_noalias by default at all, while the - // issue is being figured out. - let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias - .unwrap_or(false); - if mutable_noalias { - PointerKind::UniqueBorrowed - } else { - PointerKind::Shared - } - } - }; - - result = Some(PointeeInfo { - size, - align, - safe: Some(kind) - }); - } - - _ => { - let mut data_variant = match self.variants { - layout::Variants::NicheFilling { dataful_variant, .. } => { - // Only the niche itself is always initialized, - // so only check for a pointer at its offset. - // - // If the niche is a pointer, it's either valid - // (according to its type), or null (which the - // niche field's scalar validity range encodes). - // This allows using `dereferenceable_or_null` - // for e.g., `Option<&T>`, and this will continue - // to work as long as we don't start using more - // niches than just null (e.g., the first page - // of the address space, or unaligned pointers). - if self.fields.offset(0) == offset { - Some(self.for_variant(cx, dataful_variant)) - } else { - None - } - } - _ => Some(*self) - }; - - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let layout::FieldPlacement::Union(_) = variant.fields { - data_variant = None; - } - } - - if let Some(variant) = data_variant { - let ptr_end = offset + layout::Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - result = field.pointee_info_at(cx, offset - field_start); - break; - } - } - } - } - - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = self.ty.sty { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); - } - } - } - } - } + let result = Ty::pointee_info_at(*self, cx, offset); cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); result From 7cba55ec21c38bb08282e936e7c96bab42dc0a38 Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Fri, 28 Dec 2018 15:19:23 +0100 Subject: [PATCH 5/7] Add param_env parameter to pointee_info_at. An associated type ParamEnv has been added to TyLayoutMethods to facilitate this. --- src/librustc/ty/layout.rs | 7 +++++-- src/librustc_codegen_llvm/type_of.rs | 2 +- src/librustc_target/abi/mod.rs | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 10aa155cfd997..37dd903692fa1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1619,6 +1619,8 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> where C: LayoutOf> + HasTyCtxt<'tcx>, C::TyLayout: MaybeResult> { + type ParamEnv = ty::ParamEnv<'tcx>; + fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { let details = match this.variants { Variants::Single { index } if index == variant_index => this.details, @@ -1776,6 +1778,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> this: TyLayout<'tcx>, cx: &C, offset: Size, + param_env: Self::ParamEnv, ) -> Option { match this.ty.sty { ty::RawPtr(mt) if offset.bytes() == 0 => { @@ -1789,7 +1792,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> ty::Ref(_, ty, mt) if offset.bytes() == 0 => { let tcx = cx.tcx(); - let is_freeze = ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP); + let is_freeze = ty.is_freeze(tcx, param_env, DUMMY_SP); let kind = match mt { hir::MutImmutable => if is_freeze { PointerKind::Frozen @@ -1868,7 +1871,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> .and_then(|field| { if ptr_end <= field_start + field.size { // We found the right field, look inside it. - Self::pointee_info_at(field, cx, offset - field_start) + Self::pointee_info_at(field, cx, offset - field_start, param_env) } else { None } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 519cac27373c7..759be6e84a75c 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -388,7 +388,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { return pointee; } - let result = Ty::pointee_info_at(*self, cx, offset); + let result = Ty::pointee_info_at(*self, cx, offset, ty::ParamEnv::reveal_all()); cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); result diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index eb360965cee30..e56853f261dfe 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -936,6 +936,8 @@ pub struct PointeeInfo { } pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { + type ParamEnv; + fn for_variant( this: TyLayout<'a, Self>, cx: &C, @@ -945,7 +947,8 @@ pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { fn pointee_info_at( this: TyLayout<'a, Self>, cx: &C, - offset: Size + offset: Size, + param_env: Self::ParamEnv, ) -> Option; } From bb05cb81872dd34486facc15cc926b9aa2be45dd Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Fri, 11 Jan 2019 11:26:47 +0100 Subject: [PATCH 6/7] Make line fit within 100 character limit. --- src/librustc/ty/layout.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 37dd903692fa1..2c09d0a1b74f1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1870,8 +1870,9 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> result = field.ok() .and_then(|field| { if ptr_end <= field_start + field.size { + let off = offset - field_start; // We found the right field, look inside it. - Self::pointee_info_at(field, cx, offset - field_start, param_env) + Self::pointee_info_at(field, cx, off, param_env) } else { None } From 3ce7a68a88df917ad78fa286b6ef1fbf6c233a34 Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Mon, 11 Mar 2019 21:26:49 +0100 Subject: [PATCH 7/7] impl `pointee_info_at` in TyLayout. --- src/librustc_codegen_llvm/abi.rs | 4 ++-- src/librustc_target/abi/mod.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 5047ea9e56107..5e3b42dfc3ce4 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -22,7 +22,7 @@ use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi}; -use rustc::ty::{self, Ty, Instance}; +use rustc::ty::{self, Ty, Instance, ParamEnv}; use rustc::ty::layout::{self, PointerKind}; use libc::c_uint; @@ -487,7 +487,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } } - if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(pointee) = layout.pointee_info_at(cx, offset, ParamEnv::reveal_all()) { if let Some(kind) = pointee.safe { attrs.pointee_size = pointee.size; attrs.pointee_align = Some(pointee.align); diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index e56853f261dfe..7f255c0f1267e 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -961,6 +961,10 @@ impl<'a, Ty> TyLayout<'a, Ty> { where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { Ty::field(self, cx, i) } + pub fn pointee_info_at(self, cx: &C, offset: Size, param_env: Ty::ParamEnv) -> Option + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { + Ty::pointee_info_at(self, cx, offset, param_env) + } } impl<'a, Ty> TyLayout<'a, Ty> {