From a75f7810a7118e3bb103058091c1d6414b515786 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 17 Oct 2018 16:31:22 +0200 Subject: [PATCH] AST-borrowck: add separate mem category for thread-locals, as they are not quite rvalues (and of course they are not quite statics either). Namely, they *do* have a restricted region (like rvalues), but they also cannot be moved out of (like statics). --- src/librustc/middle/mem_categorization.rs | 29 ++++++++++++++----- src/librustc_borrowck/borrowck/check_loans.rs | 1 + .../borrowck/gather_loans/gather_moves.rs | 1 + .../borrowck/gather_loans/lifetime.rs | 2 ++ .../borrowck/gather_loans/move_error.rs | 7 ++++- .../borrowck/gather_loans/restrictions.rs | 6 ++++ src/librustc_borrowck/borrowck/mod.rs | 1 + src/librustc_passes/rvalue_promotion.rs | 1 + src/librustc_typeck/check/regionck.rs | 1 + src/librustc_typeck/check/upvar.rs | 2 ++ 10 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 13e6f7a4c745..9d3f37bc36a9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -93,6 +93,7 @@ use util::nodemap::ItemLocalSet; #[derive(Clone, Debug, PartialEq)] pub enum Categorization<'tcx> { Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope + ThreadLocal(ty::Region<'tcx>), // value that cannot move, but still restricted in scope StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable @@ -268,6 +269,7 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(ref base_cmt, _) => { base_cmt.immutability_blame() } + Categorization::ThreadLocal(..) | Categorization::StaticItem => { // Do we want to do something here? None @@ -715,17 +717,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Static(def_id, mutbl) => { - // `#[thread_local]` statics may not outlive the current function. - for attr in &self.tcx.get_attrs(def_id)[..] { - if attr.check_name("thread_local") { - return Ok(self.cat_rvalue_node(hir_id, span, expr_ty)); - } - } + // `#[thread_local]` statics may not outlive the current function, but + // they also cannot be moved out of. + let is_thread_local = self.tcx.get_attrs(def_id)[..] + .iter() + .any(|attr| attr.check_name("thread_local")); + + let cat = if is_thread_local { + let re = self.temporary_scope(hir_id.local_id); + Categorization::ThreadLocal(re) + } else { + Categorization::StaticItem + }; Ok(cmt_ { hir_id, - span:span, - cat:Categorization::StaticItem, + span, + cat, mutbl: if mutbl { McDeclared } else { McImmutable}, ty:expr_ty, note: NoteNone @@ -1408,6 +1416,7 @@ impl<'tcx> cmt_<'tcx> { match self.cat { Categorization::Rvalue(..) | Categorization::StaticItem | + Categorization::ThreadLocal(..) | Categorization::Local(..) | Categorization::Deref(_, UnsafePtr(..)) | Categorization::Deref(_, BorrowedPtr(..)) | @@ -1439,6 +1448,7 @@ impl<'tcx> cmt_<'tcx> { } Categorization::Rvalue(..) | + Categorization::ThreadLocal(..) | Categorization::Local(..) | Categorization::Upvar(..) | Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but... @@ -1485,6 +1495,9 @@ impl<'tcx> cmt_<'tcx> { Categorization::StaticItem => { "static item".into() } + Categorization::ThreadLocal(..) => { + "thread-local static item".into() + } Categorization::Rvalue(..) => { "non-place".into() } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 34ee03b895f9..033ed8008edc 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -377,6 +377,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // by-move upvars, which is local data for generators Categorization::Upvar(..) => true, + Categorization::ThreadLocal(region) | Categorization::Rvalue(region) => { // Rvalues promoted to 'static are no longer local if let RegionKind::ReStatic = *region { diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index ffc4fbfb4c9c..7bb5f411752f 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -177,6 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | + Categorization::ThreadLocal(..) | Categorization::StaticItem => { Some(cmt.clone()) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index c9dcc0d9fa26..6ef5d65d10dc 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -70,6 +70,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { match cmt.cat { Categorization::Rvalue(..) | + Categorization::ThreadLocal(..) | Categorization::Local(..) | // L-Local Categorization::Upvar(..) | Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed @@ -105,6 +106,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { //! rooting etc, and presuming `cmt` is not mutated. match cmt.cat { + Categorization::ThreadLocal(temp_scope) | Categorization::Rvalue(temp_scope) => { temp_scope } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index b29ab55f9ba7..e1a4473539c8 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -145,6 +145,8 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, match move_from.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | + Categorization::Deref(_, mc::Unique) | + Categorization::ThreadLocal(..) | Categorization::StaticItem => { bccx.cannot_move_out_of( move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast) @@ -166,7 +168,10 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, } } } - _ => { + + Categorization::Rvalue(..) | + Categorization::Local(..) | + Categorization::Upvar(..) => { span_bug!(move_from.span, "this path should not cause illegal move"); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index d9784cc2177f..52c7ebb4beb0 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -70,6 +70,12 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { RestrictionResult::Safe } + Categorization::ThreadLocal(..) => { + // Thread-locals are statics that have a scope, with + // no underlying structure to provide restrictions. + RestrictionResult::Safe + } + Categorization::Local(local_id) => { // R-Variable, locally declared let lp = new_lp(LpVar(local_id)); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0ef0d284770f..d56eb188ccd2 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -520,6 +520,7 @@ pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option { (None, false) } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 5e9169e86a98..ca58239df8ea 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -663,6 +663,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { let mut cur = cmt; loop { match cur.cat { + Categorization::ThreadLocal(..) | Categorization::Rvalue(..) => { if loan_cause == euv::MatchDiscriminant { // Ignore the dummy immutable borrow created by EUV. diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 80b4ba6240d3..212ee2698e01 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1243,6 +1243,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { | Categorization::StaticItem | Categorization::Upvar(..) | Categorization::Local(..) + | Categorization::ThreadLocal(..) | Categorization::Rvalue(..) => { // These are all "base cases" with independent lifetimes // that are not subject to inference diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 99effce4ee08..df994ad9e55c 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -401,6 +401,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | + Categorization::ThreadLocal(..) | Categorization::Rvalue(..) | Categorization::Local(_) | Categorization::Upvar(..) => { @@ -431,6 +432,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem | + Categorization::ThreadLocal(..) | Categorization::Rvalue(..) | Categorization::Local(_) | Categorization::Upvar(..) => {}