Skip to content

Commit 9abc34e

Browse files
committed
Track pointers to statics in MIR
1 parent c6d97df commit 9abc34e

25 files changed

+359
-299
lines changed

src/librustc/mir/mod.rs

+59-15
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ impl<'tcx> Body<'tcx> {
292292
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
293293
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
294294
let local = Local::new(index);
295-
if self.local_decls[local].is_user_variable.is_some() {
295+
if self.local_decls[local].is_user_variable() {
296296
None
297297
} else {
298298
Some(local)
@@ -305,7 +305,7 @@ impl<'tcx> Body<'tcx> {
305305
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
306306
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
307307
let local = Local::new(index);
308-
if self.local_decls[local].is_user_variable.is_some() {
308+
if self.local_decls[local].is_user_variable() {
309309
Some(local)
310310
} else {
311311
None
@@ -319,7 +319,7 @@ impl<'tcx> Body<'tcx> {
319319
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
320320
let local = Local::new(index);
321321
let decl = &self.local_decls[local];
322-
if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut {
322+
if decl.is_user_variable() && decl.mutability == Mutability::Mut {
323323
Some(local)
324324
} else {
325325
None
@@ -333,7 +333,7 @@ impl<'tcx> Body<'tcx> {
333333
(1..self.local_decls.len()).filter_map(move |index| {
334334
let local = Local::new(index);
335335
let decl = &self.local_decls[local];
336-
if (decl.is_user_variable.is_some() || index < self.arg_count + 1)
336+
if (decl.is_user_variable() || index < self.arg_count + 1)
337337
&& decl.mutability == Mutability::Mut
338338
{
339339
Some(local)
@@ -696,7 +696,8 @@ pub struct LocalDecl<'tcx> {
696696
/// therefore it need not be visible across crates. pnkfelix
697697
/// currently hypothesized we *need* to wrap this in a
698698
/// `ClearCrossCrate` as long as it carries as `HirId`.
699-
pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>,
699+
// FIXME(matthewjasper) Don't store in this in `Body`
700+
pub local_info: LocalInfo<'tcx>,
700701

701702
/// `true` if this is an internal local.
702703
///
@@ -721,6 +722,7 @@ pub struct LocalDecl<'tcx> {
721722
/// then it is a temporary created for evaluation of some
722723
/// subexpression of some block's tail expression (with no
723724
/// intervening statement context).
725+
// FIXME(matthewjasper) Don't store in this in `Body`
724726
pub is_block_tail: Option<BlockTailInfo>,
725727

726728
/// The type of this local.
@@ -730,6 +732,7 @@ pub struct LocalDecl<'tcx> {
730732
/// e.g., via `let x: T`, then we carry that type here. The MIR
731733
/// borrow checker needs this information since it can affect
732734
/// region inference.
735+
// FIXME(matthewjasper) Don't store in this in `Body`
733736
pub user_ty: UserTypeProjections,
734737

735738
/// The name of the local, used in debuginfo and pretty-printing.
@@ -824,6 +827,17 @@ pub struct LocalDecl<'tcx> {
824827
pub visibility_scope: SourceScope,
825828
}
826829

830+
/// Extra information about a local that's used for diagnostics.
831+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
832+
pub enum LocalInfo<'tcx> {
833+
/// A user-defined local variable or function parameter
834+
User(ClearCrossCrate<BindingForm<'tcx>>),
835+
/// A temporary created that references the static with the given `DefId`.
836+
StaticRef { def_id: DefId, is_thread_local: bool },
837+
/// Any other temporary, the return place, or an anonymous function parameter.
838+
Other,
839+
}
840+
827841
impl<'tcx> LocalDecl<'tcx> {
828842
/// Returns `true` only if local is a binding that can itself be
829843
/// made mutable via the addition of the `mut` keyword, namely
@@ -832,15 +846,17 @@ impl<'tcx> LocalDecl<'tcx> {
832846
/// - `let x = ...`,
833847
/// - or `match ... { C(x) => ... }`
834848
pub fn can_be_made_mutable(&self) -> bool {
835-
match self.is_user_variable {
836-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
849+
match self.local_info {
850+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
837851
binding_mode: ty::BindingMode::BindByValue(_),
838852
opt_ty_info: _,
839853
opt_match_place: _,
840854
pat_span: _,
841855
}))) => true,
842856

843-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm))) => true,
857+
LocalInfo::User(
858+
ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)),
859+
) => true,
844860

845861
_ => false,
846862
}
@@ -850,16 +866,26 @@ impl<'tcx> LocalDecl<'tcx> {
850866
/// `ref mut ident` binding. (Such bindings cannot be made into
851867
/// mutable bindings, but the inverse does not necessarily hold).
852868
pub fn is_nonref_binding(&self) -> bool {
853-
match self.is_user_variable {
854-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
869+
match self.local_info {
870+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
855871
binding_mode: ty::BindingMode::BindByValue(_),
856872
opt_ty_info: _,
857873
opt_match_place: _,
858874
pat_span: _,
859875
}))) => true,
860876

861-
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
877+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
878+
879+
_ => false,
880+
}
881+
}
862882

883+
/// Returns `true` if this variable is a named variable or function
884+
/// parameter declared by the user.
885+
#[inline]
886+
pub fn is_user_variable(&self) -> bool {
887+
match self.local_info {
888+
LocalInfo::User(_) => true,
863889
_ => false,
864890
}
865891
}
@@ -868,8 +894,26 @@ impl<'tcx> LocalDecl<'tcx> {
868894
/// expression that is used to access said variable for the guard of the
869895
/// match arm.
870896
pub fn is_ref_for_guard(&self) -> bool {
871-
match self.is_user_variable {
872-
Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
897+
match self.local_info {
898+
LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
899+
_ => false,
900+
}
901+
}
902+
903+
/// Returns `Some` if this is a reference to a static item that is used to
904+
/// access that static
905+
pub fn is_ref_to_static(&self) -> bool {
906+
match self.local_info {
907+
LocalInfo::StaticRef { .. } => true,
908+
_ => false,
909+
}
910+
}
911+
912+
/// Returns `Some` if this is a reference to a static item that is used to
913+
/// access that static
914+
pub fn is_ref_to_thread_local(&self) -> bool {
915+
match self.local_info {
916+
LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local,
873917
_ => false,
874918
}
875919
}
@@ -918,7 +962,7 @@ impl<'tcx> LocalDecl<'tcx> {
918962
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
919963
visibility_scope: OUTERMOST_SOURCE_SCOPE,
920964
internal,
921-
is_user_variable: None,
965+
local_info: LocalInfo::Other,
922966
is_block_tail: None,
923967
}
924968
}
@@ -937,7 +981,7 @@ impl<'tcx> LocalDecl<'tcx> {
937981
internal: false,
938982
is_block_tail: None,
939983
name: None, // FIXME maybe we do want some name here?
940-
is_user_variable: None,
984+
local_info: LocalInfo::Other,
941985
}
942986
}
943987
}

src/librustc/mir/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ macro_rules! make_mir_visitor {
691691
source_info,
692692
visibility_scope,
693693
internal: _,
694-
is_user_variable: _,
694+
local_info: _,
695695
is_block_tail: _,
696696
} = local_decl;
697697

src/librustc_mir/borrow_check/borrow_set.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
189189
location: mir::Location,
190190
) {
191191
if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
192-
if borrowed_place.ignore_borrow(
193-
self.tcx, self.body, &self.locals_state_at_exit) {
192+
if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
193+
debug!("ignoring_borrow of {:?}", borrowed_place);
194194
return;
195195
}
196196

src/librustc_mir/borrow_check/conflict_errors.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use rustc::hir::def_id::DefId;
33
use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
44
use rustc::mir::{
55
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
6-
FakeReadCause, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef,
7-
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
6+
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
7+
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
88
};
99
use rustc::ty::{self, Ty};
1010
use rustc_data_structures::fx::FxHashSet;
@@ -744,6 +744,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
744744
projection: root_place_projection,
745745
}, borrow_span));
746746

747+
if let PlaceBase::Local(local) = borrow.borrowed_place.base {
748+
if self.body.local_decls[local].is_ref_to_thread_local() {
749+
let err = self.report_thread_local_value_does_not_live_long_enough(
750+
drop_span,
751+
borrow_span,
752+
);
753+
err.buffer(&mut self.errors_buffer);
754+
return;
755+
}
756+
};
757+
747758
if let StorageDeadOrDrop::Destructor(dropped_ty) =
748759
self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
749760
{
@@ -770,9 +781,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
770781
explanation
771782
);
772783
let err = match (place_desc, explanation) {
773-
(Some(_), _) if self.is_place_thread_local(root_place) => {
774-
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
775-
}
776784
// If the outlives constraint comes from inside the closure,
777785
// for example:
778786
//
@@ -1509,19 +1517,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15091517
// place being assigned later.
15101518
let (place_description, assigned_span) = match local_decl {
15111519
Some(LocalDecl {
1512-
is_user_variable: Some(ClearCrossCrate::Clear),
1520+
local_info: LocalInfo::User(ClearCrossCrate::Clear),
15131521
..
15141522
})
15151523
| Some(LocalDecl {
1516-
is_user_variable:
1517-
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1518-
opt_match_place: None,
1519-
..
1520-
}))),
1524+
local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1525+
opt_match_place: None,
1526+
..
1527+
}))),
1528+
..
1529+
})
1530+
| Some(LocalDecl {
1531+
local_info: LocalInfo::StaticRef { .. },
15211532
..
15221533
})
15231534
| Some(LocalDecl {
1524-
is_user_variable: None,
1535+
local_info: LocalInfo::Other,
15251536
..
15261537
})
15271538
| None => (self.describe_place(place.as_ref()), assigned_span),

