Skip to content

Commit cd0fd63

Browse files
committed
resolve: Make proc macro stubs less stubby
Create real working and registered (even if dummy) `SyntaxExtension`s for them. This improves error recovery and allows to avoid all special cases for proc macro stubs (except for the error on use, of course). The introduced dummy `SyntaxExtension`s can be used for any other inappropriately resolved macros as well.
1 parent b392781 commit cd0fd63

File tree

6 files changed

+138
-75
lines changed

6 files changed

+138
-75
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,6 @@ use log::debug;
4646

4747
type Res = def::Res<NodeId>;
4848

49-
fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> {
50-
if attr::contains_name(&item.attrs, sym::proc_macro) ||
51-
attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
52-
return Some((item.ident, item.span));
53-
} else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
54-
if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
55-
if let Some(ident) = nested_meta.ident() {
56-
return Some((ident, ident.span));
57-
}
58-
}
59-
}
60-
None
61-
}
62-
6349
impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
6450
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
6551
arenas.alloc_name_binding(NameBinding {
@@ -470,9 +456,7 @@ impl<'a> Resolver<'a> {
470456

471457
// Functions introducing procedural macros reserve a slot
472458
// in the macro namespace as well (see #52225).
473-
if let Some((ident, span)) = proc_macro_stub(item) {
474-
self.define(parent, ident, MacroNS, (res, vis, span, expansion));
475-
}
459+
self.define_macro(item, expansion, &mut LegacyScope::Empty);
476460
}
477461

478462
// These items live in the type namespace.

src/librustc_resolve/lib.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use rustc_metadata::cstore::CStore;
4040
use syntax::source_map::SourceMap;
4141
use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
4242
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
43-
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
43+
use syntax::ext::base::SyntaxExtension;
4444
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
4545
use syntax::ext::base::MacroKind;
4646
use syntax::symbol::{Symbol, kw, sym};
@@ -1663,10 +1663,13 @@ pub struct Resolver<'a> {
16631663
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
16641664
pub all_macros: FxHashMap<Name, Res>,
16651665
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
1666+
dummy_ext_bang: Lrc<SyntaxExtension>,
1667+
dummy_ext_derive: Lrc<SyntaxExtension>,
16661668
non_macro_attrs: [Lrc<SyntaxExtension>; 2],
16671669
macro_defs: FxHashMap<Mark, DefId>,
16681670
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
16691671
unused_macros: NodeMap<Span>,
1672+
proc_macro_stubs: NodeSet,
16701673

16711674
/// Maps the `Mark` of an expansion to its containing module or block.
16721675
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
@@ -1925,9 +1928,8 @@ impl<'a> Resolver<'a> {
19251928
macro_defs.insert(Mark::root(), root_def_id);
19261929

19271930
let features = session.features_untracked();
1928-
let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default(
1929-
SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition()
1930-
));
1931+
let non_macro_attr =
1932+
|mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
19311933

19321934
Resolver {
19331935
session,
@@ -2002,6 +2004,8 @@ impl<'a> Resolver<'a> {
20022004
macro_use_prelude: FxHashMap::default(),
20032005
all_macros: FxHashMap::default(),
20042006
macro_map: FxHashMap::default(),
2007+
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
2008+
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
20052009
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
20062010
invocations,
20072011
macro_defs,
@@ -2010,6 +2014,7 @@ impl<'a> Resolver<'a> {
20102014
potentially_unused_imports: Vec::new(),
20112015
struct_constructors: Default::default(),
20122016
unused_macros: Default::default(),
2017+
proc_macro_stubs: Default::default(),
20132018
current_type_ascription: Vec::new(),
20142019
injected_crate: None,
20152020
active_features:
@@ -2027,6 +2032,14 @@ impl<'a> Resolver<'a> {
20272032
self.non_macro_attrs[mark_used as usize].clone()
20282033
}
20292034

2035+
fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
2036+
match macro_kind {
2037+
MacroKind::Bang => self.dummy_ext_bang.clone(),
2038+
MacroKind::Derive => self.dummy_ext_derive.clone(),
2039+
MacroKind::Attr => self.non_macro_attr(true),
2040+
}
2041+
}
2042+
20302043
/// Runs the function on each namespace.
20312044
fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
20322045
f(self, TypeNS);

src/librustc_resolve/macros.rs

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
1111
use rustc::hir::map::DefCollector;
1212
use rustc::middle::stability;
1313
use rustc::{ty, lint, span_bug};
14-
use syntax::ast::{self, Ident};
14+
use syntax::ast::{self, Ident, ItemKind};
1515
use syntax::attr::{self, StabilityLevel};
1616
use syntax::errors::DiagnosticBuilder;
1717
use syntax::ext::base::{self, Determinacy};
@@ -127,6 +127,21 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
127127
}
128128
}
129129

130+
fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
131+
if attr::contains_name(&item.attrs, sym::proc_macro) {
132+
return Some((MacroKind::Bang, item.ident, item.span));
133+
} else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
134+
return Some((MacroKind::Attr, item.ident, item.span));
135+
} else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
136+
if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
137+
if let Some(ident) = nested_meta.ident() {
138+
return Some((MacroKind::Derive, ident, ident.span));
139+
}
140+
}
141+
}
142+
None
143+
}
144+
130145
impl<'a> base::Resolver for Resolver<'a> {
131146
fn next_node_id(&mut self) -> ast::NodeId {
132147
self.session.next_node_id()
@@ -216,10 +231,9 @@ impl<'a> base::Resolver for Resolver<'a> {
216231
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
217232
let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) {
218233
Ok((res, ext)) => (res, ext),
219-
// Replace unresolved attributes with used inert attributes for better recovery.
220-
Err(Determinacy::Determined) if kind == MacroKind::Attr =>
221-
(Res::Err, self.non_macro_attr(true)),
222-
Err(determinacy) => return Err(determinacy),
234+
// Return dummy syntax extensions for unresolved macros for better recovery.
235+
Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)),
236+
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
223237
};
224238

