Skip to content

Commit b01d0b1

Browse files
authored
Rollup merge of rust-lang#76143 - jyn514:duplicate-builtin-macros, r=petrochenkov
Give a better error message for duplicate built-in macros Minor follow-up to rust-lang#75176 giving a better error message for duplicate builtin macros. This would have made it a little easier to debug. r? @petrochenkov
2 parents 738b8ea + be2947d commit b01d0b1

File tree

8 files changed

+112
-8
lines changed

8 files changed

+112
-8
lines changed

compiler/rustc_error_codes/src/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ E0768: include_str!("./error_codes/E0768.md"),
454454
E0769: include_str!("./error_codes/E0769.md"),
455455
E0770: include_str!("./error_codes/E0770.md"),
456456
E0771: include_str!("./error_codes/E0771.md"),
457+
E0773: include_str!("./error_codes/E0773.md"),
457458
;
458459
// E0006, // merged with E0005
459460
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
A builtin-macro was defined more than once.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0773
6+
#![feature(decl_macro)]
7+
#![feature(rustc_attrs)]
8+
9+
#[rustc_builtin_macro]
10+
pub macro test($item:item) {
11+
/* compiler built-in */
12+
}
13+
14+
mod inner {
15+
#[rustc_builtin_macro]
16+
pub macro test($item:item) {
17+
/* compiler built-in */
18+
}
19+
}
20+
```
21+
22+
To fix the issue, remove the duplicate declaration:
23+
24+
```
25+
#![feature(decl_macro)]
26+
#![feature(rustc_attrs)]
27+
28+
#[rustc_builtin_macro]
29+
pub macro test($item:item) {
30+
/* compiler built-in */
31+
}
32+
```
33+
34+
In very rare edge cases, this may happen when loading `core` or `std` twice,
35+
once with `check` metadata and once with `build` metadata.
36+
For more information, see [#75176].
37+
38+
[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468

compiler/rustc_resolve/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,12 @@ pub struct ExternPreludeEntry<'a> {
867867
pub introduced_by_item: bool,
868868
}
869869

870+
/// Used for better errors for E0773
871+
enum BuiltinMacroState {
872+
NotYetSeen(SyntaxExtension),
873+
AlreadySeen(Span),
874+
}
875+
870876
/// The main resolver class.
871877
///
872878
/// This is the visitor that walks the whole crate.
@@ -960,7 +966,7 @@ pub struct Resolver<'a> {
960966

961967
crate_loader: CrateLoader<'a>,
962968
macro_names: FxHashSet<Ident>,
963-
builtin_macros: FxHashMap<Symbol, SyntaxExtension>,
969+
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
964970
registered_attrs: FxHashSet<Ident>,
965971
registered_tools: FxHashSet<Ident>,
966972
macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,

compiler/rustc_resolve/src/macros.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
44
use crate::imports::ImportResolver;
55
use crate::Namespace::*;
6-
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy};
6+
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
77
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
88
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
99
use rustc_ast::{self as ast, NodeId};
1010
use rustc_ast_lowering::ResolverAstLowering;
1111
use rustc_ast_pretty::pprust;
1212
use rustc_attr::StabilityLevel;
1313
use rustc_data_structures::fx::FxHashSet;
14+
use rustc_errors::struct_span_err;
1415
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
1516
use rustc_expand::compile_declarative_macro;
1617
use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
@@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
166167
}
167168

168169
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() {
170171
self.session
171172
.span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
172173
}
@@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> {
10761077

10771078
if result.is_builtin {
10781079
// 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) {
10801081
// The macro is a built-in, replace its expander function
10811082
// 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+
}
10831097
} else {
10841098
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
10851099
self.session.span_err(item.span, &msg);
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-flags:--crate-type lib
2+
#![feature(decl_macro)]
3+
#![feature(rustc_attrs)]
4+
5+
#[rustc_builtin_macro]
6+
pub macro test($item:item) {
7+
//~^ NOTE previously defined
8+
/* compiler built-in */
9+
}
10+
11+
mod inner {
12+
#[rustc_builtin_macro]
13+
pub macro test($item:item) {
14+
//~^ ERROR attempted to define built-in macro more than once [E0773]
15+
/* compiler built-in */
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0773]: attempted to define built-in macro more than once
2+
--> $DIR/duplicate-builtin.rs:13:5
3+
|
4+
LL | / pub macro test($item:item) {
5+
LL | |
6+
LL | | /* compiler built-in */
7+
LL | | }
8+
| |_____^
9+
|
10+
note: previously defined here
11+
--> $DIR/duplicate-builtin.rs:6:1
12+
|
13+
LL | / pub macro test($item:item) {
14+
LL | |
15+
LL | | /* compiler built-in */
16+
LL | | }
17+
| |_^
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0773`.

src/test/ui/macros/unknown-builtin.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// error-pattern: cannot find a built-in macro with name `line`
1+
// error-pattern: attempted to define built-in macro more than once
22

33
#![feature(rustc_attrs)]
44

55
#[rustc_builtin_macro]
66
macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown`
77

88
#[rustc_builtin_macro]
9-
macro_rules! line { () => () }
9+
macro_rules! line { () => () } //~ NOTE previously defined here
1010

1111
fn main() {
1212
line!();

src/test/ui/macros/unknown-builtin.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown`
44
LL | macro_rules! unknown { () => () }
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
error: cannot find a built-in macro with name `line`
7+
error[E0773]: attempted to define built-in macro more than once
88
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
99
|
1010
LL | / macro_rules! line {
@@ -13,6 +13,13 @@ LL | | /* compiler built-in */
1313
LL | | };
1414
LL | | }
1515
| |_____^
16+
|
17+
note: previously defined here
18+
--> $DIR/unknown-builtin.rs:9:1
19+
|
20+
LL | macro_rules! line { () => () }
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1622

1723
error: aborting due to 2 previous errors
1824

25+
For more information about this error, try `rustc --explain E0773`.

0 commit comments

Comments
 (0)