Skip to content

Commit 64e9af4

Browse files
committed
Allow declarative macros 2.0 and use macro imports to shadow builtin macros.
1 parent f2036c7 commit 64e9af4

File tree

4 files changed

+163
-59
lines changed

4 files changed

+163
-59
lines changed

src/librustc_resolve/lib.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ use std::mem::replace;
7575
use std::rc::Rc;
7676

7777
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
78-
use macros::{InvocationData, LegacyBinding, LegacyScope};
78+
use macros::{InvocationData, LegacyBinding, LegacyScope, MacroBinding};
7979

8080
// NB: This module needs to be declared first so diagnostics are
8181
// registered before they are used.
@@ -2566,6 +2566,7 @@ impl<'a> Resolver<'a> {
25662566
self.resolve_ident_in_module(module, ident, ns, false, record_used)
25672567
} else if opt_ns == Some(MacroNS) {
25682568
self.resolve_lexical_macro_path_segment(ident, ns, record_used)
2569+
.map(MacroBinding::binding)
25692570
} else {
25702571
match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
25712572
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -3223,7 +3224,7 @@ impl<'a> Resolver<'a> {
32233224
};
32243225
let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1));
32253226
let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2));
3226-
let note = if !lexical && b1.is_glob_import() {
3227+
let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() {
32273228
format!("consider adding an explicit import of `{}` to disambiguate", name)
32283229
} else if let Def::Macro(..) = b1.def() {
32293230
format!("macro-expanded {} do not shadow",
@@ -3243,11 +3244,15 @@ impl<'a> Resolver<'a> {
32433244
let msg = format!("`{}` is ambiguous", name);
32443245
self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
32453246
} else {
3246-
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
3247-
.span_note(b1.span, &msg1)
3248-
.span_note(b2.span, &msg2)
3249-
.note(&note)
3250-
.emit();
3247+
let mut err =
3248+
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name));
3249+
err.span_note(b1.span, &msg1);
3250+
match b2.def() {
3251+
Def::Macro(..) if b2.span == DUMMY_SP =>
3252+
err.note(&format!("`{}` is also a builtin macro", name)),
3253+
_ => err.span_note(b2.span, &msg2),
3254+
};
3255+
err.note(&note).emit();
32513256
}
32523257
}
32533258

@@ -3361,22 +3366,21 @@ impl<'a> Resolver<'a> {
33613366
if self.proc_macro_enabled { return; }
33623367

33633368
for attr in attrs {
3364-
let name = unwrap_or!(attr.name(), continue);
3365-
let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| {
3366-
let ident = Ident::with_empty_ctxt(name);
3367-
self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok()
3368-
});
3369-
3370-
if let Some(binding) = maybe_binding {
3371-
if let SyntaxExtension::AttrProcMacro(..) = *binding.get_macro(self) {
3369+
if attr.path.segments.len() > 1 {
3370+
continue
3371+
}
3372+
let ident = attr.path.segments[0].identifier;
3373+
let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None);
3374+
if let Ok(binding) = result {
3375+
if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
33723376
attr::mark_known(attr);
33733377

33743378
let msg = "attribute procedural macros are experimental";
33753379
let feature = "proc_macro";
33763380

33773381
feature_err(&self.session.parse_sess, feature,
33783382
attr.span, GateIssue::Language, msg)
3379-
.span_note(binding.span, "procedural macro imported here")
3383+
.span_note(binding.span(), "procedural macro imported here")
33803384
.emit();
33813385
}
33823386
}

src/librustc_resolve/macros.rs

+64-38
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,29 @@ pub struct LegacyBinding<'a> {
8181
pub span: Span,
8282
}
8383

84+
#[derive(Copy, Clone)]
8485
pub enum MacroBinding<'a> {
8586
Legacy(&'a LegacyBinding<'a>),
87+
Builtin(&'a NameBinding<'a>),
8688
Modern(&'a NameBinding<'a>),
8789
}
8890

91+
impl<'a> MacroBinding<'a> {
92+
pub fn span(self) -> Span {
93+
match self {
94+
MacroBinding::Legacy(binding) => binding.span,
95+
MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span,
96+
}
97+
}
98+
99+
pub fn binding(self) -> &'a NameBinding<'a> {
100+
match self {
101+
MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding,
102+
MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"),
103+
}
104+
}
105+
}
106+
89107
impl<'a> base::Resolver for Resolver<'a> {
90108
fn next_node_id(&mut self) -> ast::NodeId {
91109
self.session.next_node_id()
@@ -378,18 +396,18 @@ impl<'a> Resolver<'a> {
378396
}
379397

380398
let name = path[0].name;
381-
let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
382-
Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)),
383-
Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()),
384-
None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
385-
Ok(binding) => Ok(binding.def_ignoring_ambiguity()),
386-
Err(Determinacy::Undetermined) if !force =>
387-
return Err(Determinacy::Undetermined),
399+
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false);
400+
let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
401+
Ok(Def::Macro(binding.def_id, MacroKind::Bang))
402+
} else {
403+
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
404+
Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
405+
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
388406
Err(_) => {
389407
self.found_unresolved_macro = true;
390408
Err(Determinacy::Determined)
391409
}
392-
},
410+
}
393411
};
394412

