Skip to content

Commit 47b4dd7

Browse files
committed
Auto merge of rust-lang#15923 - tamasfe:feat/better-ignored-macros2, r=Veykril
feat: ignored and disabled macro expansion Supersedes rust-lang#15117, I was having some conflicts after a rebase and since I didn't remember much of it I started clean instead. The end result is pretty much the same as the linked PR, but instead of proc macro lookups, I marked the expanders that explicitly cannot be expanded and we shouldn't even attempt to do so. ## Unresolved questions - [ ] I introduced a `DISABLED_ID` next to `DUMMY_ID` in `hir-expand`'s `ProcMacroExpander`, that is effectively exactly the same thing with slightly different semantics, dummy macros are not (yet) expanded probably due to errors, while not expanding disabled macros is part of the usual flow. I'm not sure if it's the right way to handle this, I also thought of just adding a flag instead of replacing the macro ID, so that the disabled macro can still be expanded for any reason if needed.
2 parents 3c24189 + e2a985e commit 47b4dd7

File tree

11 files changed

+139
-100
lines changed

11 files changed

+139
-100
lines changed

crates/base-db/src/input.rs

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl CrateDisplayName {
243243
CrateDisplayName { crate_name, canonical_name }
244244
}
245245
}
246+
246247
pub type TargetLayoutLoadResult = Result<Arc<str>, Arc<str>>;
247248

248249
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]

crates/hir-def/src/data.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,6 @@ impl<'a> AssocItemCollector<'a> {
634634
attr,
635635
) {
636636
Ok(ResolvedAttr::Macro(call_id)) => {
637-
self.attr_calls.push((ast_id, call_id));
638637
// If proc attribute macro expansion is disabled, skip expanding it here
639638
if !self.db.expand_proc_attr_macros() {
640639
continue 'attrs;
@@ -647,10 +646,21 @@ impl<'a> AssocItemCollector<'a> {
647646
// disabled. This is analogous to the handling in
648647
// `DefCollector::collect_macros`.
649648
if exp.is_dummy() {
649+
self.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
650+
self.module_id.local_id,
651+
loc.kind,
652+
loc.def.krate,
653+
));
654+
655+
continue 'attrs;
656+
}
657+
if exp.is_disabled() {
650658
continue 'attrs;
651659
}
652660
}
653661

662+
self.attr_calls.push((ast_id, call_id));
663+
654664
let res =
655665
self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
656666
self.collect_macro_items(res, &|| loc.kind.clone());

crates/hir-def/src/macro_expansion_tests/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
5858
name: "identity_when_valid".into(),
5959
kind: ProcMacroKind::Attr,
6060
expander: sync::Arc::new(IdentityWhenValidProcMacroExpander),
61+
disabled: false,
6162
},
6263
)];
6364
let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);

crates/hir-def/src/nameres/collector.rs

+57-36
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use either::Either;
1111
use hir_expand::{
1212
ast_id_map::FileAstId,
1313
attrs::{Attr, AttrId},
14-
builtin_attr_macro::find_builtin_attr,
14+
builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
1515
builtin_derive_macro::find_builtin_derive,
1616
builtin_fn_macro::find_builtin_macro,
1717
name::{name, AsName, Name},
@@ -98,9 +98,13 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
9898
};
9999
(
100100
name.as_name(),
101-
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
102-
idx as u32,
103-
)),
101+
if it.disabled {
102+
CustomProcMacroExpander::disabled()
103+
} else {
104+
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
105+
idx as u32,
106+
))
107+
},
104108
)
105109
})
106110
.collect())
@@ -604,9 +608,6 @@ impl DefCollector<'_> {
604608
id: ItemTreeId<item_tree::Function>,
605609
fn_id: FunctionId,
606610
) {
607-
if self.def_map.block.is_some() {
608-
return;
609-
}
610611
let kind = def.kind.to_basedb_kind();
611612
let (expander, kind) =
612613
match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) {
@@ -1120,9 +1121,16 @@ impl DefCollector<'_> {
11201121
let mut push_resolved = |directive: &MacroDirective, call_id| {
11211122
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
11221123
};
1124+
1125+
#[derive(PartialEq, Eq)]
1126+
enum Resolved {
1127+
Yes,
1128+
No,
1129+
}
1130+
11231131
let mut res = ReachedFixedPoint::Yes;
11241132
// Retain unresolved macros after this round of resolution.
1125-
macros.retain(|directive| {
1133+
let mut retain = |directive: &MacroDirective| {
11261134
let subns = match &directive.kind {
11271135
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
11281136
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@@ -1156,10 +1164,11 @@ impl DefCollector<'_> {
11561164
self.def_map.modules[directive.module_id]
11571165
.scope
11581166
.add_macro_invoc(ast_id.ast_id, call_id);
1167+
11591168
push_resolved(directive, call_id);
11601169

11611170
res = ReachedFixedPoint::No;
1162-
return false;
1171+
return Resolved::Yes;
11631172
}
11641173
}
11651174
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => {
@@ -1198,7 +1207,7 @@ impl DefCollector<'_> {
11981207

11991208
push_resolved(directive, call_id);
12001209
res = ReachedFixedPoint::No;
1201-
return false;
1210+
return Resolved::Yes;
12021211
}
12031212
}
12041213
MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
@@ -1221,7 +1230,7 @@ impl DefCollector<'_> {
12211230
}
12221231
.collect(&[*mod_item], directive.container);
12231232
res = ReachedFixedPoint::No;
1224-
false
1233+
Resolved::Yes
12251234
};
12261235

