@@ -505,14 +505,18 @@ macro_rules! stack_try_pin_init {
505505/// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
506506/// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
507507/// pointer named `this` inside of the initializer.
508+ /// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the
509+ /// struct, this initializes every field with 0 and then runs all initializers specified in the
510+ /// body. This can only be done if [`Zeroable`] is implemented for the struct.
508511///
509512/// For instance:
510513///
511514/// ```rust
512515/// # use kernel::pin_init;
513- /// # use macros::pin_data;
516+ /// # use macros::{ pin_data, Zeroable} ;
514517/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
515518/// #[pin_data]
519+ /// #[derive(Zeroable)]
516520/// struct Buf {
517521/// // `ptr` points into `buf`.
518522/// ptr: *mut u8,
@@ -525,6 +529,10 @@ macro_rules! stack_try_pin_init {
525529/// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
526530/// pin: PhantomPinned,
527531/// });
532+ /// pin_init!(Buf {
533+ /// buf: [1; 64],
534+ /// ..Zeroable::zeroed(),
535+ /// });
528536/// ```
529537///
530538/// [`try_pin_init!`]: kernel::try_pin_init
@@ -536,11 +544,12 @@ macro_rules! pin_init {
536544 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
537545 $( $fields: tt) *
538546 } ) => {
539- $crate:: try_pin_init!(
547+ $crate:: try_pin_init!( parse_zeroable_end :
540548 @this( $( $this) ?) ,
541549 @typ( $t $( :: <$( $generics) ,* >) ?) ,
542550 @fields( $( $fields) * ) ,
543551 @error( :: core:: convert:: Infallible ) ,
552+ @munch_fields( $( $fields) * ) ,
544553 )
545554 } ;
546555}
@@ -589,28 +598,76 @@ macro_rules! try_pin_init {
589598 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
590599 $( $fields: tt) *
591600 } ) => {
592- $crate:: try_pin_init!(
601+ $crate:: try_pin_init!( parse_zeroable_end :
593602 @this( $( $this) ?) ,
594603 @typ( $t $( :: <$( $generics) ,* >) ? ) ,
595604 @fields( $( $fields) * ) ,
596605 @error( $crate:: error:: Error ) ,
606+ @munch_fields( $( $fields) * ) ,
597607 )
598608 } ;
599609 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
600610 $( $fields: tt) *
601611 } ? $err: ty) => {
602- $crate:: try_pin_init!(
612+ $crate:: try_pin_init!( parse_zeroable_end :
603613 @this( $( $this) ?) ,
604614 @typ( $t $( :: <$( $generics) ,* >) ? ) ,
605615 @fields( $( $fields) * ) ,
606616 @error( $err) ,
617+ @munch_fields( $( $fields) * ) ,
618+ )
619+ } ;
620+ ( parse_zeroable_end:
621+ @this( $( $this: ident) ?) ,
622+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
623+ @fields( $( $fields: tt) * ) ,
624+ @error( $err: ty) ,
625+ @munch_fields( ) ,
626+ ) => {
627+ $crate:: try_pin_init!(
628+ @this( $( $this) ?) ,
629+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
630+ @fields( $( $fields) * ) ,
631+ @error( $err) ,
632+ @zeroed( ) , // nothing means we do not zero unmentioned fields
607633 )
608634 } ;
635+ ( parse_zeroable_end:
636+ @this( $( $this: ident) ?) ,
637+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
638+ @fields( $( $fields: tt) * ) ,
639+ @error( $err: ty) ,
640+ @munch_fields( ..Zeroable :: zeroed( ) ) ,
641+ ) => {
642+ $crate:: try_pin_init!(
643+ @this( $( $this) ?) ,
644+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
645+ @fields( $( $fields) * ) ,
646+ @error( $err) ,
647+ @zeroed( ( ) ) , // () means we zero unmentioned fields
648+ )
649+ } ;
650+ ( parse_zeroable_end:
651+ @this( $( $this: ident) ?) ,
652+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
653+ @fields( $( $fields: tt) * ) ,
654+ @error( $err: ty) ,
655+ @munch_fields( $ignore: tt $( $rest: tt) * ) ,
656+ ) => {
657+ $crate:: try_pin_init!( parse_zeroable_end:
658+ @this( $( $this) ?) ,
659+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
660+ @fields( $( $fields) * ) ,
661+ @error( $err) ,
662+ @munch_fields( $( $rest) * ) ,
663+ )
664+ } ;
609665 (
610666 @this( $( $this: ident) ?) ,
611667 @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
612668 @fields( $( $fields: tt) * ) ,
613669 @error( $err: ty) ,
670+ @zeroed( $( $init_zeroed: expr) ?) ,
614671 ) => { {
615672 // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
616673 // type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -628,6 +685,19 @@ macro_rules! try_pin_init {
628685 {
629686 // Shadow the structure so it cannot be used to return early.
630687 struct __InitOk;
688+ // If `$init_zeroed` is present, we should not error on unmentioned fields and
689+ // set the whole struct to zero first.
690+ //
691+ // For type inference reasons we do not use `init::zeroed`, but instead
692+ // write_bytes.
693+ $( {
694+ // We need to ensure the type actually implements `Zeroable`.
695+ fn is_zeroable<T : Zeroable >( ptr: * mut T ) { }
696+ is_zeroable( slot) ;
697+ // SAFETY: the type implements `Zeroable`.
698+ unsafe { :: core:: ptr:: write_bytes( slot, 0 , 1 ) } ;
699+ $init_zeroed
700+ } ) ?
631701 // Create the `this` so it can be referenced by the user inside of the
632702 // expressions creating the individual fields.
633703 $( let $this = unsafe { :: core:: ptr:: NonNull :: new_unchecked( slot) } ; ) ?
@@ -666,7 +736,7 @@ macro_rules! try_pin_init {
666736 @data( $data: ident) ,
667737 @slot( $slot: ident) ,
668738 @guards( $( $guards: ident, ) * ) ,
669- @munch_fields( $( , ) ?) ,
739+ @munch_fields( $( .. Zeroable :: zeroed ( ) ) ? $ ( , ) ?) ,
670740 ) => {
671741 // Endpoint of munching, no fields are left. If execution reaches this point, all fields
672742 // have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -730,6 +800,28 @@ macro_rules! try_pin_init {
730800 @munch_fields( $( $rest) * ) ,
731801 ) ;
732802 } ;
803+ ( make_initializer:
804+ @slot( $slot: ident) ,
805+ @type_name( $t: ident) ,
806+ @munch_fields( ..Zeroable :: zeroed( ) $( , ) ?) ,
807+ @acc( $( $acc: tt) * ) ,
808+ ) => {
809+ // Endpoint, nothing more to munch, create the initializer. Without erroring on extra
810+ // fields. We want to have the same semantics as a struct initializer with struct update
811+ // syntax, so we create one first.
812+ // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to
813+ // get the correct type inference here:
814+ unsafe {
815+ // We have to force zeroed to have the correct type.
816+ let mut zeroed = :: core:: mem:: zeroed( ) ;
817+ :: core:: ptr:: write( $slot, zeroed) ;
818+ zeroed = :: core:: mem:: zeroed( ) ;
819+ :: core:: ptr:: write( $slot, $t {
820+ $( $acc) *
821+ ..zeroed
822+ } ) ;
823+ }
824+ } ;
733825 ( make_initializer:
734826 @slot( $slot: ident) ,
735827 @type_name( $t: ident) ,
@@ -793,11 +885,12 @@ macro_rules! init {
793885 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
794886 $( $fields: tt) *
795887 } ) => {
796- $crate:: try_init!(
888+ $crate:: try_init!( parse_zeroable_end :
797889 @this( $( $this) ?) ,
798890 @typ( $t $( :: <$( $generics) ,* >) ?) ,
799891 @fields( $( $fields) * ) ,
800892 @error( :: core:: convert:: Infallible ) ,
893+ @munch_fields( $( $fields) * ) ,
801894 )
802895 }
803896}
@@ -840,28 +933,76 @@ macro_rules! try_init {
840933 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
841934 $( $fields: tt) *
842935 } ) => {
843- $crate:: try_init!(
936+ $crate:: try_init!( parse_zeroable_end :
844937 @this( $( $this) ?) ,
845938 @typ( $t $( :: <$( $generics) ,* >) ?) ,
846939 @fields( $( $fields) * ) ,
847940 @error( $crate:: error:: Error ) ,
941+ @munch_fields( $( $fields) * ) ,
848942 )
849943 } ;
850944 ( $( & $this: ident in) ? $t: ident $( :: <$( $generics: ty) ,* $( , ) ?>) ? {
851945 $( $fields: tt) *
852946 } ? $err: ty) => {
947+ $crate:: try_init!( parse_zeroable_end:
948+ @this( $( $this) ?) ,
949+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
950+ @fields( $( $fields) * ) ,
951+ @error( $err) ,
952+ @munch_fields( $( $fields) * ) ,
953+ )
954+ } ;
955+ ( parse_zeroable_end:
956+ @this( $( $this: ident) ?) ,
957+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
958+ @fields( $( $fields: tt) * ) ,
959+ @error( $err: ty) ,
960+ @munch_fields( ) ,
961+ ) => {
853962 $crate:: try_init!(
854963 @this( $( $this) ?) ,
855964 @typ( $t $( :: <$( $generics) ,* >) ?) ,
856965 @fields( $( $fields) * ) ,
857966 @error( $err) ,
967+ @zeroed( ) , // Nothing means we do not zero unmentioned fields.
858968 )
859969 } ;
970+ ( parse_zeroable_end:
971+ @this( $( $this: ident) ?) ,
972+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
973+ @fields( $( $fields: tt) * ) ,
974+ @error( $err: ty) ,
975+ @munch_fields( ..Zeroable :: zeroed( ) ) ,
976+ ) => {
977+ $crate:: try_init!(
978+ @this( $( $this) ?) ,
979+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
980+ @fields( $( $fields) * ) ,
981+ @error( $err) ,
982+ @zeroed( ( ) ) , // () means we zero unmentioned fields.
983+ )
984+ } ;
985+ ( parse_zeroable_end:
986+ @this( $( $this: ident) ?) ,
987+ @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
988+ @fields( $( $fields: tt) * ) ,
989+ @error( $err: ty) ,
990+ @munch_fields( $ignore: tt $( $rest: tt) * ) ,
991+ ) => {
992+ $crate:: try_init!( parse_zeroable_end:
993+ @this( $( $this) ?) ,
994+ @typ( $t $( :: <$( $generics) ,* >) ?) ,
995+ @fields( $( $fields) * ) ,
996+ @error( $err) ,
997+ @munch_fields( $( $rest) * ) ,
998+ )
999+ } ;
8601000 (
8611001 @this( $( $this: ident) ?) ,
8621002 @typ( $t: ident $( :: <$( $generics: ty) ,* >) ?) ,
8631003 @fields( $( $fields: tt) * ) ,
8641004 @error( $err: ty) ,
1005+ @zeroed( $( $init_zeroed: expr) ?) ,
8651006 ) => { {
8661007 // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
8671008 // type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -879,6 +1020,19 @@ macro_rules! try_init {
8791020 {
8801021 // Shadow the structure so it cannot be used to return early.
8811022 struct __InitOk;
1023+ // If `$init_zeroed` is present, we should not error on unmentioned fields and
1024+ // set the whole struct to zero first.
1025+ //
1026+ // For type inference reasons we do not use `init::zeroed`, but instead
1027+ // write_bytes.
1028+ $( {
1029+ // We need to ensure the type actually implements `Zeroable`.
1030+ fn is_zeroable<T : Zeroable >( ptr: * mut T ) { }
1031+ is_zeroable( slot) ;
1032+ // SAFETY: the type implements `Zeroable`.
1033+ unsafe { :: core:: ptr:: write_bytes( slot, 0 , 1 ) } ;
1034+ $init_zeroed
1035+ } ) ?
8821036 // Create the `this` so it can be referenced by the user inside of the
8831037 // expressions creating the individual fields.
8841038 $( let $this = unsafe { :: core:: ptr:: NonNull :: new_unchecked( slot) } ; ) ?
@@ -915,7 +1069,7 @@ macro_rules! try_init {
9151069 ( init_slot:
9161070 @slot( $slot: ident) ,
9171071 @guards( $( $guards: ident, ) * ) ,
918- @munch_fields( $( , ) ?) ,
1072+ @munch_fields( $ ( .. Zeroable :: zeroed ( ) ) ? $( , ) ?) ,
9191073 ) => {
9201074 // Endpoint of munching, no fields are left. If execution reaches this point, all fields
9211075 // have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -982,7 +1136,29 @@ macro_rules! try_init {
9821136 ( make_initializer:
9831137 @slot( $slot: ident) ,
9841138 @type_name( $t: ident) ,
985- @munch_fields( $( , ) ?) ,
1139+ @munch_fields( ..Zeroable :: zeroed( ) $( , ) ?) ,
1140+ @acc( $( $acc: tt) * ) ,
1141+ ) => {
1142+ // Endpoint, nothing more to munch, create the initializer. Without erroring on extra
1143+ // fields. We want to have the same semantics as a struct initializer with struct update
1144+ // syntax, so we create one first.
1145+ // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to
1146+ // get the correct type inference here:
1147+ unsafe {
1148+ // We have to force zeroed to have the correct type.
1149+ let mut zeroed = :: core:: mem:: zeroed( ) ;
1150+ :: core:: ptr:: write( $slot, zeroed) ;
1151+ zeroed = :: core:: mem:: zeroed( ) ;
1152+ :: core:: ptr:: write( $slot, $t {
1153+ $( $acc) *
1154+ ..zeroed
1155+ } ) ;
1156+ }
1157+ } ;
1158+ ( make_initializer:
1159+ @slot( $slot: ident) ,
1160+ @type_name( $t: ident) ,
1161+ @munch_fields( $( , ) ?) ,
9861162 @acc( $( $acc: tt) * ) ,
9871163 ) => {
9881164 // Endpoint, nothing more to munch, create the initializer.
0 commit comments