]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/cleanup_post_borrowck.rs
Auto merge of #53002 - QuietMisdreavus:brother-may-i-have-some-loops, r=pnkfelix
[rust.git] / src / librustc_mir / transform / cleanup_post_borrowck.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module provides two passes:
12 //!
13 //!   - `CleanEndRegions`, that reduces the set of `EndRegion` statements
14 //!     in the MIR.
15 //!   - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
16 //!     with `Nop`.
17 //!
18 //! The `CleanEndRegions` "pass" is actually implemented as two
19 //! traversals (aka visits) of the input MIR. The first traversal,
20 //! `GatherBorrowedRegions`, finds all of the regions in the MIR
21 //! that are involved in a borrow.
22 //!
23 //! The second traversal, `DeleteTrivialEndRegions`, walks over the
24 //! MIR and removes any `EndRegion` that is applied to a region that
25 //! was not seen in the previous pass.
26 //!
27 //! The `CleanUserAssertTy` pass runs at a distinct time from the
28 //! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
29 //! pass runs after the MIR borrowck so that the NLL type checker can
30 //! perform the type assertion when it encounters the `UserAssertTy`
31 //! statements.
32
33 use rustc_data_structures::fx::FxHashSet;
34
35 use rustc::middle::region;
36 use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
37 use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
38 use rustc::ty::{Ty, RegionKind, TyCtxt};
39 use transform::{MirPass, MirSource};
40
41 pub struct CleanEndRegions;
42
43 struct GatherBorrowedRegions {
44     seen_regions: FxHashSet<region::Scope>,
45 }
46
47 struct DeleteTrivialEndRegions<'a> {
48     seen_regions: &'a FxHashSet<region::Scope>,
49 }
50
51 impl MirPass for CleanEndRegions {
52     fn run_pass<'a, 'tcx>(&self,
53                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
54                           _source: MirSource,
55                           mir: &mut Mir<'tcx>) {
56         if !tcx.emit_end_regions() { return; }
57
58         let mut gather = GatherBorrowedRegions {
59             seen_regions: FxHashSet()
60         };
61         gather.visit_mir(mir);
62
63         let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions };
64         delete.visit_mir(mir);
65     }
66 }
67
68 impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions {
69     fn visit_rvalue(&mut self,
70                     rvalue: &Rvalue<'tcx>,
71                     location: Location) {
72         // Gather regions that are used for borrows
73         if let Rvalue::Ref(r, _, _) = *rvalue {
74             if let RegionKind::ReScope(ce) = *r {
75                 self.seen_regions.insert(ce);
76             }
77         }
78         self.super_rvalue(rvalue, location);
79     }
80
81     fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
82         // Gather regions that occur in types
83         for re in ty.walk().flat_map(|t| t.regions()) {
84             match *re {
85                 RegionKind::ReScope(ce) => { self.seen_regions.insert(ce); }
86                 _ => {},
87             }
88         }
89         self.super_ty(ty);
90     }
91 }
92
93 impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
94     fn visit_statement(&mut self,
95                        block: BasicBlock,
96                        statement: &mut Statement<'tcx>,
97                        location: Location) {
98         let mut delete_it = false;
99
100         if let StatementKind::EndRegion(ref region_scope) = statement.kind {
101             if !self.seen_regions.contains(region_scope) {
102                 delete_it = true;
103             }
104         }
105
106         if delete_it {
107             statement.make_nop();
108         }
109         self.super_statement(block, statement, location);
110     }
111 }
112
113 pub struct CleanUserAssertTy;
114
115 pub struct DeleteUserAssertTy;
116
117 impl MirPass for CleanUserAssertTy {
118     fn run_pass<'a, 'tcx>(&self,
119                           _tcx: TyCtxt<'a, 'tcx, 'tcx>,
120                           _source: MirSource,
121                           mir: &mut Mir<'tcx>) {
122         let mut delete = DeleteUserAssertTy;
123         delete.visit_mir(mir);
124     }
125 }
126
127 impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
128     fn visit_statement(&mut self,
129                        block: BasicBlock,
130                        statement: &mut Statement<'tcx>,
131                        location: Location) {
132         if let StatementKind::UserAssertTy(..) = statement.kind {
133             statement.make_nop();
134         }
135         self.super_statement(block, statement, location);
136     }
137 }