]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/checks/errors/borrowck/rust-bir-place.h
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / checks / errors / borrowck / rust-bir-place.h
CommitLineData
767698ff 1// Copyright (C) 2020-2024 Free Software Foundation, Inc.
dbd29204
JD
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#ifndef RUST_BIR_PLACE_H
20#define RUST_BIR_PLACE_H
21
22#include <limits>
23#include "rust-mapping-common.h"
24#include "rust-system.h"
25#include "rust-tyty.h"
26
27namespace Rust {
28namespace BIR {
29
30/** A unique identifier for a place in the BIR. */
31using PlaceId = uint32_t;
32
33static constexpr PlaceId INVALID_PLACE = 0;
34static constexpr PlaceId RETURN_VALUE_PLACE = 1;
35static constexpr PlaceId FIRST_VARIABLE_PLACE = RETURN_VALUE_PLACE;
36
37/**
38 * A unique identifier for a lifetime in the BIR. Only to be used INTERNALLY.
39 */
40using LifetimeID = uint32_t;
41
42constexpr LifetimeID INVALID_LIFETIME_ID = 0;
43constexpr LifetimeID STATIC_LIFETIME_ID = 1;
44constexpr LifetimeID FIRST_NORMAL_LIFETIME_ID = 2;
45
46/** Representation of lifetimes in BIR. */
47struct Lifetime
48{
49 LifetimeID id = INVALID_LIFETIME_ID;
50
51 constexpr Lifetime (LifetimeID id) : id (id) {}
52 constexpr Lifetime (const Lifetime &) = default;
53 WARN_UNUSED_RESULT bool has_lifetime () const
54 {
55 return id != INVALID_LIFETIME_ID;
56 }
57 LifetimeID operator() () const { return id; }
58};
59constexpr Lifetime NO_LIFETIME = {INVALID_LIFETIME_ID};
60constexpr Lifetime STATIC_LIFETIME = {STATIC_LIFETIME_ID};
61
62/**
63 * Representation of lvalues and constants in BIR.
64 * See bir bir design notes (in this directory) and the Polonius book.
65 */
66struct Place
67{
68 enum Kind
69 {
70 INVALID,
71 VARIABLE,
72 TEMPORARY,
73 CONSTANT,
74 FIELD,
75 INDEX,
76 DEREF,
77 };
78
79 Kind kind;
80 uint32_t variable_or_field_index; // NodeId for VARIABLE
81 /** Data for traversing paths in the PlaceDB. */
82 struct Path
83 {
84 PlaceId parent = INVALID_PLACE;
85 PlaceId first_child = INVALID_PLACE;
86 PlaceId next_sibling = INVALID_PLACE;
87
88 Path (PlaceId parent, PlaceId first_child, PlaceId next_sibling)
89 : parent (parent), first_child (first_child), next_sibling (next_sibling)
90 {}
91 Path () = default;
92 } path;
93 /** Copy trait */
94 bool is_copy;
95 /** This place can be moved from safety. */
96 bool is_rvalue;
97 Lifetime lifetime;
98 TyTy::BaseType *tyty;
99
100 Place (Kind kind, uint32_t variable_or_field_index, const Path &path,
101 bool is_copy, bool is_rvalue, const Lifetime &lifetime,
102 TyTy::BaseType *tyty)
103 : kind (kind), variable_or_field_index (variable_or_field_index),
104 path (path), is_copy (is_copy), is_rvalue (is_rvalue),
105 lifetime (lifetime), tyty (tyty)
106 {}
107};
108
109/** Allocated places and keeps track of paths. */
110class PlaceDB
111{
112 // Possible optimizations: separate variables to speedup lookup.
113 std::vector<Place> places;
114 std::unordered_map<TyTy::BaseType *, PlaceId> constants_lookup;
115
116public:
117 PlaceDB ()
118 {
119 // Reserved index for invalid place.
120 places.push_back (
121 {Place::INVALID, 0, {}, false, false, NO_LIFETIME, nullptr});
122 }
123
124 Place &operator[] (PlaceId id) { return places.at (id); }
125 const Place &operator[] (PlaceId id) const { return places.at (id); }
126
127 size_t size () const { return places.size (); }
128
129 PlaceId add_place (Place place, PlaceId last_sibling = 0)
130 {
131 places.push_back (place);
132 PlaceId new_place = places.size () - 1;
133 if (last_sibling == 0)
134 {
135 places[place.path.parent].path.first_child = new_place;
136 }
137 else
138 {
139 places[last_sibling].path.next_sibling = new_place;
140 }
141 return new_place;
142 }
143
144 PlaceId add_variable (NodeId id, TyTy::BaseType *tyty)
145 {
146 return add_place (
147 {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty},
148 0);
149 }
150
35d5f82e
JD
151 WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind,
152 TyTy::BaseType *tyty,
153 PlaceId parent, size_t id = 0)
dbd29204
JD
154 {
155 PlaceId current = 0;
156 if (parent < places.size ())
157 {
158 current = places[parent].path.first_child;
159 while (current != 0)
160 {
161 if (places[current].kind == kind
162 && places[current].variable_or_field_index == id)
163 {
164 rust_assert (places[current].tyty->is_equal (*tyty));
165 return current;
166 }
167 current = places[current].path.next_sibling;
168 }
169 }
170 return add_place (
171 {kind, id, {parent, 0, 0}, is_type_copy (tyty), false, NO_LIFETIME, tyty},
172 current);
173 }
174
32dcd3ec
JD
175 PlaceId add_temporary (TyTy::BaseType *tyty)
176 {
177 return add_place (
178 {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty},
179 0);
180 }
181
dbd29204
JD
182 PlaceId get_constant (TyTy::BaseType *tyty)
183 {
184 auto lookup = constants_lookup.find (tyty);
185 if (lookup != constants_lookup.end ())
186 return lookup->second;
187 Lifetime lifetime
188 = tyty->get_kind () == TyTy::REF ? STATIC_LIFETIME : NO_LIFETIME;
189 Place place
190 = {Place::CONSTANT, 0, {}, is_type_copy (tyty), false, lifetime, tyty};
191 places.push_back (place);
192 return places.size () - 1;
193 }
194
32dcd3ec
JD
195 PlaceId lookup_variable (NodeId id)
196 {
197 PlaceId current = FIRST_VARIABLE_PLACE;
198
199 while (current != places.size ())
200 {
201 if (places[current].kind == Place::VARIABLE
202 && places[current].variable_or_field_index == id)
203 return current;
204 current++;
205 }
206 return INVALID_PLACE;
207 };
208
209 PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty)
210 {
211 auto lookup = lookup_variable (id);
212 if (lookup != INVALID_PLACE)
213 return lookup;
c54326a8 214 add_place (
32dcd3ec
JD
215 {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty});
216 return places.size () - 1;
217 };
218
219 PlaceId into_rvalue (PlaceId place)
220 {
221 if (places[place].is_rvalue || places[place].kind == Place::CONSTANT
222 || places[place].tyty->get_kind () == TyTy::REF)
223 return place;
224 return add_place ({Place::TEMPORARY,
225 0,
226 {},
227 places[place].is_copy,
228 true,
229 NO_LIFETIME,
230 places[place].tyty});
231 }
232
dbd29204
JD
233private:
234 static bool is_type_copy (TyTy::BaseType *ty)
235 {
236 switch (ty->get_kind ())
237 {
238 case TyTy::REF:
239 case TyTy::POINTER:
240 case TyTy::SLICE:
241 case TyTy::BOOL:
242 case TyTy::CHAR:
243 case TyTy::INT:
244 case TyTy::UINT:
245 case TyTy::FLOAT:
246 case TyTy::USIZE:
247 case TyTy::ISIZE:
248 case TyTy::FNPTR:
249 case TyTy::FNDEF:
250 case TyTy::NEVER:
251 return true;
252 case TyTy::TUPLE: {
253 auto &fields = ty->as<TyTy::TupleType> ()->get_fields ();
254 return std::all_of (fields.begin (), fields.end (),
255 [] (const TyTy::TyVar &field) {
256 return is_type_copy (field.get_tyty ());
257 });
258 }
259 case TyTy::ARRAY: {
260 return is_type_copy (ty->as<TyTy::ArrayType> ()->get_element_type ());
261 }
262 case TyTy::INFER:
263 case TyTy::PARAM:
264 case TyTy::ERROR:
265 case TyTy::STR:
266 case TyTy::PLACEHOLDER:
267 rust_unreachable ();
268 case TyTy::ADT: // TODO: check trait
269 case TyTy::PROJECTION: // TODO: DUNNO
270 case TyTy::CLOSURE: // TODO: DUNNO
271 case TyTy::DYNAMIC: // TODO: dunno
272 return false;
273 }
274 rust_unreachable ();
275 }
276};
277
278} // namespace BIR
279} // namespace Rust
280
281#endif // RUST_BIR_PLACE_H