@@ -14,6 +14,7 @@ use crate::config::{ClassData, MethodData};
1414use crate :: context:: Context ;
1515use crate :: display_helper:: FormatterFn ;
1616use crate :: expr:: Expr ;
17+ use crate :: fn_utils:: follows_create_rule;
1718use crate :: id:: cfg_gate_ln;
1819use crate :: id:: ItemIdentifier ;
1920use crate :: id:: Location ;
@@ -531,6 +532,7 @@ pub enum Stmt {
531532 must_use : bool ,
532533 can_unwind : bool ,
533534 link_name : Option < String > ,
535+ returns_retained : bool ,
534536 } ,
535537 /// typedef Type TypedefName;
536538 AliasDecl {
@@ -1395,6 +1397,8 @@ impl Stmt {
13951397 warn ! ( "unexpected static method" ) ;
13961398 }
13971399
1400+ let mut returns_retained = follows_create_rule ( & id. name ) ;
1401+
13981402 immediate_children ( entity, |entity, _span| match entity. get_kind ( ) {
13991403 EntityKind :: UnexposedAttr => {
14001404 if let Some ( attr) = UnexposedAttr :: parse ( & entity, context) {
@@ -1403,9 +1407,13 @@ impl Stmt {
14031407 UnexposedAttr :: UIActor => {
14041408 warn ! ( "unhandled UIActor on function declaration" )
14051409 }
1406- UnexposedAttr :: ReturnsRetained
1407- | UnexposedAttr :: ReturnsNotRetained => {
1408- // TODO: Ignore for now, but at some point handle in a similar way to in methods
1410+ UnexposedAttr :: ReturnsRetained => {
1411+ // Override the inferred value.
1412+ returns_retained = true ;
1413+ }
1414+ UnexposedAttr :: ReturnsNotRetained => {
1415+ // Override the inferred value.
1416+ returns_retained = false ;
14091417 }
14101418 UnexposedAttr :: NoThrow => {
14111419 can_unwind = false ;
@@ -1464,6 +1472,7 @@ impl Stmt {
14641472 must_use,
14651473 can_unwind,
14661474 link_name,
1475+ returns_retained,
14671476 } ]
14681477 }
14691478 EntityKind :: UnionDecl => {
@@ -2421,14 +2430,10 @@ impl Stmt {
24212430 }
24222431 Self :: FnDecl {
24232432 id,
2424- availability : _,
24252433 arguments,
24262434 result_type,
24272435 body : Some ( _) ,
2428- safe : _,
2429- must_use : _,
2430- can_unwind : _,
2431- link_name : _,
2436+ ..
24322437 } => {
24332438 write ! ( f, "// TODO: " ) ?;
24342439 write ! ( f, "pub fn {}(" , id. name) ?;
@@ -2444,83 +2449,107 @@ impl Stmt {
24442449 arguments,
24452450 result_type,
24462451 body : None ,
2447- safe : false ,
2452+ safe,
24482453 must_use,
24492454 can_unwind,
24502455 link_name,
2456+ returns_retained,
24512457 } => {
24522458 let abi = if * can_unwind { "C-unwind" } else { "C" } ;
2453- writeln ! ( f, "extern {abi:?} {{" ) ?;
24542459
2455- write ! ( f, " {}" , self . cfg_gate_ln( config) ) ?;
2456- write ! ( f, " {availability}" ) ?;
2457- if * must_use {
2458- writeln ! ( f, " #[must_use]" ) ?;
2459- }
2460- if let Some ( link_name) = link_name {
2461- // NOTE: Currently only used on Apple targets.
2462- writeln ! (
2463- f,
2464- " #[cfg_attr(target_vendor = \" apple\" , link_name = {link_name:?})]"
2465- ) ?;
2466- }
2467- write ! ( f, " pub fn {}(" , id. name) ?;
2468- for ( param, arg_ty) in arguments {
2469- let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2470- write ! ( f, "{param}: {}," , arg_ty. fn_argument( ) ) ?;
2471- }
2472- write ! ( f, "){}" , result_type. fn_return( ) ) ?;
2473- writeln ! ( f, ";" ) ?;
2460+ let return_converter = result_type. fn_return_converter ( * returns_retained) ;
24742461
2475- writeln ! ( f, "}}" ) ?;
2476- }
2477- Self :: FnDecl {
2478- id,
2479- availability,
2480- arguments,
2481- result_type,
2482- body : None ,
2483- safe : true ,
2484- must_use,
2485- can_unwind,
2486- link_name,
2487- } => {
2488- let abi = if * can_unwind { "C-unwind" } else { "C" } ;
2489- write ! ( f, "{}" , self . cfg_gate_ln( config) ) ?;
2490- write ! ( f, "{availability}" ) ?;
2491- if * must_use {
2492- writeln ! ( f, "#[must_use]" ) ?;
2493- }
2494- writeln ! ( f, "#[inline]" ) ?;
2495- write ! ( f, "pub extern {abi:?} fn {}(" , id. name) ?;
2496- for ( param, arg_ty) in arguments {
2497- let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2498- write ! ( f, "{param}: {}," , arg_ty. fn_argument( ) ) ?;
2499- }
2500- writeln ! ( f, "){} {{" , result_type. fn_return( ) ) ?;
2462+ let needs_wrapper = * safe
2463+ || return_converter. is_some ( )
2464+ || arguments
2465+ . iter ( )
2466+ . any ( |( _, arg) | arg. fn_argument_converter ( ) . is_some ( ) ) ;
2467+
2468+ let raw_fn_decl = |f : & mut fmt:: Formatter < ' _ > , vis| {
2469+ if let Some ( link_name) = link_name {
2470+ // NOTE: Currently only used on Apple targets.
2471+ writeln ! (
2472+ f,
2473+ "#[cfg_attr(target_vendor = \" apple\" , link_name = {link_name:?})]"
2474+ ) ?;
2475+ }
2476+ write ! ( f, "{vis}fn {}(" , id. name) ?;
2477+ for ( param, arg_ty) in arguments {
2478+ let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2479+ write ! ( f, "{param}: {}," , arg_ty. fn_argument( ) ) ?;
2480+ }
2481+ writeln ! ( f, "){};" , result_type. fn_return( ) ) ?;
25012482
2502- writeln ! ( f, " extern {abi:?} {{" ) ?;
2483+ Ok ( ( ) )
2484+ } ;
25032485
2504- if let Some ( link_name) = link_name {
2505- writeln ! ( f, " #[link_name = {link_name:?}]" ) ?;
2506- }
2507- write ! ( f, " fn {}(" , id. name) ?;
2508- for ( param, arg_ty) in arguments {
2509- let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2510- write ! ( f, "{param}: {}," , arg_ty. fn_argument( ) ) ?;
2511- }
2512- writeln ! ( f, "){};" , result_type. fn_return( ) ) ?;
2486+ if needs_wrapper {
2487+ write ! ( f, "{}" , self . cfg_gate_ln( config) ) ?;
2488+ write ! ( f, "{availability}" ) ?;
2489+ if * must_use {
2490+ writeln ! ( f, "#[must_use]" ) ?;
2491+ }
2492+ writeln ! ( f, "#[inline]" ) ?;
2493+ let unsafe_ = if * safe { "" } else { "unsafe " } ;
2494+ write ! ( f, "pub {unsafe_}extern {abi:?} fn {}(" , id. name) ?;
2495+ for ( param, arg_ty) in arguments {
2496+ let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2497+ write ! ( f, "{param}: " ) ?;
2498+ if let Some ( ( converted_ty, _) ) = arg_ty. fn_argument_converter ( ) {
2499+ write ! ( f, "{converted_ty}" ) ?;
2500+ } else {
2501+ write ! ( f, "{}" , arg_ty. fn_argument( ) ) ?;
2502+ }
2503+ write ! ( f, "," ) ?;
2504+ }
2505+ write ! ( f, ")" ) ?;
2506+ if let Some ( ( ty, _, _) ) = & return_converter {
2507+ write ! ( f, "{ty}" ) ?;
2508+ } else {
2509+ write ! ( f, "{}" , result_type. fn_return( ) ) ?;
2510+ }
2511+ writeln ! ( f, " {{" ) ?;
25132512
2514- writeln ! ( f, " }}" ) ?;
2513+ // Emit raw
2514+ writeln ! ( f, " extern {abi:?} {{" ) ?;
2515+ raw_fn_decl ( f, "" ) ?;
2516+ writeln ! ( f, " }}" ) ?;
25152517
2516- write ! ( f, " unsafe {{ {}(" , id. name) ?;
2517- for ( param, _) in arguments {
2518- let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2519- write ! ( f, "{param}," ) ?;
2520- }
2521- writeln ! ( f, ") }}" ) ?;
2518+ // Call raw
2519+ write ! ( f, " " ) ?;
2520+ if let Some ( ( _, converter_start, _) ) = & return_converter {
2521+ write ! ( f, "{converter_start}" ) ?;
2522+ }
2523+ write ! ( f, "unsafe {{ {}(" , id. name) ?;
2524+ for ( param, ty) in arguments {
2525+ let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
2526+ if let Some ( ( _, converter) ) = ty. fn_argument_converter ( ) {
2527+ write ! ( f, "{converter}({param})" ) ?;
2528+ } else {
2529+ write ! ( f, "{param}" ) ?;
2530+ }
2531+ write ! ( f, "," ) ?;
2532+ }
2533+ write ! ( f, ") }}" ) ?;
2534+ if let Some ( ( _, _, converter_end) ) = & return_converter {
2535+ write ! ( f, "{converter_end}" ) ?;
2536+ }
2537+ writeln ! ( f) ?;
25222538
2523- writeln ! ( f, "}}" ) ?;
2539+ writeln ! ( f, "}}" ) ?;
2540+ } else {
2541+ writeln ! ( f, "extern {abi:?} {{" ) ?;
2542+
2543+ write ! ( f, " {}" , self . cfg_gate_ln( config) ) ?;
2544+ write ! ( f, " {availability}" ) ?;
2545+ if * must_use {
2546+ writeln ! ( f, " #[must_use]" ) ?;
2547+ }
2548+
2549+ raw_fn_decl ( f, "pub " ) ?;
2550+
2551+ writeln ! ( f, "}}" ) ?;
2552+ }
25242553 }
25252554 Self :: AliasDecl {
25262555 id,
0 commit comments