From be2947d0b7cc7fb13601c41676285bb3f6d548c3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 31 Aug 2020 00:04:01 -0400 Subject: [PATCH] Give a better error message for duplicate built-in macros Previously, this would say no such macro existed, but this was misleading, since the macro _did_ exist, it was just already seen. - Say where the macro was previously defined - Add long-form error message --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0773.md | 38 +++++++++++++++++++ compiler/rustc_resolve/src/lib.rs | 8 +++- compiler/rustc_resolve/src/macros.rs | 22 +++++++++-- src/test/ui/macros/duplicate-builtin.rs | 17 +++++++++ src/test/ui/macros/duplicate-builtin.stderr | 21 ++++++++++ src/test/ui/macros/unknown-builtin.rs | 4 +- src/test/ui/macros/unknown-builtin.stderr | 9 ++++- 8 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0773.md create mode 100644 src/test/ui/macros/duplicate-builtin.rs create mode 100644 src/test/ui/macros/duplicate-builtin.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 4e5e77f80c28a..789a1fc35a64f 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -454,6 +454,7 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0773: include_str!("./error_codes/E0773.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md new file mode 100644 index 0000000000000..b19a58bf33d2c --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -0,0 +1,38 @@ +A builtin-macro was defined more than once. + +Erroneous code example: + +```compile_fail,E0773 +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + /* compiler built-in */ + } +} +``` + +To fix the issue, remove the duplicate declaration: + +``` +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} +``` + +In very rare edge cases, this may happen when loading `core` or `std` twice, +once with `check` metadata and once with `build` metadata. +For more information, see [#75176]. + +[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468 diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5892edf7652b7..50729086ec6ac 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -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, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap, registered_attrs: FxHashSet, registered_tools: FxHashSet, macro_use_prelude: FxHashMap>, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 51518d63ae901..bea7138964764 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -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); diff --git a/src/test/ui/macros/duplicate-builtin.rs b/src/test/ui/macros/duplicate-builtin.rs new file mode 100644 index 0000000000000..35f0f429059a9 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/src/test/ui/macros/duplicate-builtin.stderr b/src/test/ui/macros/duplicate-builtin.stderr new file mode 100644 index 0000000000000..58accea27bb96 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4ff78..16f9139e6479e 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot find a built-in macro with name `line` +// error-pattern: attempted to define built-in macro more than once #![feature(rustc_attrs)] @@ -6,7 +6,7 @@ macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` #[rustc_builtin_macro] -macro_rules! line { () => () } +macro_rules! line { () => () } //~ NOTE previously defined here fn main() { line!(); diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 4b650b2c47529..7b04e05293ea1 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown` LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot find a built-in macro with name `line` +error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | / macro_rules! line { @@ -13,6 +13,13 @@ LL | | /* compiler built-in */ LL | | }; LL | | } | |_____^ + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0773`.