@@ -10,8 +10,8 @@ use thin_vec::{ThinVec, thin_vec};
1010
1111use crate :: errors:: {
1212 EiiExternTargetExpectedList , EiiExternTargetExpectedMacro , EiiExternTargetExpectedUnsafe ,
13- EiiMacroExpectedMaxOneArgument , EiiOnlyOnce , EiiSharedMacroExpectedFunction ,
14- EiiSharedMacroInStatementPosition ,
13+ EiiMacroExpectedMaxOneArgument , EiiOnlyOnce , EiiSharedMacroInStatementPosition ,
14+ EiiSharedMacroTarget , EiiStaticArgumentRequired , EiiStaticDefault ,
1515} ;
1616
1717/// ```rust
@@ -73,44 +73,63 @@ fn eii_(
7373 } ) ;
7474 return vec ! [ orig_item] ;
7575 } else {
76- ecx. dcx ( ) . emit_err ( EiiSharedMacroExpectedFunction {
76+ ecx. dcx ( ) . emit_err ( EiiSharedMacroTarget {
7777 span : eii_attr_span,
7878 name : path_to_string ( & meta_item. path ) ,
7979 } ) ;
8080 return vec ! [ orig_item] ;
8181 } ;
8282
83- let ast:: Item { attrs, id : _, span : _, vis, kind : ItemKind :: Fn ( func) , tokens : _ } =
84- item. as_ref ( )
85- else {
86- ecx. dcx ( ) . emit_err ( EiiSharedMacroExpectedFunction {
87- span : eii_attr_span,
88- name : path_to_string ( & meta_item. path ) ,
89- } ) ;
90- return vec ! [ Annotatable :: Item ( item) ] ;
83+ let ast:: Item { attrs, id : _, span : _, vis, kind, tokens : _ } = item. as_ref ( ) ;
84+ let ( item_span, foreign_item_name) = match kind {
85+ ItemKind :: Fn ( func) => ( func. sig . span , func. ident ) ,
86+ ItemKind :: Static ( stat) => {
87+ // Statics with a default are not supported yet
88+ if let Some ( stat_body) = & stat. expr {
89+ ecx. dcx ( ) . emit_err ( EiiStaticDefault {
90+ span : stat_body. span ,
91+ name : path_to_string ( & meta_item. path ) ,
92+ } ) ;
93+ return vec ! [ ] ;
94+ }
95+ // Statics must have an explicit name for the eii
96+ if meta_item. is_word ( ) {
97+ ecx. dcx ( ) . emit_err ( EiiStaticArgumentRequired {
98+ span : eii_attr_span,
99+ name : path_to_string ( & meta_item. path ) ,
100+ } ) ;
101+ return vec ! [ ] ;
102+ }
103+ ( item. span , stat. ident )
104+ }
105+ _ => {
106+ ecx. dcx ( ) . emit_err ( EiiSharedMacroTarget {
107+ span : eii_attr_span,
108+ name : path_to_string ( & meta_item. path ) ,
109+ } ) ;
110+ return vec ! [ Annotatable :: Item ( item) ] ;
111+ }
91112 } ;
113+
92114 // only clone what we need
93115 let attrs = attrs. clone ( ) ;
94- let func = ( * * func) . clone ( ) ;
95116 let vis = vis. clone ( ) ;
96117
97118 let attrs_from_decl =
98119 filter_attrs_for_multiple_eii_attr ( ecx, attrs, eii_attr_span, & meta_item. path ) ;
99120
100- let Ok ( macro_name) = name_for_impl_macro ( ecx, & func , & meta_item) else {
121+ let Ok ( macro_name) = name_for_impl_macro ( ecx, foreign_item_name , & meta_item) else {
101122 // we don't need to wrap in Annotatable::Stmt conditionally since
102123 // EII can't be used on items in statement position
103124 return vec ! [ Annotatable :: Item ( item) ] ;
104125 } ;
105126
106- // span of the declaring item without attributes
107- let item_span = func. sig . span ;
108- let foreign_item_name = func. ident ;
109-
110127 let mut module_items = Vec :: new ( ) ;
111128
112- if func. body . is_some ( ) {
113- module_items. push ( generate_default_impl (
129+ if let ItemKind :: Fn ( func) = kind
130+ && func. body . is_some ( )
131+ {
132+ module_items. push ( generate_default_func_impl (
114133 ecx,
115134 & func,
116135 impl_unsafe,
@@ -125,7 +144,7 @@ fn eii_(
125144 ecx,
126145 eii_attr_span,
127146 item_span,
128- func ,
147+ kind ,
129148 vis,
130149 & attrs_from_decl,
131150 ) ) ;
@@ -148,11 +167,11 @@ fn eii_(
148167/// declaration of the EII.
149168fn name_for_impl_macro (
150169 ecx : & mut ExtCtxt < ' _ > ,
151- func : & ast :: Fn ,
170+ item_ident : Ident ,
152171 meta_item : & MetaItem ,
153172) -> Result < Ident , ErrorGuaranteed > {
154173 if meta_item. is_word ( ) {
155- Ok ( func . ident )
174+ Ok ( item_ident )
156175 } else if let Some ( [ first] ) = meta_item. meta_item_list ( )
157176 && let Some ( m) = first. meta_item ( )
158177 && m. path . segments . len ( ) == 1
@@ -190,7 +209,7 @@ fn filter_attrs_for_multiple_eii_attr(
190209 . collect ( )
191210}
192211
193- fn generate_default_impl (
212+ fn generate_default_func_impl (
194213 ecx : & mut ExtCtxt < ' _ > ,
195214 func : & ast:: Fn ,
196215 impl_unsafe : bool ,
@@ -257,7 +276,7 @@ fn generate_foreign_item(
257276 ecx : & mut ExtCtxt < ' _ > ,
258277 eii_attr_span : Span ,
259278 item_span : Span ,
260- mut func : ast :: Fn ,
279+ item_kind : & ItemKind ,
261280 vis : Visibility ,
262281 attrs_from_decl : & [ Attribute ] ,
263282) -> Box < ast:: Item > {
@@ -268,30 +287,21 @@ fn generate_foreign_item(
268287 // This attribute makes sure that we later know that this foreign item's symbol should not be.
269288 foreign_item_attrs. push ( ecx. attr_word ( sym:: rustc_eii_foreign_item, eii_attr_span) ) ;
270289
271- let abi = match func . sig . header . ext {
272- // extern "X" fn => extern "X" {}
273- ast:: Extern :: Explicit ( lit , _ ) => Some ( lit ) ,
274- // extern fn => extern {}
275- ast :: Extern :: Implicit ( _ ) => None ,
276- // fn => extern " Rust" {}
277- ast :: Extern :: None => Some ( ast:: StrLit {
278- symbol : sym :: Rust ,
279- suffix : None ,
280- symbol_unescaped : sym :: Rust ,
281- style : ast :: StrStyle :: Cooked ,
282- span : eii_attr_span ,
283- } ) ,
290+ // We set the abi to the default "rust" abi, which can be overridden by `generate_foreign_func`,
291+ // if a specific abi was specified on the EII function
292+ let mut abi = Some ( ast:: StrLit {
293+ symbol : sym :: Rust ,
294+ suffix : None ,
295+ symbol_unescaped : sym :: Rust ,
296+ style : ast:: StrStyle :: Cooked ,
297+ span : eii_attr_span ,
298+ } ) ;
299+ let foreign_kind = match item_kind {
300+ ItemKind :: Fn ( func ) => generate_foreign_func ( func . clone ( ) , & mut abi ) ,
301+ ItemKind :: Static ( stat ) => generate_foreign_static ( stat . clone ( ) ) ,
302+ _ => unreachable ! ( "Target was checked earlier" ) ,
284303 } ;
285304
286- // ABI has been moved to the extern {} block, so we remove it from the fn item.
287- func. sig . header . ext = ast:: Extern :: None ;
288- func. body = None ;
289-
290- // And mark safe functions explicitly as `safe fn`.
291- if func. sig . header . safety == ast:: Safety :: Default {
292- func. sig . header . safety = ast:: Safety :: Safe ( func. sig . span ) ;
293- }
294-
295305 ecx. item (
296306 eii_attr_span,
297307 ThinVec :: new ( ) ,
@@ -304,13 +314,46 @@ fn generate_foreign_item(
304314 id : ast:: DUMMY_NODE_ID ,
305315 span : item_span,
306316 vis,
307- kind : ast :: ForeignItemKind :: Fn ( Box :: new ( func . clone ( ) ) ) ,
317+ kind : foreign_kind ,
308318 tokens : None ,
309319 } ) ] ) ,
310320 } ) ,
311321 )
312322}
313323
324+ fn generate_foreign_func (
325+ mut func : Box < ast:: Fn > ,
326+ abi : & mut Option < ast:: StrLit > ,
327+ ) -> ast:: ForeignItemKind {
328+ match func. sig . header . ext {
329+ // extern "X" fn => extern "X" {}
330+ ast:: Extern :: Explicit ( lit, _) => * abi = Some ( lit) ,
331+ // extern fn => extern {}
332+ ast:: Extern :: Implicit ( _) => * abi = None ,
333+ // no abi was specified, so we keep the default
334+ ast:: Extern :: None => { }
335+ } ;
336+
337+ // ABI has been moved to the extern {} block, so we remove it from the fn item.
338+ func. sig . header . ext = ast:: Extern :: None ;
339+ func. body = None ;
340+
341+ // And mark safe functions explicitly as `safe fn`.
342+ if func. sig . header . safety == ast:: Safety :: Default {
343+ func. sig . header . safety = ast:: Safety :: Safe ( func. sig . span ) ;
344+ }
345+
346+ ast:: ForeignItemKind :: Fn ( func)
347+ }
348+
349+ fn generate_foreign_static ( mut stat : Box < ast:: StaticItem > ) -> ast:: ForeignItemKind {
350+ if stat. safety == ast:: Safety :: Default {
351+ stat. safety = ast:: Safety :: Safe ( stat. ident . span ) ;
352+ }
353+
354+ ast:: ForeignItemKind :: Static ( stat)
355+ }
356+
314357/// Generate a stub macro (a bit like in core) that will roughly look like:
315358///
316359/// ```rust, ignore, example
@@ -453,19 +496,18 @@ pub(crate) fn eii_shared_macro(
453496 {
454497 item
455498 } else {
456- ecx. dcx ( ) . emit_err ( EiiSharedMacroExpectedFunction {
457- span,
458- name : path_to_string ( & meta_item. path ) ,
459- } ) ;
499+ ecx. dcx ( ) . emit_err ( EiiSharedMacroTarget { span, name : path_to_string ( & meta_item. path ) } ) ;
460500 return vec ! [ item] ;
461501 } ;
462502
463- let ItemKind :: Fn ( f) = & mut i. kind else {
464- ecx. dcx ( ) . emit_err ( EiiSharedMacroExpectedFunction {
465- span,
466- name : path_to_string ( & meta_item. path ) ,
467- } ) ;
468- return vec ! [ item] ;
503+ let eii_impls = match & mut i. kind {
504+ ItemKind :: Fn ( func) => & mut func. eii_impls ,
505+ ItemKind :: Static ( stat) => & mut stat. eii_impls ,
506+ _ => {
507+ ecx. dcx ( )
508+ . emit_err ( EiiSharedMacroTarget { span, name : path_to_string ( & meta_item. path ) } ) ;
509+ return vec ! [ item] ;
510+ }
469511 } ;
470512
471513 let is_default = if meta_item. is_word ( ) {
@@ -483,7 +525,7 @@ pub(crate) fn eii_shared_macro(
483525 return vec ! [ item] ;
484526 } ;
485527
486- f . eii_impls . push ( EiiImpl {
528+ eii_impls. push ( EiiImpl {
487529 node_id : DUMMY_NODE_ID ,
488530 inner_span : meta_item. path . span ,
489531 eii_macro_path : meta_item. path . clone ( ) ,
0 commit comments