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::Projection(proj) => {
self.append_local_to_string(local, buf)?;
}
Place::Base(PlaceBase::Static(ref static_)) => {
- match static_.promoted {
- Some(_) => {
- buf.push_str("promoted");
- }
- None => {
- buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
- }
+ if static_.promoted.is_some() {
+ buf.push_str("promoted");
+ } else {
+ buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
}
}
Place::Projection(ref proj) => {
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) = match root_place {
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),
- }
+ (true, st.promoted.is_none() && self.is_place_thread_local(&root_place))
}
Place::Base(PlaceBase::Local(_)) => {
// Locals are always dropped at function exit, and if they
}
// 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::Static(ref static_)) => {
- match static_.promoted {
- Some(_) => {
+ if static_.promoted.is_some() {
+ Ok(RootPlace {
+ place,
+ is_local_mutation_allowed,
+ })
+ } else {
+ if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
+ Err(place)
+ } else {
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::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);
- }
- }
+ assert!(promoted.is_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);
}
}
ty: self.mir.local_decls[index].ty,
},
Place::Base(PlaceBase::Static(box Static { def_id, ty: sty, promoted })) => {
+ let sty = self.sanitize_type(place, sty);
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);
);
};
}
- 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)
+ .eq_types(
+ ty,
+ sty,
+ location.to_locations(),
+ ConstraintCategory::Boring
+ )
{
span_mirbug!(
self,
sty,
terr
);
- }
- PlaceTy::Ty { ty: sty }
+ };
}
}
+ PlaceTy::Ty { ty: sty }
}
Place::Projection(ref proj) => {
let base_context = if context.is_mutating_use() {
}
}
Place::Base(PlaceBase::Static(static_)) => {
- match static_.promoted {
- Some(_) => false,
- None => {
- tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
- }
+ if static_.promoted.is_none() {
+ tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+ } else {
+ false
}
}
Place::Projection(proj) => match proj.elem {
},
(Some(p1), Some(p2)) => {
if p1 == p2 {
- if let ty::Array(_, size) =s1.ty.sty {
+ 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");
}
},
(p1_, p2_) => {
- debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
+ debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED");
Overlap::Disjoint
}
}
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
use rustc::mir::PlaceBase;
+ use rustc::mir::Static;
Ok(match *mir_place {
- Base(PlaceBase::Static(ref static_)) => {
- 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)
- }
- }
+ Base(PlaceBase::Static(box Static {promoted: Some(promoted), ty, ..})) => {
+ let instance = self.frame().instance;
+ self.const_eval_raw(GlobalId {
+ instance,
+ promoted: Some(promoted),
+ })?
+ }
+
+ Base(PlaceBase::Static(box Static {promoted: None, ty, def_id})) => {
+ assert!(!ty.needs_subst());
+ let layout = self.layout_of(ty)?;
+ let instance = ty::Instance::mono(*self.tcx, 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),
// locals are safe
}
&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)
- }], &[]);
- }
- }
+ assert!(promoted.is_none(), "unsafety checking should happen before promotion");
+
+ 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)
+ }], &[]);
}
}
};
}
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 {
// an `Index` projection would throw us off-track.
_ => 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
+ Place::Base(PlaceBase::Static(box Static {promoted: Some(promoted), ty, ..})) => {
+ 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,
}
match *place {
Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
Place::Base(PlaceBase::Static(ref static_)) => {
- match static_.promoted {
- Some(..) => bug!("qualifying already promoted MIR"),
- None => Self::in_static(cx, static_),
- }
+ assert!(static_.promoted.is_none(), "qualifying already promoted MIR");
+ Self::in_static(cx, static_)
},
Place::Projection(ref proj) => Self::in_projection(cx, proj),
}
dest = &proj.base;
},
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;
- }
- }
+ assert!(st.promoted.is_none(), "promoteds don't exist yet during promotion");
+ // 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;
}
}
};
match *place {
Place::Base(PlaceBase::Local(_)) => {}
Place::Base(PlaceBase::Static(ref global)) => {
- 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;
- }
+ assert!(global.promoted.is_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."
- );
- }
- err.emit()
- }
+ 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()
}
}
Place::Projection(ref proj) => {