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            // Doc attributes should be forwarded to the macro and the foreign item, since those are
207            // the two items you interact with as a user.
208            // FIXME: idk yet how EIIs show up in docs, might want to customize
209            _ if attr.is_doc_comment() => {
210                foreign_item_attributes.push(attr.clone());
211                macro_attributes.push(attr);
212            }
213            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"),
214            _ => {
215                ecx.dcx().emit_err(EiiAttributeNotSupported { span, attr_span: attr.span() });
216            }
217        }
218    }
219
220    (macro_attributes, foreign_item_attributes, default_attributes)
221}
222
223/// Decide on the name of the macro that can be used to implement the EII.
224/// This is either an explicitly given name, or the name of the item in the
225/// declaration of the EII.
226fn name_for_impl_macro(
227    ecx: &mut ExtCtxt<'_>,
228    item_ident: Ident,
229    meta_item: &MetaItem,
230) -> Result<Ident, ErrorGuaranteed> {
231    if meta_item.is_word() {
232        Ok(item_ident)
233    } else if let Some([first]) = meta_item.meta_item_list()
234        && let Some(m) = first.meta_item()
235        && m.path.segments.len() == 1
236    {
237        Ok(m.path.segments[0].ident)
238    } else {
239        Err(ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
240            span: meta_item.span,
241            name: path_to_string(&meta_item.path),
242        }))
243    }
244}
245
246/// Ensure that in the list of attrs, there's only a single `eii` attribute.
247fn filter_attrs_for_multiple_eii_attr(
248    ecx: &mut ExtCtxt<'_>,
249    attrs: ThinVec<Attribute>,
250    eii_attr_span: Span,
251    eii_attr_path: &Path,
252) -> ThinVec<Attribute> {
253    attrs
254        .into_iter()
255        .filter(|i| {
256            if i.has_name(sym::eii) {
257                ecx.dcx().emit_err(EiiOnlyOnce {
258                    span: i.span,
259                    first_span: eii_attr_span,
260                    name: path_to_string(eii_attr_path),
261                });
262                false
263            } else {
264                true
265            }
266        })
267        .collect()
268}
269
270fn generate_default_impl(
271    ecx: &mut ExtCtxt<'_>,
272    item_kind: &ItemKind,
273    impl_unsafe: bool,
274    macro_name: Ident,
275    eii_attr_span: Span,
276    item_span: Span,
277    foreign_item_name: Ident,
278    attrs: ThinVec<Attribute>,
279) -> Option<Box<ast::Item>> {
280    match item_kind {
281        ItemKind::Fn(func) => {
282            if func.body.is_none() {
283                return None;
284            }
285        }
286        ItemKind::Static(stat) => {
287            if stat.expr.is_none() {
288                return None;
289            }
290        }
291        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
292    };
293
294    let eii_impl = EiiImpl {
295        node_id: DUMMY_NODE_ID,
296        inner_span: macro_name.span,
297        eii_macro_path: ast::Path::from_ident(macro_name),
298        impl_safety: if impl_unsafe {
299            ast::Safety::Unsafe(eii_attr_span)
300        } else {
301            ast::Safety::Default
302        },
303        span: eii_attr_span,
304        is_default: true,
305        known_eii_macro_resolution: Some(ast::EiiDecl {
306            foreign_item: ecx.path(
307                foreign_item_name.span,
308                // prefix self to explicitly escape the const block generated below
309                // NOTE: this is why EIIs can't be used on statements
310                ::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],
311            ),
312            impl_unsafe,
313        }),
314    };
315
316    let mut item_kind = item_kind.clone();
317    match &mut item_kind {
318        ItemKind::Fn(func) => {
319            func.eii_impls.push(eii_impl);
320        }
321        ItemKind::Static(stat) => {
322            stat.eii_impls.push(eii_impl);
323        }
324        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
325    };
326
327    let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
328        let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
329        let underscore = Ident::new(kw::Underscore, item_span);
330        ecx.item_const(
331            span,
332            underscore,
333            unit,
334            ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts))),
335        )
336    };
337
338    // const _: () = {
339    //     <orig item>
340    // }
341    Some(anon_mod(
342        item_span,
343        {
    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))],
