2017-05-22 06:06:51 -05:00
|
|
|
// Copyright 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.
|
|
|
|
|
|
|
|
//! This module provides one pass, `CleanEndRegions`, that reduces the
|
|
|
|
//! set of `EndRegion` statements in the MIR.
|
|
|
|
//!
|
|
|
|
//! The "pass" is actually implemented as two traversals (aka visits)
|
|
|
|
//! of the input MIR. The first traversal, `GatherBorrowedRegions`,
|
|
|
|
//! finds all of the regions in the MIR that are involved in a borrow.
|
|
|
|
//!
|
|
|
|
//! The second traversal, `DeleteTrivialEndRegions`, walks over the
|
|
|
|
//! MIR and removes any `EndRegion` that is applied to a region that
|
|
|
|
//! was not seen in the previous pass.
|
|
|
|
|
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
|
|
|
|
2017-08-31 13:37:38 -05:00
|
|
|
use rustc::middle::region;
|
2017-11-09 16:49:51 -06:00
|
|
|
use rustc::mir::transform::MirSource;
|
2017-05-22 06:06:51 -05:00
|
|
|
use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
|
2017-10-26 18:53:31 -05:00
|
|
|
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
|
2017-07-11 16:30:30 -05:00
|
|
|
use rustc::ty::{Ty, RegionKind, TyCtxt};
|
2017-11-09 16:49:51 -06:00
|
|
|
use transform::MirPass;
|
2017-05-22 06:06:51 -05:00
|
|
|
|
|
|
|
pub struct CleanEndRegions;
|
|
|
|
|
|
|
|
struct GatherBorrowedRegions {
|
2017-08-31 13:37:38 -05:00
|
|
|
seen_regions: FxHashSet<region::Scope>,
|
2017-05-22 06:06:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct DeleteTrivialEndRegions<'a> {
|
2017-08-31 13:37:38 -05:00
|
|
|
seen_regions: &'a FxHashSet<region::Scope>,
|
2017-05-22 06:06:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MirPass for CleanEndRegions {
|
|
|
|
fn run_pass<'a, 'tcx>(&self,
|
2017-08-31 05:04:19 -05:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2017-05-22 06:06:51 -05:00
|
|
|
_source: MirSource,
|
|
|
|
mir: &mut Mir<'tcx>) {
|
2017-09-05 08:28:08 -05:00
|
|
|
if !tcx.sess.emit_end_regions() { return; }
|
2017-08-31 05:04:19 -05:00
|
|
|
|
2017-07-22 03:04:16 -05:00
|
|
|
let mut gather = GatherBorrowedRegions {
|
2017-07-25 18:44:49 -05:00
|
|
|
seen_regions: FxHashSet()
|
2017-07-22 03:04:16 -05:00
|
|
|
};
|
2017-05-22 06:06:51 -05:00
|
|
|
gather.visit_mir(mir);
|
|
|
|
|
|
|
|
let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions };
|
|
|
|
delete.visit_mir(mir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions {
|
|
|
|
fn visit_rvalue(&mut self,
|
|
|
|
rvalue: &Rvalue<'tcx>,
|
|
|
|
location: Location) {
|
2017-07-11 16:30:30 -05:00
|
|
|
// Gather regions that are used for borrows
|
2017-05-22 06:06:51 -05:00
|
|
|
if let Rvalue::Ref(r, _, _) = *rvalue {
|
|
|
|
if let RegionKind::ReScope(ce) = *r {
|
|
|
|
self.seen_regions.insert(ce);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.super_rvalue(rvalue, location);
|
|
|
|
}
|
2017-07-11 16:30:30 -05:00
|
|
|
|
2017-10-26 18:53:31 -05:00
|
|
|
fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
|
2017-07-25 18:44:49 -05:00
|
|
|
// Gather regions that occur in types
|
|
|
|
for re in ty.walk().flat_map(|t| t.regions()) {
|
|
|
|
match *re {
|
|
|
|
RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); }
|
|
|
|
_ => {},
|
2017-07-11 16:30:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.super_ty(ty);
|
|
|
|
}
|
2017-05-22 06:06:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
|
|
|
|
fn visit_statement(&mut self,
|
|
|
|
block: BasicBlock,
|
|
|
|
statement: &mut Statement<'tcx>,
|
|
|
|
location: Location) {
|
|
|
|
let mut delete_it = false;
|
|
|
|
|
2017-08-31 13:37:38 -05:00
|
|
|
if let StatementKind::EndRegion(ref region_scope) = statement.kind {
|
|
|
|
if !self.seen_regions.contains(region_scope) {
|
2017-05-22 06:06:51 -05:00
|
|
|
delete_it = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if delete_it {
|
|
|
|
statement.kind = StatementKind::Nop;
|
|
|
|
}
|
|
|
|
self.super_statement(block, statement, location);
|
|
|
|
}
|
|
|
|
}
|