Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve: Make sure indeterminate and inconsistent macro resolutions always generate errors #51145

Merged
merged 1 commit into from
May 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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