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_EXPAND_VISITOR_H
20 : #define RUST_EXPAND_VISITOR_H
21 :
22 : #include "rust-ast-pointer-visitor.h"
23 : #include "rust-ast-visitor.h"
24 : #include "rust-item.h"
25 : #include "rust-macro-expand.h"
26 : #include "rust-proc-macro.h"
27 :
28 : namespace Rust {
29 :
30 : /**
31 : * Whether or not an attribute is builtin
32 : */
33 : bool is_builtin (AST::Attribute &attr);
34 :
35 : class ExpandVisitor : public AST::PointerVisitor
36 : {
37 : public:
38 10347 : ExpandVisitor (MacroExpander &expander)
39 10347 : : expander (expander), macro_invoc_expect_id (UNKNOWN_NODEID)
40 : {}
41 :
42 : /* Expand all of the macro invocations currently contained in a crate */
43 : void go (AST::Crate &crate);
44 :
45 : using AST::PointerVisitor::reseat;
46 : using AST::PointerVisitor::visit;
47 :
48 57502 : void reseat (std::unique_ptr<AST::Expr> &ptr) override
49 : {
50 57502 : maybe_expand_expr (ptr);
51 57502 : }
52 :
53 8137 : void reseat (std::unique_ptr<AST::Type> &ptr) override
54 : {
55 8137 : maybe_expand_type (ptr);
56 8137 : }
57 :
58 25541 : void reseat (std::unique_ptr<AST::TypeNoBounds> &ptr) override
59 : {
60 25541 : maybe_expand_type (ptr);
61 25541 : }
62 :
63 6985 : void reseat (std::unique_ptr<AST::Pattern> &ptr) override
64 : {
65 6985 : maybe_expand_pattern (ptr);
66 6985 : }
67 :
68 : /**
69 : * Maybe expand a macro invocation in lieu of an expression, type or pattern.
70 : *
71 : * @ptr Core guidelines R33, this function reseats the pointer.
72 : */
73 : void maybe_expand_expr (std::unique_ptr<AST::Expr> &ptr);
74 : void maybe_expand_type (std::unique_ptr<AST::Type> &ptr);
75 : void maybe_expand_type (std::unique_ptr<AST::TypeNoBounds> &type);
76 : void maybe_expand_pattern (std::unique_ptr<AST::Pattern> &ptr);
77 :
78 : /**
79 : * Expand all macro invocations in lieu of types within a vector of struct
80 : * fields
81 : */
82 : void expand_struct_fields (std::vector<AST::StructField> &fields);
83 :
84 : /**
85 : * Expand all macro invocations in lieu of types within a vector of tuple
86 : * fields
87 : */
88 : void expand_tuple_fields (std::vector<AST::TupleField> &fields);
89 :
90 : /**
91 : * Expand all macro invocations in lieu of types within a list of function
92 : * parameters
93 : */
94 : void
95 : expand_function_params (std::vector<std::unique_ptr<AST::Param>> ¶ms);
96 :
97 : /**
98 : * Expand all macro invocations in lieu of types within a list of generic
99 : * arguments
100 : */
101 : void expand_generic_args (AST::GenericArgs &args);
102 :
103 : /**
104 : * Expand a macro invocation in lieu of a qualified path type
105 : */
106 : void expand_qualified_path_type (AST::QualifiedPathType &path_type);
107 :
108 : /**
109 : * Expand all macro invocations in lieu of types within a list of closure
110 : * parameters
111 : */
112 : void expand_closure_params (std::vector<AST::ClosureParam> ¶ms);
113 : void expand_where_clause (AST::WhereClause &where_clause);
114 :
115 : /**
116 : * Expand a set of values, erasing them if they are marked for strip, and
117 : * replacing them with expanded macro nodes if necessary.
118 : * This function is slightly different from `expand_pointer_allow_strip` as
119 : * it can only be called in certain expansion contexts - where macro
120 : * invocations are allowed.
121 : *
122 : * @param ctx Context to use for macro expansion
123 : * @param values Iterable reference over values to replace or erase
124 : * @param extractor Function to call when replacing values with the content
125 : * of an expanded AST node
126 : */
127 : template <typename T, typename U>
128 25707 : void expand_macro_children (MacroExpander::ContextType ctx, T &values,
129 : U (AST::SingleASTNode::*extractor) (void))
130 : {
131 25707 : expander.push_context (ctx);
132 :
133 25707 : expand_macro_children (values, extractor);
134 :
135 25707 : expander.pop_context ();
136 25707 : }
137 :
138 : /**
139 : * Same as `expand_macro_children`, but does not push a context. This is
140 : * useful if you're already pushing the context manually anyway for proc macro
141 : * expansion, like in `expand_inner_{items, stmts}`
142 : */
143 : template <typename T, typename U>
144 92056 : void expand_macro_children (T &values,
145 : U (AST::SingleASTNode::*extractor) (void))
146 : {
147 231665 : for (auto it = values.begin (); it != values.end ();)
148 : {
149 139609 : auto &value = *it;
150 :
151 : // Perform expansion
152 139609 : NodeId old_expect = value->get_node_id ();
153 139609 : std::swap (macro_invoc_expect_id, old_expect);
154 139609 : value->accept_vis (*this);
155 139609 : std::swap (macro_invoc_expect_id, old_expect);
156 :
157 139609 : auto final_fragment = expander.take_expanded_fragment ();
158 :
159 : // FIXME: Is that correct? It seems *extremely* dodgy
160 139609 : if (final_fragment.should_expand ())
161 : {
162 833 : it = values.erase (it);
163 4016 : for (auto &node : final_fragment.get_nodes ())
164 : {
165 3183 : U new_node = (node.*extractor) ();
166 3183 : if (new_node != nullptr)
167 : {
168 3166 : it = values.insert (it, std::move (new_node));
169 3166 : it++;
170 : }
171 : }
172 : }
173 : else
174 : {
175 138776 : ++it;
176 : }
177 : }
178 92056 : }
179 :
180 : /**
181 : * Perform in-place expansion of procedural macros and macro invocations for
182 : * an item container or statement container, such as `AST::Crate`,
183 : * `AST::Module` or `AST::BlockExpr`. This function will insert the expanded
184 : * nodes in place, and replace macro invocations with their expanded nodes.
185 : *
186 : * @param values Vector of values to mutate in-place and append into
187 : */
188 : void expand_inner_items (std::vector<std::unique_ptr<AST::Item>> &values);
189 : void expand_inner_stmts (AST::BlockExpr &expr);
190 :
191 : // TODO: See if possible to make more specialization for Impl items, Block
192 : // stmts etc? This could allow us to remove expand_macro_children or at least
193 : // its extractor parameter
194 : /**
195 : * These functions allow to easily visit `std::unique_ptr`s as well as
196 : * _replace_ them when necessary, e.g when expanding macro invocations in a
197 : * list of expressions or types. The most generic version of the function will
198 : * simply call the visitor again on the pointer, but there are two
199 : * specializations for `std::unique_ptr<Expr>` and `std::unique_ptr<Type>` to
200 : * enable replacing as well.
201 : */
202 99539 : template <typename T> void visit (std::unique_ptr<T> &value)
203 : {
204 99539 : value->accept_vis (*this);
205 34337 : }
206 :
207 : template <typename T> void visit (std::unique_ptr<AST::Expr> &expr)
208 : {
209 : maybe_expand_expr (expr);
210 : }
211 :
212 : template <typename T> void visit (std::unique_ptr<AST::Type> &type)
213 : {
214 : maybe_expand_type (type);
215 : }
216 :
217 : void visit (AST::Crate &crate) override;
218 : void visit (AST::DelimTokenTree &) override;
219 : void visit (AST::AttrInputMetaItemContainer &) override;
220 : void visit (AST::IdentifierExpr &ident_expr) override;
221 : void visit (AST::LifetimeParam &) override;
222 : void visit (AST::ConstGenericParam &) override;
223 :
224 : void visit (AST::MacroInvocation ¯o_invoc) override;
225 :
226 : void visit (AST::PathInExpression &path) override;
227 : void visit (AST::TypePathSegmentGeneric &segment) override;
228 : void visit (AST::TypePathSegmentFunction &segment) override;
229 : void visit (AST::QualifiedPathInExpression &path) override;
230 : void visit (AST::QualifiedPathInType &path) override;
231 :
232 : void visit (AST::LiteralExpr &expr) override;
233 : void visit (AST::AttrInputLiteral &) override;
234 : void visit (AST::AttrInputMacro &) override;
235 : void visit (AST::MetaItemLitExpr &) override;
236 : void visit (AST::MetaItemPathExpr &) override;
237 : void visit (AST::ArithmeticOrLogicalExpr &expr) override;
238 : void visit (AST::ComparisonExpr &expr) override;
239 : void visit (AST::LazyBooleanExpr &expr) override;
240 : void visit (AST::TypeCastExpr &expr) override;
241 : void visit (AST::AssignmentExpr &expr) override;
242 : void visit (AST::CompoundAssignmentExpr &expr) override;
243 : void visit (AST::GroupedExpr &expr) override;
244 : void visit (AST::StructExprStruct &expr) override;
245 :
246 : void visit (AST::CallExpr &expr) override;
247 : void visit (AST::ClosureExprInner &expr) override;
248 :
249 : void visit (AST::BlockExpr &expr) override;
250 :
251 : void visit (AST::ClosureExprInnerTyped &expr) override;
252 : void visit (AST::ContinueExpr &expr) override;
253 : void visit (AST::IfExpr &expr) override;
254 : void visit (AST::IfExprConseqElse &expr) override;
255 : void visit (AST::IfLetExpr &expr) override;
256 : void visit (AST::IfLetExprConseqElse &expr) override;
257 : void visit (AST::TupleExpr &expr) override;
258 : void visit (AST::TypeParam ¶m) override;
259 : void visit (AST::LifetimeWhereClauseItem &) override;
260 : void visit (AST::TypeBoundWhereClauseItem &item) override;
261 : void visit (AST::Module &module) override;
262 : void visit (AST::ExternCrate &crate) override;
263 : void visit (AST::UseTreeGlob &) override;
264 : void visit (AST::UseTreeList &) override;
265 : void visit (AST::UseTreeRebind &) override;
266 : void visit (AST::UseDeclaration &use_decl) override;
267 : void visit (AST::Function &function) override;
268 : void visit (AST::StructStruct &struct_item) override;
269 : void visit (AST::TupleStruct &tuple_struct) override;
270 : void visit (AST::EnumItem &item) override;
271 : void visit (AST::EnumItemTuple &item) override;
272 : void visit (AST::EnumItemStruct &item) override;
273 : void visit (AST::EnumItemDiscriminant &item) override;
274 : void visit (AST::Union &union_item) override;
275 : void visit (AST::ConstantItem &const_item) override;
276 : void visit (AST::StaticItem &static_item) override;
277 : void visit (AST::Trait &trait) override;
278 : void visit (AST::InherentImpl &impl) override;
279 : void visit (AST::TraitImpl &impl) override;
280 : void visit (AST::ExternalTypeItem &item) override;
281 : void visit (AST::ExternalStaticItem &item) override;
282 : void visit (AST::ExternBlock &block) override;
283 :
284 : // I don't think it would be possible to strip macros without expansion
285 : void visit (AST::MacroMatchRepetition &) override;
286 : void visit (AST::MacroMatcher &) override;
287 : void visit (AST::MacroRulesDefinition &rules_def) override;
288 : void visit (AST::MetaItemPath &) override;
289 : void visit (AST::MetaItemSeq &) override;
290 : void visit (AST::MetaListPaths &) override;
291 : void visit (AST::MetaListNameValueStr &) override;
292 : void visit (AST::StructPatternFieldIdent &field) override;
293 : void visit (AST::GroupedPattern &pattern) override;
294 : void visit (AST::SlicePatternItemsNoRest &items) override;
295 : void visit (AST::SlicePatternItemsHasRest &items) override;
296 : void visit (AST::AltPattern &pattern) override;
297 : void visit (AST::TupleStructItemsNoRest &tuple_items) override;
298 : void visit (AST::TupleStructItemsHasRest &tuple_items) override;
299 : void visit (AST::TuplePatternItemsNoRest &tuple_items) override;
300 : void visit (AST::TuplePatternItemsHasRest &tuple_items) override;
301 :
302 : void visit (AST::LetStmt &stmt) override;
303 : void visit (AST::ExprStmt &stmt) override;
304 :
305 : void visit (AST::BareFunctionType &type) override;
306 : void visit (AST::FunctionParam ¶m) override;
307 : void visit (AST::VariadicParam ¶m) override;
308 : void visit (AST::SelfParam &type) override;
309 :
310 : template <typename T>
311 : void expand_inner_attribute (T &item, AST::SimplePath &Path);
312 :
313 : template <typename T>
314 : void visit_inner_using_attrs (T &item, std::vector<AST::Attribute> &attrs);
315 :
316 : template <typename T> void visit_inner_attrs (T &item);
317 :
318 : private:
319 : MacroExpander &expander;
320 : NodeId macro_invoc_expect_id;
321 :
322 : /**
323 : * Helper to expand all macro invocations in lieu of types within a vector of
324 : * fields (StructField or TupleField).
325 : */
326 7108 : template <typename T> void expand_fields (std::vector<T> &fields)
327 : {
328 17053 : for (auto &field : fields)
329 9945 : maybe_expand_type (field.get_field_type_ptr ());
330 7108 : }
331 : };
332 :
333 : } // namespace Rust
334 :
335 : #endif // RUST_EXPAND_VISITOR_H
|