about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-02 01:29:28 +0000
committerbors <bors@rust-lang.org>2020-09-02 01:29:28 +0000
commite36e4bd0f7e722d3c97d1ca45387e58f81e4e8ea (patch)
tree505c8905fbf0db875c1be97477b65cac833bb653 /compiler/rustc_resolve/src
parent130359cb05246fcacdde61baa2613419ef6570c7 (diff)
parent4dd75f8049b722ea8bd4ff9d7c6c4a438161bad6 (diff)
Auto merge of #76231 - tmandry:rollup-ilvs9fq, r=tmandry
Rollup of 14 pull requests

Successful merges:

 - #74880 (Add trailing comma support to matches macro)
 - #76074 (Add new `-Z dump-mir-spanview` option)
 - #76088 (Add more examples to lexicographic cmp on Iterators.)
 - #76099 (Add info about `!` and `impl Trait`)
 - #76126 (Use "Fira Sans" for crate list font)
 - #76132 (Factor out StmtKind::MacCall fields into `MacCallStmt` struct)
 - #76143 (Give a better error message for duplicate built-in macros)
 - #76158 (Stabilise link-self-contained option)
 - #76201 (Move to intra-doc links for library/core/src/panic.rs)
 - #76206 (Make all methods of `std::net::Ipv6Addr` const)
 - #76207 (# Move to intra-doc links for library/core/src/clone.rs)
 - #76212 (Document lint missing_doc_code_examples is nightly-only)
 - #76218 (lexer: Tiny improvement to shebang detection)
 - #76221 (Clean up header in `iter` docs for `for` loops)

Failed merges:

r? @ghost
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/lib.rs8
-rw-r--r--compiler/rustc_resolve/src/macros.rs22
2 files changed, 25 insertions, 5 deletions
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 5892edf7652..50729086ec6 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<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>>,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 51518d63ae9..bea71389647 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);