/// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations.
#[cfg_attr(stage0, lang = "non_zero")]
-#[cfg_attr(not(stage0), rustc_layout_scalar_range_start(1))]
+#[cfg_attr(not(stage0), rustc_layout_scalar_valid_range_start(1))]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub(crate) struct NonZero<T>(pub(crate) T);
use std::hash::{Hash, Hasher};
use std::fmt;
use std::mem;
-use std::ops::Deref;
+use std::ops::{Deref, Bound};
use std::iter;
use std::sync::mpsc;
use std::sync::Arc;
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>)> {
+ /// Returns a range of the start/end indices specified with the
+ /// `rustc_layout_scalar_valid_range` attribute.
+ pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<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"),
+ let get = |name| {
+ let attr = match attrs.iter().find(|a| a.check_name(name)) {
+ Some(attr) => attr,
+ None => return Bound::Unbounded,
+ };
+ for meta in attr.meta_item_list().expect("rustc_layout_scalar_valid_range takes args") {
+ match meta.literal().expect("attribute takes lit").node {
+ ast::LitKind::Int(a, _) => return Bound::Included(a),
+ _ => span_bug!(attr.span, "rustc_layout_scalar_valid_range expects int arg"),
}
}
- bug!("no arguments to `rustc_layout_scalar_range` attribute");
+ span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_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))
+ (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end"))
}
pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
use std::i128;
use std::iter;
use std::mem;
+use std::ops::Bound;
use ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v };
- 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, _) => {
- let start = start.unwrap_or(*scalar.valid_range.start());
- let end = end.unwrap_or(*scalar.valid_range.end());
- scalar.valid_range = start..=end;
+ let (start, end) = self.tcx.layout_scalar_valid_range(def.did);
+ match st.abi {
+ Abi::Scalar(ref mut scalar) |
+ Abi::ScalarPair(ref mut scalar, _) => {
+ // the asserts ensure that we are not using the
+ // `#[rustc_layout_scalar_valid_range(n)]`
+ // attribute to widen the range of anything as that would probably
+ // result in UB somewhere
+ if let Bound::Included(start) = start {
+ assert!(*scalar.valid_range.start() <= start);
+ scalar.valid_range = start..=*scalar.valid_range.end();
+ }
+ if let Bound::Included(end) = end {
+ assert!(*scalar.valid_range.end() >= end);
+ scalar.valid_range = *scalar.valid_range.start()..=end;
}
- _ => bug!(
- "nonscalar layout for rustc_layout_scalar_range type {:?}: {:#?}",
- def,
- st,
- ),
}
+ _ => bug!(
+ "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}",
+ def,
+ st,
+ ),
}
return Ok(tcx.intern_layout(st));
}
if def.variants.len() == 1 {
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
return Ok(SizeSkeleton::Pointer {
- non_zero: 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
- }))
- }),
+ non_zero: non_zero || match tcx.layout_scalar_valid_range(def.did) {
+ (Bound::Included(start), Bound::Unbounded) => start > 0,
+ (Bound::Included(start), Bound::Included(end)) =>
+ 0 < start && start < end,
+ _ => false,
+ },
tail,
});
} else {
@vis [$v:vis]
@debug_format [$debug_format:tt]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
- #[rustc_layout_scalar_range_end($max)]
+ #[rustc_layout_scalar_valid_range_end($max)]
$v struct $type {
private: u32
}