diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index cc36ea7f713..6f27d3207bb 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -14,7 +14,8 @@ use ops::CoerceUnsized; /// 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(pub(crate) T); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d92f856fa4d..bfde4e4a3ae 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -326,8 +326,6 @@ language_item_table! { PhantomDataItem, "phantom_data", phantom_data; - NonZeroItem, "non_zero", non_zero; - ManuallyDropItem, "manually_drop", manually_drop; DebugTraitLangItem, "debug_trait", debug_trait; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index eb6f7140a7d..922308d51fb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1083,6 +1083,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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, Option)> { + let attrs = self.get_attrs(def_id); + let get = |name| -> Option { + 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>(self, value: &T) -> Option { value.lift_to_tcx(self) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 17d613a2b18..be9357dd4a7 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -761,16 +761,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { 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. - 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)); @@ -1351,7 +1354,12 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { 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 {