Auto merge of #54032 - oli-obk:layout_scalar_ranges, r=eddyb
Add forever unstable attribute to allow specifying arbitrary scalar ranges r? @eddyb for the first commit and @nikomatsakis for the second one
This commit is contained in:
commit
dfabe4b885
@ -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_valid_range_start(1))]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct NonZero<T>(pub(crate) T);
|
||||
|
@ -16,25 +16,53 @@ use std::fmt;
|
||||
use std::u32;
|
||||
|
||||
newtype_index! {
|
||||
pub struct CrateNum {
|
||||
pub struct CrateId {
|
||||
ENCODABLE = custom
|
||||
DEBUG_FORMAT = "crate{}",
|
||||
}
|
||||
}
|
||||
|
||||
/// Item definitions in the currently-compiled crate would have the CrateNum
|
||||
/// LOCAL_CRATE in their DefId.
|
||||
const LOCAL_CRATE = 0,
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum CrateNum {
|
||||
/// Virtual crate for builtin macros
|
||||
// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
|
||||
// `CrateNum`s.
|
||||
BuiltinMacros,
|
||||
/// A CrateNum value that indicates that something is wrong.
|
||||
Invalid,
|
||||
/// A special CrateNum that we use for the tcx.rcache when decoding from
|
||||
/// the incr. comp. cache.
|
||||
ReservedForIncrCompCache,
|
||||
Index(CrateId),
|
||||
}
|
||||
|
||||
/// Virtual crate for builtin macros
|
||||
// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
|
||||
// `CrateNum`s.
|
||||
const BUILTIN_MACROS_CRATE = CrateNum::MAX_AS_U32,
|
||||
impl ::std::fmt::Debug for CrateNum {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
match self {
|
||||
CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
|
||||
CrateNum::Invalid => write!(fmt, "invalid crate"),
|
||||
CrateNum::BuiltinMacros => write!(fmt, "bultin macros crate"),
|
||||
CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A CrateNum value that indicates that something is wrong.
|
||||
const INVALID_CRATE = CrateNum::MAX_AS_U32 - 1,
|
||||
/// Item definitions in the currently-compiled crate would have the CrateNum
|
||||
/// LOCAL_CRATE in their DefId.
|
||||
pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32_const(0));
|
||||
|
||||
/// A special CrateNum that we use for the tcx.rcache when decoding from
|
||||
/// the incr. comp. cache.
|
||||
const RESERVED_FOR_INCR_COMP_CACHE = CrateNum::MAX_AS_U32 - 2,
|
||||
|
||||
impl Idx for CrateNum {
|
||||
#[inline]
|
||||
fn new(value: usize) -> Self {
|
||||
CrateNum::Index(Idx::new(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self) -> usize {
|
||||
match self {
|
||||
CrateNum::Index(idx) => Idx::index(idx),
|
||||
_ => bug!("Tried to get crate index of {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,12 +71,39 @@ impl CrateNum {
|
||||
CrateNum::from_usize(x)
|
||||
}
|
||||
|
||||
pub fn from_usize(x: usize) -> CrateNum {
|
||||
CrateNum::Index(CrateId::from_usize(x))
|
||||
}
|
||||
|
||||
pub fn from_u32(x: u32) -> CrateNum {
|
||||
CrateNum::Index(CrateId::from_u32(x))
|
||||
}
|
||||
|
||||
pub fn as_usize(self) -> usize {
|
||||
match self {
|
||||
CrateNum::Index(id) => id.as_usize(),
|
||||
_ => bug!("tried to get index of nonstandard crate {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_u32(self) -> u32 {
|
||||
match self {
|
||||
CrateNum::Index(id) => id.as_u32(),
|
||||
_ => bug!("tried to get index of nonstandard crate {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } }
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.as_u32(), f)
|
||||
match self {
|
||||
CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
|
||||
CrateNum::Invalid => write!(f, "invalid crate"),
|
||||
CrateNum::BuiltinMacros => write!(f, "bultin macros crate"),
|
||||
CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,7 +772,15 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
|
||||
FnPtrAddrCast
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
|
||||
impl_stable_hash_for!(struct ::middle::region::Scope { id, data });
|
||||
|
||||
impl_stable_hash_for!(enum ::middle::region::ScopeData {
|
||||
Node,
|
||||
CallSite,
|
||||
Arguments,
|
||||
Destruction,
|
||||
Remainder(first_statement_index)
|
||||
});
|
||||
|
||||
impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
|
||||
type KeyType = region::Scope;
|
||||
@ -783,11 +791,6 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ::middle::region::BlockRemainder {
|
||||
block,
|
||||
first_statement_index
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
|
||||
custom_kind
|
||||
});
|
||||
|
@ -119,17 +119,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
let scope_decorated_tag = match scope.data() {
|
||||
region::ScopeData::Node(_) => tag,
|
||||
region::ScopeData::CallSite(_) => "scope of call-site for function",
|
||||
region::ScopeData::Arguments(_) => "scope of function body",
|
||||
region::ScopeData::Destruction(_) => {
|
||||
region::ScopeData::Node => tag,
|
||||
region::ScopeData::CallSite => "scope of call-site for function",
|
||||
region::ScopeData::Arguments => "scope of function body",
|
||||
region::ScopeData::Destruction => {
|
||||
new_string = format!("destruction scope surrounding {}", tag);
|
||||
&new_string[..]
|
||||
}
|
||||
region::ScopeData::Remainder(r) => {
|
||||
region::ScopeData::Remainder(first_statement_index) => {
|
||||
new_string = format!(
|
||||
"block suffix following statement {}",
|
||||
r.first_statement_index.index()
|
||||
first_statement_index.index()
|
||||
);
|
||||
&new_string[..]
|
||||
}
|
||||
|
@ -58,6 +58,8 @@
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(refcell_replace_swap)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(stage0, feature(attr_literals))]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_sort_by_cached_key)]
|
||||
#![feature(specialization)]
|
||||
|
@ -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;
|
||||
|
@ -20,8 +20,8 @@ use ich::{StableHashingContext, NodeIdHashingMode};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use ty;
|
||||
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::fmt;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax::source_map;
|
||||
use syntax::ast;
|
||||
@ -51,7 +51,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
/// `DestructionScope`, but those that are `terminating_scopes` do;
|
||||
/// see discussion with `ScopeTree`.
|
||||
///
|
||||
/// `Remainder(BlockRemainder { block, statement_index })` represents
|
||||
/// `Remainder { block, statement_index }` represents
|
||||
/// the scope of user code running immediately after the initializer
|
||||
/// expression for the indexed statement, until the end of the block.
|
||||
///
|
||||
@ -100,39 +100,46 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
/// placate the same deriving in `ty::FreeRegion`, but we may want to
|
||||
/// actually attach a more meaningful ordering to scopes than the one
|
||||
/// generated via deriving here.
|
||||
///
|
||||
/// Scope is a bit-packed to save space - if `code` is SCOPE_DATA_REMAINDER_MAX
|
||||
/// or less, it is a `ScopeData::Remainder`, otherwise it is a type specified
|
||||
/// by the bitpacking.
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, RustcEncodable, RustcDecodable)]
|
||||
pub struct Scope {
|
||||
pub(crate) id: hir::ItemLocalId,
|
||||
pub(crate) code: u32
|
||||
pub(crate) data: ScopeData,
|
||||
}
|
||||
|
||||
const SCOPE_DATA_NODE: u32 = !0;
|
||||
const SCOPE_DATA_CALLSITE: u32 = !1;
|
||||
const SCOPE_DATA_ARGUMENTS: u32 = !2;
|
||||
const SCOPE_DATA_DESTRUCTION: u32 = !3;
|
||||
const SCOPE_DATA_REMAINDER_MAX: u32 = !4;
|
||||
impl fmt::Debug for Scope {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.data {
|
||||
ScopeData::Node => write!(fmt, "Node({:?})", self.id),
|
||||
ScopeData::CallSite => write!(fmt, "CallSite({:?})", self.id),
|
||||
ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id),
|
||||
ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id),
|
||||
ScopeData::Remainder(fsi) => write!(
|
||||
fmt,
|
||||
"Remainder {{ block: {:?}, first_statement_index: {}}}",
|
||||
self.id,
|
||||
fsi.as_u32(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
|
||||
pub enum ScopeData {
|
||||
Node(hir::ItemLocalId),
|
||||
Node,
|
||||
|
||||
// Scope of the call-site for a function or closure
|
||||
// (outlives the arguments as well as the body).
|
||||
CallSite(hir::ItemLocalId),
|
||||
CallSite,
|
||||
|
||||
// Scope of arguments passed to a function or closure
|
||||
// (they outlive its body).
|
||||
Arguments(hir::ItemLocalId),
|
||||
Arguments,
|
||||
|
||||
// Scope of destructors for temporaries of node-id.
|
||||
Destruction(hir::ItemLocalId),
|
||||
Destruction,
|
||||
|
||||
// Scope following a `let id = expr;` binding in a block.
|
||||
Remainder(BlockRemainder)
|
||||
Remainder(FirstStatementIndex)
|
||||
}
|
||||
|
||||
/// Represents a subscope of `block` for a binding that is introduced
|
||||
@ -152,83 +159,61 @@ pub enum ScopeData {
|
||||
///
|
||||
/// * the subscope with `first_statement_index == 1` is scope of `c`,
|
||||
/// and thus does not include EXPR_2, but covers the `...`.
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
|
||||
RustcDecodable, Debug, Copy)]
|
||||
pub struct BlockRemainder {
|
||||
pub block: hir::ItemLocalId,
|
||||
pub first_statement_index: FirstStatementIndex,
|
||||
}
|
||||
|
||||
newtype_index! {
|
||||
pub struct FirstStatementIndex {
|
||||
MAX = SCOPE_DATA_REMAINDER_MAX
|
||||
}
|
||||
pub struct FirstStatementIndex { .. }
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { private });
|
||||
|
||||
impl From<ScopeData> for Scope {
|
||||
#[inline]
|
||||
fn from(scope_data: ScopeData) -> Self {
|
||||
let (id, code) = match scope_data {
|
||||
ScopeData::Node(id) => (id, SCOPE_DATA_NODE),
|
||||
ScopeData::CallSite(id) => (id, SCOPE_DATA_CALLSITE),
|
||||
ScopeData::Arguments(id) => (id, SCOPE_DATA_ARGUMENTS),
|
||||
ScopeData::Destruction(id) => (id, SCOPE_DATA_DESTRUCTION),
|
||||
ScopeData::Remainder(r) => (r.block, r.first_statement_index.index() as u32)
|
||||
};
|
||||
Self { id, code }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Scope {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.data(), formatter)
|
||||
}
|
||||
}
|
||||
// compilation error if size of `ScopeData` is not the same as a `u32`
|
||||
#[allow(dead_code)]
|
||||
// only works on stage 1 when the rustc_layout_scalar_valid_range attribute actually exists
|
||||
#[cfg(not(stage0))]
|
||||
static ASSERT: () = [()][!(mem::size_of::<ScopeData>() == 4) as usize];
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl Scope {
|
||||
#[inline]
|
||||
pub fn data(self) -> ScopeData {
|
||||
match self.code {
|
||||
SCOPE_DATA_NODE => ScopeData::Node(self.id),
|
||||
SCOPE_DATA_CALLSITE => ScopeData::CallSite(self.id),
|
||||
SCOPE_DATA_ARGUMENTS => ScopeData::Arguments(self.id),
|
||||
SCOPE_DATA_DESTRUCTION => ScopeData::Destruction(self.id),
|
||||
idx => ScopeData::Remainder(BlockRemainder {
|
||||
block: self.id,
|
||||
first_statement_index: FirstStatementIndex::new(idx as usize)
|
||||
})
|
||||
}
|
||||
self.data
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(id: hir::ItemLocalId, data: ScopeData) -> Self {
|
||||
Scope { id, data }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn Node(id: hir::ItemLocalId) -> Self {
|
||||
Self::from(ScopeData::Node(id))
|
||||
Self::new(id, ScopeData::Node)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn CallSite(id: hir::ItemLocalId) -> Self {
|
||||
Self::from(ScopeData::CallSite(id))
|
||||
Self::new(id, ScopeData::CallSite)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn Arguments(id: hir::ItemLocalId) -> Self {
|
||||
Self::from(ScopeData::Arguments(id))
|
||||
Self::new(id, ScopeData::Arguments)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn Destruction(id: hir::ItemLocalId) -> Self {
|
||||
Self::from(ScopeData::Destruction(id))
|
||||
Self::new(id, ScopeData::Destruction)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn Remainder(r: BlockRemainder) -> Self {
|
||||
Self::from(ScopeData::Remainder(r))
|
||||
pub fn Remainder(
|
||||
id: hir::ItemLocalId,
|
||||
first: FirstStatementIndex,
|
||||
) -> Self {
|
||||
Self::new(id, ScopeData::Remainder(first))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Scope {
|
||||
/// Returns a item-local id associated with this scope.
|
||||
///
|
||||
@ -259,7 +244,7 @@ impl Scope {
|
||||
return DUMMY_SP;
|
||||
}
|
||||
let span = tcx.hir.span(node_id);
|
||||
if let ScopeData::Remainder(r) = self.data() {
|
||||
if let ScopeData::Remainder(first_statement_index) = self.data() {
|
||||
if let Node::Block(ref blk) = tcx.hir.get(node_id) {
|
||||
// Want span for scope starting after the
|
||||
// indexed statement and ending at end of
|
||||
@ -269,7 +254,7 @@ impl Scope {
|
||||
// (This is the special case aluded to in the
|
||||
// doc-comment for this method)
|
||||
|
||||
let stmt_span = blk.stmts[r.first_statement_index.index()].span;
|
||||
let stmt_span = blk.stmts[first_statement_index.index()].span;
|
||||
|
||||
// To avoid issues with macro-generated spans, the span
|
||||
// of the statement must be nested in that of the block.
|
||||
@ -513,8 +498,8 @@ impl<'tcx> ScopeTree {
|
||||
}
|
||||
|
||||
// record the destruction scopes for later so we can query them
|
||||
if let ScopeData::Destruction(n) = child.data() {
|
||||
self.destruction_scopes.insert(n, child);
|
||||
if let ScopeData::Destruction = child.data() {
|
||||
self.destruction_scopes.insert(child.item_local_id(), child);
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,7 +582,7 @@ impl<'tcx> ScopeTree {
|
||||
|
||||
while let Some(&(p, _)) = self.parent_map.get(&id) {
|
||||
match p.data() {
|
||||
ScopeData::Destruction(..) => {
|
||||
ScopeData::Destruction => {
|
||||
debug!("temporary_scope({:?}) = {:?} [enclosing]",
|
||||
expr_id, id);
|
||||
return Some(id);
|
||||
@ -652,8 +637,8 @@ impl<'tcx> ScopeTree {
|
||||
/// Returns the id of the innermost containing body
|
||||
pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
|
||||
loop {
|
||||
if let ScopeData::CallSite(id) = scope.data() {
|
||||
return Some(id);
|
||||
if let ScopeData::CallSite = scope.data() {
|
||||
return Some(scope.item_local_id());
|
||||
}
|
||||
|
||||
match self.opt_encl_scope(scope) {
|
||||
@ -869,10 +854,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
|
||||
// except for the first such subscope, which has the
|
||||
// block itself as a parent.
|
||||
visitor.enter_scope(
|
||||
Scope::Remainder(BlockRemainder {
|
||||
block: blk.hir_id.local_id,
|
||||
first_statement_index: FirstStatementIndex::new(i)
|
||||
})
|
||||
Scope::Remainder(blk.hir_id.local_id, FirstStatementIndex::new(i))
|
||||
);
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
}
|
||||
@ -1035,7 +1017,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
|
||||
match visitor.scope_tree.parent_map.get(&scope) {
|
||||
// Don't cross from closure bodies to their parent.
|
||||
Some(&(superscope, _)) => match superscope.data() {
|
||||
ScopeData::CallSite(_) => break,
|
||||
ScopeData::CallSite => break,
|
||||
_ => scope = superscope
|
||||
},
|
||||
None => break
|
||||
|
@ -66,7 +66,7 @@ use std::collections::hash_map::{self, Entry};
|
||||
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;
|
||||
@ -829,10 +829,12 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
|
||||
impl<'tcx> CommonTypes<'tcx> {
|
||||
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
|
||||
// Ensure our type representation does not grow
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert!(mem::size_of::<ty::TyKind>() <= 24);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert!(mem::size_of::<ty::TyS>() <= 32);
|
||||
#[cfg(all(not(stage0), target_pointer_width = "64"))]
|
||||
#[allow(dead_code)]
|
||||
static ASSERT_TY_KIND: () = [()][!(::std::mem::size_of::<ty::TyKind>() <= 24) as usize];
|
||||
#[cfg(all(not(stage0), target_pointer_width = "64"))]
|
||||
#[allow(dead_code)]
|
||||
static ASSERT_TYS: () = [()][!(::std::mem::size_of::<ty::TyS>() <= 32) as usize];
|
||||
|
||||
let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
|
||||
let mk_region = |r| {
|
||||
@ -1083,6 +1085,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
interned
|
||||
}
|
||||
|
||||
/// 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| {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_range` attribute");
|
||||
};
|
||||
(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> {
|
||||
value.lift_to_tcx(self)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use std::fmt;
|
||||
use std::i128;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::Bound;
|
||||
|
||||
use ich::StableHashingContext;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
@ -761,17 +762,29 @@ 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<T>.
|
||||
if Some(def.did) == self.tcx.lang_items().non_zero() {
|
||||
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, 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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => assert!(
|
||||
start == Bound::Unbounded && end == Bound::Unbounded,
|
||||
"nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}",
|
||||
def,
|
||||
st,
|
||||
),
|
||||
}
|
||||
return Ok(tcx.intern_layout(st));
|
||||
}
|
||||
@ -1350,8 +1363,12 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
|
||||
if def.variants.len() == 1 {
|
||||
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(),
|
||||
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 {
|
||||
|
@ -11,8 +11,7 @@
|
||||
use dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
|
||||
use errors::Diagnostic;
|
||||
use hir;
|
||||
use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
|
||||
RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
|
||||
use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use hir::map::definitions::DefPathHash;
|
||||
use ich::{CachingSourceMapView, Fingerprint};
|
||||
use mir::{self, interpret};
|
||||
@ -566,7 +565,7 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
|
||||
let tcx = self.tcx();
|
||||
|
||||
let cache_key = ty::CReaderCacheKey {
|
||||
cnum: RESERVED_FOR_INCR_COMP_CACHE,
|
||||
cnum: CrateNum::ReservedForIncrCompCache,
|
||||
pos: shorthand,
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
use hir::def_id::DefId;
|
||||
use hir::map::definitions::DefPathData;
|
||||
use mir::interpret::ConstValue;
|
||||
use middle::region::{self, BlockRemainder};
|
||||
use middle::region;
|
||||
use ty::subst::{self, Subst};
|
||||
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
|
||||
use ty::{Bool, Char, Adt};
|
||||
@ -770,17 +770,20 @@ define_print! {
|
||||
}
|
||||
ty::ReScope(scope) if cx.identify_regions => {
|
||||
match scope.data() {
|
||||
region::ScopeData::Node(id) =>
|
||||
write!(f, "'{}s", id.as_usize()),
|
||||
region::ScopeData::CallSite(id) =>
|
||||
write!(f, "'{}cs", id.as_usize()),
|
||||
region::ScopeData::Arguments(id) =>
|
||||
write!(f, "'{}as", id.as_usize()),
|
||||
region::ScopeData::Destruction(id) =>
|
||||
write!(f, "'{}ds", id.as_usize()),
|
||||
region::ScopeData::Remainder(BlockRemainder
|
||||
{ block, first_statement_index }) =>
|
||||
write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()),
|
||||
region::ScopeData::Node =>
|
||||
write!(f, "'{}s", scope.item_local_id().as_usize()),
|
||||
region::ScopeData::CallSite =>
|
||||
write!(f, "'{}cs", scope.item_local_id().as_usize()),
|
||||
region::ScopeData::Arguments =>
|
||||
write!(f, "'{}as", scope.item_local_id().as_usize()),
|
||||
region::ScopeData::Destruction =>
|
||||
write!(f, "'{}ds", scope.item_local_id().as_usize()),
|
||||
region::ScopeData::Remainder(first_statement_index) => write!(
|
||||
f,
|
||||
"'{}_{}rs",
|
||||
scope.item_local_id().as_usize(),
|
||||
first_statement_index.index()
|
||||
),
|
||||
}
|
||||
}
|
||||
ty::ReVar(region_vid) if cx.identify_regions => {
|
||||
|
@ -72,7 +72,8 @@ macro_rules! newtype_index {
|
||||
newtype_index!(
|
||||
// Leave out derives marker so we can use its absence to ensure it comes first
|
||||
@type [$name]
|
||||
@max [::std::u32::MAX - 1]
|
||||
// shave off 256 indices at the end to allow space for packing these indices into enums
|
||||
@max [0xFFFF_FF00]
|
||||
@vis [$v]
|
||||
@debug_format ["{}"]);
|
||||
);
|
||||
@ -82,7 +83,8 @@ macro_rules! newtype_index {
|
||||
newtype_index!(
|
||||
// Leave out derives marker so we can use its absence to ensure it comes first
|
||||
@type [$name]
|
||||
@max [::std::u32::MAX - 1]
|
||||
// shave off 256 indices at the end to allow space for packing these indices into enums
|
||||
@max [0xFFFF_FF00]
|
||||
@vis [$v]
|
||||
@debug_format ["{}"]
|
||||
$($tokens)+);
|
||||
@ -97,6 +99,7 @@ macro_rules! newtype_index {
|
||||
@vis [$v:vis]
|
||||
@debug_format [$debug_format:tt]) => (
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
|
||||
#[rustc_layout_scalar_valid_range_end($max)]
|
||||
$v struct $type {
|
||||
private: u32
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl<'tcx> CFG<'tcx> {
|
||||
source_info: SourceInfo,
|
||||
region_scope: region::Scope) {
|
||||
if tcx.emit_end_regions() {
|
||||
if let region::ScopeData::CallSite(_) = region_scope.data() {
|
||||
if let region::ScopeData::CallSite = region_scope.data() {
|
||||
// The CallSite scope (aka the root scope) is sort of weird, in that it is
|
||||
// supposed to "separate" the "interior" and "exterior" of a closure. Being
|
||||
// that, it is not really a part of the region hierarchy, but for some
|
||||
|
@ -566,7 +566,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// We want `scopes[1]`, which is the `ParameterScope`.
|
||||
assert!(self.scopes.len() >= 2);
|
||||
assert!(match self.scopes[1].region_scope.data() {
|
||||
region::ScopeData::Arguments(_) => true,
|
||||
region::ScopeData::Arguments => true,
|
||||
_ => false,
|
||||
});
|
||||
self.scopes[1].region_scope
|
||||
|
@ -11,7 +11,7 @@
|
||||
use hair::*;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use rustc::middle::region::{self, BlockRemainder};
|
||||
use rustc::middle::region;
|
||||
use rustc::hir;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -71,10 +71,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
// ignore for purposes of the MIR
|
||||
}
|
||||
hir::DeclKind::Local(ref local) => {
|
||||
let remainder_scope = region::Scope::Remainder(BlockRemainder {
|
||||
block: block_id,
|
||||
first_statement_index: region::FirstStatementIndex::new(index),
|
||||
});
|
||||
let remainder_scope = region::Scope::Remainder(
|
||||
block_id,
|
||||
region::FirstStatementIndex::new(index),
|
||||
);
|
||||
|
||||
let mut pattern = cx.pattern_from_hir(&local.pat);
|
||||
|
||||
|
@ -340,7 +340,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
|
||||
let field = field.try_into().unwrap();
|
||||
let field_layout = op.layout.field(self, field)?;
|
||||
if field_layout.size.bytes() == 0 {
|
||||
if field_layout.is_zst() {
|
||||
let val = Value::Scalar(Scalar::zst().into());
|
||||
return Ok(OpTy { op: Operand::Immediate(val), layout: field_layout });
|
||||
}
|
||||
@ -397,9 +397,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
Field(field, _) => self.operand_field(base, field.index() as u64)?,
|
||||
Downcast(_, variant) => self.operand_downcast(base, variant)?,
|
||||
Deref => self.deref_operand(base)?.into(),
|
||||
// The rest should only occur as mplace, we do not use Immediates for types
|
||||
// allowing such operations. This matches place_projection forcing an allocation.
|
||||
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
|
||||
Subslice { .. } | ConstantIndex { .. } | Index(_) => if base.layout.is_zst() {
|
||||
OpTy {
|
||||
op: Operand::Immediate(Value::Scalar(Scalar::zst().into())),
|
||||
// the actual index doesn't matter, so we just pick a convenient one like 0
|
||||
layout: base.layout.field(self, 0)?,
|
||||
}
|
||||
} else {
|
||||
// The rest should only occur as mplace, we do not use Immediates for types
|
||||
// allowing such operations. This matches place_projection forcing an allocation.
|
||||
let mplace = base.to_mem_place();
|
||||
self.mplace_projection(mplace, proj_elem)?.into()
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(range_contains)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(stage0, feature(attr_literals))]
|
||||
#![feature(never_type)]
|
||||
#![feature(specialization)]
|
||||
#![feature(try_trait)]
|
||||
|
@ -22,7 +22,7 @@ use Namespace::{self, TypeNS, ValueNS, MacroNS};
|
||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||
|
||||
use rustc::hir::def::*;
|
||||
use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
||||
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
|
||||
use rustc::ty;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc_metadata::cstore::LoadedMacro;
|
||||
@ -769,7 +769,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
let def_id = self.macro_defs[&expansion];
|
||||
if let Some(id) = self.definitions.as_local_node_id(def_id) {
|
||||
self.local_macro_def_scopes[&id]
|
||||
} else if def_id.krate == BUILTIN_MACROS_CRATE {
|
||||
} else if def_id.krate == CrateNum::BuiltinMacros {
|
||||
self.injected_crate.unwrap_or(self.graph_root)
|
||||
} else {
|
||||
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
|
||||
|
@ -14,8 +14,8 @@ use ModuleOrUniformRoot;
|
||||
use Namespace::{self, TypeNS, MacroNS};
|
||||
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
|
||||
use resolve_imports::ImportResolver;
|
||||
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
|
||||
DefIndexAddressSpace};
|
||||
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex,
|
||||
CrateNum, DefIndexAddressSpace};
|
||||
use rustc::hir::def::{Def, NonMacroAttrKind};
|
||||
use rustc::hir::map::{self, DefCollector};
|
||||
use rustc::{ty, lint};
|
||||
@ -218,7 +218,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
||||
|
||||
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
|
||||
let def_id = DefId {
|
||||
krate: BUILTIN_MACROS_CRATE,
|
||||
krate: CrateNum::BuiltinMacros,
|
||||
index: DefIndex::from_array_index(self.macro_map.len(),
|
||||
DefIndexAddressSpace::Low),
|
||||
};
|
||||
@ -352,7 +352,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
||||
self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
|
||||
normal_module_def_id);
|
||||
invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
|
||||
invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
|
||||
invoc.expansion_data.mark.set_is_builtin(def_id.krate == CrateNum::BuiltinMacros);
|
||||
}
|
||||
|
||||
Ok(Some(ext))
|
||||
@ -1135,7 +1135,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
};
|
||||
|
||||
// Plugin-based syntax extensions are exempt from this check
|
||||
if krate == BUILTIN_MACROS_CRATE { return; }
|
||||
if krate == CrateNum::BuiltinMacros { return; }
|
||||
|
||||
let ext = binding.get_macro(self);
|
||||
|
||||
|
@ -64,11 +64,11 @@ fn main() {
|
||||
// bb0: {
|
||||
// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
|
||||
// StorageLive(_3);
|
||||
// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))), [(*_2): i32]);
|
||||
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
|
||||
// _3 = &ReErased (*_2);
|
||||
// Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })) (imm)]);
|
||||
// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
|
||||
// _0 = (*_3);
|
||||
// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })));
|
||||
// EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
|
||||
// StorageDead(_3);
|
||||
// return;
|
||||
// }
|
||||
|
@ -48,12 +48,12 @@ fn main() {
|
||||
// StorageLive(_1);
|
||||
// _1 = Test { x: const 0i32 };
|
||||
// StorageLive(_2);
|
||||
// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))), [_1: Test]);
|
||||
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
|
||||
// _2 = &ReErased _1;
|
||||
// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]);
|
||||
// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
|
||||
// StorageLive(_4);
|
||||
// StorageLive(_5);
|
||||
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]);
|
||||
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
|
||||
// _5 = &ReErased ((*_2).0: i32);
|
||||
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
|
||||
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
|
||||
@ -68,7 +68,7 @@ fn main() {
|
||||
// StorageDead(_4);
|
||||
// StorageDead(_5);
|
||||
// _0 = ();
|
||||
// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })));
|
||||
// EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }));
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_1);
|
||||
// return;
|
||||
|
20
src/test/run-pass-fulldeps/newtype_index.rs
Normal file
20
src/test/run-pass-fulldeps/newtype_index.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![feature(min_const_fn, rustc_attrs, rustc_private, step_trait)]
|
||||
|
||||
#[macro_use] extern crate rustc_data_structures;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA });
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(size_of::<MyIdx>(), 4);
|
||||
assert_eq!(size_of::<Option<MyIdx>>(), 4);
|
||||
assert_eq!(size_of::<Option<Option<MyIdx>>>(), 4);
|
||||
assert_eq!(size_of::<Option<Option<Option<MyIdx>>>>(), 4);
|
||||
assert_eq!(size_of::<Option<Option<Option<Option<MyIdx>>>>>(), 4);
|
||||
assert_eq!(size_of::<Option<Option<Option<Option<Option<MyIdx>>>>>>(), 4);
|
||||
assert_eq!(size_of::<Option<Option<Option<Option<Option<Option<MyIdx>>>>>>>(), 8);
|
||||
}
|
5
src/test/ui/consts/const-eval/zst_operand_eval.rs
Normal file
5
src/test/ui/consts/const-eval/zst_operand_eval.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// compile-pass
|
||||
|
||||
static ASSERT: () = [()][!(std::mem::size_of::<u32>() == 4) as usize];
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user