12271236
if let Some(ident) = path.as_ident() {
@@ -1237,13 +1246,18 @@ impl DefCollector<'_> {
12371246

12381247
let def = match resolver_def_id(path.clone()) {
12391248
Some(def) if def.is_attribute() => def,
1240-
_ => return true,
1249+
_ => return Resolved::No,
12411250
};
1242-
if matches!(
1243-
def,
1244-
MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. }
1245-
if expander.is_derive()
1246-
) {
1251+
1252+
if let MacroDefId {
1253+
kind:
1254+
MacroDefKind::BuiltInAttr(
1255+
BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst,
1256+
_,
1257+
),
1258+
..
1259+
} = def
1260+
{
12471261
// Resolved to `#[derive]`, we don't actually expand this attribute like
12481262
// normal (as that would just be an identity expansion with extra output)
12491263
// Instead we treat derive attributes special and apply them separately.
@@ -1316,16 +1330,6 @@ impl DefCollector<'_> {
13161330
let call_id =
13171331
attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
13181332

1319-
// If proc attribute macro expansion is disabled, skip expanding it here
1320-
if !self.db.expand_proc_attr_macros() {
1321-
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
1322-
directive.module_id,
1323-
self.db.lookup_intern_macro_call(call_id).kind,
1324-
def.krate,
1325-
));
1326-
return recollect_without(self);
1327-
}
1328-
13291333
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
13301334
// due to duplicating functions into macro expansions
13311335
if matches!(
@@ -1337,17 +1341,29 @@ impl DefCollector<'_> {
13371341
}
13381342

13391343
if let MacroDefKind::ProcMacro(exp, ..) = def.kind {
1340-
if exp.is_dummy() {
1341-
// If there's no expander for the proc macro (e.g.
1342-
// because proc macros are disabled, or building the
1343-
// proc macro crate failed), report this and skip
1344-
// expansion like we would if it was disabled
1344+
// If proc attribute macro expansion is disabled, skip expanding it here
1345+
if !self.db.expand_proc_attr_macros() {
13451346
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
13461347
directive.module_id,
13471348
self.db.lookup_intern_macro_call(call_id).kind,
13481349
def.krate,
13491350
));
1351+
return recollect_without(self);
1352+
}
13501353

1354+
// If there's no expander for the proc macro (e.g.
1355+
// because proc macros are disabled, or building the
1356+
// proc macro crate failed), report this and skip
1357+
// expansion like we would if it was disabled
1358+
if exp.is_dummy() {
1359+
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
1360+
directive.module_id,
1361+
self.db.lookup_intern_macro_call(call_id).kind,
1362+
def.krate,
1363+
));
1364+
return recollect_without(self);
1365+
}
1366+
if exp.is_disabled() {
13511367
return recollect_without(self);
13521368
}
13531369
}
@@ -1358,12 +1374,13 @@ impl DefCollector<'_> {
13581374

13591375
push_resolved(directive, call_id);
13601376
res = ReachedFixedPoint::No;
1361-
return false;
1377+
return Resolved::Yes;
13621378
}
13631379
}
13641380

