-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Move pointee_info_at from rustc_codegen_llvm to rustc_target. #60237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
b7266c6
e395026
ed716d4
f1f9343
d47ec57
7257fc3
82410e8
199ff02
35bd58b
8e3d9f1
852dd49
8802dc0
18679cd
94a4892
80d5478
968eb7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ use std::iter; | |
use std::mem; | ||
use std::ops::Bound; | ||
|
||
use crate::hir; | ||
use crate::ich::StableHashingContext; | ||
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; | ||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, | ||
|
@@ -1543,25 +1544,32 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> { | |
} | ||
|
||
pub trait MaybeResult<T> { | ||
fn from_ok(x: T) -> Self; | ||
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self; | ||
type Error; | ||
|
||
fn from(x: Result<T, Self::Error>) -> Self; | ||
fn to_result(self) -> Result<T, Self::Error>; | ||
} | ||
|
||
impl<T> MaybeResult<T> for T { | ||
fn from_ok(x: T) -> Self { | ||
type Error = !; | ||
|
||
fn from(x: Result<T, Self::Error>) -> Self { | ||
let Ok(x) = x; | ||
x | ||
} | ||
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self { | ||
f(self) | ||
fn to_result(self) -> Result<T, Self::Error> { | ||
Ok(self) | ||
} | ||
} | ||
|
||
impl<T, E> MaybeResult<T> for Result<T, E> { | ||
fn from_ok(x: T) -> Self { | ||
Ok(x) | ||
type Error = E; | ||
|
||
fn from(x: Result<T, Self::Error>) -> Self { | ||
x | ||
} | ||
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self { | ||
self.map(f) | ||
fn to_result(self) -> Result<T, Self::Error> { | ||
self | ||
} | ||
} | ||
|
||
|
@@ -1654,20 +1662,30 @@ impl ty::query::TyCtxtAt<'a, 'tcx, '_> { | |
} | ||
} | ||
|
||
pub trait HasParamEnv<'tcx> { | ||
fn param_env(&self) -> ty::ParamEnv<'tcx>; | ||
} | ||
|
||
impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> { | ||
saleemjaffer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fn param_env(&self) -> ty::ParamEnv<'tcx> { | ||
self.param_env | ||
} | ||
} | ||
|
||
impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> | ||
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>, | ||
C::TyLayout: MaybeResult<TyLayout<'tcx>> | ||
C::TyLayout: MaybeResult<TyLayout<'tcx>>, | ||
C: HasParamEnv<'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, | ||
|
||
Variants::Single { index } => { | ||
// Deny calling for_variant more than once for non-Single enums. | ||
cx.layout_of(this.ty).map_same(|layout| { | ||
if let Ok(layout) = cx.layout_of(this.ty).to_result() { | ||
assert_eq!(layout.variants, Variants::Single { index }); | ||
layout | ||
}); | ||
} | ||
|
||
let fields = match this.ty.sty { | ||
ty::Adt(def, _) => def.variants[variant_index].fields.len(), | ||
|
@@ -1700,10 +1718,9 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> | |
let tcx = cx.tcx(); | ||
let discr_layout = |discr: &Scalar| -> C::TyLayout { | ||
let layout = LayoutDetails::scalar(cx, discr.clone()); | ||
MaybeResult::from_ok(TyLayout { | ||
details: tcx.intern_layout(layout), | ||
ty: discr.value.to_ty(tcx) | ||
}) | ||
MaybeResult::from(Ok( | ||
TyLayout {details: tcx.intern_layout(layout),ty: discr.value.to_ty(tcx)} | ||
saleemjaffer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
)) | ||
}; | ||
|
||
cx.layout_of(match this.ty.sty { | ||
|
@@ -1737,10 +1754,12 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> | |
} else { | ||
tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) | ||
}; | ||
return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| { | ||
ptr_layout.ty = this.ty; | ||
ptr_layout | ||
}); | ||
return MaybeResult::from( | ||
cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even with this much indentation, rustfmt will keep return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(
|mut ptr_layout| {
ptr_layout.ty = this.ty;
ptr_layout
},
)); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eddyb actually rustfmt does this return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
ptr_layout.ty = this.ty;
ptr_layout
})); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only if you have less indentation than you actually do here. |
||
ptr_layout.ty = this.ty; | ||
ptr_layout | ||
}) | ||
); | ||
} | ||
|
||
match tcx.struct_tail(pointee).sty { | ||
|
@@ -1824,6 +1843,130 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> | |
} | ||
}) | ||
} | ||
|
||
fn pointee_info_at( | ||
this: TyLayout<'tcx>, | ||
cx: &C, | ||
offset: Size, | ||
) -> Option<PointeeInfo> { | ||
match this.ty.sty { | ||
ty::RawPtr(mt) if offset.bytes() == 0 => { | ||
cx.layout_of(mt.ty).to_result().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, cx.param_env(), 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 | ||
} | ||
} | ||
}; | ||
|
||
cx.layout_of(ty).to_result().ok() | ||
.map(|layout| PointeeInfo { | ||
size: layout.size, | ||
align: layout.align.abi, | ||
safe: Some(kind), | ||
}) | ||
} | ||
|
||
_ => { | ||
let mut data_variant = match this.variants { | ||
// Within the discriminant field, only the niche itself is | ||
// always initialized, so we 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). | ||
Variants::Multiple { | ||
discr_kind: DiscriminantKind::Niche { | ||
dataful_variant, | ||
.. | ||
}, | ||
discr_index, | ||
.. | ||
} if this.fields.offset(discr_index) == offset => | ||
Some(this.for_variant(cx, dataful_variant)), | ||
_ => Some(this), | ||
}; | ||
|
||
if let Some(variant) = data_variant { | ||
// We're not interested in any unions. | ||
if let FieldPlacement::Union(_) = variant.fields { | ||
data_variant = None; | ||
} | ||
} | ||
|
||
let mut result = 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.to_result().ok() | ||
.and_then(|field| { | ||
if ptr_end <= field_start + field.size { | ||
// We found the right field, look inside it. | ||
field.pointee_info_at(cx, offset - field_start) | ||
} else { | ||
None | ||
} | ||
}); | ||
if result.is_some() { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
// FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. | ||
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 { | ||
|
Uh oh!
There was an error while loading. Please reload this page.