2017-07-03 18:40:20 +02:00
|
|
|
// Copyright 2012-2017 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.
|
|
|
|
|
2017-12-04 00:56:06 +02:00
|
|
|
use rustc::hir;
|
|
|
|
use rustc::hir::def_id::DefId;
|
|
|
|
use rustc::middle::region;
|
2017-07-03 18:40:20 +02:00
|
|
|
use rustc::mir::{self, Location, Mir};
|
|
|
|
use rustc::mir::visit::Visitor;
|
2017-11-16 15:32:13 -08:00
|
|
|
use rustc::ty::{self, Region, TyCtxt};
|
2017-09-27 10:01:42 +03:00
|
|
|
use rustc::ty::RegionKind;
|
2017-07-03 18:40:20 +02:00
|
|
|
use rustc::ty::RegionKind::ReScope;
|
|
|
|
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
|
|
|
|
|
|
|
use rustc_data_structures::bitslice::{BitwiseOperator};
|
|
|
|
use rustc_data_structures::indexed_set::{IdxSet};
|
|
|
|
use rustc_data_structures::indexed_vec::{IndexVec};
|
|
|
|
|
|
|
|
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
|
|
|
|
pub use dataflow::indexes::BorrowIndex;
|
2017-11-17 04:34:02 -05:00
|
|
|
use borrow_check::nll::region_infer::RegionInferenceContext;
|
|
|
|
use borrow_check::nll::ToRegionVid;
|
2017-07-03 18:40:20 +02:00
|
|
|
|
2017-09-27 10:01:42 +03:00
|
|
|
use syntax_pos::Span;
|
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
use std::fmt;
|
2017-12-04 00:56:06 +02:00
|
|
|
use std::rc::Rc;
|
2017-07-03 18:40:20 +02:00
|
|
|
|
|
|
|
// `Borrows` maps each dataflow bit to an `Rvalue::Ref`, which can be
|
|
|
|
// uniquely identified in the MIR by the `Location` of the assigment
|
|
|
|
// statement in which it appears on the right hand side.
|
2017-10-30 05:50:39 -04:00
|
|
|
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2017-07-03 18:40:20 +02:00
|
|
|
mir: &'a Mir<'tcx>,
|
2017-12-04 00:56:06 +02:00
|
|
|
scope_tree: Rc<region::ScopeTree>,
|
|
|
|
root_scope: Option<region::Scope>,
|
2017-07-03 18:40:20 +02:00
|
|
|
borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
|
|
|
|
location_map: FxHashMap<Location, BorrowIndex>,
|
|
|
|
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
|
2017-12-04 13:21:28 +02:00
|
|
|
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
2017-09-27 10:01:42 +03:00
|
|
|
region_span_map: FxHashMap<RegionKind, Span>,
|
2017-11-17 04:34:02 -05:00
|
|
|
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>,
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// temporarily allow some dead fields: `kind` and `region` will be
|
2017-12-01 14:39:51 +02:00
|
|
|
// needed by borrowck; `place` will probably be a MovePathIndex when
|
2017-07-03 18:40:20 +02:00
|
|
|
// that is extended to include borrowed data paths.
|
|
|
|
#[allow(dead_code)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct BorrowData<'tcx> {
|
|
|
|
pub(crate) location: Location,
|
|
|
|
pub(crate) kind: mir::BorrowKind,
|
|
|
|
pub(crate) region: Region<'tcx>,
|
2017-12-01 14:39:51 +02:00
|
|
|
pub(crate) place: mir::Place<'tcx>,
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|
|
|
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let kind = match self.kind {
|
|
|
|
mir::BorrowKind::Shared => "",
|
|
|
|
mir::BorrowKind::Unique => "uniq ",
|
|
|
|
mir::BorrowKind::Mut => "mut ",
|
|
|
|
};
|
|
|
|
let region = format!("{}", self.region);
|
|
|
|
let region = if region.len() > 0 { format!("{} ", region) } else { region };
|
2017-12-01 14:39:51 +02:00
|
|
|
write!(w, "&{}{}{:?}", region, kind, self.place)
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 05:50:39 -04:00
|
|
|
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
|
2017-10-30 08:28:07 -04:00
|
|
|
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
mir: &'a Mir<'tcx>,
|
2017-12-04 00:56:06 +02:00
|
|
|
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>,
|
|
|
|
def_id: DefId,
|
|
|
|
body_id: Option<hir::BodyId>)
|
2017-10-30 08:28:07 -04:00
|
|
|
-> Self {
|
2017-12-04 00:56:06 +02:00
|
|
|
let scope_tree = tcx.region_scope_tree(def_id);
|
|
|
|
let root_scope = body_id.map(|body_id| {
|
|
|
|
region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
|
|
|
|
});
|
2017-11-16 15:32:13 -08:00
|
|
|
let mut visitor = GatherBorrows {
|
|
|
|
tcx,
|
|
|
|
mir,
|
|
|
|
idx_vec: IndexVec::new(),
|
|
|
|
location_map: FxHashMap(),
|
|
|
|
region_map: FxHashMap(),
|
2017-12-04 13:21:28 +02:00
|
|
|
local_map: FxHashMap(),
|
2017-11-16 15:32:13 -08:00
|
|
|
region_span_map: FxHashMap()
|
|
|
|
};
|
2017-07-03 18:40:20 +02:00
|
|
|
visitor.visit_mir(mir);
|
|
|
|
return Borrows { tcx: tcx,
|
|
|
|
mir: mir,
|
|
|
|
borrows: visitor.idx_vec,
|
2017-12-04 00:56:06 +02:00
|
|
|
scope_tree,
|
|
|
|
root_scope,
|
2017-07-03 18:40:20 +02:00
|
|
|
location_map: visitor.location_map,
|
2017-09-27 10:01:42 +03:00
|
|
|
region_map: visitor.region_map,
|
2017-12-04 13:21:28 +02:00
|
|
|
local_map: visitor.local_map,
|
2017-10-30 08:28:07 -04:00
|
|
|
region_span_map: visitor.region_span_map,
|
|
|
|
nonlexical_regioncx };
|
2017-07-03 18:40:20 +02:00
|
|
|
|
2017-11-16 15:32:13 -08:00
|
|
|
struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
mir: &'a Mir<'tcx>,
|
2017-07-03 18:40:20 +02:00
|
|
|
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
|
|
|
|
location_map: FxHashMap<Location, BorrowIndex>,
|
|
|
|
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
|
2017-12-04 13:21:28 +02:00
|
|
|
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
|
2017-09-27 10:01:42 +03:00
|
|
|
region_span_map: FxHashMap<RegionKind, Span>,
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
2017-11-16 15:32:13 -08:00
|
|
|
|
|
|
|
impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
|
2017-07-03 18:40:20 +02:00
|
|
|
fn visit_rvalue(&mut self,
|
|
|
|
rvalue: &mir::Rvalue<'tcx>,
|
|
|
|
location: mir::Location) {
|
2017-12-04 13:21:28 +02:00
|
|
|
fn root_local(mut p: &mir::Place<'_>) -> Option<mir::Local> {
|
|
|
|
loop { match p {
|
|
|
|
mir::Place::Projection(pi) => p = &pi.base,
|
|
|
|
mir::Place::Static(_) => return None,
|
|
|
|
mir::Place::Local(l) => return Some(*l)
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
|
|
|
|
if is_unsafe_place(self.tcx, self.mir, place) { return; }
|
2017-11-16 15:32:13 -08:00
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
let borrow = BorrowData {
|
2017-12-01 14:39:51 +02:00
|
|
|
location: location, kind: kind, region: region, place: place.clone(),
|
2017-07-03 18:40:20 +02:00
|
|
|
};
|
|
|
|
let idx = self.idx_vec.push(borrow);
|
|
|
|
self.location_map.insert(location, idx);
|
2017-12-04 13:21:28 +02:00
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
let borrows = self.region_map.entry(region).or_insert(FxHashSet());
|
|
|
|
borrows.insert(idx);
|
2017-12-04 13:21:28 +02:00
|
|
|
|
|
|
|
if let Some(local) = root_local(place) {
|
|
|
|
let borrows = self.local_map.entry(local).or_insert(FxHashSet());
|
|
|
|
borrows.insert(idx);
|
|
|
|
}
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
}
|
2017-09-27 10:01:42 +03:00
|
|
|
|
|
|
|
fn visit_statement(&mut self,
|
|
|
|
block: mir::BasicBlock,
|
|
|
|
statement: &mir::Statement<'tcx>,
|
|
|
|
location: Location) {
|
|
|
|
if let mir::StatementKind::EndRegion(region_scope) = statement.kind {
|
|
|
|
self.region_span_map.insert(ReScope(region_scope), statement.source_info.span);
|
|
|
|
}
|
|
|
|
self.super_statement(block, statement, location);
|
|
|
|
}
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrows }
|
|
|
|
|
|
|
|
pub fn location(&self, idx: BorrowIndex) -> &Location {
|
|
|
|
&self.borrows[idx].location
|
|
|
|
}
|
2017-09-27 10:01:42 +03:00
|
|
|
|
2017-10-25 14:17:17 -04:00
|
|
|
/// Returns the span for the "end point" given region. This will
|
|
|
|
/// return `None` if NLL is enabled, since that concept has no
|
2017-11-11 02:52:39 +05:30
|
|
|
/// meaning there. Otherwise, return region span if it exists and
|
|
|
|
/// span for end of the function if it doesn't exist.
|
2017-10-25 14:17:17 -04:00
|
|
|
pub fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
|
2017-11-11 02:52:39 +05:30
|
|
|
match self.nonlexical_regioncx {
|
|
|
|
Some(_) => None,
|
|
|
|
None => {
|
|
|
|
match self.region_span_map.get(region) {
|
|
|
|
Some(span) => Some(span.end_point()),
|
|
|
|
None => Some(self.mir.span.end_point())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-27 10:01:42 +03:00
|
|
|
}
|
2017-10-30 08:28:07 -04:00
|
|
|
|
|
|
|
/// Add all borrows to the kill set, if those borrows are out of scope at `location`.
|
|
|
|
fn kill_loans_out_of_scope_at_location(&self,
|
|
|
|
sets: &mut BlockSets<BorrowIndex>,
|
|
|
|
location: Location) {
|
2017-11-17 04:34:02 -05:00
|
|
|
if let Some(ref regioncx) = self.nonlexical_regioncx {
|
2017-10-30 08:28:07 -04:00
|
|
|
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
|
2017-11-06 04:15:38 -05:00
|
|
|
let borrow_region = borrow_data.region.to_region_vid();
|
2017-10-30 05:14:40 -04:00
|
|
|
if !regioncx.region_contains_point(borrow_region, location) {
|
|
|
|
// The region checker really considers the borrow
|
|
|
|
// to start at the point **after** the location of
|
|
|
|
// the borrow, but the borrow checker puts the gen
|
|
|
|
// directly **on** the location of the
|
|
|
|
// borrow. This results in a gen/kill both being
|
|
|
|
// generated for same point if we are not
|
|
|
|
// careful. Probably we should change the point of
|
|
|
|
// the gen, but for now we hackily account for the
|
|
|
|
// mismatch here by not generating a kill for the
|
|
|
|
// location on the borrow itself.
|
|
|
|
if location != borrow_data.location {
|
|
|
|
sets.kill(&borrow_index);
|
|
|
|
}
|
2017-10-30 08:28:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
|
2017-10-30 05:50:39 -04:00
|
|
|
impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
2017-07-03 18:40:20 +02:00
|
|
|
type Idx = BorrowIndex;
|
|
|
|
fn name() -> &'static str { "borrows" }
|
|
|
|
fn bits_per_block(&self) -> usize {
|
|
|
|
self.borrows.len()
|
|
|
|
}
|
|
|
|
fn start_block_effect(&self, _sets: &mut BlockSets<BorrowIndex>) {
|
2017-08-31 21:37:38 +03:00
|
|
|
// no borrows of code region_scopes have been taken prior to
|
2017-07-03 18:40:20 +02:00
|
|
|
// function execution, so this method has no effect on
|
|
|
|
// `_sets`.
|
|
|
|
}
|
|
|
|
fn statement_effect(&self,
|
|
|
|
sets: &mut BlockSets<BorrowIndex>,
|
|
|
|
location: Location) {
|
|
|
|
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
|
|
|
|
panic!("could not find block at location {:?}", location);
|
|
|
|
});
|
|
|
|
let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
|
|
|
|
panic!("could not find statement at location {:?}");
|
|
|
|
});
|
|
|
|
match stmt.kind {
|
2017-08-31 21:37:38 +03:00
|
|
|
mir::StatementKind::EndRegion(region_scope) => {
|
2017-10-02 22:40:51 +02:00
|
|
|
if let Some(borrow_indexes) = self.region_map.get(&ReScope(region_scope)) {
|
2017-10-30 08:28:07 -04:00
|
|
|
assert!(self.nonlexical_regioncx.is_none());
|
2017-12-04 13:21:28 +02:00
|
|
|
sets.kill_all(borrow_indexes);
|
2017-10-02 22:40:51 +02:00
|
|
|
} else {
|
|
|
|
// (if there is no entry, then there are no borrows to be tracked)
|
|
|
|
}
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::StatementKind::Assign(_, ref rhs) => {
|
2017-12-01 14:39:51 +02:00
|
|
|
if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
|
|
|
|
if is_unsafe_place(self.tcx, self.mir, place) { return; }
|
2017-11-27 18:13:40 +02:00
|
|
|
if let RegionKind::ReEmpty = region {
|
|
|
|
// If the borrowed value is dead, the region for it
|
|
|
|
// can be empty. Don't track the borrow in that case.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
let index = self.location_map.get(&location).unwrap_or_else(|| {
|
|
|
|
panic!("could not find BorrowIndex for location {:?}", location);
|
|
|
|
});
|
|
|
|
assert!(self.region_map.get(region).unwrap_or_else(|| {
|
|
|
|
panic!("could not find BorrowIndexs for region {:?}", region);
|
|
|
|
}).contains(&index));
|
|
|
|
sets.gen(&index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-04 13:21:28 +02:00
|
|
|
mir::StatementKind::StorageDead(local) => {
|
|
|
|
// Make sure there are no remaining borrows for locals that
|
|
|
|
// are gone out of scope.
|
|
|
|
//
|
|
|
|
// FIXME: expand this to variables that are assigned over.
|
|
|
|
if let Some(borrow_indexes) = self.local_map.get(&local) {
|
|
|
|
sets.kill_all(borrow_indexes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
mir::StatementKind::InlineAsm { .. } |
|
|
|
|
mir::StatementKind::SetDiscriminant { .. } |
|
|
|
|
mir::StatementKind::StorageLive(..) |
|
|
|
|
mir::StatementKind::Validate(..) |
|
|
|
|
mir::StatementKind::Nop => {}
|
|
|
|
|
|
|
|
}
|
2017-10-30 08:28:07 -04:00
|
|
|
|
|
|
|
self.kill_loans_out_of_scope_at_location(sets, location);
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
2017-10-30 08:28:07 -04:00
|
|
|
|
2017-07-03 18:40:20 +02:00
|
|
|
fn terminator_effect(&self,
|
2017-10-30 08:28:07 -04:00
|
|
|
sets: &mut BlockSets<BorrowIndex>,
|
|
|
|
location: Location) {
|
2017-11-19 04:26:23 -08:00
|
|
|
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
|
|
|
|
panic!("could not find block at location {:?}", location);
|
|
|
|
});
|
|
|
|
match block.terminator().kind {
|
|
|
|
mir::TerminatorKind::Resume |
|
|
|
|
mir::TerminatorKind::Return |
|
|
|
|
mir::TerminatorKind::GeneratorDrop => {
|
|
|
|
// When we return from the function, then all `ReScope`-style regions
|
|
|
|
// are guaranteed to have ended.
|
|
|
|
// Normally, there would be `EndRegion` statements that come before,
|
|
|
|
// and hence most of these loans will already be dead -- but, in some cases
|
|
|
|
// like unwind paths, we do not always emit `EndRegion` statements, so we
|
|
|
|
// add some kills here as a "backup" and to avoid spurious error messages.
|
|
|
|
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
|
2017-12-04 00:56:06 +02:00
|
|
|
if let ReScope(scope) = borrow_data.region {
|
|
|
|
// Check that the scope is not actually a scope from a function that is
|
|
|
|
// a parent of our closure. Note that the CallSite scope itself is
|
|
|
|
// *outside* of the closure, for some weird reason.
|
|
|
|
if let Some(root_scope) = self.root_scope {
|
|
|
|
if *scope != root_scope &&
|
|
|
|
self.scope_tree.is_subscope_of(*scope, root_scope)
|
|
|
|
{
|
|
|
|
sets.kill(&borrow_index);
|
|
|
|
}
|
|
|
|
}
|
2017-11-19 04:26:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mir::TerminatorKind::SwitchInt {..} |
|
|
|
|
mir::TerminatorKind::Drop {..} |
|
|
|
|
mir::TerminatorKind::DropAndReplace {..} |
|
|
|
|
mir::TerminatorKind::Call {..} |
|
|
|
|
mir::TerminatorKind::Assert {..} |
|
|
|
|
mir::TerminatorKind::Yield {..} |
|
|
|
|
mir::TerminatorKind::Goto {..} |
|
|
|
|
mir::TerminatorKind::FalseEdges {..} |
|
|
|
|
mir::TerminatorKind::Unreachable => {}
|
|
|
|
}
|
2017-10-30 08:28:07 -04:00
|
|
|
self.kill_loans_out_of_scope_at_location(sets, location);
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn propagate_call_return(&self,
|
|
|
|
_in_out: &mut IdxSet<BorrowIndex>,
|
|
|
|
_call_bb: mir::BasicBlock,
|
|
|
|
_dest_bb: mir::BasicBlock,
|
2017-12-01 14:39:51 +02:00
|
|
|
_dest_place: &mir::Place) {
|
2017-08-31 21:37:38 +03:00
|
|
|
// there are no effects on the region scopes from method calls.
|
2017-07-03 18:40:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 05:50:39 -04:00
|
|
|
impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
|
2017-07-03 18:40:20 +02:00
|
|
|
#[inline]
|
|
|
|
fn join(&self, pred1: usize, pred2: usize) -> usize {
|
|
|
|
pred1 | pred2 // union effects of preds when computing borrows
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 05:50:39 -04:00
|
|
|
impl<'a, 'gcx, 'tcx> DataflowOperator for Borrows<'a, 'gcx, 'tcx> {
|
2017-07-03 18:40:20 +02:00
|
|
|
#[inline]
|
|
|
|
fn bottom_value() -> bool {
|
|
|
|
false // bottom = no Rvalue::Refs are active by default
|
|
|
|
}
|
|
|
|
}
|
2017-11-16 15:32:13 -08:00
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>(
|
2017-11-16 15:32:13 -08:00
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
mir: &'a Mir<'tcx>,
|
2017-12-01 14:39:51 +02:00
|
|
|
place: &mir::Place<'tcx>
|
2017-11-16 15:32:13 -08:00
|
|
|
) -> bool {
|
2017-12-01 14:31:47 +02:00
|
|
|
use self::mir::Place::*;
|
2017-11-16 15:32:13 -08:00
|
|
|
use self::mir::ProjectionElem;
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
match *place {
|
2017-11-16 15:32:13 -08:00
|
|
|
Local(_) => false,
|
|
|
|
Static(ref static_) => tcx.is_static_mut(static_.def_id),
|
|
|
|
Projection(ref proj) => {
|
|
|
|
match proj.elem {
|
|
|
|
ProjectionElem::Field(..) |
|
|
|
|
ProjectionElem::Downcast(..) |
|
|
|
|
ProjectionElem::Subslice { .. } |
|
|
|
|
ProjectionElem::ConstantIndex { .. } |
|
|
|
|
ProjectionElem::Index(_) => {
|
2017-12-01 14:39:51 +02:00
|
|
|
is_unsafe_place(tcx, mir, &proj.base)
|
2017-11-16 15:32:13 -08:00
|
|
|
}
|
|
|
|
ProjectionElem::Deref => {
|
|
|
|
let ty = proj.base.ty(mir, tcx).to_ty(tcx);
|
|
|
|
match ty.sty {
|
|
|
|
ty::TyRawPtr(..) => true,
|
2017-12-01 14:39:51 +02:00
|
|
|
_ => is_unsafe_place(tcx, mir, &proj.base),
|
2017-11-16 15:32:13 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|