1365-
true
1366-
});
1381+
Resolved::No
1382+
};
1383+
macros.retain(|it| retain(it) == Resolved::No);
13671384
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
13681385
macros.extend(mem::take(&mut self.unresolved_macros));
13691386
self.unresolved_macros = macros;
@@ -1673,7 +1690,11 @@ impl ModCollector<'_, '_> {
16731690
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
16741691

16751692
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1676-
if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT {
1693+
1694+
if self.def_collector.def_map.block.is_none()
1695+
&& self.def_collector.is_proc_macro
1696+
&& self.module_id == DefMap::ROOT
1697+
{
16771698
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
16781699
self.def_collector.export_proc_macro(
16791700
proc_macro,

crates/hir-def/src/nameres/diagnostics.rs

+3
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ impl DefDiagnostic {
103103
}
104104

105105
// FIXME: Whats the difference between this and unresolved_macro_call
106+
// FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
107+
// yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
108+
// struct loses all that information!
106109
pub(crate) fn unresolved_proc_macro(
107110
container: LocalModuleId,
108111
ast: MacroCallKind,

crates/hir-expand/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub type ExpandResult<T> = ValueResult<T, ExpandError>;
129129
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
130130
pub enum ExpandError {
131131
UnresolvedProcMacro(CrateId),
132+
/// The macro expansion is disabled.
133+
MacroDisabled,
132134
Mbe(mbe::ExpandError),
133135
RecursionOverflowPoisoned,
134136
Other(Box<Box<str>>),
@@ -160,6 +162,7 @@ impl fmt::Display for ExpandError {
160162
f.write_str(it)
161163
}
162164
ExpandError::Other(it) => f.write_str(it),
165+
ExpandError::MacroDisabled => f.write_str("macro disabled"),
163166
}
164167
}
165168
}

crates/hir-expand/src/proc_macro.rs

+29-9
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,43 @@ pub struct ProcMacro {
4949
pub name: SmolStr,
5050
pub kind: ProcMacroKind,
5151
pub expander: sync::Arc<dyn ProcMacroExpander>,
52+
pub disabled: bool,
5253
}
5354

5455
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
5556
pub struct CustomProcMacroExpander {
5657
proc_macro_id: ProcMacroId,
5758
}
5859

59-
const DUMMY_ID: u32 = !0;
60-
6160
impl CustomProcMacroExpander {
61+
const DUMMY_ID: u32 = !0;
62+
const DISABLED_ID: u32 = !1;
63+
6264
pub fn new(proc_macro_id: ProcMacroId) -> Self {
63-
assert_ne!(proc_macro_id.0, DUMMY_ID);
65+
assert_ne!(proc_macro_id.0, Self::DUMMY_ID);
66+
assert_ne!(proc_macro_id.0, Self::DISABLED_ID);
6467
Self { proc_macro_id }
6568
}
6669

67-
pub fn dummy() -> Self {
68-
Self { proc_macro_id: ProcMacroId(DUMMY_ID) }
70+
/// A dummy expander that always errors. This is used for proc-macros that are missing, usually
71+
/// due to them not being built yet.
72+
pub const fn dummy() -> Self {
73+
Self { proc_macro_id: ProcMacroId(Self::DUMMY_ID) }
6974
}
7075

71-
pub fn is_dummy(&self) -> bool {
72-
self.proc_macro_id.0 == DUMMY_ID
76+
/// The macro was not yet resolved.
77+
pub const fn is_dummy(&self) -> bool {
78+
self.proc_macro_id.0 == Self::DUMMY_ID
79+
}
80+
81+
/// A dummy expander that always errors. This expander is used for macros that have been disabled.
82+
pub const fn disabled() -> Self {
83+
Self { proc_macro_id: ProcMacroId(Self::DISABLED_ID) }
84+
}
85+
86+
/// The macro is explicitly disabled and cannot be expanded.
87+
pub const fn is_disabled(&self) -> bool {
88+
self.proc_macro_id.0 == Self::DISABLED_ID
7389
}
7490

7591
pub fn expand(
@@ -84,10 +100,14 @@ impl CustomProcMacroExpander {
84100
mixed_site: Span,
85101
) -> ExpandResult<tt::Subtree> {
86102
match self.proc_macro_id {
87-
ProcMacroId(DUMMY_ID) => ExpandResult::new(
103+
ProcMacroId(Self::DUMMY_ID) => ExpandResult::new(
88104
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
89105
ExpandError::UnresolvedProcMacro(def_crate),
90106
),
107+
ProcMacroId(Self::DISABLED_ID) => ExpandResult::new(
108+
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
109+
ExpandError::MacroDisabled,
110+
),
91111
ProcMacroId(id) => {
92112
let proc_macros = db.proc_macros();
93113
let proc_macros = match proc_macros.get(&def_crate) {
@@ -110,7 +130,7 @@ impl CustomProcMacroExpander {
110130
);
111131
return ExpandResult::new(
112132
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
113-
ExpandError::other("Internal error"),
133+
ExpandError::other("Internal error: proc-macro index out of bounds"),
114134
);
115135
}
116136
};

0 commit comments

Comments
 (0)