@@ -991,6 +991,7 @@ macro_rules! __pin_data {
991
991
///
992
992
/// This macro has multiple internal call configurations, these are always the very first ident:
993
993
/// - 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.
994
995
/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
995
996
/// - `make_initializer`: recursively create the struct initializer that guarantees that every
996
997
/// field has been initialized exactly once.
@@ -1009,6 +1010,82 @@ macro_rules! __init_internal {
1009
1010
@has_data( $has_data: ident, $get_data: ident) ,
1010
1011
// `pin_init_from_closure` or `init_from_closure`.
1011
1012
@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) ?) ,
1012
1089
) => { {
1013
1090
// We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
1014
1091
// 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 {
1026
1103
{
1027
1104
// Shadow the structure so it cannot be used to return early.
1028
1105
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
+ } ) ?
1029
1117
// Create the `this` so it can be referenced by the user inside of the
1030
1118
// expressions creating the individual fields.
1031
1119
$( let $this = unsafe { :: core:: ptr:: NonNull :: new_unchecked( slot) } ; ) ?
@@ -1062,7 +1150,7 @@ macro_rules! __init_internal {
1062
1150
@data( $data: ident) ,
1063
1151
@slot( $slot: ident) ,
1064
1152
@guards( $( $guards: ident, ) * ) ,
1065
- @munch_fields( $( , ) ?) ,
1153
+ @munch_fields( $( .. Zeroable :: zeroed ( ) ) ? $ ( , ) ?) ,
1066
1154
) => {
1067
1155
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
1068
1156
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -1163,6 +1251,31 @@ macro_rules! __init_internal {
1163
1251
) ;
1164
1252
}
1165
1253
} ;
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
+ } ;
1166
1279
( make_initializer:
1167
1280
@slot( $slot: ident) ,
1168
1281
@type_name( $t: ident) ,
0 commit comments