diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index cddf57821215..6761c70550ec 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -737,16 +737,6 @@ macro_rules! make_mir_visitor { 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) => { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 8f83c025ceb4..b9877945e7ea 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1602,13 +1602,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { 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) => { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5726eba9bdaf..e92ed1f2c7ca 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1309,15 +1309,7 @@ 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)) => { - 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 @@ -1990,28 +1982,21 @@ 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::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) => { diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index d8c39e0715ad..2661d765718d 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -130,18 +130,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } 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); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 334c20761e7b..c2efd3625c32 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -454,10 +454,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { 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); @@ -480,15 +479,18 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ); }; } - 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, @@ -498,10 +500,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { sty, terr ); - } - PlaceTy::Ty { ty: sty } + }; } } + PlaceTy::Ty { ty: sty } } Place::Projection(ref proj) => { let base_context = if context.is_mutating_use() { diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 0bbd147d8243..5e691db0a2e4 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -50,11 +50,10 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { } } 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 { diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 7babdfcdd68a..c4f9df0cfe57 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -387,7 +387,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( }, (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"); @@ -404,7 +404,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( } }, (p1_, p2_) => { - debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED"); + debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED"); Overlap::Disjoint } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 62e2cdffadf3..7adcb118f843 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -582,39 +582,37 @@ where ) -> 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), diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 01cb58a481a3..2ebe28e6ac09 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -301,32 +301,27 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // 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) + }], &[]); } } }; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index bbe62fa2d7b3..3ee26e7dd26d 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -266,6 +266,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { + use rustc::mir::Static; match *place { Place::Base(PlaceBase::Local(loc)) => self.places[loc].clone(), Place::Projection(ref proj) => match proj.elem { @@ -282,31 +283,25 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { // 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, } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f0ba1306c99f..9cbb891316dc 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -189,10 +189,8 @@ trait Qualif { 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), } @@ -773,19 +771,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { 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; } } }; @@ -928,53 +922,49 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { 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; - } - - // 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() - } + 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); + + 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) => {