refactor how eii expansion is wrapped fixing 149980

This commit is contained in:
Jana Dönszelmann
2025-12-19 14:42:20 +01:00
parent 897e88c63d
commit c316c05dc5
3 changed files with 38 additions and 25 deletions
+20 -25
View File
@@ -60,12 +60,18 @@ fn eii_(
) -> Vec<Annotatable> {
let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
let (item, stmt) = if let Annotatable::Item(item) = item {
(item, false)
let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item {
(item, &Annotatable::Item)
} else if let Annotatable::Stmt(ref stmt) = item
&& let StmtKind::Item(ref item) = stmt.kind
{
(item.clone(), true)
(item.clone(), &|item| {
Annotatable::Stmt(Box::new(Stmt {
id: DUMMY_NODE_ID,
kind: StmtKind::Item(item),
span: eii_attr_span,
}))
})
} else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span: eii_attr_span,
@@ -74,23 +80,25 @@ fn eii_(
return vec![item];
};
let orig_item = item.clone();
let item = *item;
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = item else {
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
item.as_ref()
else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![Annotatable::Item(Box::new(item))];
return vec![wrap_item(item)];
};
// only clone what we need
let attrs = attrs.clone();
let func = (**func).clone();
let vis = vis.clone();
let attrs_from_decl =
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
return vec![Annotatable::Item(orig_item)];
return vec![wrap_item(item)];
};
// span of the declaring item without attributes
@@ -115,7 +123,7 @@ fn eii_(
ecx,
eii_attr_span,
item_span,
*func,
func,
vis,
&attrs_from_decl,
)));
@@ -128,20 +136,7 @@ fn eii_(
decl_span,
)));
if stmt {
return_items
.into_iter()
.map(|i| {
Annotatable::Stmt(Box::new(Stmt {
id: DUMMY_NODE_ID,
kind: StmtKind::Item(i),
span: eii_attr_span,
}))
})
.collect()
} else {
return_items.into_iter().map(|i| Annotatable::Item(i)).collect()
}
return_items.into_iter().map(wrap_item).collect()
}
/// Decide on the name of the macro that can be used to implement the EII.
+10
View File
@@ -1,6 +1,16 @@
#![feature(extern_item_impls)]
// EIIs can, despite not being super useful, be declared in statement position
// nested inside items. Items in statement position, when expanded as part of a macro,
// need to be wrapped slightly differently (in an `ast::Statement`).
// We did this on the happy path (no errors), but when there was an error, we'd
// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`.
// This caused an ICE (https://github.com/rust-lang/rust/issues/149980).
// this test fails to build, but demonstrates that no ICE is produced.
fn main() {
struct Bar;
#[eii]
//~^ ERROR `#[eii]` is only valid on functions
impl Bar {}
}
@@ -0,0 +1,8 @@
error: `#[eii]` is only valid on functions
--> $DIR/error_statement_position.rs:13:5
|
LL | #[eii]
| ^^^^^^
error: aborting due to 1 previous error