@@ -991,6 +991,7 @@ macro_rules! __pin_data {
991991///
992992/// This macro has multiple internal call configurations, these are always the very first ident:
993993/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros.
994+ /// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled.
994995/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
995996/// - `make_initializer`: recursively create the struct initializer that guarantees that every
996997/// field has been initialized exactly once.
@@ -1009,6 +1010,82 @@ macro_rules! __init_internal {
10091010 @has_data( $has_data: ident, $get_data: ident) ,
10101011 // `pin_init_from_closure` or `init_from_closure`.
10111012 @construct_closure( $construct_closure: ident) ,
1013+ @munch_fields( ) ,
1014+ ) => {
1015+ $crate:: __init_internal!( with_update_parsed:
1016+ @this( $( $this) ?) ,
1017+ @typ( $t $( :: <$( $generics) ,* >) ? ) ,
1018+ @fields( $( $fields) * ) ,
1019+ @error( $err) ,
1020+ @data( $data, $( $use_data) ?) ,
1021+ @has_data( $has_data, $get_data) ,
1022+ @construct_closure( $construct_closure) ,
1023+ @zeroed( ) , // Nothing means default behavior.
1024+ )
1025+ } ;
1026+ (
1027+ @this( $( $this: ident) ?) ,
1028+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
1029+ @fields( $( $fields: tt) * ) ,
1030+ @error( $err: ty) ,
1031+ // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData`
1032+ // case.
1033+ @data( $data: ident, $( $use_data: ident) ?) ,
1034+ // `HasPinData` or `HasInitData`.
1035+ @has_data( $has_data: ident, $get_data: ident) ,
1036+ // `pin_init_from_closure` or `init_from_closure`.
1037+ @construct_closure( $construct_closure: ident) ,
1038+ @munch_fields( ..Zeroable :: zeroed( ) ) ,
1039+ ) => {
1040+ $crate:: __init_internal!( with_update_parsed:
1041+ @this( $( $this) ?) ,
1042+ @typ( $t $( :: <$( $generics) ,* >) ? ) ,
1043+ @fields( $( $fields) * ) ,
1044+ @error( $err) ,
1045+ @data( $data, $( $use_data) ?) ,
1046+ @has_data( $has_data, $get_data) ,
1047+ @construct_closure( $construct_closure) ,
1048+ @zeroed( ( ) ) , // `()` means zero all fields not mentioned.
1049+ )
1050+ } ;
1051+ (
1052+ @this( $( $this: ident) ?) ,
1053+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
1054+ @fields( $( $fields: tt) * ) ,
1055+ @error( $err: ty) ,
1056+ // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData`
1057+ // case.
1058+ @data( $data: ident, $( $use_data: ident) ?) ,
1059+ // `HasPinData` or `HasInitData`.
1060+ @has_data( $has_data: ident, $get_data: ident) ,
1061+ // `pin_init_from_closure` or `init_from_closure`.
1062+ @construct_closure( $construct_closure: ident) ,
1063+ @munch_fields( $ignore: tt $( $rest: tt) * ) ,
1064+ ) => {
1065+ $crate:: __init_internal!(
1066+ @this( $( $this) ?) ,
1067+ @typ( $t $( :: <$( $generics) ,* >) ? ) ,
1068+ @fields( $( $fields) * ) ,
1069+ @error( $err) ,
1070+ @data( $data, $( $use_data) ?) ,
1071+ @has_data( $has_data, $get_data) ,
1072+ @construct_closure( $construct_closure) ,
1073+ @munch_fields( $( $rest) * ) ,
1074+ )
1075+ } ;
1076+ ( with_update_parsed:
1077+ @this( $( $this: ident) ?) ,
1078+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
1079+ @fields( $( $fields: tt) * ) ,
1080+ @error( $err: ty) ,
1081+ // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData`
1082+ // case.
1083+ @data( $data: ident, $( $use_data: ident) ?) ,
1084+ // `HasPinData` or `HasInitData`.
1085+ @has_data( $has_data: ident, $get_data: ident) ,
1086+ // `pin_init_from_closure` or `init_from_closure`.
1087+ @construct_closure( $construct_closure: ident) ,
1088+ @zeroed( $( $init_zeroed: expr) ?) ,
10121089 ) => { {
10131090 // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
10141091 // type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -1026,6 +1103,17 @@ macro_rules! __init_internal {
10261103 {
10271104 // Shadow the structure so it cannot be used to return early.
10281105 struct __InitOk;
1106+ // If `$init_zeroed` is present we should zero the slot now and not emit an
1107+ // error when fields are missing (since they will be zeroed). We also have to
1108+ // check that the type actually implements `Zeroable`.
1109+ $( {
1110+ fn assert_zeroable<T : $crate:: init:: Zeroable >( _: * mut T ) { }
1111+ // Ensure that the struct is indeed `Zeroable`.
1112+ assert_zeroable( slot) ;
1113+ // SAFETY: The type implements `Zeroable` by the check above.
1114+ unsafe { :: core:: ptr:: write_bytes( slot, 0 , 1 ) } ;
1115+ $init_zeroed // This will be `()` if set.
1116+ } ) ?
10291117 // Create the `this` so it can be referenced by the user inside of the
10301118 // expressions creating the individual fields.
10311119 $( let $this = unsafe { :: core:: ptr:: NonNull :: new_unchecked( slot) } ; ) ?
@@ -1062,7 +1150,7 @@ macro_rules! __init_internal {
10621150 @data( $data: ident) ,
10631151 @slot( $slot: ident) ,
10641152 @guards( $( $guards: ident, ) * ) ,
1065- @munch_fields( $( , ) ?) ,
1153+ @munch_fields( $( .. Zeroable :: zeroed ( ) ) ? $ ( , ) ?) ,
10661154 ) => {
10671155 // Endpoint of munching, no fields are left. If execution reaches this point, all fields
10681156 // have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -1163,6 +1251,31 @@ macro_rules! __init_internal {
11631251 ) ;
11641252 }
11651253 } ;
1254+ ( make_initializer:
1255+ @slot( $slot: ident) ,
1256+ @type_name( $t: ident) ,
1257+ @munch_fields( ..Zeroable :: zeroed( ) $( , ) ?) ,
1258+ @acc( $( $acc: tt) * ) ,
1259+ ) => {
1260+ // Endpoint, nothing more to munch, create the initializer. Since the users specified
1261+ // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have
1262+ // not been overwritten are thus zero and initialized. We still check that all fields are
1263+ // actually accessible by using the struct update syntax ourselves.
1264+ // We are inside of a closure that is never executed and thus we can abuse `slot` to
1265+ // get the correct type inference here:
1266+ #[ allow( unused_assignments) ]
1267+ unsafe {
1268+ let mut zeroed = :: core:: mem:: zeroed( ) ;
1269+ // We have to use type inference here to make zeroed have the correct type. This does
1270+ // not get executed, so it has no effect.
1271+ :: core:: ptr:: write( $slot, zeroed) ;
1272+ zeroed = :: core:: mem:: zeroed( ) ;
1273+ :: core:: ptr:: write( $slot, $t {
1274+ $( $acc) *
1275+ ..zeroed
1276+ } ) ;
1277+ }
1278+ } ;
11661279 ( make_initializer:
11671280 @slot( $slot: ident) ,
11681281 @type_name( $t: ident) ,
0 commit comments