1
Fork 0

Get rid of the non_zero lang item in favour of arbitrary range specifications

This commit is contained in:
Oliver Schneider 2018-09-07 13:41:59 +02:00
parent 1f02f23263
commit d272e2f6e2
4 changed files with 40 additions and 10 deletions

View file

@ -14,7 +14,8 @@ use ops::CoerceUnsized;
/// A wrapper type for raw pointers and integers that will never be /// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations. /// NULL or 0 that might allow certain optimizations.
#[lang = "non_zero"] #[cfg_attr(stage0, lang = "non_zero")]
#[cfg_attr(not(stage0), rustc_layout_scalar_range_start(1))]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct NonZero<T>(pub(crate) T); pub(crate) struct NonZero<T>(pub(crate) T);

View file

@ -326,8 +326,6 @@ language_item_table! {
PhantomDataItem, "phantom_data", phantom_data; PhantomDataItem, "phantom_data", phantom_data;
NonZeroItem, "non_zero", non_zero;
ManuallyDropItem, "manually_drop", manually_drop; ManuallyDropItem, "manually_drop", manually_drop;
DebugTraitLangItem, "debug_trait", debug_trait; DebugTraitLangItem, "debug_trait", debug_trait;

View file

@ -1083,6 +1083,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
interned interned
} }
/// Returns a range of the start/end indices specified with the `rustc_layout_scalar_range`
/// attribute. Missing range ends may be denoted by `None` and will just use the max/min of
/// the type.
pub fn layout_scalar_range(self, def_id: DefId) -> Option<(Option<u128>, Option<u128>)> {
let attrs = self.get_attrs(def_id);
let get = |name| -> Option<u128> {
let attr = attrs.iter().find(|a| a.check_name(name))?;
for meta in attr.meta_item_list().expect("rustc_layout_scalar_range takes args") {
match meta.literal().expect("rustc_layout_scalar_range attribute takes lit").node {
ast::LitKind::Int(a, _) => return Some(a),
_ => span_bug!(attr.span, "rustc_layout_scalar_range expects integer arg"),
}
}
bug!("no arguments to `rustc_layout_scalar_range` attribute");
};
let start = get("rustc_layout_scalar_range_start");
let end = get("rustc_layout_scalar_range_end");
if start.is_none() && end.is_none() {
return None;
}
Some((start, end))
}
pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> { pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
value.lift_to_tcx(self) value.lift_to_tcx(self)
} }

View file

@ -761,16 +761,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?; let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v }; st.variants = Variants::Single { index: v };
// Exclude 0 from the range of a newtype ABI NonZero<T>. if let Some((start, end)) = self.tcx.layout_scalar_range(def.did) {
if Some(def.did) == self.tcx.lang_items().non_zero() {
match st.abi { match st.abi {
Abi::Scalar(ref mut scalar) | Abi::Scalar(ref mut scalar) |
Abi::ScalarPair(ref mut scalar, _) => { Abi::ScalarPair(ref mut scalar, _) => {
if *scalar.valid_range.start() == 0 { let start = start.unwrap_or(*scalar.valid_range.start());
scalar.valid_range = 1..=*scalar.valid_range.end(); let end = end.unwrap_or(*scalar.valid_range.end());
} scalar.valid_range = start..=end;
} }
_ => {} _ => bug!(
"nonscalar layout for rustc_layout_scalar_range type {:?}: {:#?}",
def,
st,
),
} }
} }
return Ok(tcx.intern_layout(st)); return Ok(tcx.intern_layout(st));
@ -1351,7 +1354,12 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 { if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
return Ok(SizeSkeleton::Pointer { return Ok(SizeSkeleton::Pointer {
non_zero: non_zero || non_zero: non_zero ||
Some(def.did) == tcx.lang_items().non_zero(), tcx.layout_scalar_range(def.did).map_or(false, |(start, end)| {
// `n..` for `n > 0` or `n..m` for `n > 0 && m > n`
start.map_or(true, |start| start > 0 && end.map_or(true, |end| {
end > start
}))
}),
tail, tail,
}); });
} else { } else {