/// static or static mut variable
Static(Box<Static<'tcx>>),
-
- /// Constant code promoted to an injected static
- Promoted(Box<(Promoted, Ty<'tcx>)>),
}
/// The `DefId` of a static, along with its normalized type (which is
pub struct Static<'tcx> {
pub def_id: DefId,
pub ty: Ty<'tcx>,
+ pub promoted: Option<Promoted>,
}
impl_stable_hash_for!(struct Static<'tcx> {
def_id,
- ty
+ ty,
+ promoted
});
/// The `Projection` data structure defines things of the form `B.x`
match self {
Place::Base(PlaceBase::Local(local)) => Some(*local),
Place::Projection(box Projection { base, elem: _ }) => base.base_local(),
- Place::Base(PlaceBase::Promoted(..)) | Place::Base(PlaceBase::Static(..)) => None,
+ Place::Base(PlaceBase::Static(..)) => None,
}
}
}
match *self {
Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id),
- Base(PlaceBase::Static(box self::Static { def_id, ty })) => write!(
- fmt,
- "({}: {:?})",
- ty::tls::with(|tcx| tcx.def_path_str(def_id)),
- ty
- ),
- Base(PlaceBase::Promoted(ref promoted)) => write!(
- fmt,
- "({:?}: {:?})",
- promoted.0,
- promoted.1
- ),
+ 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
+ ),
+ }
+ },
Projection(ref data) => match data.elem {
ProjectionElem::Downcast(ref adt_def, index) => {
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].ident)
match *self {
Place::Base(PlaceBase::Local(index)) =>
PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
- Place::Base(PlaceBase::Promoted(ref data)) => PlaceTy::Ty { ty: data.1 },
Place::Base(PlaceBase::Static(ref data)) =>
PlaceTy::Ty { ty: data.ty },
Place::Projection(ref proj) =>
self.visit_local(local, context, location);
}
Place::Base(PlaceBase::Static(static_)) => {
+ match static_.promoted {
+ None => {
+ self.visit_static(static_, context, location);
+ }
+ Some(_) => {
+ self.visit_ty(
+ & $($mutability)? static_.ty, TyContext::Location(location)
+ );
+ }
+ }
self.visit_static(static_, context, location);
}
- Place::Base(PlaceBase::Promoted(promoted)) => {
- self.visit_ty(& $($mutability)? promoted.1, TyContext::Location(location));
- },
Place::Projection(proj) => {
self.visit_projection(proj, context, location);
}
static_: & $($mutability)? Static<'tcx>,
_context: PlaceContext<'tcx>,
location: Location) {
- let Static { def_id, ty } = static_;
+ let Static { def_id, ty, promoted: _ } = static_;
self.visit_def_id(def_id, location);
self.visit_ty(ty, TyContext::Location(location));
}
including_downcast: &IncludingDowncast,
) -> Result<(), ()> {
match *place {
- Place::Base(PlaceBase::Promoted(_)) => {
- buf.push_str("promoted");
- }
Place::Base(PlaceBase::Local(local)) => {
self.append_local_to_string(local, buf)?;
}
Place::Base(PlaceBase::Static(ref static_)) => {
- buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
+ match static_.promoted {
+ Some(_) => {
+ buf.push_str("promoted");
+ }
+ None => {
+ buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
+ }
+ }
}
Place::Projection(ref proj) => {
match proj.elem {
let local = &self.mir.local_decls[local];
self.describe_field_from_ty(&local.ty, field)
}
- Place::Base(PlaceBase::Promoted(ref prom)) =>
- self.describe_field_from_ty(&prom.1, field),
Place::Base(PlaceBase::Static(ref static_)) =>
self.describe_field_from_ty(&static_.ty, field),
Place::Projection(ref proj) => match proj.elem {
let tcx = self.infcx.tcx;
match place {
Place::Base(PlaceBase::Local(_)) |
- Place::Base(PlaceBase::Static(_)) |
- Place::Base(PlaceBase::Promoted(_)) => {
+ Place::Base(PlaceBase::Static(_)) => {
StorageDeadOrDrop::LocalStorageDead
}
Place::Projection(box PlaceProjection { base, elem }) => {
}
Operand::Move(Place::Base(PlaceBase::Static(..)))
| Operand::Copy(Place::Base(PlaceBase::Static(..)))
- | Operand::Move(Place::Base(PlaceBase::Promoted(..)))
- | Operand::Copy(Place::Base(PlaceBase::Promoted(..)))
| Operand::Constant(..) => {}
}
}
//
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) = match root_place {
- Place::Base(PlaceBase::Promoted(_)) => (true, false),
- Place::Base(PlaceBase::Static(_)) => {
- // Thread-locals might be dropped after the function exits, but
- // "true" statics will never be.
- let is_thread_local = self.is_place_thread_local(&root_place);
- (true, is_thread_local)
+ Place::Base(PlaceBase::Static(st)) => {
+ match st.promoted {
+ None => {
+ // Thread-locals might be dropped after the function exits, but
+ // "true" statics will never be.
+ let is_thread_local = self.is_place_thread_local(&root_place);
+ (true, is_thread_local)
+ }
+ Some(_) => (true, false),
+ }
}
Place::Base(PlaceBase::Local(_)) => {
// Locals are always dropped at function exit, and if they
match *last_prefix {
Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"),
Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic),
}
}
let mut place = place;
loop {
match *place {
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
// assigning to `x` does not require `x` be initialized.
break;
self.used_mut_upvars.push(field);
}
}
- RootPlace {
- place: Place::Base(PlaceBase::Promoted(..)),
- is_local_mutation_allowed: _,
- } => {}
RootPlace {
place: Place::Base(PlaceBase::Static(..)),
is_local_mutation_allowed: _,
}
// 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::Promoted(_)) => Ok(RootPlace {
- place,
- is_local_mutation_allowed,
- }),
+// Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace {
+// place,
+// is_local_mutation_allowed,
+// }),
Place::Base(PlaceBase::Static(ref static_)) => {
- if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
- Err(place)
- } else {
- Ok(RootPlace {
- place,
- is_local_mutation_allowed,
- })
+ match static_.promoted {
+ Some(_) => {
+ Ok(RootPlace {
+ place,
+ is_local_mutation_allowed,
+ })
+ }
+ None => {
+ if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
+ Err(place)
+ } else {
+ Ok(RootPlace {
+ place,
+ is_local_mutation_allowed,
+ })
+ }
+ }
}
}
Place::Projection(ref proj) => {
}
}
- Place::Base(PlaceBase::Promoted(_)) => unreachable!(),
-
- Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
- if let Place::Base(PlaceBase::Static(_)) = access_place {
- item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
- reason = String::new();
- } else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
- let static_name = &self.infcx.tcx.item_name(*def_id);
- reason = format!(", as `{}` is an immutable static item", static_name);
+ Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
+ match promoted {
+ Some(_) => unreachable!(),
+ None => {
+ if let Place::Base(PlaceBase::Static(_)) = access_place {
+ item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+ reason = String::new();
+ } else {
+ item_msg = format!("`{}`", access_place_desc.unwrap());
+ let static_name = &self.infcx.tcx.item_name(*def_id);
+ reason = format!(", as `{}` is an immutable static item", static_name);
+ }
+ }
}
}
Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty {
ty: self.mir.local_decls[index].ty,
},
- Place::Base(PlaceBase::Promoted(box (index, sty))) => {
- let sty = self.sanitize_type(place, sty);
-
- if !self.errors_reported {
- let promoted_mir = &self.mir.promoted[index];
- self.sanitize_promoted(promoted_mir, location);
-
- let promoted_ty = promoted_mir.return_ty();
-
- if let Err(terr) = self.cx.eq_types(
- sty,
- promoted_ty,
- location.to_locations(),
- ConstraintCategory::Boring,
- ) {
- span_mirbug!(
- self,
- place,
- "bad promoted type ({:?}: {:?}): {:?}",
- promoted_ty,
- sty,
- terr
- );
- };
- }
- PlaceTy::Ty { ty: sty }
- }
- Place::Base(PlaceBase::Static(box 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
- );
+ Place::Base(PlaceBase::Static(box Static { def_id, ty: sty, promoted })) => {
+ match promoted {
+ Some(pr) => {
+ let sty = self.sanitize_type(place, sty);
+
+ if !self.errors_reported {
+ let promoted_mir = &self.mir.promoted[pr];
+ self.sanitize_promoted(promoted_mir, location);
+
+ let promoted_ty = promoted_mir.return_ty();
+
+ if let Err(terr) = self.cx.eq_types(
+ sty,
+ promoted_ty,
+ location.to_locations(),
+ ConstraintCategory::Boring,
+ ) {
+ span_mirbug!(
+ self,
+ place,
+ "bad promoted type ({:?}: {:?}): {:?}",
+ promoted_ty,
+ sty,
+ terr
+ );
+ };
+ }
+ PlaceTy::Ty { ty: sty }
+ }
+ None => {
+ 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 }
+ }
}
- PlaceTy::Ty { ty: sty }
}
Place::Projection(ref proj) => {
let base_context = if context.is_mutating_use() {
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
match place {
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Static(..)) => false,
Place::Base(PlaceBase::Local(..)) => true,
Place::Projection(box proj) => {
locals_state_at_exit: &LocalsStateAtExit,
) -> bool {
match self {
- Place::Base(PlaceBase::Promoted(_)) => false,
-
// If a local variable is immutable, then we only need to track borrows to guard
// against two kinds of errors:
// * The variable being dropped while still borrowed (e.g., because the fn returns
}
}
Place::Base(PlaceBase::Static(static_)) => {
- tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+ match static_.promoted {
+ Some(_) => false,
+ None => {
+ tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+ }
+ }
}
Place::Projection(proj) => match proj.elem {
ProjectionElem::Field(..)
loop {
match p {
Place::Projection(pi) => p = &pi.base,
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Static(_)) => return None,
Place::Base(PlaceBase::Local(l)) => return Some(*l),
}
op,
),
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
let list = PlaceComponents {
component: place,
Overlap::Disjoint
}
}
- (Place::Base(PlaceBase::Static(static1)), Place::Base(PlaceBase::Static(static2))) => {
- if static1.def_id != static2.def_id {
- debug!("place_element_conflict: DISJOINT-STATIC");
- Overlap::Disjoint
- } else if tcx.is_static(static1.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
- }
- }
- (Place::Base(PlaceBase::Promoted(p1)), Place::Base(PlaceBase::Promoted(p2))) => {
- if p1.0 == p2.0 {
- if let ty::Array(_, size) = p1.1.sty {
- if size.unwrap_usize(tcx) == 0 {
- // Ignore conflicts with promoted [T; 0].
- debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
- return 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
+ }
+ },
+ (p1_, p2_) => {
+ debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
+ 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::Promoted(_))) |
- (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Local(_))) |
- (Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Static(_))) |
- (Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Promoted(_))) |
(Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Static(_))) |
(Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Local(_))) => {
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
}
match *cursor {
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Local(_)) |
Place::Base(PlaceBase::Static(_)) => return false,
Place::Projection(ref proj) => {
'cursor: loop {
let proj = match *cursor {
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
Place::Base(PlaceBase::Static(_)) => {
self.next = None;
ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static {
def_id: id,
ty: expr.ty,
+ promoted: None,
})))),
ExprKind::PlaceTypeAscription { source, user_ty } => {
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
match *place {
Place::Base(PlaceBase::Local(l)) => Some(l),
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Static(..)) => None,
Place::Projection(ref proj) => {
match proj.elem {
debug!("lookup({:?})", place);
match *place {
Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]),
- Place::Base(PlaceBase::Promoted(..)) |
Place::Base(PlaceBase::Static(..)) => {
Err(MoveError::cannot_move_out_of(self.loc, Static))
}
pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
match *place {
Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
- Place::Base(PlaceBase::Promoted(_)) |
Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
Place::Projection(ref proj) => {
match self.find(&proj.base) {
use rustc::mir::Place::*;
use rustc::mir::PlaceBase;
Ok(match *mir_place {
- Base(PlaceBase::Promoted(ref promoted)) => {
- let instance = self.frame().instance;
- self.const_eval_raw(GlobalId {
- instance,
- promoted: Some(promoted.0),
- })?
- }
-
Base(PlaceBase::Static(ref static_)) => {
- assert!(!static_.ty.needs_subst());
- let layout = self.layout_of(static_.ty)?;
- let instance = ty::Instance::mono(*self.tcx, static_.def_id);
- let cid = GlobalId {
- instance,
- promoted: None
- };
- // Just create a lazy reference, so we can support recursive statics.
- // tcx takes are of assigning every static one and only one unique AllocId.
- // When the data here is ever actually used, memory will notice,
- // and it knows how to deal with alloc_id that are present in the
- // global table but not in its local memory: It calls back into tcx through
- // a query, triggering the CTFE machinery to actually turn this lazy reference
- // into a bunch of bytes. IOW, statics are evaluated with CTFE even when
- // this EvalContext uses another Machine (e.g., in miri). This is what we
- // want! This way, computing statics works concistently between codegen
- // and miri: They use the same query to eventually obtain a `ty::Const`
- // and use that for further computation.
- let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
- MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+ match static_.promoted {
+ Some(promoted) => {
+ let instance = self.frame().instance;
+ self.const_eval_raw(GlobalId {
+ instance,
+ promoted: Some(promoted),
+ })?
+ }
+ None => {
+ assert!(!static_.ty.needs_subst());
+ let layout = self.layout_of(static_.ty)?;
+ let instance = ty::Instance::mono(*self.tcx, static_.def_id);
+ let cid = GlobalId {
+ instance,
+ promoted: None
+ };
+ // Just create a lazy reference, so we can support recursive statics.
+ // tcx takes are of assigning every static one and only one unique AllocId.
+ // When the data here is ever actually used, memory will notice,
+ // and it knows how to deal with alloc_id that are present in the
+ // global table but not in its local memory: It calls back into tcx through
+ // a query, triggering the CTFE machinery to actually turn this lazy reference
+ // into a bunch of bytes. IOW, statics are evaluated with CTFE even when
+ // this EvalContext uses another Machine (e.g., in miri). This is what we
+ // want! This way, computing statics works concistently between codegen
+ // and miri: They use the same query to eventually obtain a `ty::Const`
+ // and use that for further computation.
+ let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
+ MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+ }
+ }
}
_ => bug!("eval_place_to_mplace called on {:?}", mir_place),
match *place {
// Locals and statics have stable addresses, for sure
Base(PlaceBase::Local { .. }) |
- Base(PlaceBase::Promoted { .. }) |
Base(PlaceBase::Static { .. }) =>
true,
// Recurse for projections
&Place::Base(PlaceBase::Local(..)) => {
// locals are safe
}
- &Place::Base(PlaceBase::Promoted(_)) => {
- bug!("unsafety checking should happen before promotion")
- }
- &Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
- 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 \
- or data races will cause undefined behavior",
- UnsafetyViolationKind::General);
- } else if self.tcx.is_foreign_item(def_id) {
- let source_info = self.source_info;
- let lint_root =
- self.source_scope_local_data[source_info.scope].lint_root;
- self.register_violations(&[UnsafetyViolation {
- source_info,
- description: Symbol::intern("use of extern static").as_interned_str(),
- details:
- Symbol::intern("extern statics are not controlled by the Rust type \
- system: invalid data, aliasing violations or data \
- races will cause undefined behavior")
- .as_interned_str(),
- kind: UnsafetyViolationKind::ExternStatic(lint_root)
- }], &[]);
+ &Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
+ match promoted {
+ Some(..) => {
+ bug!("unsafety checking should happen before promotion")
+ }
+ None => {
+ 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 \
+ or data races will cause undefined behavior",
+ UnsafetyViolationKind::General);
+ } else if self.tcx.is_foreign_item(def_id) {
+ let source_info = self.source_info;
+ let lint_root =
+ self.source_scope_local_data[source_info.scope].lint_root;
+ self.register_violations(&[UnsafetyViolation {
+ source_info,
+ description: Symbol::intern("use of extern static").as_interned_str(),
+ details:
+ Symbol::intern("extern statics are not controlled by the Rust type \
+ system: invalid data, aliasing violations or data \
+ races will cause undefined behavior")
+ .as_interned_str(),
+ kind: UnsafetyViolationKind::ExternStatic(lint_root)
+ }], &[]);
+ }
+ }
}
}
};
// an `Index` projection would throw us off-track.
_ => None,
},
- Place::Base(PlaceBase::Promoted(ref promoted)) => {
- let generics = self.tcx.generics_of(self.source.def_id());
- if generics.requires_monomorphization(self.tcx) {
- // FIXME: can't handle code with generics
- return None;
+ Place::Base(PlaceBase::Static(ref static_)) => {
+ match static_.promoted {
+ Some(promoted) => {
+ let generics = self.tcx.generics_of(self.source.def_id());
+ if generics.requires_monomorphization(self.tcx) {
+ // FIXME: can't handle code with generics
+ return None;
+ }
+ let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
+ let instance = Instance::new(self.source.def_id(), substs);
+ let cid = GlobalId {
+ instance,
+ promoted: Some(promoted),
+ };
+ // cannot use `const_eval` here, because that would require having the MIR
+ // for the current function available, but we're producing said MIR right now
+ let res = self.use_ecx(source_info, |this| {
+ eval_promoted(this.tcx, cid, this.mir, this.param_env)
+ })?;
+ trace!("evaluated promoted {:?} to {:?}", promoted, res);
+ Some((res.into(), source_info.span))
+ }
+ None => None
}
- let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
- let instance = Instance::new(self.source.def_id(), substs);
- let cid = GlobalId {
- instance,
- promoted: Some(promoted.0),
- };
- // cannot use `const_eval` here, because that would require having the MIR
- // for the current function available, but we're producing said MIR right now
- let res = self.use_ecx(source_info, |this| {
- eval_promoted(this.tcx, cid, this.mir, this.param_env)
- })?;
- trace!("evaluated promoted {:?} to {:?}", promoted, res);
- Some((res.into(), source_info.span))
+
},
_ => None,
}
// Return pointer; update the place itself
*place = self.destination.clone();
},
- Place::Base(PlaceBase::Promoted(ref mut promoted)) => {
- if let Some(p) = self.promoted_map.get(promoted.0).cloned() {
- promoted.0 = p;
+ Place::Base(PlaceBase::Static(ref mut static_)) => {
+ match static_.promoted {
+ Some(promoted) => {
+ if let Some(p) = self.promoted_map.get(promoted).cloned() {
+ static_.promoted = Some(p);
+ }
+ }
+ None => self.super_place(place, _ctxt, _location)
}
},
- _ => self.super_place(place, _ctxt, _location),
}
}
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::Promoted(_)) => bug!("qualifying already promoted MIR"),
- Place::Base(PlaceBase::Static(ref static_)) => Self::in_static(cx, static_),
+ Place::Base(PlaceBase::Static(ref static_)) => {
+ match static_.promoted {
+ Some(..) => bug!("qualifying already promoted MIR"),
+ None => Self::in_static(cx, static_),
+ }
+ },
Place::Projection(ref proj) => Self::in_projection(cx, proj),
}
}
);
dest = &proj.base;
},
- Place::Base(PlaceBase::Promoted(..)) =>
- bug!("promoteds don't exist yet during promotion"),
- Place::Base(PlaceBase::Static(..)) => {
- // 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(
- dest,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
- location
- );
- return;
+ Place::Base(PlaceBase::Static(st)) => {
+ match st.promoted {
+ Some(..) => bug!("promoteds don't exist yet during promotion"),
+ None => {
+ // 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(
+ dest,
+ PlaceContext::MutatingUse(MutatingUseContext::Store),
+ location
+ );
+ return;
+ }
+ }
}
}
};
debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
self.super_place(place, context, location);
match *place {
- Place::Base(PlaceBase::Local(_)) |
- Place::Base(PlaceBase::Promoted(_)) => {}
+ Place::Base(PlaceBase::Local(_)) => {}
Place::Base(PlaceBase::Static(ref global)) => {
- if self.tcx
- .get_attrs(global.def_id)
- .iter()
- .any(|attr| attr.check_name("thread_local")) {
- if self.mode != Mode::Fn {
- span_err!(self.tcx.sess, self.span, E0625,
- "thread-local statics cannot be \
- accessed at compile-time");
- }
- return;
- }
+ match global.promoted {
+ Some(..) => {}
+ None => {
+ if self.tcx
+ .get_attrs(global.def_id)
+ .iter()
+ .any(|attr| attr.check_name("thread_local")) {
+ if self.mode != Mode::Fn {
+ span_err!(self.tcx.sess, self.span, E0625,
+ "thread-local statics cannot be \
+ accessed at compile-time");
+ }
+ return;
+ }
- // Only allow statics (not consts) to refer to other statics.
- if self.mode == Mode::Static || self.mode == Mode::StaticMut {
- if self.mode == Mode::Static && context.is_mutating_use() {
- // this is not strictly necessary as miri will also bail out
- // For interior mutability we can't really catch this statically as that
- // goes through raw pointers and intermediate temporaries, so miri has
- // to catch this anyway
- self.tcx.sess.span_err(
- self.span,
- "cannot mutate statics in the initializer of another static",
- );
- }
- return;
- }
- unleash_miri!(self);
+ // Only allow statics (not consts) to refer to other statics.
+ if self.mode == Mode::Static || self.mode == Mode::StaticMut {
+ if self.mode == Mode::Static && context.is_mutating_use() {
+ // this is not strictly necessary as miri will also bail out
+ // For interior mutability we can't really catch this statically as that
+ // goes through raw pointers and intermediate temporaries, so miri has
+ // to catch this anyway
+ self.tcx.sess.span_err(
+ self.span,
+ "cannot mutate statics in the initializer of another static",
+ );
+ }
+ return;
+ }
+ unleash_miri!(self);
- if self.mode != Mode::Fn {
- let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
- "{}s cannot refer to statics, use \
- a constant instead", self.mode);
- if self.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note(
- "Static and const variables can refer to other const variables. But a \
- const variable cannot refer to a static variable."
- );
- err.help(
- "To fix this, the value can be extracted as a const and then used."
- );
+ if self.mode != Mode::Fn {
+ let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
+ "{}s cannot refer to statics, use \
+ a constant instead", self.mode);
+ if self.tcx.sess.teach(&err.get_code().unwrap()) {
+ err.note(
+ "Static and const variables can refer to other const variables. But a \
+ const variable cannot refer to a static variable."
+ );
+ err.help(
+ "To fix this, the value can be extracted as a const and then used."
+ );
+ }
+ err.emit()
+ }
}
- err.emit()
}
}
Place::Projection(ref proj) => {
) -> McfResult {
match place {
Place::Base(PlaceBase::Local(_)) => Ok(()),
- // promoteds are always fine, they are essentially constants
- Place::Base(PlaceBase::Promoted(_)) => Ok(()),
- Place::Base(PlaceBase::Static(_)) =>
- Err((span, "cannot access `static` items in const fn".into())),
+ Place::Base(PlaceBase::Static(st)) => {
+ match st.promoted {
+ // promoteds are always fine, they are essentially constants
+ Some(..) => Ok(()),
+ None => Err((span, "cannot access `static` items in const fn".into())),
+ }
+ }
Place::Projection(proj) => {
match proj.elem {
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }