Skip to main content

rustc_builtin_macros/
eii.rs

1use rustc_ast::token::{Delimiter, TokenKind};
2use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
3use rustc_ast::{
4    Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Mutability, Path, StmtKind,
5    Visibility, ast,
6};
7use rustc_ast_pretty::pprust::path_to_string;
8use rustc_expand::base::{Annotatable, ExtCtxt};
9use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
10use thin_vec::{ThinVec, thin_vec};
11
12use crate::diagnostics::{
13    EiiAttributeNotSupported, EiiExternTargetExpectedList, EiiExternTargetExpectedMacro,
14    EiiExternTargetExpectedUnsafe, EiiMacroExpectedMaxOneArgument, EiiOnlyOnce,
15    EiiSharedMacroInStatementPosition, EiiSharedMacroTarget, EiiStaticArgumentRequired,
16    EiiStaticDefaultApple, EiiStaticMultipleImplementations, EiiStaticMutable,
17};
18
19/// ```rust
20/// #[eii]
21/// fn panic_handler();
22///
23/// // or:
24///
25/// #[eii(panic_handler)]
26/// fn panic_handler();
27///
28/// // expansion:
29///
30/// extern "Rust" {
31///     fn panic_handler();
32/// }
33///
34/// #[rustc_builtin_macro(eii_shared_macro)]
35/// #[eii_declaration(panic_handler)]
36/// macro panic_handler() {}
37/// ```
38pub(crate) fn eii(
39    ecx: &mut ExtCtxt<'_>,
40    span: Span,
41    meta_item: &ast::MetaItem,
42    item: Annotatable,
43) -> Vec<Annotatable> {
44    eii_(ecx, span, meta_item, item, false)
45}
46
47pub(crate) fn unsafe_eii(
48    ecx: &mut ExtCtxt<'_>,
49    span: Span,
50    meta_item: &ast::MetaItem,
51    item: Annotatable,
52) -> Vec<Annotatable> {
53    eii_(ecx, span, meta_item, item, true)
54}
55
56fn eii_(
57    ecx: &mut ExtCtxt<'_>,
58    eii_attr_span: Span,
59    meta_item: &ast::MetaItem,
60    orig_item: Annotatable,
61    impl_unsafe: bool,
62) -> Vec<Annotatable> {
63    let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
64
65    let item = if let Annotatable::Item(item) = orig_item {
66        item
67    } else if let Annotatable::Stmt(ref stmt) = orig_item
68        && let StmtKind::Item(ref item) = stmt.kind
69        && let ItemKind::Fn(ref f) = item.kind
70    {
71        ecx.dcx().emit_err(EiiSharedMacroInStatementPosition {
72            span: eii_attr_span.to(item.span),
73            name: path_to_string(&meta_item.path),
74            item_span: f.ident.span,
75        });
76        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [orig_item]))vec![orig_item];
77    } else {
78        ecx.dcx().emit_err(EiiSharedMacroTarget {
79            span: eii_attr_span,
80            name: path_to_string(&meta_item.path),
81        });
82        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [orig_item]))vec![orig_item];
83    };
84
85    let ast::Item { attrs, id: _, span: _, vis, kind, tokens: _ } = item.as_ref();
86    let (item_span, foreign_item_name) = match kind {
87        ItemKind::Fn(func) => (func.sig.span, func.ident),
88        ItemKind::Static(stat) => {
89            // See https://github.com/rust-lang/rust/issues/157649
90            if let Some(expr) = &stat.expr
91                && ecx.sess.target.is_like_darwin
92            {
93                ecx.dcx().emit_err(EiiStaticDefaultApple {
94                    span: expr.span,
95                    name: path_to_string(&meta_item.path),
96                });
97                return ::alloc::vec::Vec::new()vec![];
98            }
99
100            // Statics must have an explicit name for the eii
101            if meta_item.is_word() {
102                ecx.dcx().emit_err(EiiStaticArgumentRequired {
103                    span: eii_attr_span,
104                    name: path_to_string(&meta_item.path),
105                });
106                return ::alloc::vec::Vec::new()vec![];
107            }
108
109            // Mut statics are currently not supported
110            if stat.mutability == Mutability::Mut {
111                ecx.dcx().emit_err(EiiStaticMutable {
112                    span: eii_attr_span,
113                    name: path_to_string(&meta_item.path),
114                });
115            }
116
117            (item.span, stat.ident)
118        }
119        _ => {
120            ecx.dcx().emit_err(EiiSharedMacroTarget {
121                span: eii_attr_span,
122                name: path_to_string(&meta_item.path),
123            });
124            return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Annotatable::Item(item)]))vec![Annotatable::Item(item)];
125        }
126    };
127
128    // only clone what we need
129    let attrs = attrs.clone();
130    let vis = vis.clone();
131
132    let attrs_from_decl =
133        filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
134    let (macro_attrs, foreign_item_attrs, default_func_attrs) =
135        split_attrs(ecx, item_span, attrs_from_decl);
136
137    let Ok(macro_name) = name_for_impl_macro(ecx, foreign_item_name, &meta_item) else {
138        // we don't need to wrap in Annotatable::Stmt conditionally since
139        // EII can't be used on items in statement position
140        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Annotatable::Item(item)]))vec![Annotatable::Item(item)];
141    };
142
143    let mut module_items = Vec::new();
144
145    if let Some(default_impl) = generate_default_impl(
146        ecx,
147        kind,
148        impl_unsafe,
149        macro_name,
150        eii_attr_span,
151        item_span,
152        foreign_item_name,
153        default_func_attrs,
154    ) {
155        module_items.push(default_impl);
156    }
157
158    module_items.push(generate_foreign_item(
159        ecx,
160        eii_attr_span,
161        item_span,
162        kind,
163        vis,
164        foreign_item_attrs,
165    ));
166    module_items.push(generate_attribute_macro_to_implement(
167        ecx,
168        eii_attr_span,
169        macro_name,
170        foreign_item_name,
171        impl_unsafe,
172        macro_attrs,
173    ));
174
175    // we don't need to wrap in Annotatable::Stmt conditionally since
176    // EII can't be used on items in statement position
177    module_items.into_iter().map(Annotatable::Item).collect()
178}
179
180fn split_attrs(
181    ecx: &mut ExtCtxt<'_>,
182    span: Span,
183    attrs: ThinVec<Attribute>,
184) -> (ThinVec<Attribute>, ThinVec<Attribute>, ThinVec<Attribute>) {
185    let mut macro_attributes = ThinVec::new();
186    let mut foreign_item_attributes = ThinVec::new();
187    let mut default_attributes = ThinVec::new();
188
189    for attr in attrs {
190        match attr.name() {
191            // Inline only matters for the default function being inlined into callsites
192            Some(sym::inline) => default_attributes.push(attr),
193            // If an eii is marked a lang item, that's because we want to call its declaration, so
194            // mark the foreign item as the lang item
195            Some(sym::lang) => foreign_item_attributes.push(attr),
196            // Deprecating an eii means deprecating the macro and the foreign item
197            Some(sym::deprecated) => {
198                foreign_item_attributes.push(attr.clone());
199                macro_attributes.push(attr);
200            }
201            // The stability of an EII affects the usage of the macro and calling the foreign item
202            Some(sym::stable) | Some(sym::unstable) => {
203                foreign_item_attributes.push(attr.clone());
204                macro_attributes.push(attr);
205            }
206            // `#[track_caller]` goes on the foreign item only: it's the symbol callers link
207            // against, so it must carry the flag for call sites to pass the caller location.
208            // Implementations derive it during codegen (see `EiiImpls` in `codegen_attrs.rs`),
209            // so it must not be routed onto the default impl here.
210            Some(sym::track_caller) => {
211                foreign_item_attributes.push(attr);
212            }
213            // Doc attributes should be forwarded to the macro and the foreign item, since those are
214            // the two items you interact with as a user.
215            // FIXME: idk yet how EIIs show up in docs, might want to customize
216            _ if attr.is_doc_comment() => {
217                foreign_item_attributes.push(attr.clone());
218                macro_attributes.push(attr);
219            }
220            Some(sym::eii) => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("should already be filtered out")));
}unreachable!("should already be filtered out"),
221            _ => {
222                ecx.dcx().emit_err(EiiAttributeNotSupported { span, attr_span: attr.span() });
223            }
224        }
225    }
226
227    (macro_attributes, foreign_item_attributes, default_attributes)
228}
229
230/// Decide on the name of the macro that can be used to implement the EII.
231/// This is either an explicitly given name, or the name of the item in the
232/// declaration of the EII.
233fn name_for_impl_macro(
234    ecx: &mut ExtCtxt<'_>,
235    item_ident: Ident,
236    meta_item: &MetaItem,
237) -> Result<Ident, ErrorGuaranteed> {
238    if meta_item.is_word() {
239        Ok(item_ident)
240    } else if let Some([first]) = meta_item.meta_item_list()
241        && let Some(m) = first.meta_item()
242        && m.path.segments.len() == 1
243    {
244        Ok(m.path.segments[0].ident)
245    } else {
246        Err(ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
247            span: meta_item.span,
248            name: path_to_string(&meta_item.path),
249        }))
250    }
251}
252
253/// Ensure that in the list of attrs, there's only a single `eii` attribute.
254fn filter_attrs_for_multiple_eii_attr(
255    ecx: &mut ExtCtxt<'_>,
256    attrs: ThinVec<Attribute>,
257    eii_attr_span: Span,
258    eii_attr_path: &Path,
259) -> ThinVec<Attribute> {
260    attrs
261        .into_iter()
262        .filter(|i| {
263            if i.has_name(sym::eii) {
264                ecx.dcx().emit_err(EiiOnlyOnce {
265                    span: i.span,
266                    first_span: eii_attr_span,
267                    name: path_to_string(eii_attr_path),
268                });
269                false
270            } else {
271                true
272            }
273        })
274        .collect()
275}
276
277fn generate_default_impl(
278    ecx: &mut ExtCtxt<'_>,
279    item_kind: &ItemKind,
280    impl_unsafe: bool,
281    macro_name: Ident,
282    eii_attr_span: Span,
283    item_span: Span,
284    foreign_item_name: Ident,
285    attrs: ThinVec<Attribute>,
286) -> Option<Box<ast::Item>> {
287    match item_kind {
288        ItemKind::Fn(func) => {
289            if func.body.is_none() {
290                return None;
291            }
292        }
293        ItemKind::Static(stat) => {
294            if stat.expr.is_none() {
295                return None;
296            }
297        }
298        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
299    };
300
301    let eii_impl = EiiImpl {
302        node_id: DUMMY_NODE_ID,
303        inner_span: macro_name.span,
304        eii_macro_path: ast::Path::from_ident(macro_name),
305        impl_safety: if impl_unsafe {
306            ast::Safety::Unsafe(eii_attr_span)
307        } else {
308            ast::Safety::Default
309        },
310        span: eii_attr_span,
311        is_default: true,
312        known_eii_macro_resolution: Some(ast::EiiDecl {
313            foreign_item: ecx.path(
314                foreign_item_name.span,
315                // prefix self to explicitly escape the const block generated below
316                // NOTE: this is why EIIs can't be used on statements
317                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Ident::from_str_and_span("self", foreign_item_name.span),
                foreign_item_name]))vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
318            ),
319            impl_unsafe,
320        }),
321    };
322
323    let mut item_kind = item_kind.clone();
324    match &mut item_kind {
325        ItemKind::Fn(func) => {
326            func.eii_impls.push(eii_impl);
327        }
328        ItemKind::Static(stat) => {
329            stat.eii_impls.push(eii_impl);
330        }
331        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
332    };
333
334    let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
335        let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
336        let underscore = Ident::new(kw::Underscore, item_span);
337        ecx.item_const(
338            span,
339            underscore,
340            unit,
341            ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts))),
342        )
343    };
344
345    // const _: () = {
346    //     <orig item>
347    // }
348    Some(anon_mod(
349        item_span,
350        {
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(ecx.stmt_item(item_span, ecx.item(item_span, attrs, item_kind)));
    vec
}thin_vec![ecx.stmt_item(item_span, ecx.item(item_span, attrs, item_kind))],
351    ))
352}
353
354/// Generates a foreign item, like
355///
356/// ```rust, ignore
357/// extern "…" { safe fn item(); }
358/// ```
359fn generate_foreign_item(
360    ecx: &mut ExtCtxt<'_>,
361    eii_attr_span: Span,
362    item_span: Span,
363    item_kind: &ItemKind,
364    vis: Visibility,
365    attrs_from_decl: ThinVec<Attribute>,
366) -> Box<ast::Item> {
367    let mut foreign_item_attrs = attrs_from_decl;
368
369    // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled.
370    // This attribute makes sure that we later know that this foreign item's symbol should not be.
371    foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
372
373    // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
374    // if a specific abi was specified on the EII function
375    let mut abi = Some(ast::StrLit {
376        symbol: sym::Rust,
377        suffix: None,
378        symbol_unescaped: sym::Rust,
379        style: ast::StrStyle::Cooked,
380        span: eii_attr_span,
381    });
382    let foreign_kind = match item_kind {
383        ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi),
384        ItemKind::Static(stat) => generate_foreign_static(stat.clone()),
385        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
386    };
387
388    ecx.item(
389        eii_attr_span,
390        ThinVec::new(),
391        ast::ItemKind::ForeignMod(ast::ForeignMod {
392            extern_span: eii_attr_span,
393            safety: ast::Safety::Unsafe(eii_attr_span),
394            abi,
395            items: From::from([Box::new(ast::ForeignItem {
396                attrs: foreign_item_attrs,
397                id: ast::DUMMY_NODE_ID,
398                span: item_span,
399                vis,
400                kind: foreign_kind,
401                tokens: None,
402            })]),
403        }),
404    )
405}
406
407fn generate_foreign_func(
408    mut func: Box<ast::Fn>,
409    abi: &mut Option<ast::StrLit>,
410) -> ast::ForeignItemKind {
411    match func.sig.header.ext {
412        // extern "X" fn  =>  extern "X" {}
413        ast::Extern::Explicit(lit, _) => *abi = Some(lit),
414        // extern fn  =>  extern {}
415        ast::Extern::Implicit(_) => *abi = None,
416        // no abi was specified, so we keep the default
417        ast::Extern::None => {}
418    };
419
420    // ABI has been moved to the extern {} block, so we remove it from the fn item.
421    func.sig.header.ext = ast::Extern::None;
422    func.body = None;
423
424    // And mark safe functions explicitly as `safe fn`.
425    if func.sig.header.safety == ast::Safety::Default {
426        func.sig.header.safety = ast::Safety::Safe(func.sig.span);
427    }
428
429    ast::ForeignItemKind::Fn(func)
430}
431
432fn generate_foreign_static(mut stat: Box<ast::StaticItem>) -> ast::ForeignItemKind {
433    if stat.safety == ast::Safety::Default {
434        stat.safety = ast::Safety::Safe(stat.ident.span);
435    }
436
437    stat.expr = None;
438
439    ast::ForeignItemKind::Static(stat)
440}
441
442/// Generate a stub macro (a bit like in core) that will roughly look like:
443///
444/// ```rust, ignore, example
445/// // Since this a stub macro, the actual code that expands it lives in the compiler.
446/// // This attribute tells the compiler that
447/// #[builtin_macro(eii_shared_macro)]
448/// // the metadata to link this macro to the generated foreign item.
449/// #[eii_declaration(<related_foreign_item>)]
450/// macro macro_name { () => {} }
451/// ```
452fn generate_attribute_macro_to_implement(
453    ecx: &mut ExtCtxt<'_>,
454    span: Span,
455    macro_name: Ident,
456    foreign_item_name: Ident,
457    impl_unsafe: bool,
458    attrs_from_decl: ThinVec<Attribute>,
459) -> Box<ast::Item> {
460    let mut macro_attrs = attrs_from_decl;
461
462    // Avoid "missing stability attribute" errors for eiis in std. See #146993.
463    macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
464
465    // #[builtin_macro(eii_shared_macro)]
466    macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
467
468    // cant use ecx methods here to construct item since we need it to be public
469    Box::new(ast::Item {
470        attrs: macro_attrs,
471        id: ast::DUMMY_NODE_ID,
472        span,
473        // pub
474        vis: ast::Visibility { span, kind: ast::VisibilityKind::Public },
475        kind: ast::ItemKind::MacroDef(
476            // macro macro_name
477            macro_name,
478            ast::MacroDef {
479                // { () => {} }
480                body: Box::new(ast::DelimArgs {
481                    dspan: DelimSpan::from_single(span),
482                    delim: Delimiter::Brace,
483                    tokens: TokenStream::from_iter([
484                        TokenTree::Delimited(
485                            DelimSpan::from_single(span),
486                            DelimSpacing::new(Spacing::Alone, Spacing::Alone),
487                            Delimiter::Parenthesis,
488                            TokenStream::default(),
489                        ),
490                        TokenTree::token_alone(TokenKind::FatArrow, span),
491                        TokenTree::Delimited(
492                            DelimSpan::from_single(span),
493                            DelimSpacing::new(Spacing::Alone, Spacing::Alone),
494                            Delimiter::Brace,
495                            TokenStream::default(),
496                        ),
497                    ]),
498                }),
499                macro_rules: false,
500                // #[eii_declaration(foreign_item_ident)]
501                eii_declaration: Some(ast::EiiDecl {
502                    foreign_item: ast::Path::from_ident(foreign_item_name),
503                    impl_unsafe,
504                }),
505            },
506        ),
507        tokens: None,
508    })
509}
510
511pub(crate) fn eii_declaration(
512    ecx: &mut ExtCtxt<'_>,
513    span: Span,
514    meta_item: &ast::MetaItem,
515    mut item: Annotatable,
516) -> Vec<Annotatable> {
517    let i = if let Annotatable::Item(ref mut item) = item {
518        item
519    } else if let Annotatable::Stmt(ref mut stmt) = item
520        && let StmtKind::Item(ref mut item) = stmt.kind
521    {
522        item
523    } else {
524        ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
525        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
526    };
527
528    let ItemKind::MacroDef(_, d) = &mut i.kind else {
529        ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
530        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
531    };
532
533    let Some(list) = meta_item.meta_item_list() else {
534        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
535        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
536    };
537
538    if list.len() > 2 {
539        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
540        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
541    }
542
543    let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone())
544    else {
545        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
546        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
547    };
548
549    let impl_unsafe = if let Some(i) = list.get(1) {
550        if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) {
551            true
552        } else {
553            ecx.dcx().emit_err(EiiExternTargetExpectedUnsafe { span: i.span() });
554            return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
555        }
556    } else {
557        false
558    };
559
560    d.eii_declaration = Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe });
561
562    // Return the original item and the new methods.
563    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item]
564}
565
566/// all Eiis share this function as the implementation for their attribute.
567pub(crate) fn eii_shared_macro(
568    ecx: &mut ExtCtxt<'_>,
569    span: Span,
570    meta_item: &ast::MetaItem,
571    mut item: Annotatable,
572) -> Vec<Annotatable> {
573    let i = if let Annotatable::Item(ref mut item) = item {
574        item
575    } else if let Annotatable::Stmt(ref mut stmt) = item
576        && let StmtKind::Item(ref mut item) = stmt.kind
577    {
578        item
579    } else {
580        ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
581        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
582    };
583
584    let eii_impls = match &mut i.kind {
585        ItemKind::Fn(func) => &mut func.eii_impls,
586        ItemKind::Static(stat) => {
587            if !stat.eii_impls.is_empty() {
588                // Reject multiple implementations on one static item
589                // because it might be unintuitive for libraries defining statics the defined statics may alias
590                ecx.dcx().emit_err(EiiStaticMultipleImplementations { span });
591            }
592            &mut stat.eii_impls
593        }
594        _ => {
595            ecx.dcx()
596                .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
597            return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
598        }
599    };
600
601    let is_default = if meta_item.is_word() {
602        false
603    } else if let Some([first]) = meta_item.meta_item_list()
604        && let Some(m) = first.meta_item()
605        && m.path.segments.len() == 1
606    {
607        m.path.segments[0].ident.name == kw::Default
608    } else {
609        ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
610            span: meta_item.span,
611            name: path_to_string(&meta_item.path),
612        });
613        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
614    };
615
616    eii_impls.push(EiiImpl {
617        node_id: DUMMY_NODE_ID,
618        inner_span: meta_item.path.span,
619        eii_macro_path: meta_item.path.clone(),
620        impl_safety: meta_item.unsafety,
621        span,
622        is_default,
623        known_eii_macro_resolution: None,
624    });
625
626    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item]
627}