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 : #ifndef RUST_AST_STATEMENT_H
20 : #define RUST_AST_STATEMENT_H
21 :
22 : #include "optional.h"
23 : #include "rust-ast.h"
24 : #include "rust-path.h"
25 : #include "rust-expr.h"
26 : #include "rust-system.h"
27 :
28 : namespace Rust {
29 : namespace AST {
30 : // Just a semi-colon, which apparently is a statement.
31 130 : class EmptyStmt : public Stmt
32 : {
33 : location_t locus;
34 :
35 : // TODO: find another way to store this to save memory?
36 : bool marked_for_strip = false;
37 :
38 : public:
39 0 : std::string as_string () const override { return std::string (1, ';'); }
40 :
41 48 : EmptyStmt (location_t locus) : locus (locus) {}
42 :
43 46 : location_t get_locus () const override final { return locus; }
44 :
45 : void accept_vis (ASTVisitor &vis) override;
46 :
47 : // Can't think of any invalid invariants, so store boolean.
48 0 : void mark_for_strip () override { marked_for_strip = true; }
49 162 : bool is_marked_for_strip () const override { return marked_for_strip; }
50 :
51 0 : bool is_item () const override final { return false; }
52 :
53 226 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Empty; }
54 :
55 : protected:
56 : /* Use covariance to implement clone function as returning this object rather
57 : * than base */
58 130 : EmptyStmt *clone_stmt_impl () const override { return new EmptyStmt (*this); }
59 : };
60 :
61 : /* Variable assignment let statement - type of "declaration statement" as it
62 : * introduces new name into scope */
63 : class LetStmt : public Stmt
64 : {
65 : // bool has_outer_attrs;
66 : std::vector<Attribute> outer_attrs;
67 :
68 : std::unique_ptr<Pattern> variables_pattern;
69 :
70 : // bool has_type;
71 : std::unique_ptr<Type> type;
72 :
73 : // bool has_init_expr;
74 : std::unique_ptr<Expr> init_expr;
75 :
76 : tl::optional<std::unique_ptr<Expr>> else_expr;
77 :
78 : location_t locus;
79 :
80 : public:
81 : Type *inferedType;
82 :
83 : // Returns whether let statement has outer attributes.
84 : bool has_outer_attrs () const { return !outer_attrs.empty (); }
85 :
86 : // Returns whether let statement has a given return type.
87 320389 : bool has_type () const { return type != nullptr; }
88 :
89 : // Returns whether let statement has an initialisation expression.
90 320120 : bool has_init_expr () const { return init_expr != nullptr; }
91 26819 : bool has_else_expr () const { return else_expr.has_value (); }
92 :
93 : std::string as_string () const override;
94 :
95 13119 : LetStmt (std::unique_ptr<Pattern> variables_pattern,
96 : std::unique_ptr<Expr> init_expr, std::unique_ptr<Type> type,
97 : tl::optional<std::unique_ptr<Expr>> else_expr,
98 : std::vector<Attribute> outer_attrs, location_t locus)
99 26238 : : outer_attrs (std::move (outer_attrs)),
100 13119 : variables_pattern (std::move (variables_pattern)),
101 13119 : type (std::move (type)), init_expr (std::move (init_expr)),
102 13119 : else_expr (std::move (else_expr)), locus (locus)
103 13119 : {}
104 :
105 : // Copy constructor with clone
106 13748 : LetStmt (LetStmt const &other)
107 13748 : : outer_attrs (other.outer_attrs), locus (other.locus)
108 : {
109 : // guard to prevent null dereference (only required if error state)
110 13748 : if (other.variables_pattern != nullptr)
111 13748 : variables_pattern = other.variables_pattern->clone_pattern ();
112 :
113 : // guard to prevent null dereference (always required)
114 13748 : if (other.init_expr != nullptr)
115 12676 : init_expr = other.init_expr->clone_expr ();
116 13748 : if (other.else_expr.has_value ())
117 5 : else_expr = other.else_expr.value ()->clone_expr ();
118 :
119 13748 : if (other.type != nullptr)
120 2069 : type = other.type->clone_type ();
121 13748 : }
122 :
123 : // Overloaded assignment operator to clone
124 : LetStmt &operator= (LetStmt const &other)
125 : {
126 : outer_attrs = other.outer_attrs;
127 : locus = other.locus;
128 :
129 : // guard to prevent null dereference (only required if error state)
130 : if (other.variables_pattern != nullptr)
131 : variables_pattern = other.variables_pattern->clone_pattern ();
132 : else
133 : variables_pattern = nullptr;
134 :
135 : // guard to prevent null dereference (always required)
136 : if (other.init_expr != nullptr)
137 : init_expr = other.init_expr->clone_expr ();
138 : else
139 : init_expr = nullptr;
140 :
141 : if (other.else_expr != nullptr)
142 : else_expr = other.else_expr.value ()->clone_expr ();
143 : else
144 : else_expr = tl::nullopt;
145 :
146 : if (other.type != nullptr)
147 : type = other.type->clone_type ();
148 : else
149 : type = nullptr;
150 :
151 : return *this;
152 : }
153 :
154 : // move constructors
155 : LetStmt (LetStmt &&other) = default;
156 : LetStmt &operator= (LetStmt &&other) = default;
157 :
158 14113 : location_t get_locus () const override final { return locus; }
159 :
160 : void accept_vis (ASTVisitor &vis) override;
161 :
162 : // Invalid if pattern is null, so base stripping on that.
163 0 : void mark_for_strip () override { variables_pattern = nullptr; }
164 36940 : bool is_marked_for_strip () const override
165 : {
166 36940 : return variables_pattern == nullptr;
167 : }
168 :
169 : // TODO: this mutable getter seems really dodgy. Think up better way.
170 291220 : std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
171 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
172 :
173 : // TODO: is this better? Or is a "vis_block" better?
174 258070 : Expr &get_init_expr ()
175 : {
176 258070 : rust_assert (has_init_expr ());
177 258070 : return *init_expr;
178 : }
179 :
180 10 : Expr &get_else_expr ()
181 : {
182 10 : rust_assert (has_else_expr ());
183 10 : return *else_expr.value ();
184 : }
185 :
186 36562 : std::unique_ptr<Expr> &get_init_expr_ptr ()
187 : {
188 36562 : rust_assert (has_init_expr ());
189 36562 : return init_expr;
190 : }
191 :
192 : std::unique_ptr<Expr> &get_else_expr_ptr ()
193 : {
194 : rust_assert (has_else_expr ());
195 : return else_expr.value ();
196 : }
197 :
198 279989 : Pattern &get_pattern ()
199 : {
200 279989 : rust_assert (variables_pattern != nullptr);
201 279989 : return *variables_pattern;
202 : }
203 :
204 40131 : std::unique_ptr<Pattern> &get_pattern_ptr ()
205 : {
206 40131 : rust_assert (variables_pattern != nullptr);
207 40131 : return variables_pattern;
208 : }
209 :
210 41987 : Type &get_type ()
211 : {
212 41987 : rust_assert (has_type ());
213 41987 : return *type;
214 : }
215 :
216 6599 : std::unique_ptr<Type> &get_type_ptr ()
217 : {
218 6599 : rust_assert (has_type ());
219 6599 : return type;
220 : }
221 :
222 0 : bool is_item () const override final { return false; }
223 49666 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Let; }
224 :
225 : protected:
226 : /* Use covariance to implement clone function as returning this object rather
227 : * than base */
228 13748 : LetStmt *clone_stmt_impl () const override { return new LetStmt (*this); }
229 : };
230 :
231 : // Expression statements (statements containing an expression)
232 : class ExprStmt : public Stmt
233 : {
234 : std::unique_ptr<Expr> expr;
235 : location_t locus;
236 : bool semicolon_followed;
237 :
238 : public:
239 9270 : location_t get_locus () const override final { return locus; }
240 :
241 0 : bool is_item () const override final { return false; }
242 :
243 12051 : bool is_expr () const override final { return true; }
244 :
245 : // Used for the last statement for statement macros with a trailing
246 : // semicolon.
247 238 : void add_semicolon () override final { semicolon_followed = true; }
248 :
249 : std::string as_string () const override;
250 :
251 33896 : Stmt::Kind get_stmt_kind () final { return Stmt::Kind::Expr; }
252 :
253 : std::vector<LetStmt *> locals;
254 :
255 9446 : ExprStmt (std::unique_ptr<Expr> &&expr, location_t locus,
256 : bool semicolon_followed)
257 18892 : : expr (std::move (expr)), locus (locus),
258 9446 : semicolon_followed (semicolon_followed)
259 : {}
260 :
261 : // Copy constructor with clone
262 15936 : ExprStmt (ExprStmt const &other)
263 15936 : : locus (other.locus), semicolon_followed (other.semicolon_followed)
264 : {
265 : // guard to prevent null dereference (only required if error state)
266 15936 : if (other.expr != nullptr)
267 15936 : expr = other.expr->clone_expr ();
268 15936 : }
269 :
270 : // Overloaded assignment operator to clone
271 : ExprStmt &operator= (ExprStmt const &other)
272 : {
273 : Stmt::operator= (other);
274 :
275 : // guard to prevent null dereference (only required if error state)
276 : if (other.expr != nullptr)
277 : expr = other.expr->clone_expr ();
278 : else
279 : expr = nullptr;
280 :
281 : locus = other.locus;
282 : semicolon_followed = other.semicolon_followed;
283 :
284 : return *this;
285 : }
286 :
287 : // move constructors
288 : ExprStmt (ExprStmt &&other) = default;
289 : ExprStmt &operator= (ExprStmt &&other) = default;
290 :
291 : void accept_vis (ASTVisitor &vis) override;
292 :
293 : // Invalid if expr is null, so base stripping on that.
294 18 : void mark_for_strip () override { expr = nullptr; }
295 92787 : bool is_marked_for_strip () const override { return expr == nullptr; }
296 :
297 : // TODO: is this better? Or is a "vis_block" better?
298 218974 : Expr &get_expr ()
299 : {
300 218974 : rust_assert (expr != nullptr);
301 218974 : return *expr;
302 : }
303 :
304 28529 : std::unique_ptr<Expr> &get_expr_ptr ()
305 : {
306 28529 : rust_assert (expr != nullptr);
307 28529 : return expr;
308 : }
309 :
310 59 : std::unique_ptr<Expr> take_expr ()
311 : {
312 59 : rust_assert (expr != nullptr);
313 59 : return std::move (expr);
314 : }
315 :
316 22176 : bool is_semicolon_followed () const { return semicolon_followed; }
317 :
318 : protected:
319 : /* Use covariance to implement clone function as returning this object rather
320 : * than base */
321 15936 : ExprStmt *clone_stmt_impl () const override { return new ExprStmt (*this); }
322 : };
323 :
324 : } // namespace AST
325 : } // namespace Rust
326 :
327 : #endif
|