Rollup merge of #76143 - jyn514:duplicate-builtin-macros, r=petrochenkov

Give a better error message for duplicate built-in macros

Minor follow-up to https://github.com/rust-lang/rust/pull/75176 giving a better error message for duplicate builtin macros. This would have made it a little easier to debug.

r? @petrochenkov
This commit is contained in:
Tyler Mandry 2020-09-01 18:24:35 -07:00 committed by GitHub
commit b01d0b1414
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 8 deletions

View file

@ -867,6 +867,12 @@ pub struct ExternPreludeEntry<'a> {
pub introduced_by_item: bool,
}
/// Used for better errors for E0773
enum BuiltinMacroState {
NotYetSeen(SyntaxExtension),
AlreadySeen(Span),
}
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
@ -960,7 +966,7 @@ pub struct Resolver<'a> {
crate_loader: CrateLoader<'a>,
macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, SyntaxExtension>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
registered_attrs: FxHashSet<Ident>,
registered_tools: FxHashSet<Ident>,
macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,

View file

@ -3,7 +3,7 @@
use crate::imports::ImportResolver;
use crate::Namespace::*;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::{self as ast, NodeId};
@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) {
if self.builtin_macros.insert(ident.name, ext).is_some() {
if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
self.session
.span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
}
@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> {
if result.is_builtin {
// The macro was marked with `#[rustc_builtin_macro]`.
if let Some(ext) = self.builtin_macros.remove(&item.ident.name) {
if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
result.kind = ext.kind;
// If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind,
BuiltinMacroState::AlreadySeen(span) => {
struct_span_err!(
self.session,
item.span,
E0773,
"attempted to define built-in macro more than once"
)
.span_note(span, "previously defined here")
.emit();
}
}
} else {
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
self.session.span_err(item.span, &msg);