395413
self.current_module.legacy_macro_resolutions.borrow_mut()
@@ -403,42 +421,56 @@ impl<'a> Resolver<'a> {
403421
ident: Ident,
404422
ns: Namespace,
405423
record_used: Option<Span>)
406-
-> Result<&'a NameBinding<'a>, Determinacy> {
407-
let mut module = self.current_module;
408-
let mut potential_expanded_shadower: Option<&NameBinding> = None;
424+
-> Result<MacroBinding<'a>, Determinacy> {
425+
let mut module = Some(self.current_module);
426+
let mut potential_illegal_shadower = Err(Determinacy::Determined);
427+
let determinacy =
428+
if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined };
409429
loop {
410-
// Since expanded macros may not shadow the lexical scope (enforced below),
411-
// we can ignore unresolved invocations (indicated by the penultimate argument).
412-
match self.resolve_ident_in_module(module, ident, ns, true, record_used) {
430+
let result = if let Some(module) = module {
431+
// Since expanded macros may not shadow the lexical scope and
432+
// globs may not shadow builtin macros (both enforced below),
433+
// we resolve with restricted shadowing (indicated by the penultimate argument).
434+
self.resolve_ident_in_module(module, ident, ns, true, record_used)
435+
.map(MacroBinding::Modern)
436+
} else {
437+
self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy)
438+
.map(MacroBinding::Builtin)
439+
};
440+
441+
match result.map(MacroBinding::binding) {
413442
Ok(binding) => {
414443
let span = match record_used {
415444
Some(span) => span,
416-
None => return Ok(binding),
445+
None => return result,
417446
};
418-
match potential_expanded_shadower {
419-
Some(shadower) if shadower.def() != binding.def() => {
447+
if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
448+
if shadower.def() != binding.def() {
420449
let name = ident.name;
421450
self.ambiguity_errors.push(AmbiguityError {
422451
span: span, name: name, b1: shadower, b2: binding, lexical: true,
423452
legacy: false,
424453
});
425-
return Ok(shadower);
454+
return potential_illegal_shadower;
426455
}
427-
_ if binding.expansion == Mark::root() => return Ok(binding),
428-
_ => potential_expanded_shadower = Some(binding),
456+
}
457+
if binding.expansion != Mark::root() ||
458+
(binding.is_glob_import() && module.unwrap().def().is_some()) {
459+
potential_illegal_shadower = result;
460+
} else {
461+
return result;
429462
}
430463
},
431464
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
432465
Err(Determinacy::Determined) => {}
433466
}
434467

435-
match module.kind {
436-
ModuleKind::Block(..) => module = module.parent.unwrap(),
437-
ModuleKind::Def(..) => return match potential_expanded_shadower {
438-
Some(binding) => Ok(binding),
439-
None if record_used.is_some() => Err(Determinacy::Determined),
440-
None => Err(Determinacy::Undetermined),
468+
module = match module {
469+
Some(module) => match module.kind {
470+
ModuleKind::Block(..) => module.parent,
471+
ModuleKind::Def(..) => None,
441472
},
473+
None => return potential_illegal_shadower,
442474
}
443475
}
444476
}
@@ -492,7 +524,7 @@ impl<'a> Resolver<'a> {
492524
if !self.use_extern_macros {
493525
self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP);
494526
}
495-
MacroBinding::Modern(binding)
527+
MacroBinding::Builtin(binding)
496528
} else {
497529
return None;
498530
};
@@ -524,21 +556,15 @@ impl<'a> Resolver<'a> {
524556
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true);
525557
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span));
526558
match (legacy_resolution, resolution) {
527-
(Some(legacy_resolution), Ok(resolution)) => {
528-
let (legacy_span, participle) = match legacy_resolution {
529-
MacroBinding::Modern(binding)
530-
if binding.def() == resolution.def() => continue,
531-
MacroBinding::Modern(binding) => (binding.span, "imported"),
532-
MacroBinding::Legacy(binding) => (binding.span, "defined"),
533-
};
534-
let msg1 = format!("`{}` could refer to the macro {} here", ident, participle);
559+
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
560+
let msg1 = format!("`{}` could refer to the macro defined here", ident);
535561
let msg2 = format!("`{}` could also refer to the macro imported here", ident);
536562
self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
537-
.span_note(legacy_span, &msg1)
538-
.span_note(resolution.span, &msg2)
563+
.span_note(legacy_binding.span, &msg1)
564+
.span_note(binding.span, &msg2)
539565
.emit();
540566
},
541-
(Some(MacroBinding::Modern(binding)), Err(_)) => {
567+
(Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => {
542568
self.record_use(ident, MacroNS, binding, span);
543569
self.err_if_macro_use_proc_macro(ident.name, span, binding);
544570
},

src/librustc_resolve/resolve_imports.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ impl<'a> Resolver<'a> {
145145
module: Module<'a>,
146146
ident: Ident,
147147
ns: Namespace,
148-
ignore_unresolved_invocations: bool,
148+
restricted_shadowing: bool,
149149
record_used: Option<Span>)
150150
-> Result<&'a NameBinding<'a>, Determinacy> {
151151
self.populate_module_if_necessary(module);
@@ -158,9 +158,8 @@ impl<'a> Resolver<'a> {
158158
if let Some(binding) = resolution.binding {
159159
if let Some(shadowed_glob) = resolution.shadows_glob {
160160
let name = ident.name;
161-
// If we ignore unresolved invocations, we must forbid
162-
// expanded shadowing to avoid time travel.
163-
if ignore_unresolved_invocations &&
161+
// Forbid expanded shadowing to avoid time travel.
162+
if restricted_shadowing &&
164163
binding.expansion != Mark::root() &&
165164
ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
166165
binding.def() != shadowed_glob.def() {
@@ -215,7 +214,7 @@ impl<'a> Resolver<'a> {
215214
}
216215

217216
let no_unresolved_invocations =
218-
ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty();
217+
restricted_shadowing || module.unresolved_invocations.borrow().is_empty();
219218
match resolution.binding {
220219
// In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`).
221220
Some(binding) if no_unresolved_invocations || ns == MacroNS =>
@@ -225,6 +224,9 @@ impl<'a> Resolver<'a> {
225224
}
226225

227226
// Check if the globs are determined
227+
if restricted_shadowing && module.def().is_some() {
228+
return Err(Determined);
229+
}
228230
for directive in module.globs.borrow().iter() {
229231
if self.is_accessible(directive.vis.get()) {
230232
if let Some(module) = directive.imported_module.get() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2017 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+
11+
// aux-build:two_macros.rs
12+
13+
#![feature(use_extern_macros)]
14+
15+
mod foo {
16+
extern crate two_macros;
17+
pub use self::two_macros::m as panic;
18+
}
19+
20+
mod m1 {
21+
use foo::panic; // ok
22+
fn f() { panic!(); }
23+
}
24+
25+
mod m2 {
26+
use foo::*; //~ NOTE `panic` could refer to the name imported here
27+
fn f() { panic!(); } //~ ERROR ambiguous
28+
//~| NOTE `panic` is also a builtin macro
29+
//~| NOTE consider adding an explicit import of `panic` to disambiguate
30+
}
31+
32+
mod m3 {
33+
::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here
34+
//~| NOTE in this expansion
35+
fn f() { panic!(); } //~ ERROR ambiguous
36+
//~| NOTE `panic` is also a builtin macro
37+
//~| NOTE macro-expanded macro imports do not shadow
38+
}
39+
40+
mod m4 {
41+
macro_rules! panic { () => {} } // ok
42+
panic!();
43+
}
44+
45+
mod m5 {
46+
macro_rules! m { () => {
47+
macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope
48+
//~| NOTE macro-expanded `macro_rules!`s may not shadow existing macros
49+
} }
50+
m!(); //~ NOTE in this expansion
51+
//~| NOTE in this expansion
52+
panic!();
53+
}
54+
55+
#[macro_use(n)] //~ NOTE `n` could also refer to the name imported here
56+
extern crate two_macros;
57+
mod bar {
58+
pub use two_macros::m as n;
59+
}
60+
61+
mod m6 {
62+
use bar::n; // ok
63+
n!();
64+
}
65+
66+
mod m7 {
67+
use bar::*; //~ NOTE `n` could refer to the name imported here
68+
n!(); //~ ERROR ambiguous
69+
//~| NOTE consider adding an explicit import of `n` to disambiguate
70+
}
71+
72+
fn main() {}

0 commit comments

Comments
 (0)