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