diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 122543aee40..4567795184e 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -32,7 +32,7 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); @@ -43,26 +43,18 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_exit = graph.add_node(CFGNodeData::Exit); let body_exit; - // Find the function this expression is from. - let mut node_id = body.id; - loop { - let node = tcx.hir.get(node_id); - if hir::map::blocks::FnLikeNode::from_node(node).is_some() { - break; - } - let parent = tcx.hir.get_parent_node(node_id); - assert!(node_id != parent); - node_id = parent; - } + // Find the tables for this body. + let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); + let tables = tcx.item_tables(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, - tables: tcx.item_tables(tcx.hir.local_def_id(node_id)), + tables: tables, graph: graph, fn_exit: fn_exit, loop_scopes: Vec::new() }; - body_exit = cfg_builder.expr(body, entry); + body_exit = cfg_builder.expr(&body.value, entry); cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 43434b884c8..1473dbb1676 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,7 +59,7 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { construct::construct(tcx, body) } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e0233d6f8b9..2777c4d2487 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -89,8 +89,10 @@ pub enum DepNode { // Represents the MIR for a fn; also used as the task node for // things read/modify that MIR. + MirKrate, Mir(D), + BorrowCheckKrate, BorrowCheck(D), RvalueCheck(D), Reachability, @@ -114,6 +116,7 @@ pub enum DepNode { SizedConstraint(D), AssociatedItemDefIds(D), InherentImpls(D), + TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), MonomorphicConstEval(D), @@ -209,6 +212,9 @@ impl DepNode { match *self { Krate => Some(Krate), + BorrowCheckKrate => Some(BorrowCheckKrate), + MirKrate => Some(MirKrate), + TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index e365cea6d0e..7331756f35b 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -25,5 +25,6 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index f0a81fd1cfd..a34a3591c15 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -74,3 +74,13 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> }; krate.visit_all_item_likes(&mut tracking_visitor) } + +pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), +{ + let krate = tcx.hir.krate(); + for &body_id in &krate.body_ids { + let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); + callback(body_owner_def_id, body_id); + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 468421a68b5..257cdb960d5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -46,7 +46,7 @@ use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap}; use std::collections::BTreeMap; use std::iter; @@ -78,7 +78,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, - bodies: FxHashMap, + bodies: BTreeMap, trait_impls: BTreeMap>, trait_default_impl: BTreeMap, @@ -118,7 +118,7 @@ pub fn lower_crate(sess: &Session, items: BTreeMap::new(), trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), - bodies: FxHashMap(), + bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), loop_scopes: Vec::new(), @@ -196,6 +196,7 @@ impl<'a> LoweringContext<'a> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + let body_ids = body_ids(&self.bodies); hir::Crate { module: module, @@ -206,6 +207,7 @@ impl<'a> LoweringContext<'a> { trait_items: self.trait_items, impl_items: self.impl_items, bodies: self.bodies, + body_ids: body_ids, trait_impls: self.trait_impls, trait_default_impl: self.trait_default_impl, } @@ -2524,3 +2526,11 @@ impl<'a> LoweringContext<'a> { } } } + +fn body_ids(bodies: &BTreeMap) -> Vec { + // Sorting by span ensures that we get things in order within a + // file, and also puts the files in a sensible order. + let mut body_ids: Vec<_> = bodies.keys().cloned().collect(); + body_ids.sort_by_key(|b| bodies[b].value.span); + body_ids +} diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index be8780f39b1..425953c0f4f 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -259,6 +259,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { TyKind::ImplTrait(..) => { self.create_def(ty.id, DefPathData::ImplTrait); } + TyKind::Typeof(ref expr) => self.visit_ast_const_integer(expr), _ => {} } visit::walk_ty(self, ty); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index b28c5e80ea3..bf52a036cc8 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -260,7 +260,9 @@ pub enum DefPathData { /// Pattern binding Binding(InternedString), /// An `impl Trait` type node. - ImplTrait + ImplTrait, + /// A `typeof` type node. + Typeof, } impl Definitions { @@ -387,7 +389,8 @@ impl DefPathData { ClosureExpr | StructCtor | Initializer | - ImplTrait => None + ImplTrait | + Typeof => None } } @@ -415,6 +418,7 @@ impl DefPathData { StructCtor => "{{constructor}}", Initializer => "{{initializer}}", ImplTrait => "{{impl-Trait}}", + Typeof => "{{typeof}}", }; Symbol::intern(s).as_str() diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 20b4d8d8a8f..5d074903b2b 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> { }) } - fn is_body_owner(self, node_id: NodeId) -> bool { + fn associated_body(self) -> Option { match self { EntryItem(_, item) => { match item.node { ItemConst(_, body) | ItemStatic(.., body) | - ItemFn(_, _, _, _, _, body) => body.node_id == node_id, - _ => false + ItemFn(_, _, _, _, _, body) => Some(body), + _ => None, } } EntryTraitItem(_, item) => { match item.node { TraitItemKind::Const(_, Some(body)) | - TraitItemKind::Method(_, TraitMethod::Provided(body)) => { - body.node_id == node_id - } - _ => false + TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body), + _ => None } } EntryImplItem(_, item) => { match item.node { ImplItemKind::Const(_, body) | - ImplItemKind::Method(_, body) => body.node_id == node_id, - _ => false + ImplItemKind::Method(_, body) => Some(body), + _ => None, } } EntryExpr(_, expr) => { match expr.node { - ExprClosure(.., body, _) => body.node_id == node_id, - _ => false + ExprClosure(.., body, _) => Some(body), + _ => None, } } - _ => false + _ => None + } + } + + fn is_body_owner(self, node_id: NodeId) -> bool { + match self.associated_body() { + Some(b) => b.node_id == node_id, + None => false, } } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 8b6c75886ba..c1ba688974b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -31,7 +31,7 @@ pub use self::PathParameters::*; use hir::def::Def; use hir::def_id::DefId; -use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, Spanned}; @@ -409,10 +409,15 @@ pub struct Crate { pub trait_items: BTreeMap, pub impl_items: BTreeMap, - pub bodies: FxHashMap, - + pub bodies: BTreeMap, pub trait_impls: BTreeMap>, pub trait_default_impl: BTreeMap, + + /// A list of the body ids written out in the order in which they + /// appear in the crate. If you're going to process all the bodies + /// in the crate, you should iterate over this list rather than the keys + /// of bodies. + pub body_ids: Vec, } impl Crate { diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index bd35bfc9829..cdb081ab400 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -19,7 +19,7 @@ use ty::{self, TyCtxt, FreeRegion, Region}; use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct FreeRegionMap { // Stores the relation `a < b`, where `a` and `b` are regions. relation: TransitiveRelation @@ -30,6 +30,10 @@ impl FreeRegionMap { FreeRegionMap { relation: TransitiveRelation::new() } } + pub fn is_empty(&self) -> bool { + self.relation.is_empty() + } + pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, implied_bounds: &[ImpliedBound<'tcx>]) { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6961e0da362..a0aeb4107c1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -248,6 +248,11 @@ pub struct TypeckTables<'tcx> { /// If any errors occurred while type-checking this body, /// this field will be set to `true`. pub tainted_by_errors: bool, + + /// Stores the free-region relationships that were deduced from + /// its where clauses and parameter types. These are then + /// read-again by borrowck. + pub free_region_map: FreeRegionMap, } impl<'tcx> TypeckTables<'tcx> { @@ -267,6 +272,7 @@ impl<'tcx> TypeckTables<'tcx> { lints: lint::LintTable::new(), used_trait_imports: DefIdSet(), tainted_by_errors: false, + free_region_map: FreeRegionMap::new(), } } @@ -414,13 +420,6 @@ pub struct GlobalCtxt<'tcx> { pub region_maps: RegionMaps, - // For each fn declared in the local crate, type check stores the - // free-region relationships that were deduced from its where - // clauses and parameter types. These are then read-again by - // borrowck. (They are not used during trans, and hence are not - // serialized or needed for cross-crate fns.) - free_region_maps: RefCell>, - pub hir: hir_map::Map<'tcx>, pub maps: maps::Maps<'tcx>, @@ -645,16 +644,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { interned } - pub fn store_free_region_map(self, id: NodeId, map: FreeRegionMap) { - if self.free_region_maps.borrow_mut().insert(id, map).is_some() { - bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id) - } - } - - pub fn free_region_map(self, id: NodeId) -> FreeRegionMap { - self.free_region_maps.borrow()[&id].clone() - } - pub fn lift>(self, value: &T) -> Option { value.lift_to_tcx(self) } @@ -707,7 +696,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { types: common_types, named_region_map: named_region_map, region_maps: region_maps, - free_region_maps: RefCell::new(FxHashMap()), variance_computed: Cell::new(false), trait_map: resolutions.trait_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 7bf1ba155b5..448be7fe9a1 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -180,7 +180,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::MacroDef(..) | data @ DefPathData::ClosureExpr | data @ DefPathData::Binding(..) | - data @ DefPathData::ImplTrait => { + data @ DefPathData::ImplTrait | + data @ DefPathData::Typeof => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); buffer.push(&data.as_interned_str()); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8cf8a839afb..2559a670944 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2602,6 +2602,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } + /// Invokes `callback` for each body in the krate. This will + /// create a read edge from `DepNode::Krate` to the current task; + /// it is meant to be run in the context of some global task like + /// `BorrowckCrate`. The callback would then create a task like + /// `BorrowckBody(DefId)` to process each individual item. + pub fn visit_all_bodies_in_krate(self, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + { + dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback) + } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. pub fn span_of_impl(self, impl_did: DefId) -> Result { diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index dbab3bca52b..c0f681680a9 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -27,7 +27,7 @@ use rustc::middle::mem_categorization as mc; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::DUMMY_SP; #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Fragment { @@ -200,7 +200,6 @@ impl FragmentSets { pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, id: ast::NodeId) { let span_err = tcx.hir.attrs(id).iter() .any(|a| a.check_name("rustc_move_fragments")); @@ -208,6 +207,8 @@ pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, if !span_err && !print { return; } + let sp = tcx.hir.span(id); + let instrument_all_paths = |kind, vec_rc: &Vec| { for (i, mpi) in vec_rc.iter().enumerate() { let lp = || this.path_loan_path(*mpi); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 1783ca74a25..28b6c7a13f1 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -28,9 +28,6 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::hir; -use rustc::hir::Expr; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use self::restrictions::RestrictionResult; @@ -514,47 +511,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } } -/// Context used while gathering loans on static initializers -/// -/// This visitor walks static initializer's expressions and makes -/// sure the loans being taken are sound. -struct StaticInitializerCtxt<'a, 'tcx: 'a> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - body_id: hir::BodyId, -} - -impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - if let hir::ExprAddrOf(mutbl, ref base) = ex.node { - let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(self.body_id); - let mc = mc::MemCategorizationContext::new(&infcx); - let base_cmt = mc.cat_expr(&base).unwrap(); - let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); - // Check that we don't allow borrows of unsafe static items. - let err = check_aliasability(self.bccx, ex.span, - BorrowViolation(euv::AddrOf), - base_cmt, borrow_kind).is_err(); - if err { - return; // reported an error, no sense in reporting more. - } - } - - intravisit::walk_expr(self, ex); - } -} - -pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) { - debug!("gather_loans_in_static_initializer(expr={:?})", body); - - let mut sicx = StaticInitializerCtxt { - bccx: bccx, - body_id: body - }; - - let body = sicx.bccx.tcx.hir.body(body); - sicx.visit_body(body); -} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 46179b31d5c..47b614a81ae 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -32,14 +32,12 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; use std::fmt; -use std::mem; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; @@ -47,7 +45,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use rustc::hir::intravisit::{self, Visitor}; pub mod check_loans; @@ -62,93 +60,14 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; -impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl, - b: hir::BodyId, s: Span, id: ast::NodeId) { - match fk { - FnKind::ItemFn(..) | - FnKind::Method(..) => { - self.with_temp_region_map(id, |this| { - borrowck_fn(this, fk, fd, b, s, id, fk.attrs()) - }); - } - - FnKind::Closure(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()); - } - } - } - - fn visit_item(&mut self, item: &'tcx hir::Item) { - borrowck_item(self, item); - } - - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { - if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - gather_loans::gather_loans_in_static_initializer(self, expr); - } - intravisit::walk_trait_item(self, ti); - } - - fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { - if let hir::ImplItemKind::Const(_, expr) = ii.node { - gather_loans::gather_loans_in_static_initializer(self, expr); - } - intravisit::walk_impl_item(self, ii); - } -} - pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut bccx = BorrowckCtxt { - tcx: tcx, - free_region_map: FreeRegionMap::new(), - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } - }; - - tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); - - if tcx.sess.borrowck_stats() { - println!("--- borrowck stats ---"); - println!("paths requiring guarantees: {}", - bccx.stats.guaranteed_paths); - println!("paths requiring loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_same)); - println!("paths requiring imm loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_imm)); - println!("stable paths : {}", - make_stat(&bccx, bccx.stats.stable_paths)); - } - - fn make_stat(bccx: &BorrowckCtxt, stat: usize) -> String { - let total = bccx.stats.guaranteed_paths as f64; - let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total }; - format!("{} ({:.0}%)", stat, perc) - } -} - -fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) { - // Gather loans for items. Note that we don't need - // to check loans for single expressions. The check - // loan step is intended for things that have a data - // flow dependent conditions. - match item.node { - hir::ItemStatic(.., ex) | - hir::ItemConst(_, ex) => { - gather_loans::gather_loans_in_static_initializer(this, ex); - } - _ => { } - } - - intravisit::walk_item(this, item); + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { + borrowck_fn(tcx, body_id); + }); + }); + }); } /// Collection of conclusions determined via borrow checker analyses. @@ -158,40 +77,39 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, - fk: FnKind<'tcx>, - decl: &'tcx hir::FnDecl, - body_id: hir::BodyId, - sp: Span, - id: ast::NodeId, - attributes: &[ast::Attribute]) { - debug!("borrowck_fn(id={})", id); +fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { + debug!("borrowck_fn(body_id={:?})", body_id); - let body = this.tcx.hir.body(body_id); + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let attributes = tcx.get_attrs(owner_def_id); + let tables = tcx.item_tables(owner_def_id); - if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - this.with_temp_region_map(id, |this| { - mir::borrowck_mir(this, id, attributes) - }); + let mut bccx = &mut BorrowckCtxt { + tcx: tcx, + tables: tables, + }; + + let body = bccx.tcx.hir.body(body_id); + + if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { + mir::borrowck_mir(bccx, owner_id, &attributes); } - let cfg = cfg::CFG::new(this.tcx, &body.value); + let cfg = cfg::CFG::new(bccx.tcx, &body); let AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves } = - build_borrowck_dataflow_data(this, &cfg, body_id); + build_borrowck_dataflow_data(bccx, &cfg, body_id); move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, - this.tcx, - sp, - id); - move_data::fragments::build_unfragmented_map(this, + bccx.tcx, + owner_id); + move_data::fragments::build_unfragmented_map(bccx, &flowed_moves.move_data, - id); + owner_id); - check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); - - intravisit::walk_fn(this, fk, decl, body_id, sp, id); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, @@ -241,23 +159,20 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer. pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId, + body_id: hir::BodyId, cfg: &cfg::CFG) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) { + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let tables = tcx.item_tables(owner_def_id); let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } + tables: tables, }; - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body); + let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) } @@ -267,28 +182,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( pub struct BorrowckCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - // Hacky. As we visit various fns, we have to load up the - // free-region map for each one. This map is computed by during - // typeck for each fn item and stored -- closures just use the map - // from the fn item that encloses them. Since we walk the fns in - // order, we basically just overwrite this field as we enter a fn - // item and restore it afterwards in a stack-like fashion. Then - // the borrow checking code can assume that `free_region_map` is - // always the correct map for the current fn. Feels like it'd be - // better to just recompute this, rather than store it, but it's a - // bit of a pain to factor that code out at the moment. - free_region_map: FreeRegionMap, - - // Statistics: - stats: BorrowStats -} - -#[derive(Clone)] -struct BorrowStats { - loaned_paths_same: usize, - loaned_paths_imm: usize, - stable_paths: usize, - guaranteed_paths: usize + // tables for the current thing we are checking; set to + // Some in `borrowck_fn` and cleared later + tables: &'a ty::TypeckTables<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -574,19 +470,12 @@ pub enum MovedValueUseKind { // Misc impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { - fn with_temp_region_map(&mut self, id: ast::NodeId, f: F) - where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>) - { - let new_free_region_map = self.tcx.free_region_map(id); - let old_free_region_map = mem::replace(&mut self.free_region_map, new_free_region_map); - f(self); - self.free_region_map = old_free_region_map; - } - - pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region) + pub fn is_subregion_of(&self, + r_sub: &'tcx ty::Region, + r_sup: &'tcx ty::Region) -> bool { - self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) + self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { @@ -912,11 +801,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } mc::AliasableStatic | mc::AliasableStaticMut => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0388, - "{} in a static location", prefix); - err.span_label(span, &format!("cannot write data in a static definition")); - err + // This path cannot occur. It happens when we have an + // `&mut` or assignment to a static. But in the case + // of `static X`, we get a mutability violation first, + // and never get here. In the case of `static mut X`, + // that is unsafe and hence the aliasability error is + // ignored. + span_bug!(span, "aliasability violation for static `{}`", prefix) } mc::AliasableBorrowed => { let mut e = struct_span_err!( diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 88f739d1c74..db4a1701e97 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -287,27 +287,7 @@ https://doc.rust-lang.org/std/cell/ "##, E0388: r##" -A mutable borrow was attempted in a static location. - -Erroneous code example: - -```compile_fail,E0388 -static X: i32 = 1; - -static STATIC_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location - -const CONST_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location -``` - -To fix this error, you have to use constant borrow: - -``` -static X: i32 = 1; - -static STATIC_REF: &'static i32 = &X; -``` +E0388 was removed and is no longer issued. "##, E0389: r##" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index cf6bf1cf1d4..3dce4398f3b 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,6 +28,7 @@ #![feature(shared)] #![feature(collections_range)] #![feature(collections_bound)] +#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index e09e260afc8..2bce7faf08c 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,6 +9,7 @@ // except according to those terms. use bitvec::BitMatrix; +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; @@ -36,10 +37,10 @@ pub struct TransitiveRelation { closure: RefCell>, } -#[derive(Clone, PartialEq, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] struct Index(usize); -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] struct Edge { source: Index, target: Index, @@ -54,6 +55,10 @@ impl TransitiveRelation { } } + pub fn is_empty(&self) -> bool { + self.edges.is_empty() + } + fn index(&self, a: &T) -> Option { self.elements.iter().position(|e| *e == *a).map(Index) } @@ -305,6 +310,30 @@ fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { } } +impl Encodable for TransitiveRelation + where T: Encodable + Debug + PartialEq +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_struct("TransitiveRelation", 2, |s| { + s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?; + s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?; + Ok(()) + }) + } +} + +impl Decodable for TransitiveRelation + where T: Decodable + Debug + PartialEq +{ + fn decode(d: &mut D) -> Result { + d.read_struct("TransitiveRelation", 2, |d| { + let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; + let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?; + Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) }) + }) + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7fd4fa44ca4..9810f121ef2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,6 +24,7 @@ #![deny(warnings)] #![feature(box_syntax)] +#![feature(loop_break_value)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 064c4982ef0..b6978478085 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -718,13 +718,24 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mode: PpFlowGraphMode, mut out: W) -> io::Result<()> { - let cfg = match code { - blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), - blocks::Code::FnLike(fn_like) => { - let body = tcx.hir.body(fn_like.body()); - cfg::CFG::new(tcx, &body.value) - }, + let body_id = match code { + blocks::Code::Expr(expr) => { + // Find the function this expression is from. + let mut node_id = expr.id; + loop { + let node = tcx.hir.get(node_id); + if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { + break n.body(); + } + let parent = tcx.hir.get_parent_node(node_id); + assert!(node_id != parent); + node_id = parent; + } + } + blocks::Code::FnLike(fn_like) => fn_like.body(), }; + let body = tcx.hir.body(body_id); + let cfg = cfg::CFG::new(tcx, &body); let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { hir_map: &tcx.hir, diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index b075fa59992..8a8d2bd512b 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -1143,9 +1143,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { trait_items: _, impl_items: _, bodies: _, - trait_impls: _, trait_default_impl: _, + body_ids: _, } = *krate; visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b3f09c28277..58336f939d1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // to have behaviour like the above, rather than // e.g. accidentally recurring after an assert. - let cfg = cfg::CFG::new(cx.tcx, &body.value); + let cfg = cfg::CFG::new(cx.tcx, &body); let mut work_queue = vec![cfg.entry]; let mut reached_exit_without_self_call = false; diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index e0eb09fbf5d..a41489ff89f 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -30,7 +30,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::subst::Substs; use rustc::hir; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use syntax::abi::Abi; use syntax::ast; use syntax_pos::Span; @@ -39,9 +38,11 @@ use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir { - tcx: tcx - }.as_deep_visitor()); + tcx.dep_graph.with_task(DepNode::MirKrate, || { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_mir(body_owner_def_id); + }); + }); } pub fn provide(providers: &mut Providers) { @@ -180,23 +181,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -struct BuildMir<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> -} - -impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_nested_body(&mut self, body_id: hir::BodyId) { - self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id)); - - let body = self.tcx.hir.body(body_id); - self.visit_body(body); - } -} - fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_expr_id: ast::NodeId, body_id: hir::BodyId) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d21bb68d4c8..ec94e1f75e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -515,76 +515,13 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } -struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } - -impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } +impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx hir::Item) { check_item_type(self.tcx, i); - intravisit::walk_item(self, i); - } - - fn visit_ty(&mut self, t: &'tcx hir::Ty) { - match t.node { - hir::TyArray(_, length) => { - self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id)); - } - _ => {} - } - - intravisit::walk_ty(self, t); - } - - fn visit_expr(&mut self, e: &'tcx hir::Expr) { - match e.node { - hir::ExprRepeat(_, count) => { - self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id)); - } - _ => {} - } - - intravisit::walk_expr(self, e); - } -} - -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item) { - match item.node { - hir::ItemFn(..) => { - self.tcx.item_tables(self.tcx.hir.local_def_id(item.id)); - } - _ => { } - } - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - match trait_item.node { - hir::TraitItemKind::Const(_, Some(_)) | - hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { - self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id)); - } - hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) | - hir::TraitItemKind::Const(_, None) | - hir::TraitItemKind::Type(..) => { - // Nothing to do. - } - } - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - match impl_item.node { - hir::ImplItemKind::Const(..) | - hir::ImplItemKind::Method(..) => { - self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id)); - } - hir::ImplItemKind::Type(_) => { - // Nothing to do here. - } - } } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { } + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { } } pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { @@ -596,16 +533,18 @@ pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { tcx.sess.track_errors(|| { - let mut visit = CheckItemTypesVisitor { tcx: tcx }; tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType, - &mut visit.as_deep_visitor()); + &mut CheckItemTypesVisitor { tcx }); }) } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { tcx.sess.track_errors(|| { - let mut visit = CheckItemBodiesVisitor { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit); + tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_tables(body_owner_def_id); + }); + }); }) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e1067d299fa..8bfb390bd2a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -120,6 +120,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.visit_region_obligations(id); } rcx.resolve_regions_and_report_errors(); + + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } /// Region checking during the WF phase for items. `wf_tys` are the @@ -154,10 +157,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.resolve_regions_and_report_errors(); - // For the top-level fn, store the free-region-map. We don't store - // any map for closures; they just share the same map as the - // function that created them. - self.tcx.store_free_region_map(fn_id, rcx.free_region_map); + // In this mode, we also copy the free-region-map into the + // tables of the enclosing fcx. In the other regionck modes + // (e.g., `regionck_item`), we don't have an enclosing tables. + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 1382ab34ca5..7fffbd14e21 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -50,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_type_nodes(); wbcx.visit_cast_types(); wbcx.visit_lints(); + wbcx.visit_free_region_map(); let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, DefIdSet()); @@ -274,6 +275,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); } + fn visit_free_region_map(&mut self) { + self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone(); + } + fn visit_anon_types(&mut self) { let gcx = self.tcx().global_tcx(); for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7f413a0dfc3..1f622235af4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1147,6 +1147,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) { NodeTy(&hir::Ty { node: TyArray(_, body), .. }) | + NodeTy(&hir::Ty { node: TyTypeof(body), .. }) | NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. }) if body.node_id == node_id => tcx.types.usize, diff --git a/src/test/compile-fail/E0017.rs b/src/test/compile-fail/E0017.rs index 44d2f158d20..c6bec6090f2 100644 --- a/src/test/compile-fail/E0017.rs +++ b/src/test/compile-fail/E0017.rs @@ -19,8 +19,7 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 //~| NOTE statics require immutable values - //~| ERROR E0388 - //~| NOTE cannot write data in a static definition + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 diff --git a/src/test/compile-fail/E0388.rs b/src/test/compile-fail/E0388.rs index 13f2c23d8c4..2c88039d373 100644 --- a/src/test/compile-fail/E0388.rs +++ b/src/test/compile-fail/E0388.rs @@ -15,7 +15,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR E0017 - //~| ERROR E0388 + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs new file mode 100644 index 00000000000..3c1980e5b36 --- /dev/null +++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs @@ -0,0 +1,28 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #38520. Check that moves of `Foo` are not +// permitted as `Foo` is not copy (even in a static/const +// initializer). + +#![feature(const_fn)] + +struct Foo(usize); + +const fn get(x: Foo) -> usize { + x.0 +} + +const X: Foo = Foo(22); +static Y: usize = get(*&X); //~ ERROR E0507 +const Z: usize = get(*&X); //~ ERROR E0507 + +fn main() { +} diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs index 3afb34f037b..35e57dffb6c 100644 --- a/src/test/compile-fail/issue-18118.rs +++ b/src/test/compile-fail/issue-18118.rs @@ -13,6 +13,6 @@ pub fn main() { //~^ ERROR blocks in constants are limited to items and tail expressions let p = 3; //~^ ERROR blocks in constants are limited to items and tail expressions - &p + &p //~ ERROR `p` does not live long enough }; } diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index e4ed0622147..01364c07144 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -1,11 +1,3 @@ -error: cannot borrow immutable borrowed content `*a` as mutable - --> $DIR/mut-arg-hint.rs:18:5 - | -17 | pub fn foo<'a>(mut a: &'a String) { - | ---------- use `&'a mut String` here to make mutable -18 | a.push_str("foo"); - | ^ cannot borrow as mutable - error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:13:9 | @@ -14,6 +6,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable 13 | a.push_str("bar"); | ^ cannot borrow as mutable +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:18:5 + | +17 | pub fn foo<'a>(mut a: &'a String) { + | ---------- use `&'a mut String` here to make mutable +18 | a.push_str("foo"); + | ^ cannot borrow as mutable + error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:25:9 |