|
1 |
| -use rustc_ast::{ |
2 |
| - DUMMY_NODE_ID, DUMMY_NODE_ID, EIIImpl, EIIImpl, EIIMacroFor, EiiMacroFor, ItemKind, ItemKind, |
3 |
| - ast, ast, |
4 |
| -}; |
| 1 | +use rustc_ast::ptr::P; |
| 2 | +use rustc_ast::token::{Delimiter, TokenKind}; |
| 3 | +use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; |
| 4 | +use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EIIMacroFor, ItemKind, ast, token, tokenstream}; |
5 | 5 | use rustc_ast_pretty::pprust::path_to_string;
|
6 | 6 | use rustc_expand::base::{Annotatable, ExtCtxt};
|
7 |
| -use rustc_span::{Span, Span, kw, kw}; |
| 7 | +use rustc_span::{Ident, Span, kw, sym}; |
| 8 | + |
| 9 | +/* ```rust |
| 10 | +
|
| 11 | +#[eii] |
| 12 | +fn panic_handler(); |
| 13 | +
|
| 14 | +#[eii(panic_handler)] |
| 15 | +fn panic_handler(); |
| 16 | +
|
| 17 | +#[eii(panic_handler, unsafe)] |
| 18 | +fn panic_handler(); |
| 19 | +
|
| 20 | +// expansion: |
| 21 | +
|
| 22 | +extern "Rust" { |
| 23 | + fn panic_handler(); |
| 24 | +} |
| 25 | +
|
| 26 | +#[rustc_builtin_macro(eii_macro)] // eii_macro_for: panic_handler |
| 27 | +macro panic_handler() {} |
| 28 | +
|
| 29 | +``` */ |
| 30 | +pub(crate) fn eii( |
| 31 | + ecx: &mut ExtCtxt<'_>, |
| 32 | + span: Span, |
| 33 | + meta_item: &ast::MetaItem, |
| 34 | + item: Annotatable, |
| 35 | +) -> Vec<Annotatable> { |
| 36 | + let span = ecx.with_def_site_ctxt(span); |
| 37 | + |
| 38 | + let Annotatable::Item(item) = item else { |
| 39 | + ecx.dcx() |
| 40 | + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); |
| 41 | + return vec![item]; |
| 42 | + }; |
| 43 | + |
| 44 | + let macro_name = if meta_item.is_word() { |
| 45 | + item.ident |
| 46 | + } else if let Some([first]) = meta_item.meta_item_list() |
| 47 | + && let Some(m) = first.meta_item() |
| 48 | + && m.path.segments.len() == 1 |
| 49 | + { |
| 50 | + m.path.segments[0].ident |
| 51 | + } else { |
| 52 | + ecx.dcx().emit_err(EIIMacroExpectedMaxOneArgument { |
| 53 | + span: meta_item.span, |
| 54 | + name: path_to_string(&meta_item.path), |
| 55 | + }); |
| 56 | + return vec![Annotatable::Item(item)]; |
| 57 | + }; |
| 58 | + |
| 59 | + let item = item.into_inner(); |
| 60 | + |
| 61 | + let ast::Item { |
| 62 | + attrs, |
| 63 | + id: _, |
| 64 | + span: item_span, |
| 65 | + vis, |
| 66 | + ident: item_name, |
| 67 | + kind: ItemKind::Fn(mut func), |
| 68 | + tokens: _, |
| 69 | + } = item |
| 70 | + else { |
| 71 | + ecx.dcx() |
| 72 | + .emit_err(EIIMacroExpectedFunction { span, name: path_to_string(&meta_item.path) }); |
| 73 | + return vec![Annotatable::Item(P(item))]; |
| 74 | + }; |
| 75 | + |
| 76 | + let impl_unsafe = false; // TODO |
| 77 | + |
| 78 | + let abi = match func.sig.header.ext { |
| 79 | + // extern "X" fn => extern "X" {} |
| 80 | + ast::Extern::Explicit(lit, _) => Some(lit), |
| 81 | + // extern fn => extern {} |
| 82 | + ast::Extern::Implicit(_) => None, |
| 83 | + // fn => extern "Rust" {} |
| 84 | + ast::Extern::None => Some(ast::StrLit { |
| 85 | + symbol: sym::Rust, |
| 86 | + suffix: None, |
| 87 | + symbol_unescaped: sym::Rust, |
| 88 | + style: ast::StrStyle::Cooked, |
| 89 | + span, |
| 90 | + }), |
| 91 | + }; |
| 92 | + |
| 93 | + // ABI has been moved to the extern {} block, so we remove it from the fn item. |
| 94 | + func.sig.header.ext = ast::Extern::None; |
| 95 | + |
| 96 | + // And mark safe functions explicitly as `safe fn`. |
| 97 | + if func.sig.header.safety == ast::Safety::Default { |
| 98 | + func.sig.header.safety = ast::Safety::Safe(func.sig.span); |
| 99 | + } |
| 100 | + |
| 101 | + // extern "…" { safe fn item(); } |
| 102 | + let extern_block = Annotatable::Item(P(ast::Item { |
| 103 | + attrs: ast::AttrVec::default(), |
| 104 | + id: ast::DUMMY_NODE_ID, |
| 105 | + span, |
| 106 | + vis: ast::Visibility { span, kind: ast::VisibilityKind::Inherited, tokens: None }, |
| 107 | + ident: Ident::dummy(), |
| 108 | + kind: ast::ItemKind::ForeignMod(ast::ForeignMod { |
| 109 | + extern_span: span, |
| 110 | + safety: ast::Safety::Unsafe(span), |
| 111 | + abi, |
| 112 | + items: From::from([P(ast::ForeignItem { |
| 113 | + attrs, |
| 114 | + id: ast::DUMMY_NODE_ID, |
| 115 | + span: item_span, |
| 116 | + vis, |
| 117 | + ident: item_name, |
| 118 | + kind: ast::ForeignItemKind::Fn(func), |
| 119 | + tokens: None, |
| 120 | + })]), |
| 121 | + }), |
| 122 | + tokens: None, |
| 123 | + })); |
| 124 | + |
| 125 | + let macro_def = Annotatable::Item(P(ast::Item { |
| 126 | + attrs: ast::AttrVec::from_iter([ |
| 127 | + // #[eii_macro_for(item_name)] |
| 128 | + ast::Attribute { |
| 129 | + kind: ast::AttrKind::Normal(P(ast::NormalAttr { |
| 130 | + item: ast::AttrItem { |
| 131 | + unsafety: ast::Safety::Default, |
| 132 | + path: ast::Path::from_ident(Ident::new(sym::eii_macro_for, span)), |
| 133 | + args: ast::AttrArgs::Delimited(ast::DelimArgs { |
| 134 | + dspan: DelimSpan::from_single(span), |
| 135 | + delim: Delimiter::Parenthesis, |
| 136 | + tokens: TokenStream::new(vec![tokenstream::TokenTree::Token( |
| 137 | + token::Token::from_ast_ident(item_name), |
| 138 | + Spacing::Alone, |
| 139 | + )]), |
| 140 | + }), |
| 141 | + tokens: None, |
| 142 | + }, |
| 143 | + tokens: None, |
| 144 | + })), |
| 145 | + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), |
| 146 | + style: ast::AttrStyle::Outer, |
| 147 | + span, |
| 148 | + }, |
| 149 | + // #[builtin_macro(eii_macro)] |
| 150 | + ast::Attribute { |
| 151 | + kind: ast::AttrKind::Normal(P(ast::NormalAttr { |
| 152 | + item: ast::AttrItem { |
| 153 | + unsafety: ast::Safety::Default, |
| 154 | + path: ast::Path::from_ident(Ident::new(sym::rustc_builtin_macro, span)), |
| 155 | + args: ast::AttrArgs::Delimited(ast::DelimArgs { |
| 156 | + dspan: DelimSpan::from_single(span), |
| 157 | + delim: Delimiter::Parenthesis, |
| 158 | + tokens: TokenStream::new(vec![tokenstream::TokenTree::token_alone( |
| 159 | + token::TokenKind::Ident(sym::eii_macro, token::IdentIsRaw::No), |
| 160 | + span, |
| 161 | + )]), |
| 162 | + }), |
| 163 | + tokens: None, |
| 164 | + }, |
| 165 | + tokens: None, |
| 166 | + })), |
| 167 | + id: ecx.sess.psess.attr_id_generator.mk_attr_id(), |
| 168 | + style: ast::AttrStyle::Outer, |
| 169 | + span, |
| 170 | + }, |
| 171 | + ]), |
| 172 | + id: ast::DUMMY_NODE_ID, |
| 173 | + span, |
| 174 | + // pub |
| 175 | + vis: ast::Visibility { span, kind: ast::VisibilityKind::Public, tokens: None }, |
| 176 | + // macro macro_name |
| 177 | + ident: macro_name, |
| 178 | + kind: ast::ItemKind::MacroDef(ast::MacroDef { |
| 179 | + // { () => {} } |
| 180 | + body: P(ast::DelimArgs { |
| 181 | + dspan: DelimSpan::from_single(span), |
| 182 | + delim: Delimiter::Brace, |
| 183 | + tokens: TokenStream::from_iter([ |
| 184 | + TokenTree::Delimited( |
| 185 | + DelimSpan::from_single(span), |
| 186 | + DelimSpacing::new(Spacing::Alone, Spacing::Alone), |
| 187 | + Delimiter::Parenthesis, |
| 188 | + TokenStream::default(), |
| 189 | + ), |
| 190 | + TokenTree::token_alone(TokenKind::FatArrow, span), |
| 191 | + TokenTree::Delimited( |
| 192 | + DelimSpan::from_single(span), |
| 193 | + DelimSpacing::new(Spacing::Alone, Spacing::Alone), |
| 194 | + Delimiter::Brace, |
| 195 | + TokenStream::default(), |
| 196 | + ), |
| 197 | + ]), |
| 198 | + }), |
| 199 | + macro_rules: false, |
| 200 | + eii_macro_for: None, |
| 201 | + }), |
| 202 | + tokens: None, |
| 203 | + })); |
| 204 | + |
| 205 | + vec![extern_block, macro_def] |
| 206 | +} |
8 | 207 |
|
9 | 208 | use crate::errors::{
|
10 | 209 | EIIMacroExpectedFunction, EIIMacroExpectedMaxOneArgument, EIIMacroForExpectedList,
|
|
0 commit comments