Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-diagnostics.h"
20 : : #include "polonius/rust-polonius-ffi.h"
21 : : #include "rust-diagnostics.h"
22 : :
23 : : namespace Rust {
24 : : namespace BIR {
25 : :
26 : : void
27 : 36 : BorrowCheckerDiagnostics::report_errors ()
28 : : {
29 : 36 : report_move_errors ();
30 : 36 : report_loan_errors ();
31 : 36 : report_subset_errors ();
32 : 36 : }
33 : :
34 : : void
35 : 36 : BorrowCheckerDiagnostics::report_move_errors ()
36 : : {
37 : 39 : for (const auto &pair : move_errors)
38 : : {
39 : 3 : auto error_location = get_statement (pair.first).get_location ();
40 : :
41 : : // in future, we can use the assigned at location to hint the
42 : : // user to implement copy trait for the type
43 : : /*
44 : : for (auto it : facts.path_assigned_at_base)
45 : : {
46 : : if (pair.second[0] == it.first)
47 : : {
48 : : auto point_assigned_at = it.second;
49 : : auto assigned_at_location
50 : : = get_statement (point_assigned_at).get_location ();
51 : : }
52 : : }
53 : : */
54 : :
55 : 3 : std::vector<LabelLocationPair> labels{
56 : 3 : {"moved value used here", error_location}};
57 : : // add labels to all the moves for the given path
58 : 50 : for (auto it : facts.path_moved_at_base)
59 : : {
60 : 47 : if (pair.second[0] == it.first)
61 : : {
62 : 14 : auto point_moved_at = it.second;
63 : : // don't label the move location where the error occured
64 : 14 : if (pair.first != point_moved_at)
65 : : {
66 : 11 : auto move_at_location
67 : 11 : = get_statement (point_moved_at).get_location ();
68 : 11 : labels.push_back ({"value moved here", move_at_location});
69 : : }
70 : : }
71 : : }
72 : 3 : multi_label_error ("use of moved value", error_location, labels);
73 : 3 : }
74 : 36 : }
75 : :
76 : : void
77 : 36 : BorrowCheckerDiagnostics::report_loan_errors ()
78 : : {
79 : 52 : for (const auto &pair : loan_errors)
80 : : {
81 : 16 : auto error_location = get_statement (pair.first).get_location ();
82 : 32 : for (const auto &loan : pair.second)
83 : : {
84 : 16 : auto loan_struct = get_loan (loan);
85 : 16 : multi_label_error ("use of borrowed value", error_location,
86 : : {{"borrow occurs here", loan_struct.location},
87 : : {"borrowed value used here", error_location}});
88 : : }
89 : : }
90 : 36 : }
91 : :
92 : : void
93 : 36 : BorrowCheckerDiagnostics::report_subset_errors ()
94 : : {
95 : : // remove duplicates in subset_errors
96 : : //
97 : : // Polonius may output subset errors for same 2 origins at multiple points
98 : : // so to avoid duplicating the errors, we can remove the elements in subset
99 : : // errors with same origin pair
100 : 36 : std::vector<std::pair<size_t, std::pair<size_t, size_t>>>
101 : 36 : deduplicated_subset_errors;
102 : :
103 : 46 : for (auto pair : subset_errors)
104 : : {
105 : 10 : auto it = std::find_if (
106 : : deduplicated_subset_errors.begin (), deduplicated_subset_errors.end (),
107 : 8 : [&pair] (std::pair<size_t, std::pair<size_t, size_t>> element) {
108 : 8 : return element.second == pair.second;
109 : : });
110 : 10 : if (it == deduplicated_subset_errors.end ())
111 : : {
112 : 2 : deduplicated_subset_errors.push_back (pair);
113 : : }
114 : : }
115 : 38 : for (const auto &error : deduplicated_subset_errors)
116 : : {
117 : 2 : auto first_lifetime_location
118 : 2 : = get_lifetime_param (error.second.first)->get_locus ();
119 : 2 : auto second_lifetime_location
120 : 2 : = get_lifetime_param (error.second.second)->get_locus ();
121 : 2 : multi_label_error (
122 : : "subset error, some lifetime constraints need to be added",
123 : : bir_function.location,
124 : : {{"lifetime defined here", first_lifetime_location},
125 : : {"lifetime defined here", second_lifetime_location},
126 : 2 : {"subset error occurs in this function", bir_function.location}});
127 : : }
128 : 36 : }
129 : :
130 : : const BIR::Statement &
131 : 30 : BorrowCheckerDiagnostics::get_statement (Polonius::Point point)
132 : : {
133 : 30 : auto statement_index = Polonius::FullPoint::extract_stmt (point);
134 : 30 : auto bb_index = Polonius::FullPoint::extract_bb (point);
135 : : // assert that the extracted indexes are valid
136 : 30 : rust_assert (bb_index < bir_function.basic_blocks.size ());
137 : 30 : rust_assert (statement_index
138 : : < bir_function.basic_blocks[{bb_index}].statements.size ());
139 : 30 : return bir_function.basic_blocks[{bb_index}].statements[statement_index];
140 : : }
141 : :
142 : : const BIR::Loan &
143 : 16 : BorrowCheckerDiagnostics::get_loan (Polonius::Loan loan)
144 : : {
145 : 16 : return bir_function.place_db.get_loans ()[{(uint32_t) loan}];
146 : : }
147 : :
148 : : const HIR::LifetimeParam *
149 : 4 : BorrowCheckerDiagnostics::get_lifetime_param (Polonius::Origin origin)
150 : :
151 : : {
152 : 4 : return bir_function.region_hir_map.at (origin);
153 : : }
154 : :
155 : : void
156 : 21 : BorrowCheckerDiagnostics::multi_label_error (
157 : : const char *error_message, location_t error_location,
158 : : std::vector<LabelLocationPair> location_label_pairs)
159 : : {
160 : 21 : rich_location r{line_table, error_location};
161 : 73 : for (auto &label_location : location_label_pairs)
162 : : {
163 : 52 : r.add_range (label_location.location, SHOW_RANGE_WITHOUT_CARET,
164 : : &label_location.label);
165 : : }
166 : 21 : rust_error_at (r, "%s", error_message);
167 : 21 : }
168 : :
169 : : } // namespace BIR
170 : : } // namespace Rust
|