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-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
|