|
3 | 3 |
|
4 | 4 | use crate::imports::ImportResolver;
|
5 | 5 | use crate::Namespace::*;
|
6 |
| -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; |
| 6 | +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; |
7 | 7 | use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
|
8 | 8 | use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
9 | 9 | use rustc_ast::{self as ast, NodeId};
|
10 | 10 | use rustc_ast_lowering::ResolverAstLowering;
|
11 | 11 | use rustc_ast_pretty::pprust;
|
12 | 12 | use rustc_attr::StabilityLevel;
|
13 | 13 | use rustc_data_structures::fx::FxHashSet;
|
| 14 | +use rustc_errors::struct_span_err; |
14 | 15 | use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
|
15 | 16 | use rustc_expand::compile_declarative_macro;
|
16 | 17 | use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
|
@@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
166 | 167 | }
|
167 | 168 |
|
168 | 169 | fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) {
|
169 |
| - if self.builtin_macros.insert(ident.name, ext).is_some() { |
| 170 | + if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() { |
170 | 171 | self.session
|
171 | 172 | .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
|
172 | 173 | }
|
@@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> {
|
1076 | 1077 |
|
1077 | 1078 | if result.is_builtin {
|
1078 | 1079 | // The macro was marked with `#[rustc_builtin_macro]`.
|
1079 |
| - if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { |
| 1080 | + if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) { |
1080 | 1081 | // The macro is a built-in, replace its expander function
|
1081 | 1082 | // while still taking everything else from the source code.
|
1082 |
| - result.kind = ext.kind; |
| 1083 | + // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. |
| 1084 | + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { |
| 1085 | + BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind, |
| 1086 | + BuiltinMacroState::AlreadySeen(span) => { |
| 1087 | + struct_span_err!( |
| 1088 | + self.session, |
| 1089 | + item.span, |
| 1090 | + E0773, |
| 1091 | + "attempted to define built-in macro more than once" |
| 1092 | + ) |
| 1093 | + .span_note(span, "previously defined here") |
| 1094 | + .emit(); |
| 1095 | + } |
| 1096 | + } |
1083 | 1097 | } else {
|
1084 | 1098 | let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
|
1085 | 1099 | self.session.span_err(item.span, &msg);
|
|
0 commit comments