/// A wrapper type for raw pointers and integers that will never be
/// 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)]
#[repr(transparent)]
pub(crate) struct NonZero<T>(pub(crate) T);
PhantomDataItem, "phantom_data", phantom_data;
- NonZeroItem, "non_zero", non_zero;
-
ManuallyDropItem, "manually_drop", manually_drop;
DebugTraitLangItem, "debug_trait", debug_trait;
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> {
value.lift_to_tcx(self)
}
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v };
- // Exclude 0 from the range of a newtype ABI NonZero<T>.
- if Some(def.did) == self.tcx.lang_items().non_zero() {
+ if let Some((start, end)) = self.tcx.layout_scalar_range(def.did) {
match st.abi {
Abi::Scalar(ref mut scalar) |
Abi::ScalarPair(ref mut scalar, _) => {
- if *scalar.valid_range.start() == 0 {
- scalar.valid_range = 1..=*scalar.valid_range.end();
- }
+ let start = start.unwrap_or(*scalar.valid_range.start());
+ 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));
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
return Ok(SizeSkeleton::Pointer {
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,
});
} else {