]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/def_use.rs
Rollup merge of #65485 - ecstatic-morse:const-validation-mismatch-ugliness, r=eddyb
[rust.git] / src / librustc_mir / util / def_use.rs
1 //! Def-use analysis.
2
3 use rustc::mir::{Body, Local, Location, PlaceElem};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
5 use rustc_index::vec::IndexVec;
6 use std::mem;
7
8 pub struct DefUseAnalysis {
9     info: IndexVec<Local, Info>,
10 }
11
12 #[derive(Clone)]
13 pub struct Info {
14     pub defs_and_uses: Vec<Use>,
15 }
16
17 #[derive(Clone)]
18 pub struct Use {
19     pub context: PlaceContext,
20     pub location: Location,
21 }
22
23 impl DefUseAnalysis {
24     pub fn new(body: &Body<'_>) -> DefUseAnalysis {
25         DefUseAnalysis {
26             info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
27         }
28     }
29
30     pub fn analyze(&mut self, body: &Body<'_>) {
31         self.clear();
32
33         let mut finder = DefUseFinder {
34             info: mem::take(&mut self.info),
35         };
36         finder.visit_body(body);
37         self.info = finder.info
38     }
39
40     fn clear(&mut self) {
41         for info in &mut self.info {
42             info.clear();
43         }
44     }
45
46     pub fn local_info(&self, local: Local) -> &Info {
47         &self.info[local]
48     }
49
50     fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
51         for place_use in &self.info[local].defs_and_uses {
52             MutateUseVisitor::new(local,
53                                   new_local,
54                                   body).visit_location(body, place_use.location)
55         }
56     }
57
58     // FIXME(pcwalton): this should update the def-use chains.
59     pub fn replace_all_defs_and_uses_with(&self,
60                                           local: Local,
61                                           body: &mut Body<'_>,
62                                           new_local: Local) {
63         self.mutate_defs_and_uses(local, body, new_local)
64     }
65 }
66
67 struct DefUseFinder {
68     info: IndexVec<Local, Info>,
69 }
70
71 impl Visitor<'_> for DefUseFinder {
72     fn visit_local(&mut self,
73                    &local: &Local,
74                    context: PlaceContext,
75                    location: Location) {
76         self.info[local].defs_and_uses.push(Use {
77             context,
78             location,
79         });
80     }
81 }
82
83 impl Info {
84     fn new() -> Info {
85         Info {
86             defs_and_uses: vec![],
87         }
88     }
89
90     fn clear(&mut self) {
91         self.defs_and_uses.clear();
92     }
93
94     pub fn def_count(&self) -> usize {
95         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
96     }
97
98     pub fn def_count_not_including_drop(&self) -> usize {
99         self.defs_not_including_drop().count()
100     }
101
102     pub fn defs_not_including_drop(
103         &self,
104     ) -> impl Iterator<Item=&Use> {
105         self.defs_and_uses.iter().filter(|place_use| {
106             place_use.context.is_mutating_use() && !place_use.context.is_drop()
107         })
108     }
109
110     pub fn use_count(&self) -> usize {
111         self.defs_and_uses.iter().filter(|place_use| {
112             place_use.context.is_nonmutating_use()
113         }).count()
114     }
115 }
116
117 struct MutateUseVisitor {
118     query: Local,
119     new_local: Local,
120 }
121
122 impl MutateUseVisitor {
123     fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
124         MutateUseVisitor {
125             query,
126             new_local,
127         }
128     }
129 }
130
131 impl MutVisitor<'_> for MutateUseVisitor {
132     fn visit_local(&mut self,
133                     local: &mut Local,
134                     _context: PlaceContext,
135                     _location: Location) {
136         if *local == self.query {
137             *local = self.new_local;
138         }
139     }
140
141     fn process_projection_elem(
142         &mut self,
143         elem: &PlaceElem<'tcx>,
144     ) -> Option<PlaceElem<'tcx>> {
145         match elem {
146             PlaceElem::Index(local) if *local == self.query => {
147                 Some(PlaceElem::Index(self.new_local))
148             }
149             _ => None,
150         }
151     }
152 }