Skip to content

Commit c43d5e3

Browse files
authored
Rollup merge of rust-lang#40501 - jseyfried:shadow_builtin_macros, r=nrc
Allow `use` macro imports to shadow global macros Terminology: - global scope: builtin macros, macros from the prelude, `#[macro_use]`, or `#![plugin(..)]`. - legacy scope: crate-local `macro_rules!`. - modern scope: `use` macro imports, `macro` (once implemented). Today, the legacy scope can shadow the global scope (modulo RFC 1560 expanded shadowing restrictions). However, the modern scope cannot shadow or be shadowed by either the global or legacy scopes, leading to ambiguity errors. This PR allows the modern scope to shadow the global scope (subject to some restrictions). More specifically, a name in the global scope is as shadowable as a glob import in the module `self`. In other words, we imagine a special, implicit glob import in each module item: ```rust mod foo { #[lexical_only] // Not accessible via `foo::<name>`, like pre-RFC 1560 `use` imports. #[shadowable_by_legacy_scope] // for back-compat use <global_macros>::*; } ``` r? @nrc
2 parents 16bfc19 + d64d381 commit c43d5e3

File tree

5 files changed

+175
-71
lines changed

5 files changed

+175
-71
lines changed

src/librustc_resolve/build_reduced_graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ impl<'a> Resolver<'a> {
539539
binding: &'a NameBinding<'a>,
540540
span: Span,
541541
allow_shadowing: bool) {
542-
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
542+
if self.global_macros.insert(name, binding).is_some() && !allow_shadowing {
543543
let msg = format!("`{}` is already in scope", name);
544544
let note =
545545
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";

src/librustc_resolve/lib.rs

+24-20
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.
@@ -1174,7 +1174,7 @@ pub struct Resolver<'a> {
11741174

11751175
crate_loader: &'a mut CrateLoader,
11761176
macro_names: FxHashSet<Name>,
1177-
builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
1177+
global_macros: FxHashMap<Name, &'a NameBinding<'a>>,
11781178
lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
11791179
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
11801180
macro_defs: FxHashMap<Mark, DefId>,
@@ -1372,7 +1372,7 @@ impl<'a> Resolver<'a> {
13721372

13731373
crate_loader: crate_loader,
13741374
macro_names: FxHashSet(),
1375-
builtin_macros: FxHashMap(),
1375+
global_macros: FxHashMap(),
13761376
lexical_macro_resolutions: Vec::new(),
13771377
macro_map: FxHashMap(),
13781378
macro_exports: Vec::new(),
@@ -2429,9 +2429,9 @@ impl<'a> Resolver<'a> {
24292429
};
24302430
}
24312431
}
2432-
let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
2432+
let is_global = self.global_macros.get(&path[0].name).cloned()
24332433
.map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
2434-
if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
2434+
if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].name)) {
24352435
// Return some dummy definition, it's enough for error reporting.
24362436
return Some(
24372437
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
@@ -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

+71-45
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+
Global(&'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::Global(binding) | MacroBinding::Modern(binding) => binding.span,
96+
}
97+
}
98+
99+
pub fn binding(self) -> &'a NameBinding<'a> {
100+
match self {
101+
MacroBinding::Global(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()
@@ -171,7 +189,7 @@ impl<'a> base::Resolver for Resolver<'a> {
171189
vis: ty::Visibility::Invisible,
172190
expansion: Mark::root(),
173191
});
174-
self.builtin_macros.insert(ident.name, binding);
192+
self.global_macros.insert(ident.name, binding);
175193
}
176194

177195
fn resolve_imports(&mut self) {
@@ -189,7 +207,7 @@ impl<'a> base::Resolver for Resolver<'a> {
189207
attr::mark_known(&attrs[i]);
190208
}
191209

192-
match self.builtin_macros.get(&name).cloned() {
210+
match self.global_macros.get(&name).cloned() {
193211
Some(binding) => match *binding.get_macro(self) {
194212
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
195213
return Some(attrs.remove(i))
@@ -221,7 +239,7 @@ impl<'a> base::Resolver for Resolver<'a> {
221239
}
222240
let trait_name = traits[j].segments[0].identifier.name;
223241
let legacy_name = Symbol::intern(&format!("derive_{}", trait_name));
224-
if !self.builtin_macros.contains_key(&legacy_name) {
242+
if !self.global_macros.contains_key(&legacy_name) {
225243
continue
226244
}
227245
let span = traits.remove(j).span;
@@ -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 global 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.global_macros.get(&ident.name).cloned().ok_or(determinacy)
438+
.map(MacroBinding::Global)
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
}
@@ -488,11 +520,11 @@ impl<'a> Resolver<'a> {
488520

489521
let binding = if let Some(binding) = binding {
490522
MacroBinding::Legacy(binding)
491-
} else if let Some(binding) = self.builtin_macros.get(&name).cloned() {
523+
} else if let Some(binding) = self.global_macros.get(&name).cloned() {
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::Global(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::Global(binding)), Ok(MacroBinding::Global(_))) => {
542568
self.record_use(ident, MacroNS, binding, span);
543569
self.err_if_macro_use_proc_macro(ident.name, span, binding);
544570
},
@@ -567,11 +593,11 @@ impl<'a> Resolver<'a> {
567593
find_best_match_for_name(self.macro_names.iter(), name, None)
568594
} else {
569595
None
570-
// Then check builtin macros.
596+
// Then check global macros.
571597
}.or_else(|| {
572598
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
573-
let builtin_macros = self.builtin_macros.clone();
574-
let names = builtin_macros.iter().filter_map(|(name, binding)| {
599+
let global_macros = self.global_macros.clone();
600+
let names = global_macros.iter().filter_map(|(name, binding)| {
575601
if binding.get_macro(self).kind() == kind {
576602
Some(name)
577603
} else {

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() {

0 commit comments

Comments
 (0)