adding mir::StaticKind enum for static and promoted
This commit is contained in:
parent
cf2f1bb072
commit
752544b284
@ -1915,19 +1915,22 @@ pub enum PlaceBase<'tcx> {
|
||||
Static(Box<Static<'tcx>>),
|
||||
}
|
||||
|
||||
/// The `DefId` of a static, along with its normalized type (which is
|
||||
/// stored to avoid requiring normalization when reading MIR).
|
||||
/// We store the normalized type to avoid requiring normalization when reading MIR
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Static<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub promoted: Option<Promoted>,
|
||||
pub kind: StaticKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable)]
|
||||
pub enum StaticKind {
|
||||
Promoted(Promoted),
|
||||
Static(DefId),
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct Static<'tcx> {
|
||||
def_id,
|
||||
ty,
|
||||
promoted
|
||||
kind
|
||||
});
|
||||
|
||||
/// The `Projection` data structure defines things of the form `B.x`
|
||||
@ -2058,21 +2061,23 @@ impl<'tcx> Debug for Place<'tcx> {
|
||||
|
||||
match *self {
|
||||
Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id),
|
||||
Base(PlaceBase::Static(box self::Static { def_id, ty, promoted })) => {
|
||||
match promoted {
|
||||
None => write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
),
|
||||
Some(pr) => write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
pr,
|
||||
ty
|
||||
),
|
||||
}
|
||||
Base(PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) })) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
)
|
||||
},
|
||||
Base(PlaceBase::Static(
|
||||
box self::Static { ty, kind: StaticKind::Promoted(promoted) })
|
||||
) => {
|
||||
write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
promoted,
|
||||
ty
|
||||
)
|
||||
},
|
||||
Projection(ref data) => match data.elem {
|
||||
ProjectionElem::Downcast(ref adt_def, index) => {
|
||||
|
@ -725,15 +725,18 @@ macro_rules! make_mir_visitor {
|
||||
place: & $($mutability)? Place<'tcx>,
|
||||
context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
use crate::mir::{Static, StaticKind};
|
||||
match place {
|
||||
Place::Base(PlaceBase::Local(local)) => {
|
||||
self.visit_local(local, context, location);
|
||||
}
|
||||
Place::Base(PlaceBase::Static(static_)) => {
|
||||
if static_.promoted.is_none() {
|
||||
self.visit_def_id(& $($mutability)? static_.def_id, location);
|
||||
}
|
||||
self.visit_ty(& $($mutability)? static_.ty, TyContext::Location(location));
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static{kind: StaticKind::Static(def_id), ..})
|
||||
) => {
|
||||
self.visit_def_id(& $($mutability)? *def_id, location)
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static{ty, ..})) => {
|
||||
self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
|
||||
}
|
||||
Place::Projection(proj) => {
|
||||
self.visit_projection(proj, context, location);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
|
||||
use rustc::mir::{self, Place, PlaceBase};
|
||||
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -621,14 +621,18 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
// but specified directly in the code. This means it gets promoted
|
||||
// and we can then extract the value by evaluating the promoted.
|
||||
mir::Operand::Copy(
|
||||
Place::Base(PlaceBase::Static(
|
||||
box mir::Static {promoted: Some(promoted), ty, ..}
|
||||
))
|
||||
Place::Base(
|
||||
PlaceBase::Static(
|
||||
box Static { kind: StaticKind::Promoted(promoted), ty }
|
||||
)
|
||||
)
|
||||
) |
|
||||
mir::Operand::Move(
|
||||
Place::Base(PlaceBase::Static(
|
||||
box mir::Static {promoted: Some(promoted), ty, ..}
|
||||
))
|
||||
Place::Base(
|
||||
PlaceBase::Static(
|
||||
box Static { kind: StaticKind::Promoted(promoted), ty }
|
||||
)
|
||||
)
|
||||
) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
|
@ -409,7 +409,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let result = match *place {
|
||||
mir::Place::Base(mir::PlaceBase::Local(_)) => bug!(), // handled above
|
||||
mir::Place::Base(
|
||||
mir::PlaceBase::Static(box mir::Static { def_id: _, ty, promoted: Some(promoted) })
|
||||
mir::PlaceBase::Static(
|
||||
box mir::Static { ty, kind: mir::StaticKind::Promoted(promoted) }
|
||||
)
|
||||
) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
@ -438,7 +440,9 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
}
|
||||
mir::Place::Base(
|
||||
mir::PlaceBase::Static(box mir::Static { def_id, ty, promoted: None })
|
||||
mir::PlaceBase::Static(
|
||||
box mir::Static { ty, kind: mir::StaticKind::Static(def_id) }
|
||||
)
|
||||
) => {
|
||||
// NB: The layout of a static may be unsized as is the case when working
|
||||
// with a static that is an extern_type.
|
||||
|
@ -10,7 +10,7 @@ use rustc::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant,
|
||||
ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand,
|
||||
Place, PlaceBase, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind,
|
||||
TerminatorKind, VarBindingForm,
|
||||
Static, StaticKind, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc::ty::{self, DefIdTree};
|
||||
use rustc::ty::print::Print;
|
||||
@ -1601,12 +1601,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Place::Base(PlaceBase::Local(local)) => {
|
||||
self.append_local_to_string(local, buf)?;
|
||||
}
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
if static_.promoted.is_some() {
|
||||
buf.push_str("promoted");
|
||||
} else {
|
||||
buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
|
||||
buf.push_str("promoted");
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
|
||||
buf.push_str(&self.infcx.tcx.item_name(def_id).to_string());
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
@ -1808,8 +1807,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
/// Checks if a place is a thread-local static.
|
||||
pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
|
||||
if let Place::Base(PlaceBase::Static(statik)) = place {
|
||||
let attrs = self.infcx.tcx.get_attrs(statik.def_id);
|
||||
if let Place::Base(
|
||||
PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })
|
||||
) = place {
|
||||
let attrs = self.infcx.tcx.get_attrs(*def_id);
|
||||
let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
|
||||
|
||||
debug!(
|
||||
|
@ -8,7 +8,9 @@ use rustc::infer::InferCtxt;
|
||||
use rustc::lint::builtin::UNUSED_MUT;
|
||||
use rustc::middle::borrowck::SignalledError;
|
||||
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place, PlaceBase};
|
||||
use rustc::mir::{
|
||||
ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place, PlaceBase, Static, StaticKind
|
||||
};
|
||||
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind};
|
||||
use rustc::ty::query::Providers;
|
||||
@ -1308,8 +1310,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
let (might_be_alive, will_be_dropped) = match root_place {
|
||||
Place::Base(PlaceBase::Static(st)) => {
|
||||
(true, st.promoted.is_none() && self.is_place_thread_local(&root_place))
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
|
||||
(true, false)
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
|
||||
// Thread-locals might be dropped after the function exits, but
|
||||
// "true" statics will never be.
|
||||
(true, self.is_place_thread_local(&root_place))
|
||||
}
|
||||
Place::Base(PlaceBase::Local(_)) => {
|
||||
// Locals are always dropped at function exit, and if they
|
||||
@ -1982,18 +1989,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
// The rules for promotion are made by `qualify_consts`, there wouldn't even be a
|
||||
// `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
if static_.promoted.is_some() ||
|
||||
(static_.promoted.is_none() &&
|
||||
self.infcx.tcx.is_static(static_.def_id)
|
||||
== Some(hir::Mutability::MutMutable)
|
||||
){
|
||||
Place::Base(PlaceBase::Static(box Static{kind: StaticKind::Promoted(_), ..})) =>
|
||||
Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
}),
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
|
||||
if self.infcx.tcx.is_static(def_id) != Some(hir::Mutability::MutMutable) {
|
||||
Err(place)
|
||||
} else {
|
||||
Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
})
|
||||
} else {
|
||||
Err(place)
|
||||
}
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
|
@ -1,7 +1,9 @@
|
||||
use rustc::hir;
|
||||
use rustc::hir::Node;
|
||||
use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Mir};
|
||||
use rustc::mir::{Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static};
|
||||
use rustc::mir::{
|
||||
Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind,
|
||||
};
|
||||
use rustc::mir::{Terminator, TerminatorKind};
|
||||
use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -129,8 +131,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
|
||||
assert!(promoted.is_none());
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) =>
|
||||
unreachable!(),
|
||||
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. })) => {
|
||||
if let Place::Base(PlaceBase::Static(_)) = access_place {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
|
@ -453,45 +453,53 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty {
|
||||
ty: self.mir.local_decls[index].ty,
|
||||
},
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: sty, promoted })) => {
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), ty: sty })
|
||||
) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let check_err =
|
||||
|verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx> ,
|
||||
place: &Place<'tcx>,
|
||||
ty,
|
||||
sty| {
|
||||
if let Err(terr) = verifier.cx.eq_types(
|
||||
|
||||
if !self.errors_reported {
|
||||
let promoted_mir = &self.mir.promoted[promoted];
|
||||
self.sanitize_promoted(promoted_mir, location);
|
||||
|
||||
let promoted_ty = promoted_mir.return_ty();
|
||||
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
sty,
|
||||
ty,
|
||||
promoted_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
verifier,
|
||||
self,
|
||||
place,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
promoted_ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
};
|
||||
match promoted {
|
||||
Some(pr) => {
|
||||
if !self.errors_reported {
|
||||
let promoted_mir = &self.mir.promoted[pr];
|
||||
self.sanitize_promoted(promoted_mir, location);
|
||||
|
||||
let promoted_ty = promoted_mir.return_ty();
|
||||
check_err(self, place, promoted_ty, sty);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
|
||||
check_err(self, place, ty, sty);
|
||||
}
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty: sty })
|
||||
) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
"bad static type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc::hir;
|
||||
use rustc::mir::ProjectionElem;
|
||||
use rustc::mir::{Local, Mir, Place, PlaceBase, Mutability};
|
||||
use rustc::mir::{Local, Mir, Place, PlaceBase, Mutability, Static, StaticKind};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use crate::borrow_check::borrow_set::LocalsStateAtExit;
|
||||
|
||||
@ -49,9 +49,10 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Place::Base(PlaceBase::Static(static_)) => {
|
||||
static_.promoted.is_none() &&
|
||||
(tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable))
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
|
||||
false,
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
|
||||
tcx.is_static(*def_id) == Some(hir::Mutability::MutMutable)
|
||||
}
|
||||
Place::Projection(proj) => match proj.elem {
|
||||
ProjectionElem::Field(..)
|
||||
|
@ -2,7 +2,7 @@ use crate::borrow_check::ArtificialField;
|
||||
use crate::borrow_check::Overlap;
|
||||
use crate::borrow_check::{Deep, Shallow, AccessDepth};
|
||||
use rustc::hir;
|
||||
use rustc::mir::{BorrowKind, Mir, Place, PlaceBase, Projection, ProjectionElem};
|
||||
use rustc::mir::{BorrowKind, Mir, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use std::cmp::max;
|
||||
|
||||
@ -370,47 +370,71 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(Place::Base(PlaceBase::Static(s1)), Place::Base(PlaceBase::Static(s2))) => {
|
||||
match (s1.promoted, s2.promoted) {
|
||||
(None, None) => {
|
||||
if s1.def_id != s2.def_id {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC");
|
||||
Overlap::Disjoint
|
||||
} else if tcx.is_static(s1.def_id) == Some(hir::Mutability::MutMutable) {
|
||||
// We ignore mutable statics - they can only be unsafe code.
|
||||
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
},
|
||||
(Some(p1), Some(p2)) => {
|
||||
if p1 == p2 {
|
||||
if let ty::Array(_, size) = s1.ty.sty {
|
||||
if size.unwrap_usize(tcx) == 0 {
|
||||
// Ignore conflicts with promoted [T; 0].
|
||||
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
|
||||
return Overlap::Disjoint;
|
||||
}
|
||||
}
|
||||
// the same promoted - base case, equal
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
// different promoteds - base case, disjoint
|
||||
debug!("place_element_conflict: DISJOINT-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
},
|
||||
(_, _) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
(
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id_1), .. })),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id_2), .. })),
|
||||
) => {
|
||||
if *def_id_1 != *def_id_2 {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC");
|
||||
Overlap::Disjoint
|
||||
} else if tcx.is_static(*def_id_1) == Some(hir::Mutability::MutMutable) {
|
||||
// We ignore mutable statics - they can only be unsafe code.
|
||||
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Static(_))) |
|
||||
(Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Local(_))) => {
|
||||
(
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted_1), ty })
|
||||
),
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted_2), .. })
|
||||
),
|
||||
) => {
|
||||
if *promoted_1 == *promoted_2 {
|
||||
if let ty::Array(_, size) = ty.sty {
|
||||
if size.unwrap_usize(tcx) == 0 {
|
||||
// Ignore conflicts with promoted [T; 0].
|
||||
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
|
||||
return Overlap::Disjoint;
|
||||
}
|
||||
}
|
||||
// the same promoted - base case, equal
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
// different promoteds - base case, disjoint
|
||||
debug!("place_element_conflict: DISJOINT-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(
|
||||
Place::Base(PlaceBase::Local(_)),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }))
|
||||
) |
|
||||
(
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })),
|
||||
Place::Base(PlaceBase::Local(_))
|
||||
) |
|
||||
(
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }))
|
||||
) |
|
||||
(
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }))
|
||||
) |
|
||||
(
|
||||
Place::Base(PlaceBase::Local(_)),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }))
|
||||
) |
|
||||
(
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })),
|
||||
Place::Base(PlaceBase::Local(_))
|
||||
) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
|
@ -126,9 +126,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
block.and(place)
|
||||
}
|
||||
ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static {
|
||||
def_id: id,
|
||||
ty: expr.ty,
|
||||
promoted: None,
|
||||
kind: StaticKind::Static(id),
|
||||
})))),
|
||||
|
||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||
|
@ -582,9 +582,9 @@ where
|
||||
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
use rustc::mir::Place::*;
|
||||
use rustc::mir::PlaceBase;
|
||||
use rustc::mir::Static;
|
||||
use rustc::mir::{Static, StaticKind};
|
||||
Ok(match *mir_place {
|
||||
Base(PlaceBase::Static(box Static {promoted: Some(promoted), ty: _, ..})) => {
|
||||
Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })) => {
|
||||
let instance = self.frame().instance;
|
||||
self.const_eval_raw(GlobalId {
|
||||
instance,
|
||||
@ -592,7 +592,7 @@ where
|
||||
})?
|
||||
}
|
||||
|
||||
Base(PlaceBase::Static(box Static {promoted: None, ty, def_id})) => {
|
||||
Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty })) => {
|
||||
assert!(!ty.needs_subst());
|
||||
let layout = self.layout_of(ty)?;
|
||||
let instance = ty::Instance::mono(*self.tcx, def_id);
|
||||
|
@ -184,7 +184,7 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
|
||||
use rustc::ty::adjustment::CustomCoerceUnsized;
|
||||
use rustc::session::config::EntryFnType;
|
||||
use rustc::mir::{self, Location, Promoted};
|
||||
use rustc::mir::{self, Location, Place, PlaceBase, Promoted, Static, StaticKind};
|
||||
use rustc::mir::visit::Visitor as MirVisitor;
|
||||
use rustc::mir::mono::MonoItem;
|
||||
use rustc::mir::interpret::{Scalar, GlobalId, AllocKind, ErrorHandled};
|
||||
@ -655,8 +655,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||
context: mir::visit::PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
match place {
|
||||
mir::Place::Base(
|
||||
mir::PlaceBase::Static(box mir::Static{def_id, promoted:None, ..})
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static{ kind:StaticKind::Static(def_id), .. })
|
||||
) => {
|
||||
debug!("visiting static {:?} @ {:?}", def_id, location);
|
||||
|
||||
|
@ -300,9 +300,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||
&Place::Base(PlaceBase::Local(..)) => {
|
||||
// locals are safe
|
||||
}
|
||||
&Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
|
||||
assert!(promoted.is_none(), "unsafety checking should happen before promotion");
|
||||
|
||||
&Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
&Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. })
|
||||
) => {
|
||||
if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
"mutable statics can be mutated by multiple threads: aliasing violations \
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local};
|
||||
use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind};
|
||||
use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind, Static, StaticKind};
|
||||
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult};
|
||||
@ -266,7 +266,6 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
||||
}
|
||||
|
||||
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
||||
use rustc::mir::Static;
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(loc)) => self.places[loc].clone(),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
@ -283,7 +282,9 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
||||
// an `Index` projection would throw us off-track.
|
||||
_ => None,
|
||||
},
|
||||
Place::Base(PlaceBase::Static(box Static {promoted: Some(promoted), ..})) => {
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..})
|
||||
) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id());
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
|
@ -692,7 +692,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
},
|
||||
Place::Base(PlaceBase::Static(box Static { promoted: Some(promoted), .. })) => {
|
||||
Place::Base(
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })
|
||||
) => {
|
||||
if let Some(p) = self.promoted_map.get(*promoted).cloned() {
|
||||
*promoted = p;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
//! initialization and can otherwise silence errors, if
|
||||
//! move analysis runs after promotion on broken MIR.
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
@ -152,8 +151,7 @@ struct Promoter<'a, 'tcx: 'a> {
|
||||
|
||||
/// If true, all nested temps are also kept in the
|
||||
/// source MIR, not moved to the promoted MIR.
|
||||
keep_original: bool,
|
||||
def_id: DefId,
|
||||
keep_original: bool
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
@ -289,16 +287,16 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn promote_candidate(mut self, candidate: Candidate) {
|
||||
use rustc::mir::Static;
|
||||
let mut operand = {
|
||||
let def_id = self.def_id;
|
||||
let promoted = &mut self.promoted;
|
||||
let promoted_id = Promoted::new(self.source.promoted.len());
|
||||
let mut promoted_place = |ty, span| {
|
||||
promoted.span = span;
|
||||
promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
|
||||
promoted.local_decls[RETURN_PLACE] =
|
||||
LocalDecl::new_return_place(ty, span);
|
||||
Place::Base(
|
||||
PlaceBase::Static(Box::new(Static { def_id, ty, promoted: Some(promoted_id) })))
|
||||
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(promoted_id), ty })
|
||||
)
|
||||
};
|
||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||
match candidate {
|
||||
@ -371,8 +369,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
||||
pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mut temps: IndexVec<Local, TempState>,
|
||||
candidates: Vec<Candidate>,
|
||||
def_id: DefId) {
|
||||
candidates: Vec<Candidate>) {
|
||||
// Visit candidates in reverse, in case they're nested.
|
||||
debug!("promote_candidates({:?})", candidates);
|
||||
|
||||
@ -417,8 +414,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
tcx,
|
||||
source: mir,
|
||||
temps: &mut temps,
|
||||
keep_original: false,
|
||||
def_id,
|
||||
keep_original: false
|
||||
};
|
||||
promoter.promote_candidate(candidate);
|
||||
}
|
||||
|
@ -188,8 +188,9 @@ trait Qualif {
|
||||
fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
|
||||
Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) =>
|
||||
bug!("qualifying already promoted MIR"),
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
assert!(static_.promoted.is_none(), "qualifying already promoted MIR");
|
||||
Self::in_static(cx, static_)
|
||||
},
|
||||
Place::Projection(ref proj) => Self::in_projection(cx, proj),
|
||||
@ -372,11 +373,18 @@ impl Qualif for IsNotConst {
|
||||
const IDX: usize = 2;
|
||||
|
||||
fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool {
|
||||
// Only allow statics (not consts) to refer to other statics.
|
||||
let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut;
|
||||
match static_.kind {
|
||||
StaticKind::Promoted(_) => unreachable!(),
|
||||
StaticKind::Static(def_id) => {
|
||||
// Only allow statics (not consts) to refer to other statics.
|
||||
let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut;
|
||||
|
||||
!allowed ||
|
||||
cx.tcx.get_attrs(static_.def_id).iter().any(|attr| attr.check_name("thread_local"))
|
||||
!allowed ||
|
||||
cx.tcx.get_attrs(def_id).iter().any(
|
||||
|attr| attr.check_name("thread_local"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &PlaceProjection<'tcx>) -> bool {
|
||||
@ -770,8 +778,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||
);
|
||||
dest = &proj.base;
|
||||
},
|
||||
Place::Base(PlaceBase::Static(st)) => {
|
||||
assert!(st.promoted.is_none(), "promoteds don't exist yet during promotion");
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
|
||||
bug!("promoteds don't exist yet during promotion"),
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
|
||||
// Catch more errors in the destination. `visit_place` also checks that we
|
||||
// do not try to access statics from constants or try to mutate statics
|
||||
self.visit_place(
|
||||
@ -921,10 +930,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||
self.super_place(place, context, location);
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(_)) => {}
|
||||
Place::Base(PlaceBase::Static(ref global)) => {
|
||||
assert!(global.promoted.is_none());
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {}
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
|
||||
if self.tcx
|
||||
.get_attrs(global.def_id)
|
||||
.get_attrs(def_id)
|
||||
.iter()
|
||||
.any(|attr| attr.check_name("thread_local")) {
|
||||
if self.mode != Mode::Fn {
|
||||
@ -1516,7 +1525,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
||||
};
|
||||
|
||||
// Do the actual promotion, now that we know what's viable.
|
||||
promote_consts::promote_candidates(mir, tcx, temps, candidates, def_id);
|
||||
promote_consts::promote_candidates(mir, tcx, temps, candidates);
|
||||
} else {
|
||||
if !mir.control_flow_destroyed.is_empty() {
|
||||
let mut locals = mir.vars_iter();
|
||||
|
@ -257,8 +257,8 @@ fn check_place(
|
||||
match place {
|
||||
Place::Base(PlaceBase::Local(_)) => Ok(()),
|
||||
// promoteds are always fine, they are essentially constants
|
||||
Place::Base(PlaceBase::Static(box Static {def_id: _, ty: _, promoted: Some(_)})) => Ok(()),
|
||||
Place::Base(PlaceBase::Static(box Static {def_id: _, ty: _, promoted: None})) =>
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => Ok(()),
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })) =>
|
||||
Err((span, "cannot access `static` items in const fn".into())),
|
||||
Place::Projection(proj) => {
|
||||
match proj.elem {
|
||||
|
Loading…
Reference in New Issue
Block a user