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