src/librustc_mir/borrow_check/error_reporting.rs

+26-52
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc::hir::def::Namespace;
33
use rustc::hir::def_id::DefId;
44
use rustc::hir::GeneratorKind;
55
use rustc::mir::{
6-
AggregateKind, Constant, Field, Local, LocalKind, Location, Operand,
6+
AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand,
77
Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
88
Static, StaticKind, Terminator, TerminatorKind,
99
};
@@ -12,7 +12,6 @@ use rustc::ty::layout::VariantIdx;
1212
use rustc::ty::print::Print;
1313
use rustc_errors::DiagnosticBuilder;
1414
use syntax_pos::Span;
15-
use syntax::symbol::sym;
1615

1716
use super::borrow_set::BorrowData;
1817
use super::MirBorrowckCtxt;
@@ -178,6 +177,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
178177
} => {
179178
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
180179
}
180+
PlaceRef {
181+
base: &PlaceBase::Local(local),
182+
projection: [ProjectionElem::Deref]
183+
} if self.body.local_decls[local].is_ref_for_guard() => {
184+
self.append_place_to_string(
185+
PlaceRef {
186+
base: &PlaceBase::Local(local),
187+
projection: &[],
188+
},
189+
buf,
190+
autoderef,
191+
&including_downcast,
192+
)?;
193+
},
194+
PlaceRef {
195+
base: &PlaceBase::Local(local),
196+
projection: [ProjectionElem::Deref]
197+
} if self.body.local_decls[local].is_ref_to_static() => {
198+
let local_info = &self.body.local_decls[local].local_info;
199+
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
200+
buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
201+
} else {
202+
unreachable!();
203+
}
204+
},
181205
PlaceRef {
182206
base,
183207
projection: [proj_base @ .., elem],
@@ -208,32 +232,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
208232
)?;
209233
} else {
210234
match (proj_base, base) {
211-
([], PlaceBase::Local(local)) => {
212-
if self.body.local_decls[*local].is_ref_for_guard() {
213-
self.append_place_to_string(
214-
PlaceRef {
215-
base,
216-
projection: proj_base,
217-
},
218-
buf,
219-
autoderef,
220-
&including_downcast,
221-
)?;
222-
} else {
223-
// FIXME deduplicate this and the _ => body below
224-
buf.push_str(&"*");
225-
self.append_place_to_string(
226-
PlaceRef {
227-
base,
228-
projection: proj_base,
229-
},
230-
buf,
231-
autoderef,
232-
&including_downcast,
233-
)?;
234-
}
235-
}
236-
237235
_ => {
238236
buf.push_str(&"*");
239237
self.append_place_to_string(
@@ -440,30 +438,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
440438
}
441439
}
442440

443-
/// Checks if a place is a thread-local static.
444-
pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool {
445-
if let PlaceRef {
446-
base: PlaceBase::Static(box Static {
447-
kind: StaticKind::Static,
448-
def_id,
449-
..
450-
}),
451-
projection: [],
452-
} = place_ref {
453-
let attrs = self.infcx.tcx.get_attrs(*def_id);
454-
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
455-
456-
debug!(
457-
"is_place_thread_local: attrs={:?} is_thread_local={:?}",
458-
attrs, is_thread_local
459-
);
460-
is_thread_local
461-
} else {
462-
debug!("is_place_thread_local: no");
463-
false
464-
}
465-
}
466-
467441
/// Add a note that a type does not implement `Copy`
468442
pub(super) fn note_type_does_not_implement_copy(
469443
&self,

0 commit comments

Comments
 (0)