344    ))
345}
346
347/// Generates a foreign item, like
348///
349/// ```rust, ignore
350/// extern "…" { safe fn item(); }
351/// ```
352fn generate_foreign_item(
353    ecx: &mut ExtCtxt<'_>,
354    eii_attr_span: Span,
355    item_span: Span,
356    item_kind: &ItemKind,
357    vis: Visibility,
358    attrs_from_decl: ThinVec<Attribute>,
359) -> Box<ast::Item> {
360    let mut foreign_item_attrs = attrs_from_decl;
361
362    // Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled.
363    // This attribute makes sure that we later know that this foreign item's symbol should not be.
364    foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
365
366    // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
367    // if a specific abi was specified on the EII function
368    let mut abi = Some(ast::StrLit {
369        symbol: sym::Rust,
370        suffix: None,
371        symbol_unescaped: sym::Rust,
372        style: ast::StrStyle::Cooked,
373        span: eii_attr_span,
374    });
375    let foreign_kind = match item_kind {
376        ItemKind::Fn(func) => generate_foreign_func(func.clone(), &mut abi),
377        ItemKind::Static(stat) => generate_foreign_static(stat.clone()),
378        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Target was checked earlier")));
}unreachable!("Target was checked earlier"),
379    };
380
381    ecx.item(
382        eii_attr_span,
383        ThinVec::new(),
384        ast::ItemKind::ForeignMod(ast::ForeignMod {
385            extern_span: eii_attr_span,
386            safety: ast::Safety::Unsafe(eii_attr_span),
387            abi,
388            items: From::from([Box::new(ast::ForeignItem {
389                attrs: foreign_item_attrs,
390                id: ast::DUMMY_NODE_ID,
391                span: item_span,
392                vis,
393                kind: foreign_kind,
394                tokens: None,
395            })]),
396        }),
397    )
398}
399
400fn generate_foreign_func(
401    mut func: Box<ast::Fn>,
402    abi: &mut Option<ast::StrLit>,
403) -> ast::ForeignItemKind {
404    match func.sig.header.ext {
405        // extern "X" fn  =>  extern "X" {}
406        ast::Extern::Explicit(lit, _) => *abi = Some(lit),
407        // extern fn  =>  extern {}
408        ast::Extern::Implicit(_) => *abi = None,
409        // no abi was specified, so we keep the default
410        ast::Extern::None => {}
411    };
412
413    // ABI has been moved to the extern {} block, so we remove it from the fn item.
414    func.sig.header.ext = ast::Extern::None;
415    func.body = None;
416
417    // And mark safe functions explicitly as `safe fn`.
418    if func.sig.header.safety == ast::Safety::Default {
419        func.sig.header.safety = ast::Safety::Safe(func.sig.span);
420    }
421
422    ast::ForeignItemKind::Fn(func)
423}
424
425fn generate_foreign_static(mut stat: Box<ast::StaticItem>) -> ast::ForeignItemKind {
426    if stat.safety == ast::Safety::Default {
427        stat.safety = ast::Safety::Safe(stat.ident.span);
428    }
429
430    stat.expr = None;
431
432    ast::ForeignItemKind::Static(stat)
433}
434
435/// Generate a stub macro (a bit like in core) that will roughly look like:
436///
437/// ```rust, ignore, example
438/// // Since this a stub macro, the actual code that expands it lives in the compiler.
439/// // This attribute tells the compiler that
440/// #[builtin_macro(eii_shared_macro)]
441/// // the metadata to link this macro to the generated foreign item.
442/// #[eii_declaration(<related_foreign_item>)]
443/// macro macro_name { () => {} }
444/// ```
445fn generate_attribute_macro_to_implement(
446    ecx: &mut ExtCtxt<'_>,
447    span: Span,
448    macro_name: Ident,
449    foreign_item_name: Ident,
450    impl_unsafe: bool,
451    attrs_from_decl: ThinVec<Attribute>,
452) -> Box<ast::Item> {
453    let mut macro_attrs = attrs_from_decl;
454
455    // Avoid "missing stability attribute" errors for eiis in std. See #146993.
456    macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
457
458    // #[builtin_macro(eii_shared_macro)]
459    macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
460
461    // cant use ecx methods here to construct item since we need it to be public
462    Box::new(ast::Item {
463        attrs: macro_attrs,
464        id: ast::DUMMY_NODE_ID,
465        span,
466        // pub
467        vis: ast::Visibility { span, kind: ast::VisibilityKind::Public, tokens: None },
468        kind: ast::ItemKind::MacroDef(
469            // macro macro_name
470            macro_name,
471            ast::MacroDef {
472                // { () => {} }
473                body: Box::new(ast::DelimArgs {
474                    dspan: DelimSpan::from_single(span),
475                    delim: Delimiter::Brace,
476                    tokens: TokenStream::from_iter([
477                        TokenTree::Delimited(
478                            DelimSpan::from_single(span),
479                            DelimSpacing::new(Spacing::Alone, Spacing::Alone),
480                            Delimiter::Parenthesis,
481                            TokenStream::default(),
482                        ),
483                        TokenTree::token_alone(TokenKind::FatArrow, span),
484                        TokenTree::Delimited(
485                            DelimSpan::from_single(span),
486                            DelimSpacing::new(Spacing::Alone, Spacing::Alone),
487                            Delimiter::Brace,
488                            TokenStream::default(),
489                        ),
490                    ]),
491                }),
492                macro_rules: false,
493                // #[eii_declaration(foreign_item_ident)]
494                eii_declaration: Some(ast::EiiDecl {
495                    foreign_item: ast::Path::from_ident(foreign_item_name),
496                    impl_unsafe,
497                }),
498            },
499        ),
500        tokens: None,
501    })
502}
503
504pub(crate) fn eii_declaration(
505    ecx: &mut ExtCtxt<'_>,
506    span: Span,
507    meta_item: &ast::MetaItem,
508    mut item: Annotatable,
509) -> Vec<Annotatable> {
510    let i = if let Annotatable::Item(ref mut item) = item {
511        item
512    } else if let Annotatable::Stmt(ref mut stmt) = item
513        && let StmtKind::Item(ref mut item) = stmt.kind
514    {
515        item
516    } else {
517        ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
518        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
519    };
520
521    let ItemKind::MacroDef(_, d) = &mut i.kind else {
522        ecx.dcx().emit_err(EiiExternTargetExpectedMacro { span });
523        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
524    };
525
526    let Some(list) = meta_item.meta_item_list() else {
527        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
528        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
529    };
530
531    if list.len() > 2 {
532        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
533        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
534    }
535
536    let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone())
537    else {
538        ecx.dcx().emit_err(EiiExternTargetExpectedList { span: meta_item.span });
539        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
540    };
541
542    let impl_unsafe = if let Some(i) = list.get(1) {
543        if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) {
544            true
545        } else {
546            ecx.dcx().emit_err(EiiExternTargetExpectedUnsafe { span: i.span() });
547            return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
548        }
549    } else {
550        false
551    };
552
553    d.eii_declaration = Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe });
554
555    // Return the original item and the new methods.
556    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item]
557}
558
559/// all Eiis share this function as the implementation for their attribute.
560pub(crate) fn eii_shared_macro(
561    ecx: &mut ExtCtxt<'_>,
562    span: Span,
563    meta_item: &ast::MetaItem,
564    mut item: Annotatable,
565) -> Vec<Annotatable> {
566    let i = if let Annotatable::Item(ref mut item) = item {
567        item
568    } else if let Annotatable::Stmt(ref mut stmt) = item
569        && let StmtKind::Item(ref mut item) = stmt.kind
570    {
571        item
572    } else {
573        ecx.dcx().emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
574        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
575    };
576
577    let eii_impls = match &mut i.kind {
578        ItemKind::Fn(func) => &mut func.eii_impls,
579        ItemKind::Static(stat) => {
580            if !stat.eii_impls.is_empty() {
581                // Reject multiple implementations on one static item
582                // because it might be unintuitive for libraries defining statics the defined statics may alias
583                ecx.dcx().emit_err(EiiStaticMultipleImplementations { span });
584            }
585            &mut stat.eii_impls
586        }
587        _ => {
588            ecx.dcx()
589                .emit_err(EiiSharedMacroTarget { span, name: path_to_string(&meta_item.path) });
590            return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
591        }
592    };
593
594    let is_default = if meta_item.is_word() {
595        false
596    } else if let Some([first]) = meta_item.meta_item_list()
597        && let Some(m) = first.meta_item()
598        && m.path.segments.len() == 1
599    {
600        m.path.segments[0].ident.name == kw::Default
601    } else {
602        ecx.dcx().emit_err(EiiMacroExpectedMaxOneArgument {
603            span: meta_item.span,
604            name: path_to_string(&meta_item.path),
605        });
606        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item];
607    };
608
609    eii_impls.push(EiiImpl {
610        node_id: DUMMY_NODE_ID,
611        inner_span: meta_item.path.span,
612        eii_macro_path: meta_item.path.clone(),
613        impl_safety: meta_item.unsafety,
614        span,
615        is_default,
616        known_eii_macro_resolution: None,
617    });
618
619    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [item]))vec![item]
620}