Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-borrow-checker.h"
20 : #include "rust-borrow-checker-diagnostics.h"
21 : #include "rust-function-collector.h"
22 : #include "rust-bir-fact-collector.h"
23 : #include "rust-bir-builder.h"
24 : #include "rust-bir-dump.h"
25 : #include "polonius/rust-polonius.h"
26 :
27 : namespace Rust {
28 : namespace HIR {
29 :
30 : void
31 0 : dump_function_bir (const std::string &filename, BIR::Function &func,
32 : const std::string &name)
33 : {
34 0 : std::ofstream file;
35 0 : file.open (filename);
36 0 : if (file.fail ())
37 : {
38 0 : rust_error_at (UNKNOWN_LOCATION, "Failed to open file %s",
39 : filename.c_str ());
40 0 : return;
41 : }
42 0 : BIR::Dump (file, func, name).go ();
43 0 : file.close ();
44 0 : }
45 :
46 : void
47 11 : BorrowChecker::go (HIR::Crate &crate)
48 : {
49 11 : std::string crate_name;
50 :
51 11 : if (enable_dump_bir)
52 : {
53 0 : mkdir ("bir_dump", 0755);
54 0 : auto &mappings = Analysis::Mappings::get ();
55 0 : crate_name
56 0 : = *mappings.get_crate_name (crate.get_mappings ().get_crate_num ());
57 0 : mkdir ("nll_facts_gccrs", 0755);
58 : }
59 :
60 11 : FunctionCollector collector;
61 11 : collector.go (crate);
62 :
63 47 : for (auto func : collector.get_functions ())
64 : {
65 36 : rust_debug_loc (func->get_locus (), "\nChecking function %s\n",
66 36 : func->get_function_name ().as_string ().c_str ());
67 :
68 36 : BIR::BuilderContext ctx;
69 36 : BIR::Builder builder (ctx);
70 36 : auto bir = builder.build (*func);
71 :
72 36 : if (enable_dump_bir)
73 : {
74 0 : std::string filename = "bir_dump/" + crate_name + "."
75 0 : + func->get_function_name ().as_string ()
76 0 : + ".bir.dump";
77 0 : dump_function_bir (filename, bir,
78 0 : func->get_function_name ().as_string ());
79 0 : }
80 :
81 36 : auto facts = BIR::FactCollector::collect (bir);
82 :
83 36 : if (enable_dump_bir)
84 : {
85 0 : auto dir
86 0 : = "nll_facts_gccrs/" + func->get_function_name ().as_string ();
87 0 : mkdir (dir.c_str (), 0755);
88 0 : auto dump_facts_to_file
89 0 : = [&] (const std::string &suffix,
90 : void (Polonius::Facts::*fn) (std::ostream &) const) {
91 0 : std::string filename = "nll_facts_gccrs/"
92 0 : + func->get_function_name ().as_string ()
93 0 : + "/" + suffix + ".facts";
94 0 : std::ofstream file;
95 0 : file.open (filename);
96 0 : if (file.fail ())
97 : {
98 0 : abort ();
99 : }
100 :
101 : // Run dump
102 : // BEWARE: this callback charade is a workaround because gcc48
103 : // won't let me return a file from a function
104 0 : (facts.*fn) (file);
105 0 : };
106 :
107 0 : dump_facts_to_file ("loan_issued_at",
108 : &Polonius::Facts::dump_loan_issued_at);
109 0 : dump_facts_to_file ("loan_killed_at",
110 : &Polonius::Facts::dump_loan_killed_at);
111 0 : dump_facts_to_file ("loan_invalidated_at",
112 : &Polonius::Facts::dump_loan_invalidated_at);
113 0 : dump_facts_to_file ("subset_base",
114 : &Polonius::Facts::dump_subset_base);
115 0 : dump_facts_to_file ("universal_region",
116 : &Polonius::Facts::dump_universal_region);
117 0 : dump_facts_to_file ("cfg_edge", &Polonius::Facts::dump_cfg_edge);
118 0 : dump_facts_to_file ("var_used_at",
119 : &Polonius::Facts::dump_var_used_at);
120 0 : dump_facts_to_file ("var_defined_at",
121 : &Polonius::Facts::dump_var_defined_at);
122 0 : dump_facts_to_file ("var_dropped_at",
123 : &Polonius::Facts::dump_var_dropped_at);
124 0 : dump_facts_to_file ("use_of_var_derefs_origin",
125 : &Polonius::Facts::dump_use_of_var_derefs_origin);
126 0 : dump_facts_to_file ("drop_of_var_derefs_origin",
127 : &Polonius::Facts::dump_drop_of_var_derefs_origin);
128 0 : dump_facts_to_file ("child_path", &Polonius::Facts::dump_child_path);
129 0 : dump_facts_to_file ("path_is_var",
130 : &Polonius::Facts::dump_path_is_var);
131 0 : dump_facts_to_file ("known_placeholder_subset",
132 : &Polonius::Facts::dump_known_placeholder_subset);
133 0 : dump_facts_to_file ("path_moved_at_base",
134 : &Polonius::Facts::dump_path_moved_at_base);
135 0 : dump_facts_to_file ("path_accessed_at_base",
136 : &Polonius::Facts::dump_path_accessed_at_base);
137 0 : dump_facts_to_file ("path_assigned_at_base",
138 : &Polonius::Facts::dump_path_assigned_at_base);
139 0 : dump_facts_to_file ("placeholder",
140 : &Polonius::Facts::dump_placeholder);
141 0 : }
142 :
143 36 : auto result
144 36 : = Polonius::polonius_run (facts.freeze (), rust_be_debug_p ());
145 :
146 : // convert to std::vector variation for easier navigation
147 36 : auto loan_errors = make_vector (result.loan_errors);
148 36 : auto move_errors = make_vector (result.move_errors);
149 36 : auto subset_errors = make_vector (result.subset_errors);
150 :
151 : // free allocated data
152 72 : delete result.loan_errors;
153 72 : delete result.move_errors;
154 72 : delete result.subset_errors;
155 :
156 36 : BIR::BorrowCheckerDiagnostics (func, bir, facts, move_errors, loan_errors,
157 36 : subset_errors)
158 36 : .report_errors ();
159 36 : }
160 :
161 11 : for (auto closure ATTRIBUTE_UNUSED : collector.get_closures ())
162 0 : rust_sorry_at (closure->get_locus (),
163 : "Closure borrow checking is not implemented yet.");
164 11 : }
165 :
166 : } // namespace HIR
167 : } // namespace Rust
|