diff options
| author | Matthew Jasper <mjjasper1@gmail.com> | 2019-11-18 23:04:06 +0000 |
|---|---|---|
| committer | Matthew Jasper <mjjasper1@gmail.com> | 2019-11-21 20:55:17 +0000 |
| commit | 9abc34ed9d34873066a186ac5551d5aad9e783b6 (patch) | |
| tree | 15bd4c7bd6dba629cd16b586408b745d6fef5bdc | |
| parent | c6d97dfd835b5d9a740249570e008eb94f1a9e85 (diff) | |
| download | rust-9abc34ed9d34873066a186ac5551d5aad9e783b6.tar.gz rust-9abc34ed9d34873066a186ac5551d5aad9e783b6.zip | |
Track pointers to statics in MIR
25 files changed, 359 insertions, 299 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c0cd74ecf3a..2928a8ad9bc 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -292,7 +292,7 @@ impl<'tcx> Body<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable.is_some() { + if self.local_decls[local].is_user_variable() { None } else { Some(local) @@ -305,7 +305,7 @@ impl<'tcx> Body<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable.is_some() { + if self.local_decls[local].is_user_variable() { Some(local) } else { None @@ -319,7 +319,7 @@ impl<'tcx> Body<'tcx> { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; - if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut { + if decl.is_user_variable() && decl.mutability == Mutability::Mut { Some(local) } else { None @@ -333,7 +333,7 @@ impl<'tcx> Body<'tcx> { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; - if (decl.is_user_variable.is_some() || index < self.arg_count + 1) + if (decl.is_user_variable() || index < self.arg_count + 1) && decl.mutability == Mutability::Mut { Some(local) @@ -696,7 +696,8 @@ pub struct LocalDecl<'tcx> { /// therefore it need not be visible across crates. pnkfelix /// currently hypothesized we *need* to wrap this in a /// `ClearCrossCrate` as long as it carries as `HirId`. - pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>, + // FIXME(matthewjasper) Don't store in this in `Body` + pub local_info: LocalInfo<'tcx>, /// `true` if this is an internal local. /// @@ -721,6 +722,7 @@ pub struct LocalDecl<'tcx> { /// then it is a temporary created for evaluation of some /// subexpression of some block's tail expression (with no /// intervening statement context). + // FIXME(matthewjasper) Don't store in this in `Body` pub is_block_tail: Option<BlockTailInfo>, /// The type of this local. @@ -730,6 +732,7 @@ pub struct LocalDecl<'tcx> { /// e.g., via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. + // FIXME(matthewjasper) Don't store in this in `Body` pub user_ty: UserTypeProjections, /// The name of the local, used in debuginfo and pretty-printing. @@ -824,6 +827,17 @@ pub struct LocalDecl<'tcx> { pub visibility_scope: SourceScope, } +/// Extra information about a local that's used for diagnostics. +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] +pub enum LocalInfo<'tcx> { + /// A user-defined local variable or function parameter + User(ClearCrossCrate<BindingForm<'tcx>>), + /// A temporary created that references the static with the given `DefId`. + StaticRef { def_id: DefId, is_thread_local: bool }, + /// Any other temporary, the return place, or an anonymous function parameter. + Other, +} + impl<'tcx> LocalDecl<'tcx> { /// Returns `true` only if local is a binding that can itself be /// made mutable via the addition of the `mut` keyword, namely @@ -832,15 +846,17 @@ impl<'tcx> LocalDecl<'tcx> { /// - `let x = ...`, /// - or `match ... { C(x) => ... }` pub fn can_be_made_mutable(&self) -> bool { - match self.is_user_variable { - Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + match self.local_info { + LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }))) => true, - Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm))) => true, + LocalInfo::User( + ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)), + ) => true, _ => false, } @@ -850,16 +866,26 @@ impl<'tcx> LocalDecl<'tcx> { /// `ref mut ident` binding. (Such bindings cannot be made into /// mutable bindings, but the inverse does not necessarily hold). pub fn is_nonref_binding(&self) -> bool { - match self.is_user_variable { - Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + match self.local_info { + LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }))) => true, - Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true, + LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true, + + _ => false, + } + } + /// Returns `true` if this variable is a named variable or function + /// parameter declared by the user. + #[inline] + pub fn is_user_variable(&self) -> bool { + match self.local_info { + LocalInfo::User(_) => true, _ => false, } } @@ -868,8 +894,26 @@ impl<'tcx> LocalDecl<'tcx> { /// expression that is used to access said variable for the guard of the /// match arm. pub fn is_ref_for_guard(&self) -> bool { - match self.is_user_variable { - Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true, + match self.local_info { + LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true, + _ => false, + } + } + + /// Returns `Some` if this is a reference to a static item that is used to + /// access that static + pub fn is_ref_to_static(&self) -> bool { + match self.local_info { + LocalInfo::StaticRef { .. } => true, + _ => false, + } + } + + /// Returns `Some` if this is a reference to a static item that is used to + /// access that static + pub fn is_ref_to_thread_local(&self) -> bool { + match self.local_info { + LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local, _ => false, } } @@ -918,7 +962,7 @@ impl<'tcx> LocalDecl<'tcx> { source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, visibility_scope: OUTERMOST_SOURCE_SCOPE, internal, - is_user_variable: None, + local_info: LocalInfo::Other, is_block_tail: None, } } @@ -937,7 +981,7 @@ impl<'tcx> LocalDecl<'tcx> { internal: false, is_block_tail: None, name: None, // FIXME maybe we do want some name here? - is_user_variable: None, + local_info: LocalInfo::Other, } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 6a41b843e57..fc0e77aab43 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -691,7 +691,7 @@ macro_rules! make_mir_visitor { source_info, visibility_scope, internal: _, - is_user_variable: _, + local_info: _, is_block_tail: _, } = local_decl; diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 98641031c17..94323431990 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -189,8 +189,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { location: mir::Location, ) { if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { - if borrowed_place.ignore_borrow( - self.tcx, self.body, &self.locals_state_at_exit) { + if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) { + debug!("ignoring_borrow of {:?}", borrowed_place); return; } diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index ebc25138a06..3595312f3f4 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -3,8 +3,8 @@ use rustc::hir::def_id::DefId; use rustc::hir::{AsyncGeneratorKind, GeneratorKind}; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, + FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashSet; @@ -744,6 +744,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection: root_place_projection, }, borrow_span)); + if let PlaceBase::Local(local) = borrow.borrowed_place.base { + if self.body.local_decls[local].is_ref_to_thread_local() { + let err = self.report_thread_local_value_does_not_live_long_enough( + drop_span, + borrow_span, + ); + err.buffer(&mut self.errors_buffer); + return; + } + }; + if let StorageDeadOrDrop::Destructor(dropped_ty) = self.classify_drop_access_kind(borrow.borrowed_place.as_ref()) { @@ -770,9 +781,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { explanation ); let err = match (place_desc, explanation) { - (Some(_), _) if self.is_place_thread_local(root_place) => { - self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span) - } // If the outlives constraint comes from inside the closure, // for example: // @@ -1509,19 +1517,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // place being assigned later. let (place_description, assigned_span) = match local_decl { Some(LocalDecl { - is_user_variable: Some(ClearCrossCrate::Clear), + local_info: LocalInfo::User(ClearCrossCrate::Clear), .. }) | Some(LocalDecl { - is_user_variable: - Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: None, - .. - }))), + local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: None, + .. + }))), + .. + }) + | Some(LocalDecl { + local_info: LocalInfo::StaticRef { .. }, .. }) | Some(LocalDecl { - is_user_variable: None, + local_info: LocalInfo::Other, .. }) | None => (self.describe_place(place.as_ref()), assigned_span), diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 4036e9db33b..3835503b0ef 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -3,7 +3,7 @@ use rustc::hir::def::Namespace; use rustc::hir::def_id::DefId; use rustc::hir::GeneratorKind; use rustc::mir::{ - AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, + AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Static, StaticKind, Terminator, TerminatorKind, }; @@ -12,7 +12,6 @@ use rustc::ty::layout::VariantIdx; use rustc::ty::print::Print; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; -use syntax::symbol::sym; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -179,6 +178,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); } PlaceRef { + base: &PlaceBase::Local(local), + projection: [ProjectionElem::Deref] + } if self.body.local_decls[local].is_ref_for_guard() => { + self.append_place_to_string( + PlaceRef { + base: &PlaceBase::Local(local), + projection: &[], + }, + buf, + autoderef, + &including_downcast, + )?; + }, + PlaceRef { + base: &PlaceBase::Local(local), + projection: [ProjectionElem::Deref] + } if self.body.local_decls[local].is_ref_to_static() => { + let local_info = &self.body.local_decls[local].local_info; + if let LocalInfo::StaticRef { def_id, .. } = *local_info { + buf.push_str(&self.infcx.tcx.item_name(def_id).as_str()); + } else { + unreachable!(); + } + }, + PlaceRef { base, projection: [proj_base @ .., elem], } => { @@ -208,32 +232,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { )?; } else { match (proj_base, base) { - ([], PlaceBase::Local(local)) => { - if self.body.local_decls[*local].is_ref_for_guard() { - self.append_place_to_string( - PlaceRef { - base, - projection: proj_base, - }, - buf, - autoderef, - &including_downcast, - )?; - } else { - // FIXME deduplicate this and the _ => body below - buf.push_str(&"*"); - self.append_place_to_string( - PlaceRef { - base, - projection: proj_base, - }, - buf, - autoderef, - &including_downcast, - )?; - } - } - _ => { buf.push_str(&"*"); self.append_place_to_string( @@ -440,30 +438,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - /// Checks if a place is a thread-local static. - 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, - .. - }), - projection: [], - } = place_ref { - let attrs = self.infcx.tcx.get_attrs(*def_id); - let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); - - debug!( - "is_place_thread_local: attrs={:?} is_thread_local={:?}", - attrs, is_thread_local - ); - is_thread_local - } else { - debug!("is_place_thread_local: no"); - false - } - } - /// Add a note that a type does not implement `Copy` pub(super) fn note_type_does_not_implement_copy( &self, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index b8b4a1053e5..8e34eb6f413 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -308,7 +308,7 @@ fn do_mir_borrowck<'a, 'tcx>( // would have a chance of erroneously adding non-user-defined mutable vars // to the set. let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter() - .filter(|&local| mbcx.body.local_decls[*local].is_user_variable.is_none()) + .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable()) .cloned() .collect(); // For the remaining unused locals that are marked as mutable, we avoid linting any that @@ -1287,7 +1287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match *operand { Operand::Move(ref place) | Operand::Copy(ref place) => { match place.as_local() { - Some(local) if self.body.local_decls[local].is_user_variable.is_none() => { + Some(local) if !self.body.local_decls[local].is_user_variable() => { if self.body.local_decls[local].ty.is_mutable_ptr() { // The variable will be marked as mutable by the borrow. return; @@ -1399,7 +1399,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) { debug!("check_for_invalidation_at_exit({:?})", borrow); let place = &borrow.borrowed_place; - let root_place = self.prefixes(place.as_ref(), PrefixSet::All).last().unwrap(); + let deref = [ProjectionElem::Deref]; + let mut root_place = PlaceRef { base: &place.base, projection: &[] }; // FIXME(nll-rfc#40): do more precise destructor tracking here. For now // we just know that all locals are dropped at function exit (otherwise @@ -1407,26 +1408,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // FIXME: allow thread-locals to borrow other thread locals? - assert!(root_place.projection.is_empty()); let (might_be_alive, will_be_dropped) = match root_place.base { - PlaceBase::Static(box Static { - kind: StaticKind::Promoted(..), - .. - }) => { + PlaceBase::Static(_) => { (true, false) } - PlaceBase::Static(box Static { - kind: StaticKind::Static, - .. - }) => { - // Thread-locals might be dropped after the function exits, but - // "true" statics will never be. - (true, self.is_place_thread_local(root_place)) - } - PlaceBase::Local(_) => { - // Locals are always dropped at function exit, and if they - // have a destructor it would've been called already. - (false, self.locals_are_invalidated_at_exit) + PlaceBase::Local(local) => { + if self.body.local_decls[*local].is_ref_to_thread_local() { + // Thread-locals might be dropped after the function exits + // We have to dereference the outer reference because + // borrows don't conflict behind shared references. + root_place.projection = &deref; + (true, true) + } else { + (false, self.locals_are_invalidated_at_exit) + } } }; diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index d9e958d9450..b1f63d729ba 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -104,13 +104,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // opt_match_place is None for let [mut] x = ... statements, // whether or not the right-hand side is a place expression - if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }))) = local_decl.is_user_variable - { + if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + opt_match_place: Some((ref opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }, + ))) = local_decl.local_info { let stmt_source_info = self.body.source_info(location); self.append_binding_error( grouped_errors, @@ -242,7 +243,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ( match kind { IllegalMoveOriginKind::Static => { - self.report_cannot_move_from_static(original_path, span) + unreachable!(); } IllegalMoveOriginKind::BorrowedContent { target_place } => { self.report_cannot_move_from_borrowed_content( @@ -272,12 +273,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { place: &Place<'tcx>, span: Span ) -> DiagnosticBuilder<'a> { - let description = if place.projection.is_empty() { + let description = if place.projection.len() == 1 { format!("static item `{}`", self.describe_place(place.as_ref()).unwrap()) } else { let base_static = PlaceRef { base: &place.base, - projection: &place.projection[..1], + projection: &[ProjectionElem::Deref], }; format!( @@ -327,6 +328,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "variables bound in patterns cannot be moved from \ until after the end of the pattern guard"); return err; + } else if decl.is_ref_to_static() { + return self.report_cannot_move_from_static(move_place, span); } } @@ -508,12 +511,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; - if let Some( + if let LocalInfo::User( ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { pat_span, .. })) - ) = bind_to.is_user_variable { + ) = bind_to.local_info { if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) { if pat_snippet.starts_with('&') { diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 11e89de810e..404684c07a0 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -1,9 +1,7 @@ use rustc::hir; use rustc::hir::Node; -use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body}; -use rustc::mir::{ - Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind -}; +use rustc::mir::{self, Body, ClearCrossCrate, Local, LocalInfo, Location}; +use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_index::vec::Idx; use syntax_pos::Span; @@ -77,6 +75,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { + base: &PlaceBase::Local(local), + projection: [ProjectionElem::Deref], + } if self.body.local_decls[local].is_ref_for_guard() => { + item_msg = format!("`{}`", access_place_desc.unwrap()); + reason = ", as it is immutable for the pattern guard".to_string(); + } + PlaceRef { + base: &PlaceBase::Local(local), + projection: [ProjectionElem::Deref], + } if self.body.local_decls[local].is_ref_to_static() => { + if access_place.projection.len() == 1 { + item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); + reason = String::new(); + } else { + item_msg = format!("`{}`", access_place_desc.unwrap()); + let local_info = &self.body.local_decls[local].local_info; + if let LocalInfo::StaticRef { def_id, .. } = *local_info { + let static_name = &self.infcx.tcx.item_name(def_id); + reason = format!(", as `{}` is an immutable static item", static_name); + } else { + bug!("is_ref_to_static return true, but not ref to static?"); + } + } + } + PlaceRef { base: _, projection: [proj_base @ .., ProjectionElem::Deref], } => { @@ -101,15 +124,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { ", as `Fn` closures cannot mutate their captured variables".to_string() } - } else if { - if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) { - self.body.local_decls[*local].is_ref_for_guard() - } else { - false - } - } { - item_msg = format!("`{}`", access_place_desc.unwrap()); - reason = ", as it is immutable for the pattern guard".to_string(); } else { let source = self.borrowed_content_source(PlaceRef { base: the_place_err.base, @@ -133,37 +147,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { - base: - PlaceBase::Static(box Static { - kind: StaticKind::Promoted(..), - .. - }), - projection: [], - } => unreachable!(), - - PlaceRef { - base: - PlaceBase::Static(box Static { - kind: StaticKind::Static, - def_id, - .. - }), - projection: [], - } => { - if let PlaceRef { - base: &PlaceBase::Static(_), - projection: &[], - } = access_place.as_ref() { - 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); - } + base: PlaceBase::Static(_), + .. } - - PlaceRef { + | PlaceRef { base: _, projection: [.., ProjectionElem::Index(_)], } @@ -257,15 +244,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { projection: [], } if { self.body.local_decls.get(*local).map(|local_decl| { - if let ClearCrossCrate::Set( + if let LocalInfo::User(ClearCrossCrate::Set( mir::BindingForm::ImplicitSelf(kind) - ) = local_decl.is_user_variable.as_ref().unwrap() { + )) = local_decl.local_info { // Check if the user variable is a `&mut self` and we can therefore // suggest removing the `&mut`. // // Deliberately fall into this case for all implicit self types, // so that we don't fall in to the next case with them. - *kind == mir::ImplicitSelfKind::MutRef + kind == mir::ImplicitSelfKind::MutRef } else if Some(kw::SelfLower) == local_decl.name { // Otherwise, check if the name is the self kewyord - in which case // we have an explicit self. Do the same thing in this case and check @@ -360,16 +347,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref], - } if { - if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = - self.body.local_decls[*local].is_user_variable - { - true - } else { - false - } - } => - { + } if self.body.local_decls[*local].is_ref_for_guard() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.note( "variables bound in patterns are immutable until the end of the pattern guard", @@ -384,38 +362,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref], - } if self.body.local_decls[*local].is_user_variable.is_some() => + } if self.body.local_decls[*local].is_user_variable() => { let local_decl = &self.body.local_decls[*local]; - let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { - ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_)) => { + let suggestion = match local_decl.local_info { + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => { Some(suggest_ampmut_self(self.infcx.tcx, local_decl)) } - ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - })) => Some(suggest_ampmut( + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + }, + ))) => Some(suggest_ampmut( self.infcx.tcx, self.body, *local, local_decl, - *opt_ty_info, + opt_ty_info, )), - ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - })) => { + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + }, + ))) => { let pattern_span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) .map(|replacement| (pattern_span, replacement)) } - ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(), + LocalInfo::User(ClearCrossCrate::Clear) => bug!("saw cleared local state"), - ClearCrossCrate::Clear => bug!("saw cleared local state"), + _ => unreachable!(), }; let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { 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 9f20a24a183..99bcfa9bc25 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1387,7 +1387,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } else { ConstraintCategory::Return }, - Some(l) if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -1693,7 +1693,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Return } } - Some(l) if !body.local_decls[l].is_user_variable.is_some() => { + Some(l) if !body.local_decls[l].is_user_variable() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index f0d2927ba45..c62de2af55f 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,6 @@ use rustc::hir; use rustc::mir::ProjectionElem; -use rustc::mir::{Body, Place, PlaceBase, Mutability, Static, StaticKind}; +use rustc::mir::{Body, Place, PlaceBase, Mutability}; use rustc::ty::{self, TyCtxt}; use crate::borrow_check::borrow_set::LocalsStateAtExit; @@ -25,7 +25,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - let ignore = match self.base { + let local = match self.base { // 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 @@ -34,22 +34,22 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { // // In particular, the variable cannot be mutated -- the "access checks" will fail -- // so we don't have to worry about mutation while borrowed. - PlaceBase::Local(index) => { + PlaceBase::Local(local) => { match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => false, + LocalsStateAtExit::AllAreInvalidated => local, LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(index) && - body.local_decls[index].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", index, ignore); - ignore + let ignore = !has_storage_dead_or_moved.contains(local) && + body.local_decls[local].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", local, ignore); + if ignore { + return true; + } else { + local + } } } } - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => - false, - PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { - tcx.is_mutable_static(def_id) - } + PlaceBase::Static(_) => return true, }; for (i, elem) in self.projection.iter().enumerate() { @@ -57,22 +57,33 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { if *elem == ProjectionElem::Deref { let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty; - if let ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Immutable) = ty.kind { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - return true; + match ty.kind { + ty::Ref(_, _, hir::Mutability::Immutable) if i == 0 => { + // For references to thread-local statics, we do need + // to track the borrow. + if body.local_decls[local].is_ref_to_thread_local() { + continue; + } + return true; + } + ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Immutable) => { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + return true; + } + _ => {} } } } - ignore + false } } diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 39bdc871d83..6db7ec65096 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -45,6 +45,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { literal, } }, + ExprKind::StaticRef { literal, .. } => { + Constant { + span, + user_ty: None, + literal, + } + } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index aed4759322c..f66f1cb7366 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -285,6 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::Literal { .. } + | ExprKind::StaticRef { .. } | ExprKind::InlineAsm { .. } | ExprKind::Yield { .. } | ExprKind::Call { .. } => { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 3bbd8093d3b..37eb0cc9d96 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -270,6 +270,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { resume.and(this.unit_rvalue()) } ExprKind::Literal { .. } + | ExprKind::StaticRef { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } | ExprKind::NeverToAny { .. } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 18332ed68f8..864b449c29c 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -6,6 +6,7 @@ use crate::hair::*; use rustc::hir; use rustc::middle::region; use rustc::mir::*; +use syntax_pos::symbol::sym; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building @@ -63,6 +64,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(tail_info) = this.block_context.currently_in_block_tail() { local_decl = local_decl.block_tail(tail_info); } + if let ExprKind::StaticRef { def_id, .. } = expr.kind { + let attrs = this.hir.tcx().get_attrs(def_id); + let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); + local_decl.local_info = LocalInfo::StaticRef {def_id, is_thread_local }; + } this.local_decls.push(local_decl) }; let temp_place = &Place::from(temp); diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index e7b68acc2ef..270a1a64474 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -65,7 +65,8 @@ impl Category { | ExprKind::Yield { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), - ExprKind::Literal { .. } => Some(Category::Constant), + ExprKind::Literal { .. } + | ExprKind::StaticRef { .. } => Some(Category::Constant), ExprKind::Loop { .. } | ExprKind::Block { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 1a19878a1f1..e991181189f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, visibility_scope: source_info.scope, internal: true, - is_user_variable: None, + local_info: LocalInfo::Other, is_block_tail: None, }); let ptr_temp = Place::from(ptr_temp); @@ -425,6 +425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Tuple { .. } | ExprKind::Closure { .. } | ExprKind::Literal { .. } + | ExprKind::StaticRef { .. } | ExprKind::Yield { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { // should be handled above diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 667b37bbd80..ada547aa39c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -458,10 +458,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for binding in &candidate.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. - }))) = self.local_decls[local].is_user_variable + }))) = self.local_decls[local].local_info { *match_place = Some(initializer.clone()); } else { @@ -1734,16 +1734,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visibility_scope, internal: false, is_block_tail: None, - is_user_variable: Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode, - // hypothetically, `visit_bindings` could try to unzip - // an outermost hir::Ty as we descend, matching up - // idents in pat; but complex w/ unclear UI payoff. - // Instead, just abandon providing diagnostic info. - opt_ty_info: None, - opt_match_place, - pat_span, - }))), + local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + binding_mode, + // hypothetically, `visit_bindings` could try to unzip + // an outermost hir::Ty as we descend, matching up + // idents in pat; but complex w/ unclear UI payoff. + // Instead, just abandon providing diagnostic info. + opt_ty_info: None, + opt_match_place, + pat_span, + }, + ))), }; let for_arm_body = self.local_decls.push(local); let locals = if has_guard.0 { @@ -1758,7 +1760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visibility_scope, internal: false, is_block_tail: None, - is_user_variable: Some(ClearCrossCrate::Set(BindingForm::RefForGuard)), + local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)), }); LocalsForNode::ForGuard { ref_for_guard, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index fb605bb2b55..6b458cc244c 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -820,7 +820,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visibility_scope: source_info.scope, name, internal: false, - is_user_variable: None, + local_info: LocalInfo::Other, is_block_tail: None, }); } @@ -855,17 +855,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; - self.local_decls[local].is_user_variable = + self.local_decls[local].local_info = if let Some(kind) = self_binding { - Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))) + LocalInfo::User(ClearCrossCrate::Set( + BindingForm::ImplicitSelf(*kind), + )) } else { let binding_mode = ty::BindingMode::BindByValue(mutability.into()); - Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - binding_mode, - opt_ty_info, - opt_match_place: Some((Some(place.clone()), span)), - pat_span: span, - }))) + LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + binding_mode, + opt_ty_info, + opt_match_place: Some((Some(place.clone()), span)), + pat_span: span, + }, + ))) }; self.var_indices.insert(var, LocalsForNode::One(local)); } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 5e64144df2c..402e5aeacbf 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -209,7 +209,9 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // local must conflict. This is purely an optimization so we don't have to call // `places_conflict` for every borrow. if place.projection.is_empty() { - trans.kill_all(other_borrows_of_local); + if !self.body.local_decls[local].is_ref_to_static() { + trans.kill_all(other_borrows_of_local); + } return; } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 28794859c56..f47c92cbd54 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -264,6 +264,11 @@ pub enum ExprKind<'tcx> { literal: &'tcx Const<'tcx>, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, }, + /// A literal containing the address of a `static` + StaticRef { + literal: &'tcx Const<'tcx>, + def_id: DefId, + }, InlineAsm { asm: &'tcx hir::InlineAsmInner, outputs: Vec<ExprRef<'tcx>>, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2913d6e59eb..17f5e3d4e47 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -152,7 +152,7 @@ fn temp_decl(mutability: Mutability, ty: Ty<'_>, span: Span) -> LocalDecl<'_> { source_info, visibility_scope: source_info.scope, internal: false, - is_user_variable: None, + local_info: LocalInfo::Other, is_block_tail: None, } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 772f27fb7e1..bee37f69a5e 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -1,6 +1,6 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use rustc::hir::HirId; +use rustc::hir::{HirId, def_id::DefId}; use rustc::middle::lang_items; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::*; @@ -288,6 +288,15 @@ impl Validator<'a, 'mir, 'tcx> { let span = self.span; self.check_op_spanned(op, span) } + + fn check_static(&mut self, def_id: DefId, span: Span) -> CheckOpResult { + let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local); + if is_thread_local { + self.check_op_spanned(ops::ThreadLocalAccess, span) + } else { + self.check_op_spanned(ops::StaticAccess, span) + } + } } impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { @@ -422,12 +431,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { self.super_operand(op, location); if let Operand::Constant(c) = op { if let Some(def_id) = c.check_static_ptr(self.tcx) { - let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local); - if is_thread_local { - self.check_op(ops::ThreadLocalAccess); - } else { - self.check_op(ops::StaticAccess); - } + self.check_static(def_id, self.span); } } } @@ -506,14 +510,24 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { match elem { ProjectionElem::Deref => { - if context.is_mutating_use() { - self.check_op(ops::MutDeref); - } - let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; if let ty::RawPtr(_) = base_ty.kind { + if proj_base.is_empty() { + if let (PlaceBase::Local(local), []) = (place_base, proj_base) { + let decl = &self.body.local_decls[*local]; + if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { + let span = decl.source_info.span; + self.check_static(def_id, span); + return; + } + } + } self.check_op(ops::RawPtrDeref); } + + if context.is_mutating_use() { + self.check_op(ops::MutDeref); + } } ProjectionElem::ConstantIndex {..} | diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 9374109c82e..b7cc4e9fcf6 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -206,25 +206,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // Locals are safe. } PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { - bug!("unsafety checking should happen before promotion") + bug!("unsafety checking should happen before promotion"); } - 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 \ - violations or data races will cause undefined behavior", - UnsafetyViolationKind::General, - ); - } else if self.tcx.is_foreign_item(def_id) { - self.require_unsafe( - "use of extern static", - "extern statics are not controlled by the Rust type system: \ - invalid data, aliasing violations or data races will cause \ - undefined behavior", - UnsafetyViolationKind::General, - ); - } + PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { + bug!("StaticKind::Static should not exist"); } } @@ -264,11 +249,31 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } let old_source_info = self.source_info; if let (PlaceBase::Local(local), []) = (&place.base, proj_base) { - if self.body.local_decls[*local].internal { + let decl = &self.body.local_decls[*local]; + if decl.internal { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. self.source_info = self.body.local_decls[*local].source_info; + } else if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { + if self.tcx.is_mutable_static(def_id) { + 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, + ); + return; + } else if self.tcx.is_foreign_item(def_id) { + self.require_unsafe( + "use of extern static", + "extern statics are not controlled by the Rust type system: \ + invalid data, aliasing violations or data races will cause \ + undefined behavior", + UnsafetyViolationKind::General, + ); + return; + } } } let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 37c239001a5..524b6b08790 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -432,7 +432,7 @@ fn replace_result_variable<'tcx>( visibility_scope: source_info.scope, internal: false, is_block_tail: None, - is_user_variable: None, + local_info: LocalInfo::Other }; let new_ret_local = Local::new(body.local_decls.len()); body.local_decls.push(new_ret); @@ -967,7 +967,7 @@ fn create_generator_drop_shim<'tcx>( visibility_scope: source_info.scope, internal: false, is_block_tail: None, - is_user_variable: None, + local_info: LocalInfo::Other }; make_generator_state_argument_indirect(tcx, def_id, &mut body); @@ -985,7 +985,7 @@ fn create_generator_drop_shim<'tcx>( visibility_scope: source_info.scope, internal: false, is_block_tail: None, - is_user_variable: None, + local_info: LocalInfo::Other }; if tcx.sess.opts.debugging_opts.mir_emit_retag { // Alias tracking must know we changed the type diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index c79d382a374..86ecfbb4fbe 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -512,35 +512,10 @@ impl<'tcx> Validator<'_, 'tcx> { projection: [], } => self.validate_local(*local), PlaceRef { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted { .. }, - .. - }), + base: PlaceBase::Static(_), projection: [], } => bug!("qualifying already promoted MIR"), PlaceRef { - base: PlaceBase::Static(box Static { - kind: StaticKind::Static, - def_id, - .. - }), - projection: [], - } => { - // Only allow statics (not consts) to refer to other statics. - // FIXME(eddyb) does this matter at all for promotion? - let is_static = self.const_kind.map_or(false, |k| k.is_static()); - if !is_static { - return Err(Unpromotable); - } - - let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local); - if is_thread_local { - return Err(Unpromotable); - } - - Ok(()) - } - PlaceRef { base: _, projection: [proj_base @ .., elem], } => { @@ -584,7 +559,23 @@ impl<'tcx> Validator<'_, 'tcx> { // The qualifs for a constant (e.g. `HasMutInterior`) are checked in // `validate_rvalue` upon access. - Operand::Constant(_) => Ok(()), + Operand::Constant(c) => { + if let Some(def_id) = c.check_static_ptr(self.tcx) { + // Only allow statics (not consts) to refer to other statics. + // FIXME(eddyb) does this matter at all for promotion? + let is_static = self.const_kind.map_or(false, |k| k.is_static()); + if !is_static { + return Err(Unpromotable); + } + + let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local); + if is_thread_local { + return Err(Unpromotable); + } + } + + Ok(()) + }, } } |
