Line data Source code
1 : // Copyright (C) 2024-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_BUILTIN_NODES_H
20 : #define RUST_AST_BUILTIN_NODES_H
21 :
22 : #include "rust-system.h"
23 : #include "line-map.h"
24 : #include "optional.h"
25 : #include "rust-ast.h"
26 : #include "rust-fmt.h"
27 :
28 : namespace Rust {
29 : namespace AST {
30 :
31 : // Definitions, from rustc's `FormatArgs` AST struct
32 : // https://github.com/rust-lang/rust/blob/1be468815c/compiler/rustc_ast/src/format.rs
33 : //
34 : // format_args!("hello {abc:.xyz$}!!", abc="world");
35 : // └──────────────────────────────────────────────┘
36 : // FormatArgs
37 : //
38 : // format_args!("hello {abc:.xyz$}!!", abc="world");
39 : // └─────────┘
40 : // argument
41 : //
42 : // format_args!("hello {abc:.xyz$}!!", abc="world");
43 : // └───────────────────┘
44 : // template
45 : //
46 : // format_args!("hello {abc:.xyz$}!!", abc="world");
47 : // └────┘└─────────┘└┘
48 : // pieces
49 : //
50 : // format_args!("hello {abc:.xyz$}!!", abc="world");
51 : // └────┘ └┘
52 : // literal pieces
53 : //
54 : // format_args!("hello {abc:.xyz$}!!", abc="world");
55 : // └─────────┘
56 : // placeholder
57 : //
58 : // format_args!("hello {abc:.xyz$}!!", abc="world");
59 : // └─┘ └─┘
60 : // positions (could be names, numbers, empty, or `*`)
61 :
62 : // FIXME: Merge with the class below this one?
63 4 : class FormatArgumentKind
64 : {
65 : public:
66 : enum class Kind
67 : {
68 : Normal,
69 : Named,
70 : Captured,
71 : } kind;
72 :
73 0 : Identifier &get_ident ()
74 : {
75 0 : rust_assert (kind == Kind::Captured || kind == Kind::Named);
76 :
77 0 : return ident.value ();
78 : }
79 :
80 4 : FormatArgumentKind (Kind kind, tl::optional<Identifier> ident)
81 8 : : kind (kind), ident (ident)
82 : {}
83 :
84 13 : FormatArgumentKind (const FormatArgumentKind &other)
85 13 : {
86 13 : kind = other.kind;
87 13 : ident = other.ident;
88 : }
89 :
90 : FormatArgumentKind operator= (const FormatArgumentKind &other)
91 : {
92 : kind = other.kind;
93 : ident = other.ident;
94 :
95 : return *this;
96 : }
97 :
98 : private:
99 : tl::optional<Identifier> ident;
100 : };
101 :
102 : class FormatArgument
103 : {
104 : public:
105 4 : static FormatArgument normal (std::unique_ptr<Expr> expr)
106 : {
107 4 : return FormatArgument (FormatArgumentKind::Kind::Normal, tl::nullopt,
108 4 : std::move (expr));
109 : }
110 :
111 0 : static FormatArgument named (Identifier ident, std::unique_ptr<Expr> expr)
112 : {
113 0 : return FormatArgument (FormatArgumentKind::Kind::Named, ident,
114 0 : std::move (expr));
115 : }
116 :
117 : static FormatArgument captured (Identifier ident, std::unique_ptr<Expr> expr)
118 : {
119 : return FormatArgument (FormatArgumentKind::Kind::Captured, ident,
120 : std::move (expr));
121 : }
122 :
123 9 : FormatArgument (const FormatArgument &other)
124 9 : : kind (other.kind), expr (other.expr->clone_expr ())
125 9 : {}
126 :
127 : FormatArgument operator= (const FormatArgument &other)
128 : {
129 : kind = other.kind;
130 : expr = other.expr->clone_expr ();
131 :
132 : return *this;
133 : }
134 :
135 4 : FormatArgumentKind get_kind () const { return kind; }
136 : const Expr &get_expr () const { return *expr; }
137 4 : Expr &get_expr () { return *expr; }
138 :
139 : private:
140 4 : FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
141 : std::unique_ptr<Expr> expr)
142 4 : : kind (FormatArgumentKind (kind, ident)), expr (std::move (expr))
143 4 : {}
144 :
145 : FormatArgumentKind kind;
146 : std::unique_ptr<Expr> expr;
147 : };
148 :
149 6 : class FormatArguments
150 : {
151 : public:
152 3 : FormatArguments () {}
153 3 : FormatArguments (FormatArguments &&) = default;
154 0 : FormatArguments (const FormatArguments &other)
155 0 : {
156 0 : args = std::vector<FormatArgument> ();
157 0 : args.reserve (other.args.size ());
158 :
159 0 : for (const auto &arg : other.args)
160 0 : args.emplace_back (arg);
161 0 : };
162 :
163 : FormatArguments &operator= (const FormatArguments &other) = default;
164 :
165 4 : void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
166 4 : const FormatArgument at (size_t idx) const { return args.at (idx); }
167 :
168 : const std::vector<FormatArgument> &get_args () const { return args; }
169 0 : std::vector<FormatArgument> &get_args () { return args; }
170 : size_t size () const { return args.size (); }
171 0 : bool empty () const { return args.empty (); }
172 :
173 : private:
174 : std::vector<FormatArgument> args;
175 : };
176 :
177 : // TODO: Format documentation better
178 : // Having a separate AST node for `format_args!()` expansion allows some
179 : // important optimizations which help reduce generated code a lot. For example,
180 : // turning `format_args!("a {} {} {}", 15, "hey", 'a')` directly into
181 : // `format_args!("a 15 hey a")`, since all arguments are literals. Or,
182 : // flattening imbricated `format_args!()` calls: `format_args!("heyo {}",
183 : // format_args!("result: {}", some_result))` -> `format_args!("heyo result: {}",
184 : // some_result)`
185 : // FIXME: Move to rust-macro.h
186 : class FormatArgs : public Expr
187 : {
188 : public:
189 : enum class Newline
190 : {
191 : Yes,
192 : No
193 : };
194 :
195 3 : FormatArgs (location_t loc, Fmt::Pieces &&template_str,
196 : FormatArguments &&arguments)
197 6 : : loc (loc), template_pieces (std::move (template_str)),
198 3 : arguments (std::move (arguments))
199 3 : {}
200 :
201 : FormatArgs (FormatArgs &&other) = default;
202 0 : FormatArgs (const FormatArgs &other) = default;
203 : FormatArgs &operator= (const FormatArgs &other) = default;
204 :
205 : void accept_vis (AST::ASTVisitor &vis) override;
206 :
207 3 : const Fmt::Pieces &get_template () const { return template_pieces; }
208 : const FormatArguments &get_arguments () const { return arguments; }
209 3 : FormatArguments &get_arguments () { return arguments; }
210 : virtual location_t get_locus () const override;
211 :
212 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::FormatArgs; }
213 :
214 : private:
215 : location_t loc;
216 : // FIXME: This probably needs to be a separate type - it is one in rustc's
217 : // expansion of format_args!(). There is extra handling associated with it.
218 : // we can maybe do that in rust-fmt.cc? in collect_pieces()? like do the
219 : // transformation into something we can handle better
220 : Fmt::Pieces template_pieces;
221 : FormatArguments arguments;
222 :
223 : bool marked_for_strip = false;
224 :
225 : protected:
226 : virtual std::string as_string () const override;
227 : virtual bool is_expr_without_block () const override;
228 : virtual void mark_for_strip () override;
229 : virtual bool is_marked_for_strip () const override;
230 : virtual std::vector<Attribute> &get_outer_attrs () override;
231 : virtual void set_outer_attrs (std::vector<Attribute>) override;
232 : virtual Expr *clone_expr_impl () const override;
233 : };
234 :
235 : /**
236 : * The node associated with the builtin offset_of!() macro
237 : */
238 : class OffsetOf : public Expr
239 : {
240 : public:
241 16 : OffsetOf (std::unique_ptr<Type> &&type, Identifier field, location_t loc)
242 16 : : type (std::move (type)), field (field), loc (loc)
243 16 : {}
244 :
245 96 : OffsetOf (const OffsetOf &other)
246 96 : : type (other.type->clone_type ()), field (other.field), loc (other.loc),
247 96 : marked_for_strip (other.marked_for_strip)
248 96 : {}
249 :
250 : OffsetOf &operator= (const OffsetOf &other)
251 : {
252 : type = other.type->clone_type ();
253 : field = other.field;
254 : loc = other.loc;
255 : marked_for_strip = other.marked_for_strip;
256 :
257 : return *this;
258 : }
259 :
260 : void accept_vis (AST::ASTVisitor &vis) override;
261 :
262 30 : virtual location_t get_locus () const override { return loc; }
263 : const Type &get_type () const { return *type; }
264 154 : Type &get_type () { return *type; }
265 30 : std::unique_ptr<Type> &get_type_ptr () { return type; }
266 15 : const Identifier &get_field () const { return field; }
267 :
268 0 : bool is_expr_without_block () const override { return false; }
269 :
270 0 : void mark_for_strip () override { marked_for_strip = true; }
271 30 : bool is_marked_for_strip () const override { return marked_for_strip; }
272 :
273 : std::string as_string () const override;
274 :
275 : std::vector<Attribute> &get_outer_attrs () override;
276 : void set_outer_attrs (std::vector<Attribute>) override;
277 : Expr *clone_expr_impl () const override;
278 :
279 15 : Expr::Kind get_expr_kind () const override { return Expr::Kind::OffsetOf; }
280 :
281 : private:
282 : std::unique_ptr<Type> type;
283 : Identifier field;
284 :
285 : location_t loc;
286 : bool marked_for_strip = false;
287 : };
288 :
289 : } // namespace AST
290 : } // namespace Rust
291 :
292 : #endif // ! RUST_AST_BUILTIN_NODES_H
|