]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/facts.rs
Rollup merge of #69665 - tmiasko:new-pass-manager-thin-lto-opt, r=nikic
[rust.git] / src / librustc_mir / borrow_check / facts.rs
1 use crate::borrow_check::location::{LocationIndex, LocationTable};
2 use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
3 use polonius_engine::AllFacts as PoloniusFacts;
4 use polonius_engine::Atom;
5 use rustc::mir::Local;
6 use rustc::ty::{RegionVid, TyCtxt};
7 use rustc_index::vec::Idx;
8 use std::error::Error;
9 use std::fmt::Debug;
10 use std::fs::{self, File};
11 use std::io::{BufWriter, Write};
12 use std::path::Path;
13
14 #[derive(Copy, Clone, Debug)]
15 crate struct RustcFacts;
16
17 impl polonius_engine::FactTypes for RustcFacts {
18     type Origin = RegionVid;
19     type Loan = BorrowIndex;
20     type Point = LocationIndex;
21     type Variable = Local;
22     type Path = MovePathIndex;
23 }
24
25 crate type AllFacts = PoloniusFacts<RustcFacts>;
26
27 crate trait AllFactsExt {
28     /// Returns `true` if there is a need to gather `AllFacts` given the
29     /// current `-Z` flags.
30     fn enabled(tcx: TyCtxt<'_>) -> bool;
31
32     fn write_to_dir(
33         &self,
34         dir: impl AsRef<Path>,
35         location_table: &LocationTable,
36     ) -> Result<(), Box<dyn Error>>;
37 }
38
39 impl AllFactsExt for AllFacts {
40     /// Return
41     fn enabled(tcx: TyCtxt<'_>) -> bool {
42         tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius
43     }
44
45     fn write_to_dir(
46         &self,
47         dir: impl AsRef<Path>,
48         location_table: &LocationTable,
49     ) -> Result<(), Box<dyn Error>> {
50         let dir: &Path = dir.as_ref();
51         fs::create_dir_all(dir)?;
52         let wr = FactWriter { location_table, dir };
53         macro_rules! write_facts_to_path {
54             ($wr:ident . write_facts_to_path($this:ident . [
55                 $($field:ident,)*
56             ])) => {
57                 $(
58                     $wr.write_facts_to_path(
59                         &$this.$field,
60                         &format!("{}.facts", stringify!($field))
61                     )?;
62                 )*
63             }
64         }
65         write_facts_to_path! {
66             wr.write_facts_to_path(self.[
67                 borrow_region,
68                 universal_region,
69                 placeholder,
70                 cfg_edge,
71                 killed,
72                 outlives,
73                 invalidates,
74                 var_used_at,
75                 var_defined_at,
76                 var_dropped_at,
77                 use_of_var_derefs_origin,
78                 drop_of_var_derefs_origin,
79                 child_path,
80                 path_is_var,
81                 path_assigned_at_base,
82                 path_moved_at_base,
83                 path_accessed_at_base,
84                 known_subset,
85             ])
86         }
87         Ok(())
88     }
89 }
90
91 impl Atom for BorrowIndex {
92     fn index(self) -> usize {
93         Idx::index(self)
94     }
95 }
96
97 impl Atom for LocationIndex {
98     fn index(self) -> usize {
99         Idx::index(self)
100     }
101 }
102
103 impl Atom for MovePathIndex {
104     fn index(self) -> usize {
105         Idx::index(self)
106     }
107 }
108
109 struct FactWriter<'w> {
110     location_table: &'w LocationTable,
111     dir: &'w Path,
112 }
113
114 impl<'w> FactWriter<'w> {
115     fn write_facts_to_path<T>(&self, rows: &[T], file_name: &str) -> Result<(), Box<dyn Error>>
116     where
117         T: FactRow,
118     {
119         let file = &self.dir.join(file_name);
120         let mut file = BufWriter::new(File::create(file)?);
121         for row in rows {
122             row.write(&mut file, self.location_table)?;
123         }
124         Ok(())
125     }
126 }
127
128 trait FactRow {
129     fn write(
130         &self,
131         out: &mut dyn Write,
132         location_table: &LocationTable,
133     ) -> Result<(), Box<dyn Error>>;
134 }
135
136 impl FactRow for RegionVid {
137     fn write(
138         &self,
139         out: &mut dyn Write,
140         location_table: &LocationTable,
141     ) -> Result<(), Box<dyn Error>> {
142         write_row(out, location_table, &[self])
143     }
144 }
145
146 impl<A, B> FactRow for (A, B)
147 where
148     A: FactCell,
149     B: FactCell,
150 {
151     fn write(
152         &self,
153         out: &mut dyn Write,
154         location_table: &LocationTable,
155     ) -> Result<(), Box<dyn Error>> {
156         write_row(out, location_table, &[&self.0, &self.1])
157     }
158 }
159
160 impl<A, B, C> FactRow for (A, B, C)
161 where
162     A: FactCell,
163     B: FactCell,
164     C: FactCell,
165 {
166     fn write(
167         &self,
168         out: &mut dyn Write,
169         location_table: &LocationTable,
170     ) -> Result<(), Box<dyn Error>> {
171         write_row(out, location_table, &[&self.0, &self.1, &self.2])
172     }
173 }
174
175 impl<A, B, C, D> FactRow for (A, B, C, D)
176 where
177     A: FactCell,
178     B: FactCell,
179     C: FactCell,
180     D: FactCell,
181 {
182     fn write(
183         &self,
184         out: &mut dyn Write,
185         location_table: &LocationTable,
186     ) -> Result<(), Box<dyn Error>> {
187         write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
188     }
189 }
190
191 fn write_row(
192     out: &mut dyn Write,
193     location_table: &LocationTable,
194     columns: &[&dyn FactCell],
195 ) -> Result<(), Box<dyn Error>> {
196     for (index, c) in columns.iter().enumerate() {
197         let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
198         write!(out, "{:?}{}", c.to_string(location_table), tail)?;
199     }
200     Ok(())
201 }
202
203 trait FactCell {
204     fn to_string(&self, location_table: &LocationTable) -> String;
205 }
206
207 impl<A: Debug> FactCell for A {
208     default fn to_string(&self, _location_table: &LocationTable) -> String {
209         format!("{:?}", self)
210     }
211 }
212
213 impl FactCell for LocationIndex {
214     fn to_string(&self, location_table: &LocationTable) -> String {
215         format!("{:?}", location_table.to_location(*self))
216     }
217 }