Auto merge of #39927 - nikomatsakis:incr-comp-skip-borrowck-2, r=eddyb
transition borrowck to visit all **bodies** and not item-likes This is a better structure for incremental compilation and also more compatible with the eventual borrowck mir. It also fixes #38520 as a drive-by fix. r? @eddyb
This commit is contained in:
commit
06c63f6e9e
@ -32,7 +32,7 @@ struct LoopScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
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 mut graph = graph::Graph::new();
|
||||||
let entry = graph.add_node(CFGNodeData::Entry);
|
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 fn_exit = graph.add_node(CFGNodeData::Exit);
|
||||||
let body_exit;
|
let body_exit;
|
||||||
|
|
||||||
// Find the function this expression is from.
|
// Find the tables for this body.
|
||||||
let mut node_id = body.id;
|
let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id()));
|
||||||
loop {
|
let tables = tcx.item_tables(owner_def_id);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cfg_builder = CFGBuilder {
|
let mut cfg_builder = CFGBuilder {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
tables: tcx.item_tables(tcx.hir.local_def_id(node_id)),
|
tables: tables,
|
||||||
graph: graph,
|
graph: graph,
|
||||||
fn_exit: fn_exit,
|
fn_exit: fn_exit,
|
||||||
loop_scopes: Vec::new()
|
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);
|
cfg_builder.add_contained_edge(body_exit, fn_exit);
|
||||||
let CFGBuilder {graph, ..} = cfg_builder;
|
let CFGBuilder {graph, ..} = cfg_builder;
|
||||||
CFG {graph: graph,
|
CFG {graph: graph,
|
||||||
|
@ -59,7 +59,7 @@ pub type CFGEdge = graph::Edge<CFGEdgeData>;
|
|||||||
|
|
||||||
impl CFG {
|
impl CFG {
|
||||||
pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
body: &hir::Expr) -> CFG {
|
body: &hir::Body) -> CFG {
|
||||||
construct::construct(tcx, body)
|
construct::construct(tcx, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,10 @@ pub enum DepNode<D: Clone + Debug> {
|
|||||||
|
|
||||||
// Represents the MIR for a fn; also used as the task node for
|
// Represents the MIR for a fn; also used as the task node for
|
||||||
// things read/modify that MIR.
|
// things read/modify that MIR.
|
||||||
|
MirKrate,
|
||||||
Mir(D),
|
Mir(D),
|
||||||
|
|
||||||
|
BorrowCheckKrate,
|
||||||
BorrowCheck(D),
|
BorrowCheck(D),
|
||||||
RvalueCheck(D),
|
RvalueCheck(D),
|
||||||
Reachability,
|
Reachability,
|
||||||
@ -114,6 +116,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||||||
SizedConstraint(D),
|
SizedConstraint(D),
|
||||||
AssociatedItemDefIds(D),
|
AssociatedItemDefIds(D),
|
||||||
InherentImpls(D),
|
InherentImpls(D),
|
||||||
|
TypeckBodiesKrate,
|
||||||
TypeckTables(D),
|
TypeckTables(D),
|
||||||
UsedTraitImports(D),
|
UsedTraitImports(D),
|
||||||
MonomorphicConstEval(D),
|
MonomorphicConstEval(D),
|
||||||
@ -209,6 +212,9 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Krate => Some(Krate),
|
Krate => Some(Krate),
|
||||||
|
BorrowCheckKrate => Some(BorrowCheckKrate),
|
||||||
|
MirKrate => Some(MirKrate),
|
||||||
|
TypeckBodiesKrate => Some(TypeckBodiesKrate),
|
||||||
CollectLanguageItems => Some(CollectLanguageItems),
|
CollectLanguageItems => Some(CollectLanguageItems),
|
||||||
CheckStaticRecursion => Some(CheckStaticRecursion),
|
CheckStaticRecursion => Some(CheckStaticRecursion),
|
||||||
ResolveLifetimes => Some(ResolveLifetimes),
|
ResolveLifetimes => Some(ResolveLifetimes),
|
||||||
|
@ -25,5 +25,6 @@ pub use self::dep_node::WorkProductId;
|
|||||||
pub use self::graph::DepGraph;
|
pub use self::graph::DepGraph;
|
||||||
pub use self::graph::WorkProduct;
|
pub use self::graph::WorkProduct;
|
||||||
pub use self::query::DepGraphQuery;
|
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::visit::visit_all_item_likes_in_krate;
|
||||||
pub use self::raii::DepTask;
|
pub use self::raii::DepTask;
|
||||||
|
@ -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)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,7 +46,7 @@ use hir::map::definitions::DefPathData;
|
|||||||
use hir::def_id::{DefIndex, DefId};
|
use hir::def_id::{DefIndex, DefId};
|
||||||
use hir::def::{Def, PathResolution};
|
use hir::def::{Def, PathResolution};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use util::nodemap::{DefIdMap, NodeMap, FxHashMap};
|
use util::nodemap::{DefIdMap, NodeMap};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@ -78,7 +78,7 @@ pub struct LoweringContext<'a> {
|
|||||||
|
|
||||||
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
|
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
|
||||||
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
||||||
bodies: FxHashMap<hir::BodyId, hir::Body>,
|
bodies: BTreeMap<hir::BodyId, hir::Body>,
|
||||||
|
|
||||||
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||||
trait_default_impl: BTreeMap<DefId, NodeId>,
|
trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||||
@ -118,7 +118,7 @@ pub fn lower_crate(sess: &Session,
|
|||||||
items: BTreeMap::new(),
|
items: BTreeMap::new(),
|
||||||
trait_items: BTreeMap::new(),
|
trait_items: BTreeMap::new(),
|
||||||
impl_items: BTreeMap::new(),
|
impl_items: BTreeMap::new(),
|
||||||
bodies: FxHashMap(),
|
bodies: BTreeMap::new(),
|
||||||
trait_impls: BTreeMap::new(),
|
trait_impls: BTreeMap::new(),
|
||||||
trait_default_impl: BTreeMap::new(),
|
trait_default_impl: BTreeMap::new(),
|
||||||
loop_scopes: Vec::new(),
|
loop_scopes: Vec::new(),
|
||||||
@ -196,6 +196,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let module = self.lower_mod(&c.module);
|
let module = self.lower_mod(&c.module);
|
||||||
let attrs = self.lower_attrs(&c.attrs);
|
let attrs = self.lower_attrs(&c.attrs);
|
||||||
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
|
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
|
||||||
|
let body_ids = body_ids(&self.bodies);
|
||||||
|
|
||||||
hir::Crate {
|
hir::Crate {
|
||||||
module: module,
|
module: module,
|
||||||
@ -206,6 +207,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
trait_items: self.trait_items,
|
trait_items: self.trait_items,
|
||||||
impl_items: self.impl_items,
|
impl_items: self.impl_items,
|
||||||
bodies: self.bodies,
|
bodies: self.bodies,
|
||||||
|
body_ids: body_ids,
|
||||||
trait_impls: self.trait_impls,
|
trait_impls: self.trait_impls,
|
||||||
trait_default_impl: self.trait_default_impl,
|
trait_default_impl: self.trait_default_impl,
|
||||||
}
|
}
|
||||||
@ -2524,3 +2526,11 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
@ -259,6 +259,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||||||
TyKind::ImplTrait(..) => {
|
TyKind::ImplTrait(..) => {
|
||||||
self.create_def(ty.id, DefPathData::ImplTrait);
|
self.create_def(ty.id, DefPathData::ImplTrait);
|
||||||
}
|
}
|
||||||
|
TyKind::Typeof(ref expr) => self.visit_ast_const_integer(expr),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_ty(self, ty);
|
visit::walk_ty(self, ty);
|
||||||
|
@ -260,7 +260,9 @@ pub enum DefPathData {
|
|||||||
/// Pattern binding
|
/// Pattern binding
|
||||||
Binding(InternedString),
|
Binding(InternedString),
|
||||||
/// An `impl Trait` type node.
|
/// An `impl Trait` type node.
|
||||||
ImplTrait
|
ImplTrait,
|
||||||
|
/// A `typeof` type node.
|
||||||
|
Typeof,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Definitions {
|
impl Definitions {
|
||||||
@ -387,7 +389,8 @@ impl DefPathData {
|
|||||||
ClosureExpr |
|
ClosureExpr |
|
||||||
StructCtor |
|
StructCtor |
|
||||||
Initializer |
|
Initializer |
|
||||||
ImplTrait => None
|
ImplTrait |
|
||||||
|
Typeof => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,6 +418,7 @@ impl DefPathData {
|
|||||||
StructCtor => "{{constructor}}",
|
StructCtor => "{{constructor}}",
|
||||||
Initializer => "{{initializer}}",
|
Initializer => "{{initializer}}",
|
||||||
ImplTrait => "{{impl-Trait}}",
|
ImplTrait => "{{impl-Trait}}",
|
||||||
|
Typeof => "{{typeof}}",
|
||||||
};
|
};
|
||||||
|
|
||||||
Symbol::intern(s).as_str()
|
Symbol::intern(s).as_str()
|
||||||
|
@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_body_owner(self, node_id: NodeId) -> bool {
|
fn associated_body(self) -> Option<BodyId> {
|
||||||
match self {
|
match self {
|
||||||
EntryItem(_, item) => {
|
EntryItem(_, item) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
ItemConst(_, body) |
|
ItemConst(_, body) |
|
||||||
ItemStatic(.., body) |
|
ItemStatic(.., body) |
|
||||||
ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
|
ItemFn(_, _, _, _, _, body) => Some(body),
|
||||||
_ => false
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryTraitItem(_, item) => {
|
EntryTraitItem(_, item) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
TraitItemKind::Const(_, Some(body)) |
|
TraitItemKind::Const(_, Some(body)) |
|
||||||
TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
|
TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body),
|
||||||
body.node_id == node_id
|
_ => None
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryImplItem(_, item) => {
|
EntryImplItem(_, item) => {
|
||||||
match item.node {
|
match item.node {
|
||||||
ImplItemKind::Const(_, body) |
|
ImplItemKind::Const(_, body) |
|
||||||
ImplItemKind::Method(_, body) => body.node_id == node_id,
|
ImplItemKind::Method(_, body) => Some(body),
|
||||||
_ => false
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryExpr(_, expr) => {
|
EntryExpr(_, expr) => {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ExprClosure(.., body, _) => body.node_id == node_id,
|
ExprClosure(.., body, _) => Some(body),
|
||||||
_ => false
|
_ => 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ pub use self::PathParameters::*;
|
|||||||
|
|
||||||
use hir::def::Def;
|
use hir::def::Def;
|
||||||
use hir::def_id::DefId;
|
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_pos::{Span, ExpnId, DUMMY_SP};
|
||||||
use syntax::codemap::{self, Spanned};
|
use syntax::codemap::{self, Spanned};
|
||||||
@ -409,10 +409,15 @@ pub struct Crate {
|
|||||||
|
|
||||||
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
|
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
|
||||||
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
|
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
|
||||||
pub bodies: FxHashMap<BodyId, Body>,
|
pub bodies: BTreeMap<BodyId, Body>,
|
||||||
|
|
||||||
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||||
pub trait_default_impl: BTreeMap<DefId, NodeId>,
|
pub trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||||
|
|
||||||
|
/// 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<BodyId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Crate {
|
impl Crate {
|
||||||
|
@ -19,7 +19,7 @@ use ty::{self, TyCtxt, FreeRegion, Region};
|
|||||||
use ty::wf::ImpliedBound;
|
use ty::wf::ImpliedBound;
|
||||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||||
pub struct FreeRegionMap {
|
pub struct FreeRegionMap {
|
||||||
// Stores the relation `a < b`, where `a` and `b` are regions.
|
// Stores the relation `a < b`, where `a` and `b` are regions.
|
||||||
relation: TransitiveRelation<Region>
|
relation: TransitiveRelation<Region>
|
||||||
@ -30,6 +30,10 @@ impl FreeRegionMap {
|
|||||||
FreeRegionMap { relation: TransitiveRelation::new() }
|
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,
|
pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
|
||||||
implied_bounds: &[ImpliedBound<'tcx>])
|
implied_bounds: &[ImpliedBound<'tcx>])
|
||||||
{
|
{
|
||||||
|
@ -248,6 +248,11 @@ pub struct TypeckTables<'tcx> {
|
|||||||
/// If any errors occurred while type-checking this body,
|
/// If any errors occurred while type-checking this body,
|
||||||
/// this field will be set to `true`.
|
/// this field will be set to `true`.
|
||||||
pub tainted_by_errors: bool,
|
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> {
|
impl<'tcx> TypeckTables<'tcx> {
|
||||||
@ -267,6 +272,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
|||||||
lints: lint::LintTable::new(),
|
lints: lint::LintTable::new(),
|
||||||
used_trait_imports: DefIdSet(),
|
used_trait_imports: DefIdSet(),
|
||||||
tainted_by_errors: false,
|
tainted_by_errors: false,
|
||||||
|
free_region_map: FreeRegionMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,13 +420,6 @@ pub struct GlobalCtxt<'tcx> {
|
|||||||
|
|
||||||
pub region_maps: RegionMaps,
|
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<NodeMap<FreeRegionMap>>,
|
|
||||||
|
|
||||||
pub hir: hir_map::Map<'tcx>,
|
pub hir: hir_map::Map<'tcx>,
|
||||||
pub maps: maps::Maps<'tcx>,
|
pub maps: maps::Maps<'tcx>,
|
||||||
|
|
||||||
@ -645,16 +644,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
interned
|
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<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
|
pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
|
||||||
value.lift_to_tcx(self)
|
value.lift_to_tcx(self)
|
||||||
}
|
}
|
||||||
@ -707,7 +696,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
types: common_types,
|
types: common_types,
|
||||||
named_region_map: named_region_map,
|
named_region_map: named_region_map,
|
||||||
region_maps: region_maps,
|
region_maps: region_maps,
|
||||||
free_region_maps: RefCell::new(FxHashMap()),
|
|
||||||
variance_computed: Cell::new(false),
|
variance_computed: Cell::new(false),
|
||||||
trait_map: resolutions.trait_map,
|
trait_map: resolutions.trait_map,
|
||||||
fulfilled_predicates: RefCell::new(fulfilled_predicates),
|
fulfilled_predicates: RefCell::new(fulfilled_predicates),
|
||||||
|
@ -180,7 +180,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
data @ DefPathData::MacroDef(..) |
|
data @ DefPathData::MacroDef(..) |
|
||||||
data @ DefPathData::ClosureExpr |
|
data @ DefPathData::ClosureExpr |
|
||||||
data @ DefPathData::Binding(..) |
|
data @ DefPathData::Binding(..) |
|
||||||
data @ DefPathData::ImplTrait => {
|
data @ DefPathData::ImplTrait |
|
||||||
|
data @ DefPathData::Typeof => {
|
||||||
let parent_def_id = self.parent_def_id(def_id).unwrap();
|
let parent_def_id = self.parent_def_id(def_id).unwrap();
|
||||||
self.push_item_path(buffer, parent_def_id);
|
self.push_item_path(buffer, parent_def_id);
|
||||||
buffer.push(&data.as_interned_str());
|
buffer.push(&data.as_interned_str());
|
||||||
|
@ -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);
|
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<C>(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`
|
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
|
||||||
/// with the name of the crate containing the impl.
|
/// with the name of the crate containing the impl.
|
||||||
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
|
pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
|
||||||
|
@ -27,7 +27,7 @@ use rustc::middle::mem_categorization as mc;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum Fragment {
|
enum Fragment {
|
||||||
@ -200,7 +200,6 @@ impl FragmentSets {
|
|||||||
|
|
||||||
pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>,
|
pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
sp: Span,
|
|
||||||
id: ast::NodeId) {
|
id: ast::NodeId) {
|
||||||
let span_err = tcx.hir.attrs(id).iter()
|
let span_err = tcx.hir.attrs(id).iter()
|
||||||
.any(|a| a.check_name("rustc_move_fragments"));
|
.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; }
|
if !span_err && !print { return; }
|
||||||
|
|
||||||
|
let sp = tcx.hir.span(id);
|
||||||
|
|
||||||
let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
|
let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
|
||||||
for (i, mpi) in vec_rc.iter().enumerate() {
|
for (i, mpi) in vec_rc.iter().enumerate() {
|
||||||
let lp = || this.path_loan_path(*mpi);
|
let lp = || this.path_loan_path(*mpi);
|
||||||
|
@ -28,9 +28,6 @@ use rustc::ty::{self, TyCtxt};
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::Expr;
|
|
||||||
use rustc::hir::intravisit;
|
|
||||||
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
|
|
||||||
|
|
||||||
use self::restrictions::RestrictionResult;
|
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);
|
|
||||||
}
|
|
||||||
|
@ -32,14 +32,12 @@ use rustc::middle::dataflow::DataFlowOperator;
|
|||||||
use rustc::middle::dataflow::KillFrom;
|
use rustc::middle::dataflow::KillFrom;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
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 as mc;
|
||||||
use rustc::middle::mem_categorization::Categorization;
|
use rustc::middle::mem_categorization::Categorization;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
@ -47,7 +45,7 @@ use syntax_pos::{MultiSpan, Span};
|
|||||||
use errors::DiagnosticBuilder;
|
use errors::DiagnosticBuilder;
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
|
use rustc::hir::intravisit::{self, Visitor};
|
||||||
|
|
||||||
pub mod check_loans;
|
pub mod check_loans;
|
||||||
|
|
||||||
@ -62,93 +60,14 @@ pub struct LoanDataFlowOperator;
|
|||||||
|
|
||||||
pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, 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>) {
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
let mut bccx = BorrowckCtxt {
|
tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || {
|
||||||
tcx: tcx,
|
tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
|
||||||
free_region_map: FreeRegionMap::new(),
|
tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || {
|
||||||
stats: BorrowStats {
|
borrowck_fn(tcx, body_id);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collection of conclusions determined via borrow checker analyses.
|
/// 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>,
|
pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
|
fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) {
|
||||||
fk: FnKind<'tcx>,
|
debug!("borrowck_fn(body_id={:?})", body_id);
|
||||||
decl: &'tcx hir::FnDecl,
|
|
||||||
body_id: hir::BodyId,
|
|
||||||
sp: Span,
|
|
||||||
id: ast::NodeId,
|
|
||||||
attributes: &[ast::Attribute]) {
|
|
||||||
debug!("borrowck_fn(id={})", 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")) {
|
let mut bccx = &mut BorrowckCtxt {
|
||||||
this.with_temp_region_map(id, |this| {
|
tcx: tcx,
|
||||||
mir::borrowck_mir(this, id, attributes)
|
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,
|
let AnalysisData { all_loans,
|
||||||
loans: loan_dfcx,
|
loans: loan_dfcx,
|
||||||
move_data: flowed_moves } =
|
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,
|
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
|
||||||
this.tcx,
|
bccx.tcx,
|
||||||
sp,
|
owner_id);
|
||||||
id);
|
move_data::fragments::build_unfragmented_map(bccx,
|
||||||
move_data::fragments::build_unfragmented_map(this,
|
|
||||||
&flowed_moves.move_data,
|
&flowed_moves.move_data,
|
||||||
id);
|
owner_id);
|
||||||
|
|
||||||
check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body);
|
check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body);
|
||||||
|
|
||||||
intravisit::walk_fn(this, fk, decl, body_id, sp, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
|
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.
|
/// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
|
||||||
pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
|
pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
body: hir::BodyId,
|
body_id: hir::BodyId,
|
||||||
cfg: &cfg::CFG)
|
cfg: &cfg::CFG)
|
||||||
-> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
|
-> (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 {
|
let mut bccx = BorrowckCtxt {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
free_region_map: FreeRegionMap::new(),
|
tables: tables,
|
||||||
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);
|
let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id);
|
||||||
(bccx, dataflow_data)
|
(bccx, dataflow_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,28 +182,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
|
|||||||
pub struct BorrowckCtxt<'a, 'tcx: 'a> {
|
pub struct BorrowckCtxt<'a, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
|
||||||
// Hacky. As we visit various fns, we have to load up the
|
// tables for the current thing we are checking; set to
|
||||||
// free-region map for each one. This map is computed by during
|
// Some in `borrowck_fn` and cleared later
|
||||||
// typeck for each fn item and stored -- closures just use the map
|
tables: &'a ty::TypeckTables<'tcx>,
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -574,19 +470,12 @@ pub enum MovedValueUseKind {
|
|||||||
// Misc
|
// Misc
|
||||||
|
|
||||||
impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
fn with_temp_region_map<F>(&mut self, id: ast::NodeId, f: F)
|
pub fn is_subregion_of(&self,
|
||||||
where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>)
|
r_sub: &'tcx ty::Region,
|
||||||
{
|
r_sup: &'tcx ty::Region)
|
||||||
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)
|
|
||||||
-> bool
|
-> 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>) {
|
pub fn report(&self, err: BckError<'tcx>) {
|
||||||
@ -912,11 +801,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
mc::AliasableStatic |
|
mc::AliasableStatic |
|
||||||
mc::AliasableStaticMut => {
|
mc::AliasableStaticMut => {
|
||||||
let mut err = struct_span_err!(
|
// This path cannot occur. It happens when we have an
|
||||||
self.tcx.sess, span, E0388,
|
// `&mut` or assignment to a static. But in the case
|
||||||
"{} in a static location", prefix);
|
// of `static X`, we get a mutability violation first,
|
||||||
err.span_label(span, &format!("cannot write data in a static definition"));
|
// and never get here. In the case of `static mut X`,
|
||||||
err
|
// that is unsafe and hence the aliasability error is
|
||||||
|
// ignored.
|
||||||
|
span_bug!(span, "aliasability violation for static `{}`", prefix)
|
||||||
}
|
}
|
||||||
mc::AliasableBorrowed => {
|
mc::AliasableBorrowed => {
|
||||||
let mut e = struct_span_err!(
|
let mut e = struct_span_err!(
|
||||||
|
@ -287,27 +287,7 @@ https://doc.rust-lang.org/std/cell/
|
|||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0388: r##"
|
E0388: r##"
|
||||||
A mutable borrow was attempted in a static location.
|
E0388 was removed and is no longer issued.
|
||||||
|
|
||||||
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;
|
|
||||||
```
|
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0389: r##"
|
E0389: r##"
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#![feature(shared)]
|
#![feature(shared)]
|
||||||
#![feature(collections_range)]
|
#![feature(collections_range)]
|
||||||
#![feature(collections_bound)]
|
#![feature(collections_bound)]
|
||||||
|
#![cfg_attr(stage0,feature(field_init_shorthand))]
|
||||||
#![feature(nonzero)]
|
#![feature(nonzero)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use bitvec::BitMatrix;
|
use bitvec::BitMatrix;
|
||||||
|
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -36,10 +37,10 @@ pub struct TransitiveRelation<T: Debug + PartialEq> {
|
|||||||
closure: RefCell<Option<BitMatrix>>,
|
closure: RefCell<Option<BitMatrix>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, PartialOrd)]
|
#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
|
||||||
struct Index(usize);
|
struct Index(usize);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||||
struct Edge {
|
struct Edge {
|
||||||
source: Index,
|
source: Index,
|
||||||
target: Index,
|
target: Index,
|
||||||
@ -54,6 +55,10 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.edges.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn index(&self, a: &T) -> Option<Index> {
|
fn index(&self, a: &T) -> Option<Index> {
|
||||||
self.elements.iter().position(|e| *e == *a).map(Index)
|
self.elements.iter().position(|e| *e == *a).map(Index)
|
||||||
}
|
}
|
||||||
@ -305,6 +310,30 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Encodable for TransitiveRelation<T>
|
||||||
|
where T: Encodable + Debug + PartialEq
|
||||||
|
{
|
||||||
|
fn encode<E: Encoder>(&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<T> Decodable for TransitiveRelation<T>
|
||||||
|
where T: Decodable + Debug + PartialEq
|
||||||
|
{
|
||||||
|
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
|
||||||
|
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]
|
#[test]
|
||||||
fn test_one_step() {
|
fn test_one_step() {
|
||||||
let mut relation = TransitiveRelation::new();
|
let mut relation = TransitiveRelation::new();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![feature(loop_break_value)]
|
||||||
#![feature(libc)]
|
#![feature(libc)]
|
||||||
#![feature(quote)]
|
#![feature(quote)]
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
@ -718,13 +718,24 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
|
|||||||
mode: PpFlowGraphMode,
|
mode: PpFlowGraphMode,
|
||||||
mut out: W)
|
mut out: W)
|
||||||
-> io::Result<()> {
|
-> io::Result<()> {
|
||||||
let cfg = match code {
|
let body_id = match code {
|
||||||
blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
|
blocks::Code::Expr(expr) => {
|
||||||
blocks::Code::FnLike(fn_like) => {
|
// Find the function this expression is from.
|
||||||
let body = tcx.hir.body(fn_like.body());
|
let mut node_id = expr.id;
|
||||||
cfg::CFG::new(tcx, &body.value)
|
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 labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
|
||||||
let lcfg = LabelledCFG {
|
let lcfg = LabelledCFG {
|
||||||
hir_map: &tcx.hir,
|
hir_map: &tcx.hir,
|
||||||
|
@ -1143,9 +1143,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
|
|||||||
trait_items: _,
|
trait_items: _,
|
||||||
impl_items: _,
|
impl_items: _,
|
||||||
bodies: _,
|
bodies: _,
|
||||||
|
|
||||||
trait_impls: _,
|
trait_impls: _,
|
||||||
trait_default_impl: _,
|
trait_default_impl: _,
|
||||||
|
body_ids: _,
|
||||||
} = *krate;
|
} = *krate;
|
||||||
|
|
||||||
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
|
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
|
||||||
|
@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
|
|||||||
// to have behaviour like the above, rather than
|
// to have behaviour like the above, rather than
|
||||||
// e.g. accidentally recurring after an assert.
|
// 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 work_queue = vec![cfg.entry];
|
||||||
let mut reached_exit_without_self_call = false;
|
let mut reached_exit_without_self_call = false;
|
||||||
|
@ -30,7 +30,6 @@ use rustc::ty::{self, Ty, TyCtxt};
|
|||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
|
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
@ -39,9 +38,11 @@ use std::cell::RefCell;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
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.dep_graph.with_task(DepNode::MirKrate, || {
|
||||||
tcx: tcx
|
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
|
||||||
}.as_deep_visitor());
|
tcx.item_mir(body_owner_def_id);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
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
|
// 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>,
|
fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
closure_expr_id: ast::NodeId,
|
closure_expr_id: ast::NodeId,
|
||||||
body_id: hir::BodyId)
|
body_id: hir::BodyId)
|
||||||
|
@ -515,76 +515,13 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, '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) {
|
fn visit_item(&mut self, i: &'tcx hir::Item) {
|
||||||
check_item_type(self.tcx, i);
|
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 {
|
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 {
|
pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
|
||||||
tcx.sess.track_errors(|| {
|
tcx.sess.track_errors(|| {
|
||||||
let mut visit = CheckItemTypesVisitor { tcx: tcx };
|
|
||||||
tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
|
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 {
|
pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
|
||||||
tcx.sess.track_errors(|| {
|
tcx.sess.track_errors(|| {
|
||||||
let mut visit = CheckItemBodiesVisitor { tcx: tcx };
|
tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || {
|
||||||
tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
|
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
|
||||||
|
tcx.item_tables(body_owner_def_id);
|
||||||
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +120,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
rcx.visit_region_obligations(id);
|
rcx.visit_region_obligations(id);
|
||||||
}
|
}
|
||||||
rcx.resolve_regions_and_report_errors();
|
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
|
/// 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();
|
rcx.resolve_regions_and_report_errors();
|
||||||
|
|
||||||
// For the top-level fn, store the free-region-map. We don't store
|
// In this mode, we also copy the free-region-map into the
|
||||||
// any map for closures; they just share the same map as the
|
// tables of the enclosing fcx. In the other regionck modes
|
||||||
// function that created them.
|
// (e.g., `regionck_item`), we don't have an enclosing tables.
|
||||||
self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
|
assert!(self.tables.borrow().free_region_map.is_empty());
|
||||||
|
self.tables.borrow_mut().free_region_map = rcx.free_region_map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
wbcx.visit_type_nodes();
|
wbcx.visit_type_nodes();
|
||||||
wbcx.visit_cast_types();
|
wbcx.visit_cast_types();
|
||||||
wbcx.visit_lints();
|
wbcx.visit_lints();
|
||||||
|
wbcx.visit_free_region_map();
|
||||||
|
|
||||||
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
|
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
|
||||||
DefIdSet());
|
DefIdSet());
|
||||||
@ -274,6 +275,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||||||
self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
|
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) {
|
fn visit_anon_types(&mut self) {
|
||||||
let gcx = self.tcx().global_tcx();
|
let gcx = self.tcx().global_tcx();
|
||||||
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
|
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
|
||||||
|
@ -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)) {
|
NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
|
||||||
NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
|
NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
|
||||||
|
NodeTy(&hir::Ty { node: TyTypeof(body), .. }) |
|
||||||
NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
|
NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
|
||||||
if body.node_id == node_id => tcx.types.usize,
|
if body.node_id == node_id => tcx.types.usize,
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
|
|||||||
//~| NOTE statics require immutable values
|
//~| NOTE statics require immutable values
|
||||||
//~| ERROR E0017
|
//~| ERROR E0017
|
||||||
//~| NOTE statics require immutable values
|
//~| NOTE statics require immutable values
|
||||||
//~| ERROR E0388
|
//~| ERROR cannot borrow
|
||||||
//~| NOTE cannot write data in a static definition
|
|
||||||
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
|
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
|
||||||
//~| NOTE statics require immutable values
|
//~| NOTE statics require immutable values
|
||||||
//~| ERROR E0017
|
//~| ERROR E0017
|
||||||
|
@ -15,7 +15,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017
|
|||||||
//~| ERROR E0017
|
//~| ERROR E0017
|
||||||
static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
|
static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
|
||||||
//~| ERROR E0017
|
//~| ERROR E0017
|
||||||
//~| ERROR E0388
|
//~| ERROR cannot borrow
|
||||||
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
|
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
|
||||||
//~| ERROR E0017
|
//~| ERROR E0017
|
||||||
|
|
||||||
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {
|
||||||
|
}
|
@ -13,6 +13,6 @@ pub fn main() {
|
|||||||
//~^ ERROR blocks in constants are limited to items and tail expressions
|
//~^ ERROR blocks in constants are limited to items and tail expressions
|
||||||
let p = 3;
|
let p = 3;
|
||||||
//~^ ERROR blocks in constants are limited to items and tail expressions
|
//~^ ERROR blocks in constants are limited to items and tail expressions
|
||||||
&p
|
&p //~ ERROR `p` does not live long enough
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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
|
error: cannot borrow immutable borrowed content `*a` as mutable
|
||||||
--> $DIR/mut-arg-hint.rs:13:9
|
--> $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");
|
13 | a.push_str("bar");
|
||||||
| ^ cannot borrow as mutable
|
| ^ 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
|
error: cannot borrow immutable borrowed content `*a` as mutable
|
||||||
--> $DIR/mut-arg-hint.rs:25:9
|
--> $DIR/mut-arg-hint.rs:25:9
|
||||||
|
|
|
|
||||||
|
Loading…
Reference in New Issue
Block a user