From b3a482ca9b1622a2fd04d8338ac99f5df802b9e2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Feb 2017 12:46:44 -0500 Subject: [PATCH 01/16] move the `FreeRegionMap` into `TypeckTables` --- src/librustc/middle/free_region.rs | 6 ++- src/librustc/ty/context.rs | 24 +++------ src/librustc_borrowck/borrowck/mod.rs | 51 +++++++------------ src/librustc_data_structures/lib.rs | 1 + .../transitive_relation.rs | 33 +++++++++++- src/librustc_typeck/check/regionck.rs | 12 +++-- src/librustc_typeck/check/writeback.rs | 5 ++ 7 files changed, 75 insertions(+), 57 deletions(-) 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_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 46179b31d5c..06133de0757 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; @@ -72,9 +70,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - self.with_temp_region_map(id, |this| { - borrowck_fn(this, fk, fd, b, s, id, fk.attrs()) - }); + borrowck_fn(self, fk, fd, b, s, id, fk.attrs()) } FnKind::Closure(..) => { @@ -105,7 +101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), + tables: None, stats: BorrowStats { loaned_paths_same: 0, loaned_paths_imm: 0, @@ -167,12 +163,15 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, attributes: &[ast::Attribute]) { debug!("borrowck_fn(id={})", id); + assert!(this.tables.is_none()); + let owner_def_id = this.tcx.hir.local_def_id(this.tcx.hir.body_owner(body_id)); + let tables = this.tcx.item_tables(owner_def_id); + this.tables = Some(tables); + let body = this.tcx.hir.body(body_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) - }); + mir::borrowck_mir(this, id, attributes); } let cfg = cfg::CFG::new(this.tcx, &body.value); @@ -191,6 +190,8 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); + this.tables = None; + intravisit::walk_fn(this, fk, decl, body_id, sp, id); } @@ -248,7 +249,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), + tables: None, stats: BorrowStats { loaned_paths_same: 0, loaned_paths_imm: 0, @@ -267,17 +268,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, + // tables for the current thing we are checking; set to + // Some in `borrowck_fn` and cleared later + tables: Option<&'a ty::TypeckTables<'tcx>>, // Statistics: stats: BorrowStats @@ -574,19 +567,13 @@ 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.unwrap().free_region_map + .is_subregion_of(self.tcx, r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { 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_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() { From d885e4ce9d21c3283a46803a01c5a23d8d10f556 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 15 Feb 2017 05:17:30 -0500 Subject: [PATCH 02/16] add `visit_all_bodies_in_krate` helper --- src/librustc/dep_graph/mod.rs | 1 + src/librustc/dep_graph/visit.rs | 10 ++++++++++ src/librustc/ty/mod.rs | 11 +++++++++++ 3 files changed, 22 insertions(+) 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..f807437750d 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.bodies.keys().cloned() { + 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/ty/mod.rs b/src/librustc/ty/mod.rs index 55b6f61148d..328d5c234e1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2613,6 +2613,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 { From 03e8b26f35c737138f75ebd33b44784ea0a8dc9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:23:25 -0500 Subject: [PATCH 03/16] rewrite `borrowck_fn` to only use the body-id --- src/librustc_borrowck/borrowck/fragments.rs | 5 ++-- src/librustc_borrowck/borrowck/mod.rs | 31 +++++++++------------ 2 files changed, 16 insertions(+), 20 deletions(-) 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/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 06133de0757..07e654c3880 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -70,11 +70,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()) + borrowck_fn(self, b); + intravisit::walk_fn(self, fk, fd, b, s, id); } FnKind::Closure(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()); + borrowck_fn(self, b); + intravisit::walk_fn(self, fk, fd, b, s, id); } } } @@ -154,24 +156,20 @@ 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>(this: &mut BorrowckCtxt<'a, 'tcx>, body_id: hir::BodyId) { + debug!("borrowck_fn(body_id={:?})", body_id); assert!(this.tables.is_none()); - let owner_def_id = this.tcx.hir.local_def_id(this.tcx.hir.body_owner(body_id)); + let owner_id = this.tcx.hir.body_owner(body_id); + let owner_def_id = this.tcx.hir.local_def_id(owner_id); + let attributes = this.tcx.get_attrs(owner_def_id); let tables = this.tcx.item_tables(owner_def_id); this.tables = Some(tables); let body = this.tcx.hir.body(body_id); - if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - mir::borrowck_mir(this, id, attributes); + if this.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { + mir::borrowck_mir(this, owner_id, &attributes); } let cfg = cfg::CFG::new(this.tcx, &body.value); @@ -182,17 +180,14 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, this.tcx, - sp, - id); + owner_id); move_data::fragments::build_unfragmented_map(this, &flowed_moves.move_data, - id); + owner_id); check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); this.tables = None; - - intravisit::walk_fn(this, fk, decl, body_id, sp, id); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, From 530b92cfdd415d553050f2f64c5d8ad66f8c4b54 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:47:01 -0500 Subject: [PATCH 04/16] remove the borrowck stats --- src/librustc_borrowck/borrowck/mod.rs | 41 --------------------------- 1 file changed, 41 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 07e654c3880..2011cbe416f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -104,33 +104,9 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut bccx = BorrowckCtxt { tcx: tcx, tables: None, - 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) { @@ -245,12 +221,6 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let mut bccx = BorrowckCtxt { tcx: tcx, tables: None, - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body); @@ -266,17 +236,6 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later tables: Option<&'a ty::TypeckTables<'tcx>>, - - // Statistics: - stats: BorrowStats -} - -#[derive(Clone)] -struct BorrowStats { - loaned_paths_same: usize, - loaned_paths_imm: usize, - stable_paths: usize, - guaranteed_paths: usize } /////////////////////////////////////////////////////////////////////////// From a9ec8841ef02ceb3278e6bedd98821bec332fd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 05:59:48 -0500 Subject: [PATCH 05/16] make `borrowck_fn` and friends create `bccx` --- .../borrowck/gather_loans/mod.rs | 8 +- src/librustc_borrowck/borrowck/mod.rs | 73 +++++++++---------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 1783ca74a25..b31b54a2541 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -547,9 +547,15 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> { } } -pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) { +pub fn gather_loans_in_static_initializer<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + body: hir::BodyId) { debug!("gather_loans_in_static_initializer(expr={:?})", body); + let bccx = &BorrowckCtxt { + tcx: tcx, + tables: None + }; + let mut sicx = StaticInitializerCtxt { bccx: bccx, body_id: body diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2011cbe416f..9c29cd375ff 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -70,31 +70,43 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { - borrowck_fn(self, b); + borrowck_fn(self.tcx, b); intravisit::walk_fn(self, fk, fd, b, s, id); } FnKind::Closure(..) => { - borrowck_fn(self, b); + borrowck_fn(self.tcx, b); intravisit::walk_fn(self, fk, fd, b, s, id); } } } fn visit_item(&mut self, item: &'tcx hir::Item) { - borrowck_item(self, 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(self.tcx, ex); + } + _ => { } + } + + intravisit::walk_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); + gather_loans::gather_loans_in_static_initializer(self.tcx, 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); + gather_loans::gather_loans_in_static_initializer(self.tcx, expr); } intravisit::walk_impl_item(self, ii); } @@ -109,22 +121,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); } -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); -} - /// Collection of conclusions determined via borrow checker analyses. pub struct AnalysisData<'a, 'tcx: 'a> { pub all_loans: Vec>, @@ -132,38 +128,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>, body_id: hir::BodyId) { +fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { debug!("borrowck_fn(body_id={:?})", body_id); - assert!(this.tables.is_none()); - let owner_id = this.tcx.hir.body_owner(body_id); - let owner_def_id = this.tcx.hir.local_def_id(owner_id); - let attributes = this.tcx.get_attrs(owner_def_id); - let tables = this.tcx.item_tables(owner_def_id); - this.tables = Some(tables); + 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); - let body = this.tcx.hir.body(body_id); + let mut bccx = &mut BorrowckCtxt { + tcx: tcx, + tables: Some(tables), + }; - if this.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { - mir::borrowck_mir(this, owner_id, &attributes); + 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.value); 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, + bccx.tcx, owner_id); - move_data::fragments::build_unfragmented_map(this, + move_data::fragments::build_unfragmented_map(bccx, &flowed_moves.move_data, owner_id); - check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); - - this.tables = None; + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, From 085d71c3efe453863739c1fb68fd9bd1beff214f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 06:52:16 -0500 Subject: [PATCH 06/16] remove special-case code for statics and just use `borrowck_fn` Fixes #38520 --- src/librustc/cfg/construct.rs | 20 +++---- src/librustc/cfg/mod.rs | 2 +- .../borrowck/gather_loans/mod.rs | 53 ------------------- src/librustc_borrowck/borrowck/mod.rs | 8 +-- src/librustc_driver/lib.rs | 1 + src/librustc_driver/pretty.rs | 23 +++++--- src/librustc_lint/builtin.rs | 2 +- src/test/compile-fail/E0017.rs | 3 +- src/test/compile-fail/E0388.rs | 2 +- .../move-in-static-initializer-issue-38520.rs | 28 ++++++++++ src/test/compile-fail/issue-18118.rs | 2 +- 11 files changed, 61 insertions(+), 83 deletions(-) create mode 100644 src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs 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_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index b31b54a2541..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,53 +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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId) { - debug!("gather_loans_in_static_initializer(expr={:?})", body); - - let bccx = &BorrowckCtxt { - tcx: tcx, - tables: None - }; - - 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 9c29cd375ff..613f28138a5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -89,7 +89,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { match item.node { hir::ItemStatic(.., ex) | hir::ItemConst(_, ex) => { - gather_loans::gather_loans_in_static_initializer(self.tcx, ex); + borrowck_fn(self.tcx, ex); } _ => { } } @@ -99,14 +99,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { 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.tcx, expr); + borrowck_fn(self.tcx, 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.tcx, expr); + borrowck_fn(self.tcx, expr); } intravisit::walk_impl_item(self, ii); } @@ -147,7 +147,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { mir::borrowck_mir(bccx, owner_id, &attributes); } - let cfg = cfg::CFG::new(bccx.tcx, &body.value); + let cfg = cfg::CFG::new(bccx.tcx, &body); let AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves } = 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_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/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 }; } From cc2e4cd7e33d195a8ba8ea334d4baa291a438a56 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 07:07:02 -0500 Subject: [PATCH 07/16] use `visit_all_bodies_in_krate` for borrowck instead of item-likes --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc_borrowck/borrowck/mod.rs | 67 ++++----------------------- 2 files changed, 10 insertions(+), 59 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e0233d6f8b9..bb8f4b75282 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -91,6 +91,7 @@ pub enum DepNode { // things read/modify that MIR. Mir(D), + BorrowCheckKrate, BorrowCheck(D), RvalueCheck(D), Reachability, @@ -209,6 +210,7 @@ impl DepNode { match *self { Krate => Some(Krate), + BorrowCheckKrate => Some(BorrowCheckKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 613f28138a5..f0381dd1b70 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -45,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; @@ -60,65 +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(..) => { - borrowck_fn(self.tcx, b); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - - FnKind::Closure(..) => { - borrowck_fn(self.tcx, b); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - } - } - - fn visit_item(&mut self, 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) => { - borrowck_fn(self.tcx, ex); - } - _ => { } - } - - intravisit::walk_item(self, item); - } - - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { - if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - borrowck_fn(self.tcx, 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 { - borrowck_fn(self.tcx, expr); - } - intravisit::walk_impl_item(self, ii); - } -} - pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut bccx = BorrowckCtxt { - tcx: tcx, - tables: None, - }; - - tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); + 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. From 3e9bddad7bcd2b1bb4e5d534c271c6005739ab9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Feb 2017 07:12:21 -0500 Subject: [PATCH 08/16] remove `Option` from the `tables` field --- src/librustc_borrowck/borrowck/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f0381dd1b70..f5d6780213b 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -87,7 +87,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { let mut bccx = &mut BorrowckCtxt { tcx: tcx, - tables: Some(tables), + tables: tables, }; let body = bccx.tcx.hir.body(body_id); @@ -159,17 +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, - tables: None, + 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) } @@ -181,7 +184,7 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later - tables: Option<&'a ty::TypeckTables<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -472,8 +475,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { r_sup: &'tcx ty::Region) -> bool { - self.tables.unwrap().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>) { From d79ad36cf5c8f11e37001a090abae5ff94fbab1b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Feb 2017 21:18:16 -0500 Subject: [PATCH 09/16] walk the bodies "in order" by traversing the crate Otherwise the errors from borrowck come out in an unpredictable order. --- src/librustc/dep_graph/visit.rs | 28 ++++++++++++++++++++++++--- src/librustc/hir/map/mod.rs | 29 ++++++++++++++++------------ src/test/ui/span/mut-arg-hint.stderr | 16 +++++++-------- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index f807437750d..0d10049bc1e 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -11,6 +11,7 @@ use hir; use hir::def_id::DefId; use hir::itemlikevisit::ItemLikeVisitor; +use hir::intravisit::{self, NestedVisitorMap, Visitor}; use ty::TyCtxt; use super::dep_node::DepNode; @@ -78,9 +79,30 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> 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), { + // NB: we use a visitor here rather than walking the keys of the + // hashmap so as to ensure we visit the bodies "in order". + let krate = tcx.hir.krate(); - for body_id in krate.bodies.keys().cloned() { - let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); - callback(body_owner_def_id, body_id); + intravisit::walk_crate(&mut V { tcx, callback }, krate); + + struct V<'a, 'tcx: 'a, C> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + callback: C + } + + impl<'a, 'tcx, C> Visitor<'tcx> for V<'a, 'tcx, C> + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.tcx.hir) + } + + fn visit_body(&mut self, body: &'tcx hir::Body) { + let body_id = body.id(); + let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); + (self.callback)(body_owner_def_id, body_id); + + intravisit::walk_body(self, body); + } } } 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/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 | From 2b5c0267b45edaefa19427b70a7381782b6330fc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 10:35:16 -0500 Subject: [PATCH 10/16] kill the code path for E0388 This was specific to the old special-case handling of statics in borrowck. --- src/librustc_borrowck/borrowck/mod.rs | 12 +++++++----- src/librustc_borrowck/diagnostics.rs | 22 +--------------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f5d6780213b..47b614a81ae 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -801,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##" From 1bb1e16e920567f92f6d7ac147c1b51db5b686ec Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 10:55:40 -0500 Subject: [PATCH 11/16] switch bodies to a btreemap --- src/librustc/hir/lowering.rs | 6 +++--- src/librustc/hir/mod.rs | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 468421a68b5..9f55e039d3b 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(), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 8b6c75886ba..56d381efa92 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,8 +409,7 @@ 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, } From fab202c0a82ea14e6fa4cde9080c789732f1213b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Feb 2017 12:23:47 -0500 Subject: [PATCH 12/16] store the visit order in the Crate --- src/librustc/dep_graph/visit.rs | 28 ++----------------- src/librustc/hir/lowering.rs | 10 +++++++ src/librustc/hir/mod.rs | 6 ++++ .../calculate_svh/svh_visitor.rs | 2 +- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 0d10049bc1e..a34a3591c15 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -11,7 +11,6 @@ use hir; use hir::def_id::DefId; use hir::itemlikevisit::ItemLikeVisitor; -use hir::intravisit::{self, NestedVisitorMap, Visitor}; use ty::TyCtxt; use super::dep_node::DepNode; @@ -79,30 +78,9 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> 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), { - // NB: we use a visitor here rather than walking the keys of the - // hashmap so as to ensure we visit the bodies "in order". - let krate = tcx.hir.krate(); - intravisit::walk_crate(&mut V { tcx, callback }, krate); - - struct V<'a, 'tcx: 'a, C> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - callback: C - } - - impl<'a, 'tcx, C> Visitor<'tcx> for V<'a, 'tcx, C> - where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), - { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.tcx.hir) - } - - fn visit_body(&mut self, body: &'tcx hir::Body) { - let body_id = body.id(); - let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); - (self.callback)(body_owner_def_id, body_id); - - intravisit::walk_body(self, body); - } + 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 9f55e039d3b..257cdb960d5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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/mod.rs b/src/librustc/hir/mod.rs index 56d381efa92..c1ba688974b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -412,6 +412,12 @@ pub struct Crate { 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_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 150a2c39db7..041e966fa73 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -1167,9 +1167,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); From a780fa3f67dc6d1f4a450b4f367727a7e87a7867 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 28 Feb 2017 09:44:34 -0500 Subject: [PATCH 13/16] rewrite typeck bodies to iterate over the bodies vector --- src/librustc/dep_graph/dep_node.rs | 2 ++ src/librustc_typeck/check/mod.rs | 46 ++++-------------------------- 2 files changed, 7 insertions(+), 41 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index bb8f4b75282..2e7bac67c5f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -115,6 +115,7 @@ pub enum DepNode { SizedConstraint(D), AssociatedItemDefIds(D), InherentImpls(D), + TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), MonomorphicConstEval(D), @@ -211,6 +212,7 @@ impl DepNode { match *self { Krate => Some(Krate), BorrowCheckKrate => Some(BorrowCheckKrate), + TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0337727dcba..3c2b44653e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -118,7 +118,6 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; @@ -515,7 +514,6 @@ 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> { @@ -550,43 +548,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { } } -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. - } - } - } -} - pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { tcx.sess.track_errors(|| { let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); @@ -604,8 +565,11 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult 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); + }); + }); }) } From 384f044d826f68827802ce6f255a09282e437a09 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 28 Feb 2017 12:32:54 -0500 Subject: [PATCH 14/16] convert MIR to iterate over the bodies vector --- src/librustc/dep_graph/dep_node.rs | 2 ++ src/librustc_mir/mir_map.rs | 26 +++++--------------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 2e7bac67c5f..2777c4d2487 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -89,6 +89,7 @@ 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, @@ -212,6 +213,7 @@ impl DepNode { match *self { Krate => Some(Krate), BorrowCheckKrate => Some(BorrowCheckKrate), + MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), 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) From f704ef5ff763f090f3ab98a65c160c830f660302 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 28 Feb 2017 16:08:01 -0500 Subject: [PATCH 15/16] simplify check-item-types too --- src/librustc_typeck/check/mod.rs | 35 +++++--------------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3c2b44653e0..9fa9b1bc552 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -118,6 +118,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; @@ -515,37 +516,12 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { struct CheckItemTypesVisitor<'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); } + 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 { @@ -557,9 +533,8 @@ 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 }); }) } From d572aa2fd4012698097efa00db6331197f3e44ac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 Mar 2017 17:04:01 -0500 Subject: [PATCH 16/16] fix tests to handle the Typeof bodies --- src/librustc/hir/map/def_collector.rs | 1 + src/librustc/hir/map/definitions.rs | 8 ++++++-- src/librustc/ty/item_path.rs | 3 ++- src/librustc_typeck/collect.rs | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) 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/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_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,