Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-early-name-resolver-2.0.h"
20 : : #include "rust-ast-full.h"
21 : : #include "rust-toplevel-name-resolver-2.0.h"
22 : : #include "rust-attributes.h"
23 : :
24 : : namespace Rust {
25 : : namespace Resolver2_0 {
26 : :
27 : 35 : Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
28 : :
29 : : void
30 : 16 : Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
31 : : {
32 : : // TODO: Should we use `ctx.mark_resolved()`?
33 : 16 : AST::MacroRulesDefinition *definition;
34 : 16 : auto ok = ctx.mappings.lookup_macro_def (resolved, &definition);
35 : :
36 : 16 : rust_assert (ok);
37 : :
38 : 16 : AST::MacroRulesDefinition *existing;
39 : 16 : auto exists = ctx.mappings.lookup_macro_invocation (invocation, &existing);
40 : :
41 : 16 : if (!exists)
42 : 16 : ctx.mappings.insert_macro_invocation (invocation, definition);
43 : 16 : }
44 : :
45 : : void
46 : 23 : Early::insert_once (AST::MacroRulesDefinition &def)
47 : : {
48 : : // TODO: Should we use `ctx.mark_resolved()`?
49 : 23 : AST::MacroRulesDefinition *definition;
50 : 23 : auto exists = ctx.mappings.lookup_macro_def (def.get_node_id (), &definition);
51 : :
52 : 23 : if (!exists)
53 : 0 : ctx.mappings.insert_macro_def (&def);
54 : 23 : }
55 : :
56 : : void
57 : 35 : Early::go (AST::Crate &crate)
58 : : {
59 : : // First we go through TopLevel resolution to get all our declared items
60 : 35 : auto toplevel = TopLevel (ctx);
61 : 35 : toplevel.go (crate);
62 : :
63 : 35 : textual_scope.push ();
64 : :
65 : : // Then we proceed to the proper "early" name resolution: Import and macro
66 : : // name resolution
67 : 139 : for (auto &item : crate.items)
68 : 104 : item->accept_vis (*this);
69 : :
70 : 35 : textual_scope.pop ();
71 : 35 : }
72 : :
73 : : void
74 : 151 : Early::TextualScope::push ()
75 : : {
76 : : // push a new empty scope
77 : 151 : scopes.emplace_back ();
78 : 151 : }
79 : :
80 : : void
81 : 151 : Early::TextualScope::pop ()
82 : : {
83 : 151 : rust_assert (!scopes.empty ());
84 : :
85 : 151 : scopes.pop_back ();
86 : 151 : }
87 : :
88 : : void
89 : 23 : Early::TextualScope::insert (std::string name, NodeId id)
90 : : {
91 : 23 : rust_assert (!scopes.empty ());
92 : :
93 : : // we can ignore the return value as we always want the latest defined macro
94 : : // to shadow a previous one - so if two macros have the same name and get
95 : : // inserted with the same key, it's not a bug
96 : 23 : scopes.back ().insert ({name, id});
97 : 23 : }
98 : :
99 : : tl::optional<NodeId>
100 : 10 : Early::TextualScope::get (const std::string &name)
101 : : {
102 : 24 : for (auto iterator = scopes.rbegin (); iterator != scopes.rend (); iterator++)
103 : : {
104 : 17 : auto scope = *iterator;
105 : 17 : auto found = scope.find (name);
106 : 17 : if (found != scope.end ())
107 : 3 : return found->second;
108 : 17 : }
109 : :
110 : 7 : return tl::nullopt;
111 : : }
112 : :
113 : : void
114 : 23 : Early::visit (AST::MacroRulesDefinition &def)
115 : : {
116 : 23 : DefaultResolver::visit (def);
117 : :
118 : 23 : textual_scope.insert (def.get_rule_name ().as_string (), def.get_node_id ());
119 : 23 : insert_once (def);
120 : 23 : }
121 : :
122 : : void
123 : 71 : Early::visit (AST::BlockExpr &block)
124 : : {
125 : 71 : textual_scope.push ();
126 : :
127 : 71 : DefaultResolver::visit (block);
128 : :
129 : 71 : textual_scope.pop ();
130 : 71 : }
131 : :
132 : : void
133 : 45 : Early::visit (AST::Module &module)
134 : : {
135 : 45 : textual_scope.push ();
136 : :
137 : 45 : DefaultResolver::visit (module);
138 : :
139 : 45 : textual_scope.pop ();
140 : 45 : }
141 : :
142 : : void
143 : 22 : Early::visit (AST::MacroInvocation &invoc)
144 : : {
145 : 22 : auto path = invoc.get_invoc_data ().get_path ();
146 : :
147 : : // When a macro is invoked by an unqualified identifier (not part of a
148 : : // multi-part path), it is first looked up in textual scoping. If this does
149 : : // not yield any results, then it is looked up in path-based scoping. If the
150 : : // macro's name is qualified with a path, then it is only looked up in
151 : : // path-based scoping.
152 : :
153 : : // https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
154 : :
155 : 22 : tl::optional<Rib::Definition> definition = tl::nullopt;
156 : 22 : if (path.get_segments ().size () == 1)
157 : 10 : definition
158 : 10 : = textual_scope.get (path.get_final_segment ().as_string ())
159 : 16 : .map ([] (NodeId id) { return Rib::Definition::NonShadowable (id); });
160 : :
161 : : // we won't have changed `definition` from `nullopt` if there are more
162 : : // than one segments in our path
163 : 22 : if (!definition.has_value ())
164 : 32 : definition = ctx.macros.resolve_path (path.get_segments ());
165 : :
166 : : // if the definition still does not have a value, then it's an error
167 : 22 : if (!definition.has_value ())
168 : : {
169 : 12 : collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
170 : 6 : "could not resolve macro invocation"));
171 : 6 : return;
172 : : }
173 : :
174 : 16 : insert_once (invoc, definition->get_node_id ());
175 : :
176 : : // now do we need to keep mappings or something? or insert "uses" into our
177 : : // ForeverStack? can we do that? are mappings simpler?
178 : 16 : auto mappings = Analysis::Mappings::get ();
179 : 16 : AST::MacroRulesDefinition *rules_def = nullptr;
180 : 16 : if (!mappings->lookup_macro_def (definition->get_node_id (), &rules_def))
181 : : {
182 : : // Macro definition not found, maybe it is not expanded yet.
183 : : return;
184 : : }
185 : :
186 : 16 : AST::MacroRulesDefinition *tmp_def = nullptr;
187 : 16 : if (mappings->lookup_macro_invocation (invoc, &tmp_def))
188 : : return;
189 : :
190 : 0 : mappings->insert_macro_invocation (invoc, rules_def);
191 : 22 : }
192 : :
193 : : void
194 : 81 : Early::visit_attributes (std::vector<AST::Attribute> &attrs)
195 : : {
196 : 81 : auto mappings = Analysis::Mappings::get ();
197 : :
198 : 83 : for (auto &attr : attrs)
199 : : {
200 : 2 : auto name = attr.get_path ().get_segments ().at (0).get_segment_name ();
201 : :
202 : 2 : if (attr.is_derive ())
203 : : {
204 : 0 : auto traits = attr.get_traits_to_derive ();
205 : 0 : for (auto &trait : traits)
206 : : {
207 : 0 : auto definition
208 : 0 : = ctx.macros.resolve_path (trait.get ().get_segments ());
209 : 0 : if (!definition.has_value ())
210 : : {
211 : : // FIXME: Change to proper error message
212 : 0 : rust_error_at (trait.get ().get_locus (),
213 : : "could not resolve trait");
214 : 0 : continue;
215 : : }
216 : :
217 : 0 : auto pm_def = mappings->lookup_derive_proc_macro_def (
218 : : definition->get_node_id ());
219 : :
220 : 0 : rust_assert (pm_def.has_value ());
221 : :
222 : 0 : mappings->insert_derive_proc_macro_invocation (trait,
223 : 0 : pm_def.value ());
224 : 0 : }
225 : 0 : }
226 : 4 : else if (Analysis::BuiltinAttributeMappings::get ()
227 : 2 : ->lookup_builtin (name)
228 : 2 : .is_error ()) // Do not resolve builtins
229 : : {
230 : 0 : auto definition
231 : 0 : = ctx.macros.resolve_path (attr.get_path ().get_segments ());
232 : 0 : if (!definition.has_value ())
233 : : {
234 : : // FIXME: Change to proper error message
235 : 0 : rust_error_at (attr.get_locus (),
236 : : "could not resolve attribute macro invocation");
237 : 0 : return;
238 : : }
239 : 0 : auto pm_def = mappings->lookup_attribute_proc_macro_def (
240 : : definition->get_node_id ());
241 : :
242 : 0 : rust_assert (pm_def.has_value ());
243 : :
244 : 0 : mappings->insert_attribute_proc_macro_invocation (attr.get_path (),
245 : 0 : pm_def.value ());
246 : 0 : }
247 : 2 : }
248 : : }
249 : :
250 : : void
251 : 69 : Early::visit (AST::Function &fn)
252 : : {
253 : 69 : visit_attributes (fn.get_outer_attrs ());
254 : 69 : DefaultResolver::visit (fn);
255 : 69 : }
256 : :
257 : : void
258 : 12 : Early::visit (AST::StructStruct &s)
259 : : {
260 : 12 : visit_attributes (s.get_outer_attrs ());
261 : 12 : DefaultResolver::visit (s);
262 : 12 : }
263 : :
264 : : } // namespace Resolver2_0
265 : : } // namespace Rust
|