#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct Static<'tcx> {
pub ty: Ty<'tcx>,
- pub kind: StaticKind,
+ pub kind: StaticKind<'tcx>,
+ pub def_id: DefId,
}
#[derive(
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable,
)]
-pub enum StaticKind {
- Promoted(Promoted),
- Static(DefId),
+pub enum StaticKind<'tcx> {
+ Promoted(Promoted, SubstsRef<'tcx>),
+ Static,
}
impl_stable_hash_for!(struct Static<'tcx> {
ty,
- kind
+ kind,
+ def_id
});
/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
PlaceBase::Local(id) => write!(fmt, "{:?}", id),
- PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => {
+ PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => {
write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty)
}
- PlaceBase::Static(box self::Static { ty, kind: StaticKind::Promoted(promoted) }) => {
+ PlaceBase::Static(box self::Static {
+ ty, kind: StaticKind::Promoted(promoted, _), def_id: _
+ }) => {
write!(fmt, "({:?}: {:?})", promoted, ty)
}
}
PlaceBase::Local(local) => {
self.visit_local(local, context, location);
}
- PlaceBase::Static(box Static { kind: _, ty }) => {
+ PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => {
self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
}
}
mir::Operand::Copy(
Place {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(promoted),
+ kind: StaticKind::Promoted(promoted, _),
ty,
+ def_id: _,
}),
projection: None,
}
mir::Operand::Move(
Place {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(promoted),
+ kind: StaticKind::Promoted(promoted, _),
ty,
+ def_id: _,
}),
projection: None,
}
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Instance, Ty};
+use rustc::ty::subst::Subst;
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
use rustc::mir;
use rustc::mir::tcx::PlaceTy;
mir::PlaceRef {
base: mir::PlaceBase::Static(box mir::Static {
ty,
- kind: mir::StaticKind::Promoted(promoted),
+ kind: mir::StaticKind::Promoted(promoted, substs),
+ def_id,
}),
projection: None,
} => {
+ debug!("promoted={:?}, def_id={:?}, substs={:?}, self_substs={:?}", promoted, def_id, substs, self.instance.substs);
let param_env = ty::ParamEnv::reveal_all();
+ let instance = Instance::new(*def_id, substs.subst(bx.tcx(), self.instance.substs));
+ debug!("instance: {:?}", instance);
let cid = mir::interpret::GlobalId {
- instance: self.instance,
+ instance: instance,
promoted: Some(*promoted),
};
- let layout = cx.layout_of(self.monomorphize(&ty));
+ let mono_ty = tcx.subst_and_normalize_erasing_regions(
+ instance.substs,
+ param_env,
+ ty,
+ );
+ let layout = cx.layout_of(mono_ty);
match bx.tcx().const_eval(param_env.and(cid)) {
Ok(val) => match val.val {
mir::interpret::ConstValue::ByRef { alloc, offset } => {
mir::PlaceRef {
base: mir::PlaceBase::Static(box mir::Static {
ty,
- kind: mir::StaticKind::Static(def_id),
+ kind: mir::StaticKind::Static,
+ def_id,
}),
projection: None,
} => {
PlaceRef {
base:
PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}),
projection: None,
PlaceRef {
base:
PlaceBase::Static(box Static {
- kind: StaticKind::Static(def_id),
+ kind: StaticKind::Static,
+ def_id,
..
}),
projection: None,
pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool {
if let PlaceRef {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Static(def_id),
+ kind: StaticKind::Static,
+ def_id,
..
}),
projection: None,
assert!(root_place.projection.is_none());
let (might_be_alive, will_be_dropped) = match root_place.base {
PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}) => {
(true, false)
}
PlaceBase::Static(box Static {
- kind: StaticKind::Static(_),
+ kind: StaticKind::Static,
..
}) => {
// Thread-locals might be dropped after the function exits, but
// `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
PlaceRef {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}),
projection: None,
}),
PlaceRef {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Static(def_id),
+ kind: StaticKind::Static,
+ def_id,
..
}),
projection: None,
PlaceRef {
base:
PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}),
projection: None,
PlaceRef {
base:
PlaceBase::Static(box Static {
- kind: StaticKind::Static(def_id),
+ kind: StaticKind::Static,
+ def_id,
..
}),
projection: None,
let mut place_ty = match place_base {
PlaceBase::Local(index) =>
PlaceTy::from_ty(self.body.local_decls[*index].ty),
- PlaceBase::Static(box Static { kind, ty: sty }) => {
+ PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
let sty = self.sanitize_type(place, sty);
let check_err =
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
};
};
match kind {
- StaticKind::Promoted(promoted) => {
+ StaticKind::Promoted(promoted, _) => {
if !self.errors_reported {
let promoted_body = &self.promoted[*promoted];
self.sanitize_promoted(promoted_body, location);
check_err(self, place, promoted_ty, sty);
}
}
- StaticKind::Static(def_id) => {
+ StaticKind::Static => {
let ty = self.tcx().type_of(*def_id);
let ty = self.cx.normalize(ty, location);
let is_promoted = match place {
Place {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}),
projection: None,
}
}
}
- PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) =>
+ PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
false,
- PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
+ PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
tcx.is_mutable_static(*def_id)
}
};
}
(PlaceBase::Static(s1), PlaceBase::Static(s2)) => {
match (&s1.kind, &s2.kind) {
- (StaticKind::Static(def_id_1), StaticKind::Static(def_id_2)) => {
- if def_id_1 != def_id_2 {
+ (StaticKind::Static, StaticKind::Static) => {
+ if s1.def_id != s2.def_id {
debug!("place_element_conflict: DISJOINT-STATIC");
Overlap::Disjoint
- } else if tcx.is_mutable_static(*def_id_1) {
+ } else if tcx.is_mutable_static(s1.def_id) {
// We ignore mutable statics - they can only be unsafe code.
debug!("place_element_conflict: IGNORE-STATIC-MUT");
Overlap::Disjoint
Overlap::EqualOrDisjoint
}
},
- (StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => {
+ (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => {
if promoted_1 == promoted_2 {
if let ty::Array(_, len) = s1.ty.sty {
if let Some(0) = len.try_eval_usize(tcx, param_env) {
ExprKind::StaticRef { id } => block.and(Place {
base: PlaceBase::Static(Box::new(Static {
ty: expr.ty,
- kind: StaticKind::Static(id),
+ kind: StaticKind::Static,
+ def_id: id,
})),
projection: None,
}),
use rustc::mir::StaticKind;
Ok(match place_static.kind {
- StaticKind::Promoted(promoted) => {
+ StaticKind::Promoted(promoted, _) => {
let instance = self.frame().instance;
self.const_eval_raw(GlobalId {
instance,
})?
}
- StaticKind::Static(def_id) => {
+ StaticKind::Static => {
let ty = place_static.ty;
assert!(!ty.needs_subst());
let layout = self.layout_of(ty)?;
- let instance = ty::Instance::mono(*self.tcx, def_id);
+ let instance = ty::Instance::mono(*self.tcx, place_static.def_id);
let cid = GlobalId {
instance,
promoted: None
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
-use rustc::ty::subst::{InternalSubsts, SubstsRef};
+use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance};
use rustc::ty::print::obsolete::DefPathBasedNames;
use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
_context: mir::visit::PlaceContext,
location: Location) {
match place_base {
- PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => {
+ PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
debug!("visiting static {:?} @ {:?}", def_id, location);
let tcx = self.tcx;
self.output.push(MonoItem::Static(*def_id));
}
}
- PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => {
- // FIXME: should we handle promoteds here instead of eagerly in collect_neighbours?
+ PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted, substs), def_id, .. }) => {
+ debug!("collecting promoted(def_id: {:?}, promoted: {:?}, substs: {:?})", def_id, promoted, substs);
+ debug!("param_substs: {:?}", self.param_substs);
+ let param_env = ty::ParamEnv::reveal_all();
+ let cid = GlobalId {
+ instance: Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)),
+ promoted: Some(*promoted),
+ };
+ debug!("cid: {:?}", cid);
+ match self.tcx.const_eval(param_env.and(cid)) {
+ Ok(val) => collect_const(self.tcx, val, substs, self.output),
+ Err(ErrorHandled::Reported) => {},
+ Err(ErrorHandled::TooGeneric) => {
+ let span = self.tcx.promoted_mir(*def_id)[*promoted].span;
+ span_bug!(span, "collection encountered polymorphic constant")
+ },
+ }
}
PlaceBase::Local(_) => {
// Locals have no relevance for collector
output,
param_substs: instance.substs,
}.visit_body(&body);
-
- if let ty::InstanceDef::Item(def_id) = instance.def {
- let param_env = ty::ParamEnv::reveal_all();
- let promoted = tcx.promoted_mir(def_id);
- for (promoted, promoted_body) in promoted.iter_enumerated() {
- let cid = GlobalId {
- instance,
- promoted: Some(promoted),
- };
- match tcx.const_eval(param_env.and(cid)) {
- Ok(val) => collect_const(tcx, val, instance.substs, output),
- Err(ErrorHandled::Reported) => {},
- Err(ErrorHandled::TooGeneric) => span_bug!(
- promoted_body.span, "collection encountered polymorphic constant",
- ),
- }
- }
- }
}
fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String {
PlaceBase::Local(..) => {
// Locals are safe.
}
- PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => {
+ PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
bug!("unsafety checking should happen before promotion")
}
- PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => {
+ PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
if self.tcx.is_mutable_static(*def_id) {
self.require_unsafe("use of mutable static",
"mutable statics can be mutated by multiple threads: aliasing \
place.iterate(|place_base, place_projection| {
let mut eval = match place_base {
PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
- PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => {
+ 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
let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len());
let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len());
- let promoted_map = IndexVec::with_capacity(self.tcx.promoted_mir(callsite.callee).len());
for mut scope in callee_body.source_scopes.iter().cloned() {
if scope.parent_scope.is_none() {
local_map.push(idx);
}
- //TODO fixme
- //promoted_map.extend(
- // self.tcx.promoted_mir(callsite.callee).iter().cloned().map(|p| caller_body.promoted.push(p))
- //);
-
// If the call is something like `a[*i] = f(i)`, where
// `i : &mut usize`, then just duplicating the `a[*i]`
// Place could result in two different locations if `f`
args: &args,
local_map,
scope_map,
- promoted_map,
- _callsite: callsite,
+ callsite,
destination: dest,
return_block,
cleanup_block: cleanup,
- in_cleanup_block: false
+ in_cleanup_block: false,
+ tcx: self.tcx,
};
args: &'a [Local],
local_map: IndexVec<Local, Local>,
scope_map: IndexVec<SourceScope, SourceScope>,
- promoted_map: IndexVec<Promoted, Promoted>,
- _callsite: CallSite<'tcx>,
+ callsite: CallSite<'tcx>,
destination: Place<'tcx>,
return_block: BasicBlock,
cleanup_block: Option<BasicBlock>,
in_cleanup_block: bool,
+ tcx: TyCtxt<'tcx>,
}
impl<'a, 'tcx> Integrator<'a, 'tcx> {
},
Place {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(promoted),
+ kind: StaticKind::Promoted(_, substs),
..
}),
projection: None,
} => {
- if let Some(p) = self.promoted_map.get(*promoted).cloned() {
- *promoted = p;
- }
+ let adjusted_substs = substs.subst(self.tcx, self.callsite.substs);
+ debug!("replacing substs {:?} with {:?}", substs, adjusted_substs);
+ *substs = adjusted_substs;
},
_ => self.super_place(place, _ctxt, _location)
}
//! 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;
+use rustc::ty::subst::InternalSubsts;
use rustc::ty::TyCtxt;
use syntax_pos::Span;
new_temp
}
- fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Option<Body<'tcx>> {
+ fn promote_candidate(mut self, def_id: DefId, candidate: Candidate, next_promoted_id: usize) -> Option<Body<'tcx>> {
let mut operand = {
let promoted = &mut self.promoted;
let promoted_id = Promoted::new(next_promoted_id);
- let mut promoted_place = |ty, span| {
+ let mut promoted_place = |ty, substs, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
Place {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(promoted_id),
- ty
+ kind: StaticKind::Promoted(promoted_id, substs),
+ ty,
+ def_id,
}),
projection: None,
}
let span = statement.source_info.span;
Operand::Move(Place {
- base: mem::replace(&mut place.base, promoted_place(ty, span).base),
+ base: mem::replace(
+ &mut place.base,
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span,
+ ).base
+ ),
projection: None,
})
}
StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
let ty = operand.ty(local_decls, self.tcx);
let span = statement.source_info.span;
- mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
+ mem::replace(
+ operand,
+ Operand::Copy(
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span,
+ )
+ )
+ )
}
_ => bug!()
}
TerminatorKind::Call { ref mut args, .. } => {
let ty = args[index].ty(local_decls, self.tcx);
let span = terminator.source_info.span;
- let operand = Operand::Copy(promoted_place(ty, span));
+ let operand =
+ Operand::Copy(
+ promoted_place(
+ ty,
+ InternalSubsts::identity_for_item(self.tcx, def_id),
+ span));
mem::replace(&mut args[index], operand)
}
// We expected a `TerminatorKind::Call` for which we'd like to promote an
}
pub fn promote_candidates<'tcx>(
+ def_id: DefId,
body: &mut Body<'tcx>,
tcx: TyCtxt<'tcx>,
mut temps: IndexVec<Local, TempState>,
keep_original: false
};
- if let Some(promoted) = promoter.promote_candidate(candidate, promotions.len()) {
+ if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) {
promotions.push(promoted);
}
}
} => Self::in_local(cx, *local),
PlaceRef {
base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}),
projection: None,
fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool {
match static_.kind {
- StaticKind::Promoted(_) => unreachable!(),
- StaticKind::Static(def_id) => {
+ StaticKind::Promoted(_, _) => unreachable!(),
+ StaticKind::Static => {
// 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(def_id).iter().any(
+ cx.tcx.get_attrs(static_.def_id).iter().any(
|attr| attr.check_name(sym::thread_local)
)
}
dest_projection = &proj.base;
},
(&PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
+ kind: StaticKind::Promoted(..),
..
}), None) => bug!("promoteds don't exist yet during promotion"),
(&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
self.super_place_base(place_base, context, location);
match place_base {
PlaceBase::Local(_) => {}
- PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
+ PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => {
unreachable!()
}
- PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
+ PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
if self.tcx
.get_attrs(*def_id)
.iter()
// Do the actual promotion, now that we know what's viable.
self.promoted.set(
- Some(promote_consts::promote_candidates(body, tcx, temps, candidates))
+ Some(promote_consts::promote_candidates(def_id, body, tcx, temps, candidates))
);
} else {
if !body.control_flow_destroyed.is_empty() {
}
match place_base {
- PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => {
+ PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
Err((span, "cannot access `static` items in const fn".into()))
}
PlaceBase::Local(_)
- | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()),
+ | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
}
})
}