225239
let span = invoc.span();
@@ -305,13 +319,14 @@ impl<'a> Resolver<'a> {
305319
Res::Def(DefKind::Macro(_), def_id) => {
306320
if let Some(node_id) = self.definitions.as_local_node_id(def_id) {
307321
self.unused_macros.remove(&node_id);
322+
if self.proc_macro_stubs.contains(&node_id) {
323+
self.session.span_err(
324+
path.span,
325+
"can't use a procedural macro from the same crate that defines it",
326+
);
327+
}
308328
}
309329
}
310-
Res::Def(DefKind::Fn, _) => {
311-
let msg = "can't use a procedural macro from the same crate that defines it";
312-
self.session.span_err(path.span, msg);
313-
return Err(Determinacy::Determined);
314-
}
315330
Res::NonMacroAttr(attr_kind) => {
316331
if kind == MacroKind::Attr {
317332
if attr_kind == NonMacroAttrKind::Custom {
@@ -1100,19 +1115,32 @@ impl<'a> Resolver<'a> {
11001115
item: &ast::Item,
11011116
expansion: Mark,
11021117
current_legacy_scope: &mut LegacyScope<'a>) {
1103-
self.local_macro_def_scopes.insert(item.id, self.current_module);
1104-
let ident = item.ident;
1118+
let (ext, ident, span, is_legacy) = match &item.node {
1119+
ItemKind::MacroDef(def) => {
1120+
let ext = Lrc::new(macro_rules::compile(
1121+
&self.session.parse_sess,
1122+
&self.session.features_untracked(),
1123+
item,
1124+
self.session.edition(),
1125+
));
1126+
(ext, item.ident, item.span, def.legacy)
1127+
}
1128+
ItemKind::Fn(..) => match proc_macro_stub(item) {
1129+
Some((macro_kind, ident, span)) => {
1130+
self.proc_macro_stubs.insert(item.id);
1131+
(self.dummy_ext(macro_kind), ident, span, false)
1132+
}
1133+
None => return,
1134+
}
1135+
_ => unreachable!(),
1136+
};
11051137

11061138
let def_id = self.definitions.local_def_id(item.id);
1107-
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
1108-
&self.session.features_untracked(),
1109-
item, self.session.edition()));
1110-
let macro_kind = ext.macro_kind();
1111-
let res = Res::Def(DefKind::Macro(macro_kind), def_id);
1139+
let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
11121140
self.macro_map.insert(def_id, ext);
1141+
self.local_macro_def_scopes.insert(item.id, self.current_module);
11131142

1114-
let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
1115-
if def.legacy {
1143+
if is_legacy {
11161144
let ident = ident.modern();
11171145
self.macro_names.insert(ident);
11181146
let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
@@ -1121,7 +1149,7 @@ impl<'a> Resolver<'a> {
11211149
} else {
11221150
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
11231151
};
1124-
let binding = (res, vis, item.span, expansion).to_name_binding(self.arenas);
1152+
let binding = (res, vis, span, expansion).to_name_binding(self.arenas);
11251153
self.set_binding_parent_module(binding, self.current_module);
11261154
let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding {
11271155
parent_legacy_scope: *current_legacy_scope, binding, ident
@@ -1131,18 +1159,18 @@ impl<'a> Resolver<'a> {
11311159
if is_macro_export {
11321160
let module = self.graph_root;
11331161
self.define(module, ident, MacroNS,
1134-
(res, vis, item.span, expansion, IsMacroExport));
1162+
(res, vis, span, expansion, IsMacroExport));
11351163
} else {
11361164
self.check_reserved_macro_name(ident, res);
1137-
self.unused_macros.insert(item.id, item.span);
1165+
self.unused_macros.insert(item.id, span);
11381166
}
11391167
} else {
11401168
let module = self.current_module;
11411169
let vis = self.resolve_visibility(&item.vis);
11421170
if vis != ty::Visibility::Public {
1143-
self.unused_macros.insert(item.id, item.span);
1171+
self.unused_macros.insert(item.id, span);
11441172
}
1145-
self.define(module, ident, MacroNS, (res, vis, item.span, expansion));
1173+
self.define(module, ident, MacroNS, (res, vis, span, expansion));
11461174
}
11471175
}
11481176
}

src/libsyntax/ext/base.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::parse::token;
1010
use crate::ptr::P;
1111
use crate::symbol::{kw, sym, Ident, Symbol};
1212
use crate::{ThinVec, MACRO_ARGUMENTS};
13-
use crate::tokenstream::{self, TokenStream};
13+
use crate::tokenstream::{self, TokenStream, TokenTree};
1414

1515
use errors::{DiagnosticBuilder, DiagnosticId};
1616
use smallvec::{smallvec, SmallVec};
@@ -640,6 +640,26 @@ impl SyntaxExtension {
640640
}
641641
}
642642

643+
pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
644+
fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree])
645+
-> Box<dyn MacResult + 'cx> {
646+
DummyResult::any(span)
647+
}
648+
SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition)
649+
}
650+
651+
pub fn dummy_derive(edition: Edition) -> SyntaxExtension {
652+
fn expander(_: &mut ExtCtxt<'_>, _: Span, _: &ast::MetaItem, _: Annotatable)
653+
-> Vec<Annotatable> {
654+
Vec::new()
655+
}
656+
SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition)
657+
}
658+
659+
pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension {
660+
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition)
661+
}
662+
643663
pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo {
644664
ExpnInfo {
645665
call_site,

src/test/ui/proc-macro/macro-namespace-reserved-2.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,24 @@ fn check_bang1() {
2525
my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
2626
}
2727
fn check_bang2() {
28-
my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it
28+
my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope
2929
}
3030
fn check_bang3() {
31-
MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
31+
MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope
3232
}
3333

34-
#[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
34+
#[my_macro] //~ ERROR attribute `my_macro` is currently unknown
3535
fn check_attr1() {}
3636
#[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it
3737
fn check_attr2() {}
3838
#[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it
39+
//~| ERROR `MyTrait` is a derive macro
3940
fn check_attr3() {}
4041

41-
#[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it
42+
#[derive(my_macro)] //~ ERROR cannot find derive macro `my_macro` in this scope
4243
struct CheckDerive1;
4344
#[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it
45+
//~| ERROR macro `my_macro_attr` may not be used for derive attributes
4446
struct CheckDerive2;
4547
#[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it
4648
struct CheckDerive3;

src/test/ui/proc-macro/macro-namespace-reserved-2.stderr

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,6 @@ error: can't use a procedural macro from the same crate that defines it
44
LL | my_macro!();
55
| ^^^^^^^^
66

7-
error: can't use a procedural macro from the same crate that defines it
8-
--> $DIR/macro-namespace-reserved-2.rs:28:5
9-
|
10-
LL | my_macro_attr!();
11-
| ^^^^^^^^^^^^^
12-
13-
error: can't use a procedural macro from the same crate that defines it
14-
--> $DIR/macro-namespace-reserved-2.rs:31:5
15-
|
16-
LL | MyTrait!();
17-
| ^^^^^^^
18-
19-
error: can't use a procedural macro from the same crate that defines it
20-
--> $DIR/macro-namespace-reserved-2.rs:34:3
21-
|
22-
LL | #[my_macro]
23-
| ^^^^^^^^
24-
257
error: can't use a procedural macro from the same crate that defines it
268
--> $DIR/macro-namespace-reserved-2.rs:36:3
279
|
@@ -34,23 +16,57 @@ error: can't use a procedural macro from the same crate that defines it
3416
LL | #[MyTrait]
3517
| ^^^^^^^
3618

37-
error: can't use a procedural macro from the same crate that defines it
38-
--> $DIR/macro-namespace-reserved-2.rs:41:10
19+
error: `MyTrait` is a derive macro
20+
--> $DIR/macro-namespace-reserved-2.rs:38:1
3921
|
40-
LL | #[derive(my_macro)]
41-
| ^^^^^^^^
22+
LL | #[MyTrait]
23+
| ^^^^^^^^^^
4224

4325
error: can't use a procedural macro from the same crate that defines it
44-
--> $DIR/macro-namespace-reserved-2.rs:43:10
26+
--> $DIR/macro-namespace-reserved-2.rs:44:10
27+
|
28+
LL | #[derive(my_macro_attr)]
29+
| ^^^^^^^^^^^^^
30+
31+
error: macro `my_macro_attr` may not be used for derive attributes
32+
--> $DIR/macro-namespace-reserved-2.rs:44:10
4533
|
4634
LL | #[derive(my_macro_attr)]
4735
| ^^^^^^^^^^^^^
4836

4937
error: can't use a procedural macro from the same crate that defines it
50-
--> $DIR/macro-namespace-reserved-2.rs:45:10
38+
--> $DIR/macro-namespace-reserved-2.rs:47:10
5139
|
5240
LL | #[derive(MyTrait)]
5341
| ^^^^^^^
5442

55-
error: aborting due to 9 previous errors
43+
error[E0658]: The attribute `my_macro` is currently unknown to the compiler and may have meaning added to it in the future
44+
--> $DIR/macro-namespace-reserved-2.rs:34:3
45+
|
46+
LL | #[my_macro]
47+
| ^^^^^^^^
48+
|
49+
= note: for more information, see https://github.com/rust-lang/rust/issues/29642
50+
= help: add #![feature(custom_attribute)] to the crate attributes to enable
51+
52+
error: cannot find derive macro `my_macro` in this scope
53+
--> $DIR/macro-namespace-reserved-2.rs:42:10
54+
|
55+
LL | #[derive(my_macro)]
56+
| ^^^^^^^^
57+
58+
error: cannot find macro `my_macro_attr!` in this scope
59+
--> $DIR/macro-namespace-reserved-2.rs:28:5
60+
|
61+
LL | my_macro_attr!();
62+
| ^^^^^^^^^^^^^
63+
64+
error: cannot find macro `MyTrait!` in this scope
65+
--> $DIR/macro-namespace-reserved-2.rs:31:5
66+
|
67+
LL | MyTrait!();
68+
| ^^^^^^^
69+
70+
error: aborting due to 11 previous errors
5671

72+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)