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