]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
476ff2be | 11 | use {AmbiguityError, Resolver, ResolutionError, resolve_error}; |
32a655c1 | 12 | use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; |
476ff2be | 13 | use Namespace::{self, MacroNS}; |
c30ab7b3 | 14 | use build_reduced_graph::BuildReducedGraphVisitor; |
476ff2be | 15 | use resolve_imports::ImportResolver; |
abe05a73 | 16 | use rustc_data_structures::indexed_vec::Idx; |
476ff2be SL |
17 | use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; |
18 | use rustc::hir::def::{Def, Export}; | |
c30ab7b3 | 19 | use rustc::hir::map::{self, DefCollector}; |
7cac9316 | 20 | use rustc::{ty, lint}; |
32a655c1 | 21 | use syntax::ast::{self, Name, Ident}; |
8bb4bdeb | 22 | use syntax::attr::{self, HasAttrs}; |
3b2f2976 | 23 | use syntax::codemap::respan; |
9e0c209e | 24 | use syntax::errors::DiagnosticBuilder; |
8bb4bdeb XL |
25 | use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; |
26 | use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; | |
27 | use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; | |
9e0c209e | 28 | use syntax::ext::hygiene::Mark; |
8bb4bdeb | 29 | use syntax::ext::placeholders::placeholder; |
9e0c209e | 30 | use syntax::ext::tt::macro_rules; |
8bb4bdeb | 31 | use syntax::feature_gate::{self, emit_feature_err, GateIssue}; |
476ff2be | 32 | use syntax::fold::{self, Folder}; |
cc61c64b XL |
33 | use syntax::parse::parser::PathStyle; |
34 | use syntax::parse::token::{self, Token}; | |
476ff2be | 35 | use syntax::ptr::P; |
8bb4bdeb | 36 | use syntax::symbol::{Symbol, keywords}; |
cc61c64b | 37 | use syntax::tokenstream::{TokenStream, TokenTree, Delimited}; |
9e0c209e | 38 | use syntax::util::lev_distance::find_best_match_for_name; |
476ff2be | 39 | use syntax_pos::{Span, DUMMY_SP}; |
9e0c209e | 40 | |
8bb4bdeb XL |
41 | use std::cell::Cell; |
42 | use std::mem; | |
43 | use std::rc::Rc; | |
44 | ||
c30ab7b3 SL |
45 | #[derive(Clone)] |
46 | pub struct InvocationData<'a> { | |
47 | pub module: Cell<Module<'a>>, | |
48 | pub def_index: DefIndex, | |
32a655c1 SL |
49 | // True if this expansion is in a `const_expr` position, for example `[u32; m!()]`. |
50 | // c.f. `DefCollector::visit_const_expr`. | |
51 | pub const_expr: bool, | |
c30ab7b3 SL |
52 | // The scope in which the invocation path is resolved. |
53 | pub legacy_scope: Cell<LegacyScope<'a>>, | |
54 | // The smallest scope that includes this invocation's expansion, | |
55 | // or `Empty` if this invocation has not been expanded yet. | |
56 | pub expansion: Cell<LegacyScope<'a>>, | |
9e0c209e SL |
57 | } |
58 | ||
c30ab7b3 SL |
59 | impl<'a> InvocationData<'a> { |
60 | pub fn root(graph_root: Module<'a>) -> Self { | |
61 | InvocationData { | |
62 | module: Cell::new(graph_root), | |
63 | def_index: CRATE_DEF_INDEX, | |
32a655c1 | 64 | const_expr: false, |
c30ab7b3 SL |
65 | legacy_scope: Cell::new(LegacyScope::Empty), |
66 | expansion: Cell::new(LegacyScope::Empty), | |
67 | } | |
68 | } | |
69 | } | |
70 | ||
71 | #[derive(Copy, Clone)] | |
72 | pub enum LegacyScope<'a> { | |
73 | Empty, | |
74 | Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion | |
75 | Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion | |
76 | Binding(&'a LegacyBinding<'a>), | |
77 | } | |
78 | ||
c30ab7b3 | 79 | pub struct LegacyBinding<'a> { |
476ff2be | 80 | pub parent: Cell<LegacyScope<'a>>, |
7cac9316 | 81 | pub ident: Ident, |
8bb4bdeb | 82 | def_id: DefId, |
c30ab7b3 | 83 | pub span: Span, |
9e0c209e SL |
84 | } |
85 | ||
cc61c64b | 86 | #[derive(Copy, Clone)] |
476ff2be SL |
87 | pub enum MacroBinding<'a> { |
88 | Legacy(&'a LegacyBinding<'a>), | |
cc61c64b | 89 | Global(&'a NameBinding<'a>), |
476ff2be SL |
90 | Modern(&'a NameBinding<'a>), |
91 | } | |
92 | ||
cc61c64b XL |
93 | impl<'a> MacroBinding<'a> { |
94 | pub fn span(self) -> Span { | |
95 | match self { | |
96 | MacroBinding::Legacy(binding) => binding.span, | |
97 | MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding.span, | |
98 | } | |
99 | } | |
100 | ||
101 | pub fn binding(self) -> &'a NameBinding<'a> { | |
102 | match self { | |
103 | MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding, | |
104 | MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
9e0c209e SL |
109 | impl<'a> base::Resolver for Resolver<'a> { |
110 | fn next_node_id(&mut self) -> ast::NodeId { | |
111 | self.session.next_node_id() | |
112 | } | |
113 | ||
c30ab7b3 | 114 | fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { |
7cac9316 | 115 | let mark = Mark::fresh(Mark::root()); |
32a655c1 | 116 | let module = self.module_map[&self.definitions.local_def_id(id)]; |
c30ab7b3 SL |
117 | self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { |
118 | module: Cell::new(module), | |
119 | def_index: module.def_id().unwrap().index, | |
32a655c1 | 120 | const_expr: false, |
c30ab7b3 SL |
121 | legacy_scope: Cell::new(LegacyScope::Empty), |
122 | expansion: Cell::new(LegacyScope::Empty), | |
123 | })); | |
124 | mark | |
125 | } | |
126 | ||
476ff2be | 127 | fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { |
7cac9316 | 128 | struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span); |
476ff2be SL |
129 | |
130 | impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { | |
131 | fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { | |
132 | let ident = path.segments[0].identifier; | |
041b39d2 | 133 | if ident.name == keywords::DollarCrate.name() { |
32a655c1 | 134 | path.segments[0].identifier.name = keywords::CrateRoot.name(); |
7cac9316 | 135 | let module = self.0.resolve_crate_root(ident.ctxt); |
32a655c1 | 136 | if !module.is_local() { |
8bb4bdeb | 137 | let span = path.segments[0].span; |
32a655c1 | 138 | path.segments.insert(1, match module.kind { |
8bb4bdeb XL |
139 | ModuleKind::Def(_, name) => ast::PathSegment::from_ident( |
140 | ast::Ident::with_empty_ctxt(name), span | |
141 | ), | |
476ff2be | 142 | _ => unreachable!(), |
32a655c1 | 143 | }) |
476ff2be SL |
144 | } |
145 | } | |
146 | path | |
147 | } | |
148 | ||
149 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { | |
150 | fold::noop_fold_mac(mac, self) | |
151 | } | |
152 | } | |
153 | ||
7cac9316 | 154 | EliminateCrateVar(self, item.span).fold_item(item).expect_one("") |
476ff2be SL |
155 | } |
156 | ||
32a655c1 SL |
157 | fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool { |
158 | self.whitelisted_legacy_custom_derives.contains(&name) | |
159 | } | |
160 | ||
8bb4bdeb | 161 | fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]) { |
c30ab7b3 | 162 | let invocation = self.invocations[&mark]; |
7cac9316 | 163 | self.collect_def_ids(mark, invocation, expansion); |
c30ab7b3 SL |
164 | |
165 | self.current_module = invocation.module.get(); | |
476ff2be | 166 | self.current_module.unresolved_invocations.borrow_mut().remove(&mark); |
8bb4bdeb XL |
167 | self.current_module.unresolved_invocations.borrow_mut().extend(derives); |
168 | for &derive in derives { | |
169 | self.invocations.insert(derive, invocation); | |
170 | } | |
c30ab7b3 | 171 | let mut visitor = BuildReducedGraphVisitor { |
9e0c209e | 172 | resolver: self, |
c30ab7b3 SL |
173 | legacy_scope: LegacyScope::Invocation(invocation), |
174 | expansion: mark, | |
175 | }; | |
176 | expansion.visit_with(&mut visitor); | |
177 | invocation.expansion.set(visitor.legacy_scope); | |
9e0c209e SL |
178 | } |
179 | ||
8bb4bdeb | 180 | fn add_builtin(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) { |
476ff2be SL |
181 | let def_id = DefId { |
182 | krate: BUILTIN_MACROS_CRATE, | |
183 | index: DefIndex::new(self.macro_map.len()), | |
184 | }; | |
8bb4bdeb | 185 | let kind = ext.kind(); |
476ff2be SL |
186 | self.macro_map.insert(def_id, ext); |
187 | let binding = self.arenas.alloc_name_binding(NameBinding { | |
8bb4bdeb | 188 | kind: NameBindingKind::Def(Def::Macro(def_id, kind)), |
476ff2be | 189 | span: DUMMY_SP, |
32a655c1 | 190 | vis: ty::Visibility::Invisible, |
476ff2be SL |
191 | expansion: Mark::root(), |
192 | }); | |
cc61c64b | 193 | self.global_macros.insert(ident.name, binding); |
9e0c209e SL |
194 | } |
195 | ||
476ff2be SL |
196 | fn resolve_imports(&mut self) { |
197 | ImportResolver { resolver: self }.resolve_imports() | |
198 | } | |
199 | ||
8bb4bdeb XL |
200 | // Resolves attribute and derive legacy macros from `#![plugin(..)]`. |
201 | fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) | |
202 | -> Option<ast::Attribute> { | |
9e0c209e | 203 | for i in 0..attrs.len() { |
cc61c64b XL |
204 | let name = unwrap_or!(attrs[i].name(), continue); |
205 | ||
8bb4bdeb | 206 | if self.session.plugin_attributes.borrow().iter() |
cc61c64b | 207 | .any(|&(ref attr_nm, _)| name == &**attr_nm) { |
8bb4bdeb XL |
208 | attr::mark_known(&attrs[i]); |
209 | } | |
210 | ||
cc61c64b | 211 | match self.global_macros.get(&name).cloned() { |
476ff2be | 212 | Some(binding) => match *binding.get_macro(self) { |
9e0c209e SL |
213 | MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { |
214 | return Some(attrs.remove(i)) | |
215 | } | |
216 | _ => {} | |
217 | }, | |
218 | None => {} | |
219 | } | |
8bb4bdeb | 220 | } |
32a655c1 | 221 | |
8bb4bdeb XL |
222 | // Check for legacy derives |
223 | for i in 0..attrs.len() { | |
cc61c64b XL |
224 | let name = unwrap_or!(attrs[i].name(), continue); |
225 | ||
226 | if name == "derive" { | |
227 | let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { | |
228 | parser.parse_path_allowing_meta(PathStyle::Mod) | |
229 | }); | |
230 | ||
231 | let mut traits = match result { | |
232 | Ok(traits) => traits, | |
233 | Err(mut e) => { | |
234 | e.cancel(); | |
235 | continue | |
236 | } | |
8bb4bdeb XL |
237 | }; |
238 | ||
239 | for j in 0..traits.len() { | |
cc61c64b XL |
240 | if traits[j].segments.len() > 1 { |
241 | continue | |
242 | } | |
243 | let trait_name = traits[j].segments[0].identifier.name; | |
244 | let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); | |
245 | if !self.global_macros.contains_key(&legacy_name) { | |
8bb4bdeb XL |
246 | continue |
247 | } | |
248 | let span = traits.remove(j).span; | |
249 | self.gate_legacy_custom_derive(legacy_name, span); | |
250 | if traits.is_empty() { | |
251 | attrs.remove(i); | |
252 | } else { | |
cc61c64b XL |
253 | let mut tokens = Vec::new(); |
254 | for (j, path) in traits.iter().enumerate() { | |
255 | if j > 0 { | |
256 | tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); | |
257 | } | |
258 | for (k, segment) in path.segments.iter().enumerate() { | |
259 | if k > 0 { | |
260 | tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); | |
261 | } | |
262 | let tok = Token::Ident(segment.identifier); | |
263 | tokens.push(TokenTree::Token(path.span, tok).into()); | |
264 | } | |
265 | } | |
266 | attrs[i].tokens = TokenTree::Delimited(attrs[i].span, Delimited { | |
267 | delim: token::Paren, | |
268 | tts: TokenStream::concat(tokens).into(), | |
269 | }).into(); | |
8bb4bdeb XL |
270 | } |
271 | return Some(ast::Attribute { | |
cc61c64b XL |
272 | path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)), |
273 | tokens: TokenStream::empty(), | |
8bb4bdeb XL |
274 | id: attr::mk_attr_id(), |
275 | style: ast::AttrStyle::Outer, | |
276 | is_sugared_doc: false, | |
3b2f2976 | 277 | span, |
8bb4bdeb XL |
278 | }); |
279 | } | |
32a655c1 | 280 | } |
9e0c209e | 281 | } |
8bb4bdeb | 282 | |
9e0c209e SL |
283 | None |
284 | } | |
285 | ||
8bb4bdeb XL |
286 | fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) |
287 | -> Result<Option<Rc<SyntaxExtension>>, Determinacy> { | |
288 | let def = match invoc.kind { | |
289 | InvocationKind::Attr { attr: None, .. } => return Ok(None), | |
041b39d2 | 290 | _ => self.resolve_invoc_to_def(invoc, scope, force)?, |
8bb4bdeb | 291 | }; |
7cac9316 | 292 | |
8bb4bdeb | 293 | self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); |
7cac9316 XL |
294 | let normal_module_def_id = |
295 | self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id; | |
296 | self.definitions.add_macro_def_scope(invoc.expansion_data.mark, normal_module_def_id); | |
297 | ||
298 | self.unused_macros.remove(&def.def_id()); | |
299 | let ext = self.get_macro(def); | |
300 | if ext.is_modern() { | |
301 | invoc.expansion_data.mark.set_modern(); | |
302 | } | |
303 | Ok(Some(ext)) | |
8bb4bdeb XL |
304 | } |
305 | ||
306 | fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) | |
c30ab7b3 | 307 | -> Result<Rc<SyntaxExtension>, Determinacy> { |
7cac9316 XL |
308 | self.resolve_macro_to_def(scope, path, kind, force).map(|def| { |
309 | self.unused_macros.remove(&def.def_id()); | |
310 | self.get_macro(def) | |
311 | }) | |
312 | } | |
313 | ||
314 | fn check_unused_macros(&self) { | |
315 | for did in self.unused_macros.iter() { | |
316 | let id_span = match *self.macro_map[did] { | |
3b2f2976 | 317 | SyntaxExtension::NormalTT { def_info, .. } => def_info, |
7cac9316 XL |
318 | SyntaxExtension::DeclMacro(.., osp) => osp, |
319 | _ => None, | |
320 | }; | |
321 | if let Some((id, span)) = id_span { | |
322 | let lint = lint::builtin::UNUSED_MACROS; | |
3b2f2976 XL |
323 | let msg = "unused macro definition"; |
324 | self.session.buffer_lint(lint, id, span, msg); | |
7cac9316 XL |
325 | } else { |
326 | bug!("attempted to create unused macro error, but span not available"); | |
327 | } | |
328 | } | |
8bb4bdeb XL |
329 | } |
330 | } | |
331 | ||
332 | impl<'a> Resolver<'a> { | |
333 | fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) | |
334 | -> Result<Def, Determinacy> { | |
335 | let (attr, traits, item) = match invoc.kind { | |
336 | InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), | |
337 | InvocationKind::Bang { ref mac, .. } => { | |
338 | return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); | |
339 | } | |
cc61c64b XL |
340 | InvocationKind::Derive { ref path, .. } => { |
341 | return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force); | |
8bb4bdeb XL |
342 | } |
343 | }; | |
344 | ||
8bb4bdeb | 345 | |
cc61c64b XL |
346 | let path = attr.as_ref().unwrap().path.clone(); |
347 | let mut determinacy = Determinacy::Determined; | |
8bb4bdeb XL |
348 | match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { |
349 | Ok(def) => return Ok(def), | |
cc61c64b | 350 | Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, |
8bb4bdeb XL |
351 | Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), |
352 | Err(Determinacy::Determined) => {} | |
353 | } | |
354 | ||
cc61c64b XL |
355 | let attr_name = match path.segments.len() { |
356 | 1 => path.segments[0].identifier.name, | |
357 | _ => return Err(determinacy), | |
358 | }; | |
359 | for path in traits { | |
360 | match self.resolve_macro(scope, path, MacroKind::Derive, force) { | |
8bb4bdeb XL |
361 | Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { |
362 | if inert_attrs.contains(&attr_name) { | |
363 | // FIXME(jseyfried) Avoid `mem::replace` here. | |
364 | let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) | |
365 | .make_items().pop().unwrap(); | |
366 | let dummy_item = Annotatable::Item(dummy_item); | |
367 | *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| { | |
368 | let inert_attr = attr.take().unwrap(); | |
369 | attr::mark_known(&inert_attr); | |
370 | if self.proc_macro_enabled { | |
371 | *attr = find_attr_invoc(&mut attrs); | |
372 | } | |
373 | attrs.push(inert_attr); | |
374 | attrs | |
375 | }); | |
376 | } | |
377 | return Err(Determinacy::Undetermined); | |
378 | }, | |
cc61c64b | 379 | Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, |
8bb4bdeb XL |
380 | Err(Determinacy::Determined) => {} |
381 | } | |
382 | } | |
383 | ||
cc61c64b | 384 | Err(determinacy) |
8bb4bdeb XL |
385 | } |
386 | ||
387 | fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) | |
388 | -> Result<Def, Determinacy> { | |
3b2f2976 XL |
389 | let def = self.resolve_macro_to_def_inner(scope, path, kind, force); |
390 | if def != Err(Determinacy::Undetermined) { | |
391 | // Do not report duplicated errors on every undetermined resolution. | |
392 | path.segments.iter().find(|segment| segment.parameters.is_some()).map(|segment| { | |
393 | self.session.span_err(segment.parameters.as_ref().unwrap().span(), | |
394 | "generic arguments in macro path"); | |
395 | }); | |
c30ab7b3 | 396 | } |
3b2f2976 XL |
397 | def |
398 | } | |
c30ab7b3 | 399 | |
3b2f2976 XL |
400 | fn resolve_macro_to_def_inner(&mut self, scope: Mark, path: &ast::Path, |
401 | kind: MacroKind, force: bool) | |
402 | -> Result<Def, Determinacy> { | |
403 | let ast::Path { ref segments, span } = *path; | |
404 | let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect(); | |
c30ab7b3 | 405 | let invocation = self.invocations[&scope]; |
ea8adc8c XL |
406 | let module = invocation.module.get(); |
407 | self.current_module = if module.is_trait() { module.parent.unwrap() } else { module }; | |
476ff2be | 408 | |
32a655c1 | 409 | if path.len() > 1 { |
cc61c64b | 410 | if !self.use_extern_macros && self.gated_errors.insert(span) { |
476ff2be SL |
411 | let msg = "non-ident macro paths are experimental"; |
412 | let feature = "use_extern_macros"; | |
413 | emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg); | |
8bb4bdeb | 414 | self.found_unresolved_macro = true; |
476ff2be | 415 | return Err(Determinacy::Determined); |
9e0c209e | 416 | } |
476ff2be | 417 | |
7cac9316 | 418 | let def = match self.resolve_path(&path, Some(MacroNS), false, span) { |
8bb4bdeb | 419 | PathResult::NonModule(path_res) => match path_res.base_def() { |
32a655c1 | 420 | Def::Err => Err(Determinacy::Determined), |
8bb4bdeb | 421 | def @ _ => Ok(def), |
32a655c1 | 422 | }, |
476ff2be SL |
423 | PathResult::Module(..) => unreachable!(), |
424 | PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), | |
8bb4bdeb XL |
425 | _ => { |
426 | self.found_unresolved_macro = true; | |
427 | Err(Determinacy::Determined) | |
428 | }, | |
476ff2be | 429 | }; |
3b2f2976 | 430 | let path = path.iter().map(|p| p.node).collect::<Vec<_>>(); |
8bb4bdeb | 431 | self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() |
32a655c1 | 432 | .push((path.into_boxed_slice(), span)); |
8bb4bdeb | 433 | return def; |
476ff2be SL |
434 | } |
435 | ||
3b2f2976 XL |
436 | let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, |
437 | path[0].node, | |
438 | false); | |
cc61c64b XL |
439 | let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { |
440 | Ok(Def::Macro(binding.def_id, MacroKind::Bang)) | |
441 | } else { | |
3b2f2976 | 442 | match self.resolve_lexical_macro_path_segment(path[0].node, MacroNS, false, span) { |
cc61c64b XL |
443 | Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), |
444 | Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), | |
8bb4bdeb XL |
445 | Err(_) => { |
446 | self.found_unresolved_macro = true; | |
447 | Err(Determinacy::Determined) | |
448 | } | |
cc61c64b | 449 | } |
476ff2be SL |
450 | }; |
451 | ||
8bb4bdeb | 452 | self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() |
3b2f2976 | 453 | .push((scope, path[0].node, span, kind)); |
8bb4bdeb | 454 | |
476ff2be | 455 | result |
c30ab7b3 | 456 | } |
9e0c209e | 457 | |
476ff2be SL |
458 | // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) |
459 | pub fn resolve_lexical_macro_path_segment(&mut self, | |
7cac9316 | 460 | mut ident: Ident, |
476ff2be | 461 | ns: Namespace, |
7cac9316 XL |
462 | record_used: bool, |
463 | path_span: Span) | |
cc61c64b | 464 | -> Result<MacroBinding<'a>, Determinacy> { |
7cac9316 | 465 | ident = ident.modern(); |
cc61c64b XL |
466 | let mut module = Some(self.current_module); |
467 | let mut potential_illegal_shadower = Err(Determinacy::Determined); | |
468 | let determinacy = | |
7cac9316 | 469 | if record_used { Determinacy::Determined } else { Determinacy::Undetermined }; |
476ff2be | 470 | loop { |
7cac9316 | 471 | let orig_current_module = self.current_module; |
cc61c64b | 472 | let result = if let Some(module) = module { |
7cac9316 | 473 | self.current_module = module; // Lexical resolutions can never be a privacy error. |
cc61c64b XL |
474 | // Since expanded macros may not shadow the lexical scope and |
475 | // globs may not shadow global macros (both enforced below), | |
476 | // we resolve with restricted shadowing (indicated by the penultimate argument). | |
7cac9316 XL |
477 | self.resolve_ident_in_module_unadjusted( |
478 | module, ident, ns, true, record_used, path_span, | |
479 | ).map(MacroBinding::Modern) | |
cc61c64b XL |
480 | } else { |
481 | self.global_macros.get(&ident.name).cloned().ok_or(determinacy) | |
482 | .map(MacroBinding::Global) | |
483 | }; | |
7cac9316 | 484 | self.current_module = orig_current_module; |
cc61c64b XL |
485 | |
486 | match result.map(MacroBinding::binding) { | |
476ff2be | 487 | Ok(binding) => { |
7cac9316 XL |
488 | if !record_used { |
489 | return result; | |
490 | } | |
cc61c64b XL |
491 | if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower { |
492 | if shadower.def() != binding.def() { | |
32a655c1 | 493 | let name = ident.name; |
476ff2be | 494 | self.ambiguity_errors.push(AmbiguityError { |
7cac9316 | 495 | span: path_span, |
3b2f2976 | 496 | name, |
7cac9316 XL |
497 | b1: shadower, |
498 | b2: binding, | |
499 | lexical: true, | |
476ff2be SL |
500 | legacy: false, |
501 | }); | |
cc61c64b | 502 | return potential_illegal_shadower; |
476ff2be | 503 | } |
cc61c64b XL |
504 | } |
505 | if binding.expansion != Mark::root() || | |
506 | (binding.is_glob_import() && module.unwrap().def().is_some()) { | |
507 | potential_illegal_shadower = result; | |
508 | } else { | |
509 | return result; | |
476ff2be SL |
510 | } |
511 | }, | |
512 | Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), | |
513 | Err(Determinacy::Determined) => {} | |
514 | } | |
515 | ||
cc61c64b | 516 | module = match module { |
7cac9316 | 517 | Some(module) => self.hygienic_lexical_parent(module, &mut ident.ctxt), |
cc61c64b | 518 | None => return potential_illegal_shadower, |
476ff2be SL |
519 | } |
520 | } | |
521 | } | |
522 | ||
523 | pub fn resolve_legacy_scope(&mut self, | |
524 | mut scope: &'a Cell<LegacyScope<'a>>, | |
7cac9316 | 525 | ident: Ident, |
476ff2be SL |
526 | record_used: bool) |
527 | -> Option<MacroBinding<'a>> { | |
7cac9316 | 528 | let ident = ident.modern(); |
c30ab7b3 SL |
529 | let mut possible_time_travel = None; |
530 | let mut relative_depth: u32 = 0; | |
476ff2be | 531 | let mut binding = None; |
9e0c209e | 532 | loop { |
476ff2be | 533 | match scope.get() { |
c30ab7b3 SL |
534 | LegacyScope::Empty => break, |
535 | LegacyScope::Expansion(invocation) => { | |
476ff2be SL |
536 | match invocation.expansion.get() { |
537 | LegacyScope::Invocation(_) => scope.set(invocation.legacy_scope.get()), | |
538 | LegacyScope::Empty => { | |
539 | if possible_time_travel.is_none() { | |
540 | possible_time_travel = Some(scope); | |
541 | } | |
542 | scope = &invocation.legacy_scope; | |
543 | } | |
544 | _ => { | |
545 | relative_depth += 1; | |
546 | scope = &invocation.expansion; | |
c30ab7b3 | 547 | } |
c30ab7b3 SL |
548 | } |
549 | } | |
550 | LegacyScope::Invocation(invocation) => { | |
551 | relative_depth = relative_depth.saturating_sub(1); | |
476ff2be | 552 | scope = &invocation.legacy_scope; |
c30ab7b3 | 553 | } |
476ff2be | 554 | LegacyScope::Binding(potential_binding) => { |
7cac9316 | 555 | if potential_binding.ident == ident { |
476ff2be SL |
556 | if (!self.use_extern_macros || record_used) && relative_depth > 0 { |
557 | self.disallowed_shadowing.push(potential_binding); | |
c30ab7b3 | 558 | } |
476ff2be SL |
559 | binding = Some(potential_binding); |
560 | break | |
c30ab7b3 | 561 | } |
476ff2be | 562 | scope = &potential_binding.parent; |
c30ab7b3 SL |
563 | } |
564 | }; | |
9e0c209e SL |
565 | } |
566 | ||
32a655c1 SL |
567 | let binding = if let Some(binding) = binding { |
568 | MacroBinding::Legacy(binding) | |
7cac9316 | 569 | } else if let Some(binding) = self.global_macros.get(&ident.name).cloned() { |
32a655c1 | 570 | if !self.use_extern_macros { |
7cac9316 | 571 | self.record_use(ident, MacroNS, binding, DUMMY_SP); |
32a655c1 | 572 | } |
cc61c64b | 573 | MacroBinding::Global(binding) |
32a655c1 SL |
574 | } else { |
575 | return None; | |
476ff2be SL |
576 | }; |
577 | ||
578 | if !self.use_extern_macros { | |
579 | if let Some(scope) = possible_time_travel { | |
580 | // Check for disallowed shadowing later | |
7cac9316 | 581 | self.lexical_macro_resolutions.push((ident, scope)); |
476ff2be SL |
582 | } |
583 | } | |
584 | ||
585 | Some(binding) | |
586 | } | |
587 | ||
588 | pub fn finalize_current_module_macro_resolutions(&mut self) { | |
589 | let module = self.current_module; | |
32a655c1 | 590 | for &(ref path, span) in module.macro_resolutions.borrow().iter() { |
3b2f2976 XL |
591 | let path = path.iter().map(|p| respan(span, *p)).collect::<Vec<_>>(); |
592 | match self.resolve_path(&path, Some(MacroNS), true, span) { | |
476ff2be | 593 | PathResult::NonModule(_) => {}, |
3b2f2976 | 594 | PathResult::Failed(span, msg, _) => { |
476ff2be SL |
595 | resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); |
596 | } | |
597 | _ => unreachable!(), | |
598 | } | |
599 | } | |
600 | ||
8bb4bdeb | 601 | for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() { |
476ff2be | 602 | let legacy_scope = &self.invocations[&mark].legacy_scope; |
7cac9316 XL |
603 | let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true); |
604 | let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span); | |
8bb4bdeb | 605 | match (legacy_resolution, resolution) { |
cc61c64b XL |
606 | (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => { |
607 | let msg1 = format!("`{}` could refer to the macro defined here", ident); | |
8bb4bdeb XL |
608 | let msg2 = format!("`{}` could also refer to the macro imported here", ident); |
609 | self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident)) | |
cc61c64b XL |
610 | .span_note(legacy_binding.span, &msg1) |
611 | .span_note(binding.span, &msg2) | |
8bb4bdeb XL |
612 | .emit(); |
613 | }, | |
cc61c64b | 614 | (Some(MacroBinding::Global(binding)), Ok(MacroBinding::Global(_))) => { |
32a655c1 SL |
615 | self.record_use(ident, MacroNS, binding, span); |
616 | self.err_if_macro_use_proc_macro(ident.name, span, binding); | |
32a655c1 | 617 | }, |
8bb4bdeb XL |
618 | (None, Err(_)) => { |
619 | let msg = match kind { | |
620 | MacroKind::Bang => | |
621 | format!("cannot find macro `{}!` in this scope", ident), | |
622 | MacroKind::Attr => | |
623 | format!("cannot find attribute macro `{}` in this scope", ident), | |
624 | MacroKind::Derive => | |
625 | format!("cannot find derive macro `{}` in this scope", ident), | |
626 | }; | |
627 | let mut err = self.session.struct_span_err(span, &msg); | |
7cac9316 | 628 | self.suggest_macro_name(&ident.name.as_str(), kind, &mut err, span); |
8bb4bdeb XL |
629 | err.emit(); |
630 | }, | |
631 | _ => {}, | |
476ff2be | 632 | }; |
c30ab7b3 | 633 | } |
9e0c209e | 634 | } |
9e0c209e | 635 | |
8bb4bdeb | 636 | fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, |
7cac9316 | 637 | err: &mut DiagnosticBuilder<'a>, span: Span) { |
8bb4bdeb XL |
638 | // First check if this is a locally-defined bang macro. |
639 | let suggestion = if let MacroKind::Bang = kind { | |
7cac9316 | 640 | find_best_match_for_name(self.macro_names.iter().map(|ident| &ident.name), name, None) |
8bb4bdeb XL |
641 | } else { |
642 | None | |
cc61c64b | 643 | // Then check global macros. |
8bb4bdeb XL |
644 | }.or_else(|| { |
645 | // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? | |
cc61c64b XL |
646 | let global_macros = self.global_macros.clone(); |
647 | let names = global_macros.iter().filter_map(|(name, binding)| { | |
8bb4bdeb XL |
648 | if binding.get_macro(self).kind() == kind { |
649 | Some(name) | |
650 | } else { | |
651 | None | |
652 | } | |
653 | }); | |
654 | find_best_match_for_name(names, name, None) | |
655 | // Then check modules. | |
656 | }).or_else(|| { | |
657 | if !self.use_extern_macros { | |
658 | return None; | |
659 | } | |
660 | let is_macro = |def| { | |
661 | if let Def::Macro(_, def_kind) = def { | |
662 | def_kind == kind | |
663 | } else { | |
664 | false | |
665 | } | |
666 | }; | |
667 | let ident = Ident::from_str(name); | |
3b2f2976 | 668 | self.lookup_typo_candidate(&vec![respan(span, ident)], MacroNS, is_macro, span) |
8bb4bdeb XL |
669 | }); |
670 | ||
671 | if let Some(suggestion) = suggestion { | |
9e0c209e | 672 | if suggestion != name { |
8bb4bdeb | 673 | if let MacroKind::Bang = kind { |
041b39d2 XL |
674 | err.span_suggestion(span, "you could try the macro", |
675 | format!("{}!", suggestion)); | |
8bb4bdeb | 676 | } else { |
041b39d2 | 677 | err.span_suggestion(span, "try", suggestion.to_string()); |
8bb4bdeb | 678 | } |
9e0c209e | 679 | } else { |
7cac9316 | 680 | err.help("have you added the `#[macro_use]` on the module/import?"); |
9e0c209e SL |
681 | } |
682 | } | |
683 | } | |
684 | ||
7cac9316 XL |
685 | fn collect_def_ids(&mut self, |
686 | mark: Mark, | |
687 | invocation: &'a InvocationData<'a>, | |
688 | expansion: &Expansion) { | |
c30ab7b3 | 689 | let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; |
32a655c1 | 690 | let InvocationData { def_index, const_expr, .. } = *invocation; |
9e0c209e | 691 | |
c30ab7b3 SL |
692 | let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { |
693 | invocations.entry(invoc.mark).or_insert_with(|| { | |
694 | arenas.alloc_invocation_data(InvocationData { | |
695 | def_index: invoc.def_index, | |
32a655c1 | 696 | const_expr: invoc.const_expr, |
c30ab7b3 SL |
697 | module: Cell::new(graph_root), |
698 | expansion: Cell::new(LegacyScope::Empty), | |
699 | legacy_scope: Cell::new(LegacyScope::Empty), | |
700 | }) | |
701 | }); | |
702 | }; | |
9e0c209e | 703 | |
7cac9316 | 704 | let mut def_collector = DefCollector::new(&mut self.definitions, mark); |
c30ab7b3 SL |
705 | def_collector.visit_macro_invoc = Some(visit_macro_invoc); |
706 | def_collector.with_parent(def_index, |def_collector| { | |
32a655c1 | 707 | if const_expr { |
c30ab7b3 | 708 | if let Expansion::Expr(ref expr) = *expansion { |
32a655c1 | 709 | def_collector.visit_const_expr(expr); |
9e0c209e | 710 | } |
9e0c209e | 711 | } |
c30ab7b3 SL |
712 | expansion.visit_with(def_collector) |
713 | }); | |
9e0c209e | 714 | } |
32a655c1 | 715 | |
7cac9316 XL |
716 | pub fn define_macro(&mut self, |
717 | item: &ast::Item, | |
718 | expansion: Mark, | |
719 | legacy_scope: &mut LegacyScope<'a>) { | |
8bb4bdeb XL |
720 | self.local_macro_def_scopes.insert(item.id, self.current_module); |
721 | let ident = item.ident; | |
722 | if ident.name == "macro_rules" { | |
32a655c1 SL |
723 | self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); |
724 | } | |
725 | ||
8bb4bdeb | 726 | let def_id = self.definitions.local_def_id(item.id); |
cc61c64b XL |
727 | let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, |
728 | &self.session.features, | |
729 | item)); | |
8bb4bdeb | 730 | self.macro_map.insert(def_id, ext); |
32a655c1 | 731 | |
7cac9316 XL |
732 | let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() }; |
733 | if def.legacy { | |
734 | let ident = ident.modern(); | |
735 | self.macro_names.insert(ident); | |
736 | *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { | |
737 | parent: Cell::new(*legacy_scope), ident: ident, def_id: def_id, span: item.span, | |
738 | })); | |
739 | if attr::contains_name(&item.attrs, "macro_export") { | |
740 | let def = Def::Macro(def_id, MacroKind::Bang); | |
741 | self.macro_exports | |
742 | .push(Export { ident: ident.modern(), def: def, span: item.span }); | |
743 | } else { | |
744 | self.unused_macros.insert(def_id); | |
745 | } | |
746 | } else { | |
747 | let module = self.current_module; | |
8bb4bdeb | 748 | let def = Def::Macro(def_id, MacroKind::Bang); |
7cac9316 XL |
749 | let vis = self.resolve_visibility(&item.vis); |
750 | if vis != ty::Visibility::Public { | |
751 | self.unused_macros.insert(def_id); | |
752 | } | |
753 | self.define(module, ident, MacroNS, (def, vis, item.span, expansion)); | |
32a655c1 SL |
754 | } |
755 | } | |
756 | ||
757 | /// Error if `ext` is a Macros 1.1 procedural macro being imported by `#[macro_use]` | |
758 | fn err_if_macro_use_proc_macro(&mut self, name: Name, use_span: Span, | |
759 | binding: &NameBinding<'a>) { | |
760 | use self::SyntaxExtension::*; | |
761 | ||
762 | let krate = binding.def().def_id().krate; | |
763 | ||
764 | // Plugin-based syntax extensions are exempt from this check | |
765 | if krate == BUILTIN_MACROS_CRATE { return; } | |
766 | ||
767 | let ext = binding.get_macro(self); | |
768 | ||
769 | match *ext { | |
770 | // If `ext` is a procedural macro, check if we've already warned about it | |
771 | AttrProcMacro(_) | ProcMacro(_) => if !self.warned_proc_macros.insert(name) { return; }, | |
772 | _ => return, | |
773 | } | |
774 | ||
775 | let warn_msg = match *ext { | |
776 | AttrProcMacro(_) => "attribute procedural macros cannot be \ | |
777 | imported with `#[macro_use]`", | |
778 | ProcMacro(_) => "procedural macros cannot be imported with `#[macro_use]`", | |
779 | _ => return, | |
780 | }; | |
781 | ||
ea8adc8c | 782 | let crate_name = self.cstore.crate_name_untracked(krate); |
32a655c1 SL |
783 | |
784 | self.session.struct_span_err(use_span, warn_msg) | |
785 | .help(&format!("instead, import the procedural macro like any other item: \ | |
786 | `use {}::{};`", crate_name, name)) | |
787 | .emit(); | |
788 | } | |
8bb4bdeb XL |
789 | |
790 | fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) { | |
791 | if !self.session.features.borrow().custom_derive { | |
792 | let sess = &self.session.parse_sess; | |
793 | let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE; | |
794 | emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain); | |
795 | } else if !self.is_whitelisted_legacy_custom_derive(name) { | |
796 | self.session.span_warn(span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); | |
797 | } | |
798 | } | |
9e0c209e | 799 | } |