Skip to content

Commit

Permalink
resolve: Make sure indeterminate and inconsistent macro resolutions a…
Browse files Browse the repository at this point in the history
…lways generate errors
  • Loading branch information
petrochenkov committed May 30, 2018
1 parent 74d0939 commit 345e7c3
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/librustc/hir/def.rs
Expand Up @@ -210,7 +210,7 @@ impl Def {
Def::Upvar(..) => "closure capture",
Def::Label(..) => "label",
Def::SelfTy(..) => "self type",
Def::Macro(..) => "macro",
Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm",
Def::Err => "unresolved item",
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/lib.rs
Expand Up @@ -1000,7 +1000,7 @@ pub struct ModuleData<'a> {
normal_ancestor_id: DefId,

resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, Span, MacroKind)>>,
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, MacroKind, Option<Def>)>>,
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,

// Macro invocations that can expand into items in this module.
Expand Down
72 changes: 57 additions & 15 deletions src/librustc_resolve/macros.rs
Expand Up @@ -107,6 +107,14 @@ impl<'a> MacroBinding<'a> {
MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"),
}
}

pub fn def_ignoring_ambiguity(self) -> Def {
match self {
MacroBinding::Legacy(binding) => Def::Macro(binding.def_id, MacroKind::Bang),
MacroBinding::Global(binding) | MacroBinding::Modern(binding) =>
binding.def_ignoring_ambiguity(),
}
}
}

impl<'a> base::Resolver for Resolver<'a> {
Expand Down Expand Up @@ -476,7 +484,7 @@ impl<'a> Resolver<'a> {
};

self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
.push((scope, path[0], span, kind));
.push((scope, path[0], kind, result.ok()));

result
}
Expand Down Expand Up @@ -622,10 +630,33 @@ impl<'a> Resolver<'a> {
}
}

for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
for &(mark, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
let span = ident.span;
let legacy_scope = &self.invocations[&mark].legacy_scope;
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true);
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span);

let check_consistency = |this: &Self, binding: MacroBinding| {
if let Some(def) = def {
if this.ambiguity_errors.is_empty() && this.disallowed_shadowing.is_empty() &&
binding.def_ignoring_ambiguity() != def {
// Make sure compilation does not succeed if preferred macro resolution
// has changed after the macro had been expanded. In theory all such
// situations should be reported as ambiguity errors, so this is span-bug.
span_bug!(span, "inconsistent resolution for a macro");
}
} else {
// It's possible that the macro was unresolved (indeterminate) and silently
// expanded into a dummy fragment for recovery during expansion.
// Now, post-expansion, the resolution may succeed, but we can't change the
// past and need to report an error.
let msg =
format!("cannot determine resolution for the {} `{}`", kind.descr(), ident);
let msg_note = "import resolution is stuck, try simplifying macro imports";
this.session.struct_span_err(span, &msg).note(msg_note).emit();
}
};

match (legacy_resolution, resolution) {
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
let msg1 = format!("`{}` could refer to the macro defined here", ident);
Expand All @@ -635,24 +666,35 @@ impl<'a> Resolver<'a> {
.span_note(binding.span, &msg2)
.emit();
},
(Some(MacroBinding::Global(binding)), Ok(MacroBinding::Global(_))) => {
self.record_use(ident, MacroNS, binding, span);
self.err_if_macro_use_proc_macro(ident.name, span, binding);
},
(None, Err(_)) => {
let msg = match kind {
MacroKind::Bang =>
format!("cannot find macro `{}!` in this scope", ident),
MacroKind::Attr =>
format!("cannot find attribute macro `{}` in this scope", ident),
MacroKind::Derive =>
format!("cannot find derive macro `{}` in this scope", ident),
};
assert!(def.is_none());
let bang = if kind == MacroKind::Bang { "!" } else { "" };
let msg =
format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
let mut err = self.session.struct_span_err(span, &msg);
self.suggest_macro_name(&ident.as_str(), kind, &mut err, span);
err.emit();
},
_ => {},
(Some(MacroBinding::Modern(_)), _) | (_, Ok(MacroBinding::Legacy(_))) => {
span_bug!(span, "impossible macro resolution result");
}
// OK, unambiguous resolution
(Some(binding), Err(_)) | (None, Ok(binding)) |
// OK, legacy wins over global even if their definitions are different
(Some(binding @ MacroBinding::Legacy(_)), Ok(MacroBinding::Global(_))) |
// OK, modern wins over global even if their definitions are different
(Some(MacroBinding::Global(_)), Ok(binding @ MacroBinding::Modern(_))) => {
check_consistency(self, binding);
}
(Some(MacroBinding::Global(binding1)), Ok(MacroBinding::Global(binding2))) => {
if binding1.def() != binding2.def() {
span_bug!(span, "mismatch between same global macro resolutions");
}
check_consistency(self, MacroBinding::Global(binding1));

self.record_use(ident, MacroNS, binding1, span);
self.err_if_macro_use_proc_macro(ident.name, span, binding1);
},
};
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/ext/base.rs
Expand Up @@ -572,6 +572,16 @@ pub enum MacroKind {
Derive,
}

impl MacroKind {
pub fn descr(self) -> &'static str {
match self {
MacroKind::Bang => "macro",
MacroKind::Attr => "attribute macro",
MacroKind::Derive => "derive macro",
}
}
}

/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
/// A syntax extension that is attached to an item and creates new items
Expand Down

0 comments on commit 345e7c3

Please sign in to comment.