]>
Commit | Line | Data |
---|---|---|
e1599b0c XL |
1 | //! A bunch of methods and structures more or less related to resolving macros and |
2 | //! interface provided by `Resolver` to macro expander. | |
3 | ||
dfeec247 | 4 | use crate::imports::ImportResolver; |
9fa01778 | 5 | use crate::Namespace::*; |
dfeec247 XL |
6 | use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; |
7 | use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; | |
8 | use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; | |
f9f354fc | 9 | use rustc_ast::ast::{self, NodeId}; |
74b04a01 XL |
10 | use rustc_ast_pretty::pprust; |
11 | use rustc_attr::{self as attr, StabilityLevel}; | |
dfeec247 XL |
12 | use rustc_data_structures::fx::FxHashSet; |
13 | use rustc_expand::base::SyntaxExtension; | |
14 | use rustc_expand::base::{self, Indeterminate, InvocationRes}; | |
15 | use rustc_expand::compile_declarative_macro; | |
16 | use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; | |
60c5eb7d | 17 | use rustc_feature::is_builtin_attr_name; |
dfeec247 XL |
18 | use rustc_hir::def::{self, DefKind, NonMacroAttrKind}; |
19 | use rustc_hir::def_id; | |
ba9703b0 XL |
20 | use rustc_middle::middle::stability; |
21 | use rustc_middle::{span_bug, ty}; | |
22 | use rustc_session::lint::builtin::UNUSED_MACROS; | |
23 | use rustc_session::Session; | |
dfeec247 XL |
24 | use rustc_span::edition::Edition; |
25 | use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind}; | |
f9f354fc | 26 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
dfeec247 | 27 | use rustc_span::{Span, DUMMY_SP}; |
9e0c209e | 28 | |
0531ce1d | 29 | use rustc_data_structures::sync::Lrc; |
dfeec247 XL |
30 | use rustc_span::hygiene::{AstPass, MacroKind}; |
31 | use std::{mem, ptr}; | |
b7449926 | 32 | |
e1599b0c | 33 | type Res = def::Res<NodeId>; |
c30ab7b3 | 34 | |
b7449926 | 35 | /// Binding produced by a `macro_rules` item. |
ba9703b0 | 36 | /// Not modularized, can shadow previous `macro_rules` bindings, etc. |
0bf4aa26 | 37 | #[derive(Debug)] |
ba9703b0 | 38 | pub struct MacroRulesBinding<'a> { |
416331ca | 39 | crate binding: &'a NameBinding<'a>, |
ba9703b0 XL |
40 | /// `macro_rules` scope into which the `macro_rules` item was planted. |
41 | crate parent_macro_rules_scope: MacroRulesScope<'a>, | |
416331ca | 42 | crate ident: Ident, |
b7449926 XL |
43 | } |
44 | ||
9fa01778 XL |
45 | /// The scope introduced by a `macro_rules!` macro. |
46 | /// This starts at the macro's definition and ends at the end of the macro's parent | |
47 | /// module (named or unnamed), or even further if it escapes with `#[macro_use]`. | |
ba9703b0 | 48 | /// Some macro invocations need to introduce `macro_rules` scopes too because they |
9fa01778 | 49 | /// can potentially expand into macro definitions. |
0bf4aa26 | 50 | #[derive(Copy, Clone, Debug)] |
ba9703b0 | 51 | pub enum MacroRulesScope<'a> { |
b7449926 | 52 | /// Empty "root" scope at the crate start containing no names. |
c30ab7b3 | 53 | Empty, |
9fa01778 | 54 | /// The scope introduced by a `macro_rules!` macro definition. |
ba9703b0 | 55 | Binding(&'a MacroRulesBinding<'a>), |
9fa01778 | 56 | /// The scope introduced by a macro invocation that can potentially |
b7449926 | 57 | /// create a `macro_rules!` macro definition. |
e1599b0c | 58 | Invocation(ExpnId), |
c30ab7b3 SL |
59 | } |
60 | ||
b7449926 XL |
61 | // Macro namespace is separated into two sub-namespaces, one for bang macros and |
62 | // one for attribute-like macros (attributes, derives). | |
63 | // We ignore resolutions from one sub-namespace when searching names in scope for another. | |
13cf67c4 | 64 | fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool { |
b7449926 | 65 | #[derive(PartialEq)] |
dfeec247 XL |
66 | enum SubNS { |
67 | Bang, | |
68 | AttrLike, | |
69 | } | |
b7449926 | 70 | let sub_ns = |kind| match kind { |
416331ca XL |
71 | MacroKind::Bang => SubNS::Bang, |
72 | MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, | |
b7449926 | 73 | }; |
416331ca XL |
74 | let candidate = candidate.map(sub_ns); |
75 | let requirement = requirement.map(sub_ns); | |
b7449926 | 76 | // "No specific sub-namespace" means "matches anything" for both requirements and candidates. |
13cf67c4 | 77 | candidate.is_none() || requirement.is_none() || candidate == requirement |
cc61c64b XL |
78 | } |
79 | ||
dc9dc135 XL |
80 | // We don't want to format a path using pretty-printing, |
81 | // `format!("{}", path)`, because that tries to insert | |
82 | // line-breaks and is slow. | |
416331ca XL |
83 | fn fast_print_path(path: &ast::Path) -> Symbol { |
84 | if path.segments.len() == 1 { | |
ba9703b0 | 85 | path.segments[0].ident.name |
416331ca XL |
86 | } else { |
87 | let mut path_str = String::with_capacity(64); | |
88 | for (i, segment) in path.segments.iter().enumerate() { | |
89 | if i != 0 { | |
90 | path_str.push_str("::"); | |
91 | } | |
92 | if segment.ident.name != kw::PathRoot { | |
93 | path_str.push_str(&segment.ident.as_str()) | |
94 | } | |
dc9dc135 | 95 | } |
416331ca | 96 | Symbol::intern(&path_str) |
dc9dc135 | 97 | } |
dc9dc135 XL |
98 | } |
99 | ||
60c5eb7d XL |
100 | /// The code common between processing `#![register_tool]` and `#![register_attr]`. |
101 | fn registered_idents( | |
102 | sess: &Session, | |
103 | attrs: &[ast::Attribute], | |
104 | attr_name: Symbol, | |
105 | descr: &str, | |
106 | ) -> FxHashSet<Ident> { | |
107 | let mut registered = FxHashSet::default(); | |
108 | for attr in attr::filter_by_name(attrs, attr_name) { | |
109 | for nested_meta in attr.meta_item_list().unwrap_or_default() { | |
110 | match nested_meta.ident() { | |
dfeec247 XL |
111 | Some(ident) => { |
112 | if let Some(old_ident) = registered.replace(ident) { | |
113 | let msg = format!("{} `{}` was already registered", descr, ident); | |
114 | sess.struct_span_err(ident.span, &msg) | |
115 | .span_label(old_ident.span, "already registered here") | |
116 | .emit(); | |
117 | } | |
60c5eb7d XL |
118 | } |
119 | None => { | |
120 | let msg = format!("`{}` only accepts identifiers", attr_name); | |
121 | let span = nested_meta.span(); | |
122 | sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit(); | |
123 | } | |
124 | } | |
125 | } | |
126 | } | |
127 | registered | |
128 | } | |
129 | ||
130 | crate fn registered_attrs_and_tools( | |
131 | sess: &Session, | |
132 | attrs: &[ast::Attribute], | |
133 | ) -> (FxHashSet<Ident>, FxHashSet<Ident>) { | |
134 | let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute"); | |
135 | let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool"); | |
136 | // We implicitly add `rustfmt` and `clippy` to known tools, | |
137 | // but it's not an error to register them explicitly. | |
138 | let predefined_tools = [sym::clippy, sym::rustfmt]; | |
139 | registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); | |
140 | (registered_attrs, registered_tools) | |
141 | } | |
142 | ||
0731742a | 143 | impl<'a> base::Resolver for Resolver<'a> { |
e1599b0c | 144 | fn next_node_id(&mut self) -> NodeId { |
60c5eb7d | 145 | self.next_node_id() |
9e0c209e SL |
146 | } |
147 | ||
416331ca XL |
148 | fn resolve_dollar_crates(&mut self) { |
149 | hygiene::update_dollar_crate_names(|ctxt| { | |
150 | let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); | |
151 | match self.resolve_crate_root(ident).kind { | |
152 | ModuleKind::Def(.., name) if name != kw::Invalid => name, | |
153 | _ => kw::Crate, | |
476ff2be | 154 | } |
416331ca | 155 | }); |
32a655c1 SL |
156 | } |
157 | ||
e74abb32 | 158 | fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) { |
e1599b0c XL |
159 | // Integrate the new AST fragment into all the definition and module structures. |
160 | // We are inside the `expansion` now, but other parent scope components are still the same. | |
161 | let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] }; | |
ba9703b0 XL |
162 | let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); |
163 | self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); | |
e1599b0c XL |
164 | |
165 | parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); | |
9e0c209e SL |
166 | } |
167 | ||
f9f354fc | 168 | fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) { |
416331ca | 169 | if self.builtin_macros.insert(ident.name, ext).is_some() { |
dfeec247 XL |
170 | self.session |
171 | .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); | |
b7449926 | 172 | } |
9e0c209e SL |
173 | } |
174 | ||
e1599b0c XL |
175 | // Create a new Expansion with a definition site of the provided module, or |
176 | // a fake empty `#[no_implicit_prelude]` module if no module is provided. | |
177 | fn expansion_for_ast_pass( | |
178 | &mut self, | |
179 | call_site: Span, | |
180 | pass: AstPass, | |
181 | features: &[Symbol], | |
182 | parent_module_id: Option<NodeId>, | |
183 | ) -> ExpnId { | |
184 | let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable( | |
185 | ExpnKind::AstPass(pass), | |
186 | call_site, | |
187 | self.session.edition(), | |
188 | features.into(), | |
f9f354fc | 189 | None, |
e1599b0c XL |
190 | ))); |
191 | ||
192 | let parent_scope = if let Some(module_id) = parent_module_id { | |
193 | let parent_def_id = self.definitions.local_def_id(module_id); | |
ba9703b0 | 194 | self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id.to_def_id()); |
e1599b0c XL |
195 | self.module_map[&parent_def_id] |
196 | } else { | |
197 | self.definitions.add_parent_module_of_macro_def( | |
198 | expn_id, | |
199 | def_id::DefId::local(def_id::CRATE_DEF_INDEX), | |
200 | ); | |
201 | self.empty_module | |
202 | }; | |
203 | self.ast_transform_scopes.insert(expn_id, parent_scope); | |
204 | expn_id | |
205 | } | |
206 | ||
476ff2be | 207 | fn resolve_imports(&mut self) { |
416331ca | 208 | ImportResolver { r: self }.resolve_imports() |
476ff2be SL |
209 | } |
210 | ||
e1599b0c | 211 | fn resolve_macro_invocation( |
dfeec247 XL |
212 | &mut self, |
213 | invoc: &Invocation, | |
214 | eager_expansion_root: ExpnId, | |
215 | force: bool, | |
e1599b0c | 216 | ) -> Result<InvocationRes, Indeterminate> { |
416331ca | 217 | let invoc_id = invoc.expansion_data.id; |
e1599b0c XL |
218 | let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) { |
219 | Some(parent_scope) => *parent_scope, | |
220 | None => { | |
221 | // If there's no entry in the table, then we are resolving an eagerly expanded | |
222 | // macro, which should inherit its parent scope from its eager expansion root - | |
223 | // the macro that requested this eager expansion. | |
dfeec247 XL |
224 | let parent_scope = *self |
225 | .invocation_parent_scopes | |
226 | .get(&eager_expansion_root) | |
e1599b0c XL |
227 | .expect("non-eager expansion without a parent scope"); |
228 | self.invocation_parent_scopes.insert(invoc_id, parent_scope); | |
229 | parent_scope | |
230 | } | |
231 | }; | |
232 | ||
233 | let (path, kind, derives, after_derive) = match invoc.kind { | |
dfeec247 XL |
234 | InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => ( |
235 | &attr.get_normal_item().path, | |
236 | MacroKind::Attr, | |
237 | self.arenas.alloc_ast_paths(derives), | |
238 | after_derive, | |
239 | ), | |
240 | InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false), | |
241 | InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false), | |
416331ca | 242 | InvocationKind::DeriveContainer { ref derives, .. } => { |
e1599b0c XL |
243 | // Block expansion of the container until we resolve all derives in it. |
244 | // This is required for two reasons: | |
245 | // - Derive helper attributes are in scope for the item to which the `#[derive]` | |
246 | // is applied, so they have to be produced by the container's expansion rather | |
247 | // than by individual derives. | |
248 | // - Derives in the container need to know whether one of them is a built-in `Copy`. | |
249 | // FIXME: Try to avoid repeated resolutions for derives here and in expansion. | |
250 | let mut exts = Vec::new(); | |
60c5eb7d | 251 | let mut helper_attrs = Vec::new(); |
e1599b0c | 252 | for path in derives { |
dfeec247 XL |
253 | exts.push( |
254 | match self.resolve_macro_path( | |
255 | path, | |
256 | Some(MacroKind::Derive), | |
257 | &parent_scope, | |
258 | true, | |
259 | force, | |
260 | ) { | |
261 | Ok((Some(ext), _)) => { | |
ba9703b0 XL |
262 | let span = path |
263 | .segments | |
264 | .last() | |
265 | .unwrap() | |
266 | .ident | |
267 | .span | |
268 | .normalize_to_macros_2_0(); | |
dfeec247 XL |
269 | helper_attrs.extend( |
270 | ext.helper_attrs.iter().map(|name| Ident::new(*name, span)), | |
271 | ); | |
272 | if ext.is_derive_copy { | |
273 | self.add_derive_copy(invoc_id); | |
274 | } | |
275 | ext | |
60c5eb7d | 276 | } |
dfeec247 XL |
277 | Ok(_) | Err(Determinacy::Determined) => { |
278 | self.dummy_ext(MacroKind::Derive) | |
279 | } | |
280 | Err(Determinacy::Undetermined) => return Err(Indeterminate), | |
281 | }, | |
282 | ) | |
416331ca | 283 | } |
60c5eb7d | 284 | self.helper_attrs.insert(invoc_id, helper_attrs); |
e1599b0c | 285 | return Ok(InvocationRes::DeriveContainer(exts)); |
416331ca | 286 | } |
8bb4bdeb | 287 | }; |
b7449926 | 288 | |
e1599b0c XL |
289 | // Derives are not included when `invocations` are collected, so we have to add them here. |
290 | let parent_scope = &ParentScope { derives, ..parent_scope }; | |
416331ca | 291 | let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; |
b7449926 | 292 | |
416331ca | 293 | let span = invoc.span(); |
f9f354fc XL |
294 | invoc_id.set_expn_data(ext.expn_data( |
295 | parent_scope.expansion, | |
296 | span, | |
297 | fast_print_path(path), | |
298 | res.opt_def_id(), | |
299 | )); | |
300 | ||
301 | if let Res::Def(_, _) = res { | |
0bf4aa26 | 302 | if after_derive { |
416331ca | 303 | self.session.span_err(span, "macro attributes must be placed before `#[derive]`"); |
b7449926 | 304 | } |
416331ca XL |
305 | let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id; |
306 | self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); | |
8faf50e0 | 307 | } |
b7449926 | 308 | |
e1599b0c XL |
309 | match invoc.fragment_kind { |
310 | AstFragmentKind::Arms | |
dfeec247 XL |
311 | | AstFragmentKind::Fields |
312 | | AstFragmentKind::FieldPats | |
313 | | AstFragmentKind::GenericParams | |
314 | | AstFragmentKind::Params | |
315 | | AstFragmentKind::StructFields | |
316 | | AstFragmentKind::Variants => { | |
e1599b0c XL |
317 | if let Res::Def(..) = res { |
318 | self.session.span_err( | |
319 | span, | |
dfeec247 XL |
320 | &format!( |
321 | "expected an inert attribute, found {} {}", | |
322 | res.article(), | |
323 | res.descr() | |
324 | ), | |
e1599b0c XL |
325 | ); |
326 | return Ok(InvocationRes::Single(self.dummy_ext(kind))); | |
327 | } | |
dfeec247 | 328 | } |
e1599b0c XL |
329 | _ => {} |
330 | } | |
331 | ||
332 | Ok(InvocationRes::Single(ext)) | |
8bb4bdeb XL |
333 | } |
334 | ||
e74abb32 | 335 | fn check_unused_macros(&mut self) { |
f9f354fc | 336 | for (_, &(node_id, span)) in self.unused_macros.iter() { |
ba9703b0 | 337 | self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition"); |
7cac9316 | 338 | } |
8bb4bdeb | 339 | } |
416331ca | 340 | |
60c5eb7d XL |
341 | fn has_derive_copy(&self, expn_id: ExpnId) -> bool { |
342 | self.containers_deriving_copy.contains(&expn_id) | |
416331ca XL |
343 | } |
344 | ||
60c5eb7d XL |
345 | fn add_derive_copy(&mut self, expn_id: ExpnId) { |
346 | self.containers_deriving_copy.insert(expn_id); | |
416331ca | 347 | } |
ba9703b0 XL |
348 | |
349 | // The function that implements the resolution logic of `#[cfg_accessible(path)]`. | |
350 | // Returns true if the path can certainly be resolved in one of three namespaces, | |
351 | // returns false if the path certainly cannot be resolved in any of the three namespaces. | |
352 | // Returns `Indeterminate` if we cannot give a certain answer yet. | |
353 | fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate> { | |
354 | let span = path.span; | |
355 | let path = &Segment::from_path(path); | |
356 | let parent_scope = self.invocation_parent_scopes[&expn_id]; | |
357 | ||
358 | let mut indeterminate = false; | |
359 | for ns in [TypeNS, ValueNS, MacroNS].iter().copied() { | |
360 | match self.resolve_path(path, Some(ns), &parent_scope, false, span, CrateLint::No) { | |
361 | PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), | |
362 | PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { | |
363 | return Ok(true); | |
364 | } | |
365 | PathResult::Indeterminate => indeterminate = true, | |
366 | // FIXME: `resolve_path` is not ready to report partially resolved paths | |
367 | // correctly, so we just report an error if the path was reported as unresolved. | |
368 | // This needs to be fixed for `cfg_accessible` to be useful. | |
369 | PathResult::NonModule(..) | PathResult::Failed { .. } => {} | |
370 | PathResult::Module(_) => panic!("unexpected path resolution"), | |
371 | } | |
372 | } | |
373 | ||
374 | if indeterminate { | |
375 | return Err(Indeterminate); | |
376 | } | |
377 | ||
378 | self.session | |
379 | .struct_span_err(span, "not sure whether the path is accessible or not") | |
380 | .span_note(span, "`cfg_accessible` is not fully implemented") | |
381 | .emit(); | |
382 | Ok(false) | |
383 | } | |
8bb4bdeb XL |
384 | } |
385 | ||
0731742a | 386 | impl<'a> Resolver<'a> { |
416331ca XL |
387 | /// Resolve macro path with error reporting and recovery. |
388 | fn smart_resolve_macro_path( | |
b7449926 XL |
389 | &mut self, |
390 | path: &ast::Path, | |
391 | kind: MacroKind, | |
392 | parent_scope: &ParentScope<'a>, | |
393 | force: bool, | |
416331ca | 394 | ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> { |
dfeec247 XL |
395 | let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) |
396 | { | |
416331ca XL |
397 | Ok((Some(ext), res)) => (ext, res), |
398 | // Use dummy syntax extensions for unresolved macros for better recovery. | |
399 | Ok((None, res)) => (self.dummy_ext(kind), res), | |
400 | Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), | |
401 | Err(Determinacy::Undetermined) => return Err(Indeterminate), | |
402 | }; | |
b7449926 | 403 | |
ba9703b0 | 404 | // Report errors for the resolved macro. |
416331ca XL |
405 | for segment in &path.segments { |
406 | if let Some(args) = &segment.args { | |
407 | self.session.span_err(args.span(), "generic arguments in macro path"); | |
408 | } | |
ba9703b0 XL |
409 | if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") { |
410 | self.session.span_err( | |
411 | segment.ident.span, | |
412 | "attributes starting with `rustc` are reserved for use by the `rustc` compiler", | |
413 | ); | |
8bb4bdeb XL |
414 | } |
415 | } | |
416 | ||
48663c56 | 417 | match res { |
416331ca | 418 | Res::Def(DefKind::Macro(_), def_id) => { |
f9f354fc XL |
419 | if let Some(def_id) = def_id.as_local() { |
420 | self.unused_macros.remove(&def_id); | |
421 | if self.proc_macro_stubs.contains(&def_id) { | |
416331ca XL |
422 | self.session.span_err( |
423 | path.span, | |
424 | "can't use a procedural macro from the same crate that defines it", | |
425 | ); | |
b7449926 | 426 | } |
b7449926 | 427 | } |
83c7162d | 428 | } |
416331ca | 429 | Res::NonMacroAttr(..) | Res::Err => {} |
48663c56 | 430 | _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), |
416331ca | 431 | }; |
9fa01778 | 432 | |
416331ca | 433 | self.check_stability_and_deprecation(&ext, path); |
9fa01778 | 434 | |
416331ca | 435 | Ok(if ext.macro_kind() != kind { |
e1599b0c | 436 | let expected = kind.descr_expected(); |
e74abb32 XL |
437 | let path_str = pprust::path_to_string(path); |
438 | let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); | |
dfeec247 XL |
439 | self.session |
440 | .struct_span_err(path.span, &msg) | |
441 | .span_label(path.span, format!("not {} {}", kind.article(), expected)) | |
442 | .emit(); | |
416331ca XL |
443 | // Use dummy syntax extensions for unexpected macro kinds for better recovery. |
444 | (self.dummy_ext(kind), Res::Err) | |
445 | } else { | |
446 | (ext, res) | |
447 | }) | |
9fa01778 XL |
448 | } |
449 | ||
416331ca | 450 | pub fn resolve_macro_path( |
b7449926 XL |
451 | &mut self, |
452 | path: &ast::Path, | |
416331ca | 453 | kind: Option<MacroKind>, |
b7449926 | 454 | parent_scope: &ParentScope<'a>, |
13cf67c4 | 455 | trace: bool, |
b7449926 | 456 | force: bool, |
416331ca | 457 | ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { |
0bf4aa26 | 458 | let path_span = path.span; |
13cf67c4 | 459 | let mut path = Segment::from_path(path); |
476ff2be | 460 | |
8faf50e0 | 461 | // Possibly apply the macro helper hack |
dfeec247 XL |
462 | if kind == Some(MacroKind::Bang) |
463 | && path.len() == 1 | |
464 | && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros | |
465 | { | |
dc9dc135 | 466 | let root = Ident::new(kw::DollarCrate, path[0].ident.span); |
13cf67c4 | 467 | path.insert(0, Segment::from_ident(root)); |
8faf50e0 XL |
468 | } |
469 | ||
416331ca | 470 | let res = if path.len() > 1 { |
dfeec247 XL |
471 | let res = match self.resolve_path( |
472 | &path, | |
473 | Some(MacroNS), | |
474 | parent_scope, | |
475 | false, | |
476 | path_span, | |
477 | CrateLint::No, | |
478 | ) { | |
13cf67c4 | 479 | PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { |
48663c56 | 480 | Ok(path_res.base_res()) |
13cf67c4 | 481 | } |
476ff2be | 482 | PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), |
532ac7d7 XL |
483 | PathResult::NonModule(..) |
484 | | PathResult::Indeterminate | |
485 | | PathResult::Failed { .. } => Err(Determinacy::Determined), | |
13cf67c4 | 486 | PathResult::Module(..) => unreachable!(), |
476ff2be | 487 | }; |
0bf4aa26 | 488 | |
13cf67c4 | 489 | if trace { |
416331ca | 490 | let kind = kind.expect("macro kind must be specified if tracing is enabled"); |
dfeec247 XL |
491 | self.multi_segment_macro_resolutions.push(( |
492 | path, | |
493 | path_span, | |
494 | kind, | |
495 | *parent_scope, | |
496 | res.ok(), | |
497 | )); | |
13cf67c4 | 498 | } |
476ff2be | 499 | |
48663c56 XL |
500 | self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); |
501 | res | |
cc61c64b | 502 | } else { |
416331ca | 503 | let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro); |
0bf4aa26 | 504 | let binding = self.early_resolve_ident_in_lexical_scope( |
dfeec247 XL |
505 | path[0].ident, |
506 | scope_set, | |
507 | parent_scope, | |
508 | false, | |
509 | force, | |
510 | path_span, | |
0bf4aa26 | 511 | ); |
0731742a XL |
512 | if let Err(Determinacy::Undetermined) = binding { |
513 | return Err(Determinacy::Undetermined); | |
cc61c64b | 514 | } |
476ff2be | 515 | |
13cf67c4 | 516 | if trace { |
416331ca | 517 | let kind = kind.expect("macro kind must be specified if tracing is enabled"); |
dfeec247 XL |
518 | self.single_segment_macro_resolutions.push(( |
519 | path[0].ident, | |
520 | kind, | |
521 | *parent_scope, | |
522 | binding.ok(), | |
523 | )); | |
13cf67c4 | 524 | } |
8bb4bdeb | 525 | |
48663c56 XL |
526 | let res = binding.map(|binding| binding.res()); |
527 | self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); | |
528 | res | |
416331ca XL |
529 | }; |
530 | ||
531 | res.map(|res| (self.get_macro(res), res)) | |
c30ab7b3 | 532 | } |
9e0c209e | 533 | |
0bf4aa26 | 534 | // Resolve an identifier in lexical scope. |
b7449926 XL |
535 | // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during |
536 | // expansion and import resolution (perhaps they can be merged in the future). | |
0731742a | 537 | // The function is used for resolving initial segments of macro paths (e.g., `foo` in |
13cf67c4 | 538 | // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. |
0bf4aa26 | 539 | crate fn early_resolve_ident_in_lexical_scope( |
b7449926 | 540 | &mut self, |
13cf67c4 XL |
541 | orig_ident: Ident, |
542 | scope_set: ScopeSet, | |
b7449926 XL |
543 | parent_scope: &ParentScope<'a>, |
544 | record_used: bool, | |
545 | force: bool, | |
546 | path_span: Span, | |
0bf4aa26 | 547 | ) -> Result<&'a NameBinding<'a>, Determinacy> { |
9fa01778 | 548 | bitflags::bitflags! { |
0bf4aa26 | 549 | struct Flags: u8 { |
60c5eb7d XL |
550 | const MACRO_RULES = 1 << 0; |
551 | const MODULE = 1 << 1; | |
552 | const DERIVE_HELPER_COMPAT = 1 << 2; | |
553 | const MISC_SUGGEST_CRATE = 1 << 3; | |
554 | const MISC_SUGGEST_SELF = 1 << 4; | |
555 | const MISC_FROM_PRELUDE = 1 << 5; | |
0bf4aa26 XL |
556 | } |
557 | } | |
b7449926 | 558 | |
b7449926 | 559 | assert!(force || !record_used); // `record_used` implies `force` |
13cf67c4 XL |
560 | |
561 | // Make sure `self`, `super` etc produce an error when passed to here. | |
416331ca | 562 | if orig_ident.is_path_segment_keyword() { |
13cf67c4 XL |
563 | return Err(Determinacy::Determined); |
564 | } | |
b7449926 | 565 | |
416331ca XL |
566 | let (ns, macro_kind, is_import) = match scope_set { |
567 | ScopeSet::All(ns, is_import) => (ns, None, is_import), | |
568 | ScopeSet::AbsolutePath(ns) => (ns, None, false), | |
569 | ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), | |
570 | }; | |
571 | ||
b7449926 XL |
572 | // This is *the* result, resolution from the scope closest to the resolved identifier. |
573 | // However, sometimes this result is "weak" because it comes from a glob import or | |
574 | // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g. | |
575 | // mod m { ... } // solution in outer scope | |
576 | // { | |
577 | // use prefix::*; // imports another `m` - innermost solution | |
578 | // // weak, cannot shadow the outer `m`, need to report ambiguity error | |
579 | // m::mac!(); | |
580 | // } | |
581 | // So we have to save the innermost solution and continue searching in outer scopes | |
582 | // to detect potential ambiguities. | |
9fa01778 | 583 | let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None; |
416331ca | 584 | let mut determinacy = Determinacy::Determined; |
b7449926 XL |
585 | |
586 | // Go through all the scopes and try to resolve the name. | |
dfeec247 XL |
587 | let break_result = self.visit_scopes( |
588 | scope_set, | |
589 | parent_scope, | |
590 | orig_ident, | |
591 | |this, scope, use_prelude, ident| { | |
592 | let ok = |res, span, arenas| { | |
593 | Ok(( | |
594 | (res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas), | |
595 | Flags::empty(), | |
596 | )) | |
597 | }; | |
598 | let result = match scope { | |
599 | Scope::DeriveHelpers(expn_id) => { | |
600 | if let Some(attr) = this | |
601 | .helper_attrs | |
602 | .get(&expn_id) | |
603 | .and_then(|attrs| attrs.iter().rfind(|i| ident == **i)) | |
604 | { | |
605 | let binding = ( | |
606 | Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), | |
607 | ty::Visibility::Public, | |
608 | attr.span, | |
609 | expn_id, | |
610 | ) | |
611 | .to_name_binding(this.arenas); | |
612 | Ok((binding, Flags::empty())) | |
613 | } else { | |
614 | Err(Determinacy::Determined) | |
615 | } | |
60c5eb7d | 616 | } |
dfeec247 XL |
617 | Scope::DeriveHelpersCompat => { |
618 | let mut result = Err(Determinacy::Determined); | |
619 | for derive in parent_scope.derives { | |
620 | let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; | |
621 | match this.resolve_macro_path( | |
622 | derive, | |
623 | Some(MacroKind::Derive), | |
624 | parent_scope, | |
625 | true, | |
626 | force, | |
627 | ) { | |
628 | Ok((Some(ext), _)) => { | |
629 | if ext.helper_attrs.contains(&ident.name) { | |
630 | let binding = ( | |
631 | Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), | |
632 | ty::Visibility::Public, | |
633 | derive.span, | |
634 | ExpnId::root(), | |
635 | ) | |
636 | .to_name_binding(this.arenas); | |
637 | result = Ok((binding, Flags::DERIVE_HELPER_COMPAT)); | |
638 | break; | |
639 | } | |
640 | } | |
641 | Ok(_) | Err(Determinacy::Determined) => {} | |
642 | Err(Determinacy::Undetermined) => { | |
643 | result = Err(Determinacy::Undetermined) | |
644 | } | |
0bf4aa26 XL |
645 | } |
646 | } | |
dfeec247 | 647 | result |
0bf4aa26 | 648 | } |
ba9703b0 XL |
649 | Scope::MacroRules(macro_rules_scope) => match macro_rules_scope { |
650 | MacroRulesScope::Binding(macro_rules_binding) | |
651 | if ident == macro_rules_binding.ident => | |
652 | { | |
653 | Ok((macro_rules_binding.binding, Flags::MACRO_RULES)) | |
13cf67c4 | 654 | } |
ba9703b0 XL |
655 | MacroRulesScope::Invocation(invoc_id) |
656 | if !this.output_macro_rules_scopes.contains_key(&invoc_id) => | |
dfeec247 XL |
657 | { |
658 | Err(Determinacy::Undetermined) | |
659 | } | |
660 | _ => Err(Determinacy::Determined), | |
661 | }, | |
662 | Scope::CrateRoot => { | |
663 | let root_ident = Ident::new(kw::PathRoot, ident.span); | |
664 | let root_module = this.resolve_crate_root(root_ident); | |
665 | let binding = this.resolve_ident_in_module_ext( | |
666 | ModuleOrUniformRoot::Module(root_module), | |
416331ca XL |
667 | ident, |
668 | ns, | |
669 | parent_scope, | |
dfeec247 | 670 | record_used, |
416331ca | 671 | path_span, |
dfeec247 XL |
672 | ); |
673 | match binding { | |
674 | Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)), | |
675 | Err((Determinacy::Undetermined, Weak::No)) => { | |
676 | return Some(Err(Determinacy::determined(force))); | |
677 | } | |
678 | Err((Determinacy::Undetermined, Weak::Yes)) => { | |
679 | Err(Determinacy::Undetermined) | |
b7449926 | 680 | } |
dfeec247 | 681 | Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), |
b7449926 XL |
682 | } |
683 | } | |
dfeec247 XL |
684 | Scope::Module(module) => { |
685 | let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; | |
686 | let binding = this.resolve_ident_in_module_unadjusted_ext( | |
687 | ModuleOrUniformRoot::Module(module), | |
688 | ident, | |
689 | ns, | |
690 | adjusted_parent_scope, | |
691 | true, | |
692 | record_used, | |
693 | path_span, | |
694 | ); | |
695 | match binding { | |
696 | Ok(binding) => { | |
697 | let misc_flags = if ptr::eq(module, this.graph_root) { | |
698 | Flags::MISC_SUGGEST_CRATE | |
699 | } else if module.is_normal() { | |
700 | Flags::MISC_SUGGEST_SELF | |
701 | } else { | |
702 | Flags::empty() | |
703 | }; | |
704 | Ok((binding, Flags::MODULE | misc_flags)) | |
705 | } | |
706 | Err((Determinacy::Undetermined, Weak::No)) => { | |
707 | return Some(Err(Determinacy::determined(force))); | |
708 | } | |
709 | Err((Determinacy::Undetermined, Weak::Yes)) => { | |
710 | Err(Determinacy::Undetermined) | |
711 | } | |
712 | Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), | |
713 | } | |
714 | } | |
715 | Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() { | |
716 | Some(ident) => ok( | |
717 | Res::NonMacroAttr(NonMacroAttrKind::Registered), | |
718 | ident.span, | |
719 | this.arenas, | |
720 | ), | |
721 | None => Err(Determinacy::Determined), | |
722 | }, | |
723 | Scope::MacroUsePrelude => { | |
724 | match this.macro_use_prelude.get(&ident.name).cloned() { | |
725 | Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), | |
726 | None => Err(Determinacy::determined( | |
727 | this.graph_root.unexpanded_invocations.borrow().is_empty(), | |
728 | )), | |
729 | } | |
730 | } | |
731 | Scope::BuiltinAttrs => { | |
732 | if is_builtin_attr_name(ident.name) { | |
733 | ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas) | |
734 | } else { | |
735 | Err(Determinacy::Determined) | |
736 | } | |
7cac9316 | 737 | } |
dfeec247 XL |
738 | Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) { |
739 | Some(binding) => Ok((binding, Flags::empty())), | |
740 | None => Err(Determinacy::determined( | |
741 | this.graph_root.unexpanded_invocations.borrow().is_empty(), | |
742 | )), | |
743 | }, | |
744 | Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() { | |
745 | Some(ident) => ok(Res::ToolMod, ident.span, this.arenas), | |
746 | None => Err(Determinacy::Determined), | |
747 | }, | |
748 | Scope::StdLibPrelude => { | |
749 | let mut result = Err(Determinacy::Determined); | |
750 | if let Some(prelude) = this.prelude { | |
751 | if let Ok(binding) = this.resolve_ident_in_module_unadjusted( | |
752 | ModuleOrUniformRoot::Module(prelude), | |
753 | ident, | |
754 | ns, | |
755 | parent_scope, | |
756 | false, | |
757 | path_span, | |
758 | ) { | |
759 | if use_prelude || this.is_builtin_macro(binding.res()) { | |
760 | result = Ok((binding, Flags::MISC_FROM_PRELUDE)); | |
761 | } | |
762 | } | |
763 | } | |
764 | result | |
765 | } | |
766 | Scope::BuiltinTypes => { | |
767 | match this.primitive_type_table.primitive_types.get(&ident.name).cloned() { | |
768 | Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas), | |
769 | None => Err(Determinacy::Determined), | |
770 | } | |
771 | } | |
772 | }; | |
773 | ||
774 | match result { | |
775 | Ok((binding, flags)) | |
776 | if sub_namespace_match(binding.macro_kind(), macro_kind) => | |
777 | { | |
778 | if !record_used { | |
779 | return Some(Ok(binding)); | |
780 | } | |
781 | ||
782 | if let Some((innermost_binding, innermost_flags)) = innermost_result { | |
783 | // Found another solution, if the first one was "weak", report an error. | |
784 | let (res, innermost_res) = (binding.res(), innermost_binding.res()); | |
785 | if res != innermost_res { | |
786 | let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin); | |
787 | let is_derive_helper_compat = |res, flags: Flags| { | |
788 | res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper) | |
789 | && flags.contains(Flags::DERIVE_HELPER_COMPAT) | |
790 | }; | |
b7449926 | 791 | |
dfeec247 XL |
792 | let ambiguity_error_kind = if is_import { |
793 | Some(AmbiguityKind::Import) | |
794 | } else if innermost_res == builtin || res == builtin { | |
795 | Some(AmbiguityKind::BuiltinAttr) | |
796 | } else if is_derive_helper_compat(innermost_res, innermost_flags) | |
797 | || is_derive_helper_compat(res, flags) | |
798 | { | |
799 | Some(AmbiguityKind::DeriveHelper) | |
800 | } else if innermost_flags.contains(Flags::MACRO_RULES) | |
801 | && flags.contains(Flags::MODULE) | |
ba9703b0 XL |
802 | && !this.disambiguate_macro_rules_vs_modularized( |
803 | innermost_binding, | |
804 | binding, | |
805 | ) | |
dfeec247 XL |
806 | || flags.contains(Flags::MACRO_RULES) |
807 | && innermost_flags.contains(Flags::MODULE) | |
ba9703b0 | 808 | && !this.disambiguate_macro_rules_vs_modularized( |
dfeec247 XL |
809 | binding, |
810 | innermost_binding, | |
811 | ) | |
812 | { | |
ba9703b0 | 813 | Some(AmbiguityKind::MacroRulesVsModularized) |
dfeec247 XL |
814 | } else if innermost_binding.is_glob_import() { |
815 | Some(AmbiguityKind::GlobVsOuter) | |
816 | } else if innermost_binding | |
817 | .may_appear_after(parent_scope.expansion, binding) | |
818 | { | |
819 | Some(AmbiguityKind::MoreExpandedVsOuter) | |
13cf67c4 | 820 | } else { |
dfeec247 | 821 | None |
13cf67c4 | 822 | }; |
dfeec247 XL |
823 | if let Some(kind) = ambiguity_error_kind { |
824 | let misc = |f: Flags| { | |
825 | if f.contains(Flags::MISC_SUGGEST_CRATE) { | |
826 | AmbiguityErrorMisc::SuggestCrate | |
827 | } else if f.contains(Flags::MISC_SUGGEST_SELF) { | |
828 | AmbiguityErrorMisc::SuggestSelf | |
829 | } else if f.contains(Flags::MISC_FROM_PRELUDE) { | |
830 | AmbiguityErrorMisc::FromPrelude | |
831 | } else { | |
832 | AmbiguityErrorMisc::None | |
833 | } | |
834 | }; | |
835 | this.ambiguity_errors.push(AmbiguityError { | |
836 | kind, | |
837 | ident: orig_ident, | |
838 | b1: innermost_binding, | |
839 | b2: binding, | |
840 | misc1: misc(innermost_flags), | |
841 | misc2: misc(flags), | |
842 | }); | |
843 | return Some(Ok(innermost_binding)); | |
844 | } | |
13cf67c4 | 845 | } |
dfeec247 XL |
846 | } else { |
847 | // Found the first solution. | |
848 | innermost_result = Some((binding, flags)); | |
476ff2be | 849 | } |
476ff2be | 850 | } |
dfeec247 XL |
851 | Ok(..) | Err(Determinacy::Determined) => {} |
852 | Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, | |
b7449926 | 853 | } |
13cf67c4 | 854 | |
dfeec247 XL |
855 | None |
856 | }, | |
857 | ); | |
13cf67c4 | 858 | |
416331ca XL |
859 | if let Some(break_result) = break_result { |
860 | return break_result; | |
b7449926 | 861 | } |
476ff2be | 862 | |
b7449926 | 863 | // The first found solution was the only one, return it. |
532ac7d7 | 864 | if let Some((binding, _)) = innermost_result { |
0bf4aa26 | 865 | return Ok(binding); |
b7449926 XL |
866 | } |
867 | ||
60c5eb7d | 868 | Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) |
476ff2be SL |
869 | } |
870 | ||
e1599b0c | 871 | crate fn finalize_macro_resolutions(&mut self) { |
dfeec247 XL |
872 | let check_consistency = |this: &mut Self, |
873 | path: &[Segment], | |
874 | span, | |
875 | kind: MacroKind, | |
876 | initial_res: Option<Res>, | |
877 | res: Res| { | |
48663c56 XL |
878 | if let Some(initial_res) = initial_res { |
879 | if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() { | |
13cf67c4 XL |
880 | // Make sure compilation does not succeed if preferred macro resolution |
881 | // has changed after the macro had been expanded. In theory all such | |
882 | // situations should be reported as ambiguity errors, so this is a bug. | |
60c5eb7d | 883 | span_bug!(span, "inconsistent resolution for a macro"); |
13cf67c4 XL |
884 | } |
885 | } else { | |
886 | // It's possible that the macro was unresolved (indeterminate) and silently | |
887 | // expanded into a dummy fragment for recovery during expansion. | |
888 | // Now, post-expansion, the resolution may succeed, but we can't change the | |
889 | // past and need to report an error. | |
890 | // However, non-speculative `resolve_path` can successfully return private items | |
891 | // even if speculative `resolve_path` returned nothing previously, so we skip this | |
892 | // less informative error if the privacy error is reported elsewhere. | |
893 | if this.privacy_errors.is_empty() { | |
dfeec247 XL |
894 | let msg = format!( |
895 | "cannot determine resolution for the {} `{}`", | |
896 | kind.descr(), | |
897 | Segment::names_to_string(path) | |
898 | ); | |
13cf67c4 XL |
899 | let msg_note = "import resolution is stuck, try simplifying macro imports"; |
900 | this.session.struct_span_err(span, &msg).note(msg_note).emit(); | |
901 | } | |
902 | } | |
903 | }; | |
904 | ||
e1599b0c | 905 | let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); |
48663c56 | 906 | for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { |
13cf67c4 | 907 | // FIXME: Path resolution will ICE if segment IDs present. |
dfeec247 XL |
908 | for seg in &mut path { |
909 | seg.id = None; | |
910 | } | |
416331ca | 911 | match self.resolve_path( |
dfeec247 XL |
912 | &path, |
913 | Some(MacroNS), | |
914 | &parent_scope, | |
915 | true, | |
916 | path_span, | |
917 | CrateLint::No, | |
416331ca | 918 | ) { |
13cf67c4 | 919 | PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { |
48663c56 XL |
920 | let res = path_res.base_res(); |
921 | check_consistency(self, &path, path_span, kind, initial_res, res); | |
13cf67c4 | 922 | } |
532ac7d7 XL |
923 | path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { |
924 | let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { | |
925 | (span, label) | |
13cf67c4 | 926 | } else { |
dfeec247 XL |
927 | ( |
928 | path_span, | |
929 | format!( | |
930 | "partially resolved path in {} {}", | |
931 | kind.article(), | |
932 | kind.descr() | |
933 | ), | |
934 | ) | |
13cf67c4 | 935 | }; |
dfeec247 XL |
936 | self.report_error( |
937 | span, | |
938 | ResolutionError::FailedToResolve { label, suggestion: None }, | |
939 | ); | |
476ff2be | 940 | } |
13cf67c4 | 941 | PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), |
476ff2be SL |
942 | } |
943 | } | |
944 | ||
e1599b0c | 945 | let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); |
13cf67c4 | 946 | for (ident, kind, parent_scope, initial_binding) in macro_resolutions { |
dfeec247 XL |
947 | match self.early_resolve_ident_in_lexical_scope( |
948 | ident, | |
949 | ScopeSet::Macro(kind), | |
950 | &parent_scope, | |
951 | true, | |
952 | true, | |
953 | ident.span, | |
954 | ) { | |
0bf4aa26 | 955 | Ok(binding) => { |
48663c56 | 956 | let initial_res = initial_binding.map(|initial_binding| { |
13cf67c4 | 957 | self.record_use(ident, MacroNS, initial_binding, false); |
48663c56 | 958 | initial_binding.res() |
13cf67c4 | 959 | }); |
48663c56 | 960 | let res = binding.res(); |
13cf67c4 | 961 | let seg = Segment::from_ident(ident); |
48663c56 | 962 | check_consistency(self, &[seg], ident.span, kind, initial_res, res); |
94b46f34 | 963 | } |
0bf4aa26 | 964 | Err(..) => { |
e1599b0c XL |
965 | let expected = kind.descr_expected(); |
966 | let msg = format!("cannot find {} `{}` in this scope", expected, ident); | |
0bf4aa26 | 967 | let mut err = self.session.struct_span_err(ident.span, &msg); |
416331ca | 968 | self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident); |
8bb4bdeb | 969 | err.emit(); |
b7449926 | 970 | } |
0bf4aa26 | 971 | } |
c30ab7b3 | 972 | } |
b7449926 | 973 | |
e1599b0c | 974 | let builtin_attrs = mem::take(&mut self.builtin_attrs); |
b7449926 | 975 | for (ident, parent_scope) in builtin_attrs { |
13cf67c4 | 976 | let _ = self.early_resolve_ident_in_lexical_scope( |
dfeec247 XL |
977 | ident, |
978 | ScopeSet::Macro(MacroKind::Attr), | |
979 | &parent_scope, | |
980 | true, | |
981 | true, | |
982 | ident.span, | |
0bf4aa26 | 983 | ); |
b7449926 | 984 | } |
9e0c209e | 985 | } |
9e0c209e | 986 | |
e74abb32 | 987 | fn check_stability_and_deprecation(&mut self, ext: &SyntaxExtension, path: &ast::Path) { |
416331ca XL |
988 | let span = path.span; |
989 | if let Some(stability) = &ext.stability { | |
990 | if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { | |
991 | let feature = stability.feature; | |
992 | if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { | |
e74abb32 XL |
993 | let node_id = ast::CRATE_NODE_ID; |
994 | let lint_buffer = &mut self.lint_buffer; | |
dfeec247 XL |
995 | let soft_handler = |
996 | |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg); | |
e74abb32 | 997 | stability::report_unstable( |
dfeec247 XL |
998 | self.session, |
999 | feature, | |
1000 | reason, | |
1001 | issue, | |
1002 | is_soft, | |
1003 | span, | |
1004 | soft_handler, | |
e74abb32 | 1005 | ); |
416331ca XL |
1006 | } |
1007 | } | |
1008 | if let Some(depr) = &stability.rustc_depr { | |
e74abb32 XL |
1009 | let path = pprust::path_to_string(path); |
1010 | let (message, lint) = stability::rustc_deprecation_message(depr, &path); | |
416331ca | 1011 | stability::early_report_deprecation( |
dfeec247 XL |
1012 | &mut self.lint_buffer, |
1013 | &message, | |
1014 | depr.suggestion, | |
1015 | lint, | |
1016 | span, | |
416331ca XL |
1017 | ); |
1018 | } | |
1019 | } | |
1020 | if let Some(depr) = &ext.deprecation { | |
e74abb32 XL |
1021 | let path = pprust::path_to_string(&path); |
1022 | let (message, lint) = stability::deprecation_message(depr, &path); | |
1023 | stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span); | |
416331ca XL |
1024 | } |
1025 | } | |
1026 | ||
dfeec247 XL |
1027 | fn prohibit_imported_non_macro_attrs( |
1028 | &self, | |
1029 | binding: Option<&'a NameBinding<'a>>, | |
1030 | res: Option<Res>, | |
1031 | span: Span, | |
1032 | ) { | |
48663c56 | 1033 | if let Some(Res::NonMacroAttr(kind)) = res { |
69743fb6 | 1034 | if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { |
60c5eb7d XL |
1035 | let msg = |
1036 | format!("cannot use {} {} through an import", kind.article(), kind.descr()); | |
69743fb6 XL |
1037 | let mut err = self.session.struct_span_err(span, &msg); |
1038 | if let Some(binding) = binding { | |
1039 | err.span_note(binding.span, &format!("the {} imported here", kind.descr())); | |
1040 | } | |
1041 | err.emit(); | |
1042 | } | |
1043 | } | |
1044 | } | |
1045 | ||
416331ca XL |
1046 | crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { |
1047 | // Reserve some names that are not quite covered by the general check | |
1048 | // performed on `Resolver::builtin_attrs`. | |
1049 | if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive { | |
1050 | let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind()); | |
1051 | if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { | |
1052 | self.session.span_err( | |
dfeec247 XL |
1053 | ident.span, |
1054 | &format!("name `{}` is reserved in attribute namespace", ident), | |
416331ca XL |
1055 | ); |
1056 | } | |
dc9dc135 | 1057 | } |
416331ca | 1058 | } |
dc9dc135 | 1059 | |
60c5eb7d XL |
1060 | /// Compile the macro into a `SyntaxExtension` and possibly replace |
1061 | /// its expander to a pre-defined one for built-in macros. | |
e1599b0c | 1062 | crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension { |
e74abb32 | 1063 | let mut result = compile_declarative_macro( |
dfeec247 XL |
1064 | &self.session.parse_sess, |
1065 | self.session.features_untracked(), | |
1066 | item, | |
1067 | edition, | |
416331ca | 1068 | ); |
8bb4bdeb | 1069 | |
416331ca XL |
1070 | if result.is_builtin { |
1071 | // The macro was marked with `#[rustc_builtin_macro]`. | |
1072 | if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { | |
60c5eb7d XL |
1073 | // The macro is a built-in, replace its expander function |
1074 | // while still taking everything else from the source code. | |
1075 | result.kind = ext.kind; | |
9e0c209e | 1076 | } else { |
416331ca XL |
1077 | let msg = format!("cannot find a built-in macro with name `{}`", item.ident); |
1078 | self.session.span_err(item.span, &msg); | |
9e0c209e SL |
1079 | } |
1080 | } | |
32a655c1 | 1081 | |
e1599b0c | 1082 | result |
32a655c1 | 1083 | } |
9e0c209e | 1084 | } |