@@ -525,7 +525,7 @@ Our proposed syntax looks closer to structured comments:
525525
526526``` rust
527527#[safety:: checked(
528- valid_ptr, align , initialized = " `self.head_tail()` returns two slices to live elements." ,
528+ valid_ptr, aligned , initialized = " `self.head_tail()` returns two slices to live elements." ,
529529 not_owned = " because we incremented..." ,
530530)]
531531unsafe { ptr :: read (elem ) }
@@ -610,6 +610,71 @@ following cases:
610610But we believe safety requirements are almost mostly imposed by unsafe functions, so tagging a
611611struct, enum, or union is neither needed nor permitted.
612612
613+ ## ` #[safety::batch_checked] ` Shares Tag Discharging
614+
615+ Discharging the same tags simultaneously can be convenient. However, supporting this means that tags
616+ in ` checked ` are applied to multiple unsafe operations. As a result, obligations are discharged
617+ extensively across various contexts, including nested and chained calls, different calls, as well as
618+ repeated calls with different values. This could lead to confusion and potential misuse, making it
619+ unclear what has been checked in shared mode or single mode. Partial discharging can be dangerous.
620+
621+ I believe it is less error-prone to let ` safety::checked ` handle atomic discharging. Therefore, we
622+ should introduce a new attribute named ` safety::batch_checked ` to support the discharging of shared
623+ tags. This approach allows us to distinguish between different discharging semantics through
624+ different syntaxes.
625+
626+ ``` rust
627+ #[safety:: batch_checked( // automatically merged this tag into `checked` if it's required
628+ aligned = " the place is aligned correctly for i32 by providing correct layout above"
629+ )]
630+ unsafe {
631+ #[safety:: checked(
632+ valid_for_reads = " the place is newly allocated, so we have exclusive ownership of it"
633+ )]
634+ ptr . write (42 );
635+
636+ #[safety:: checked(
637+ valid_for_reads = " we have exclusive ownership" ,
638+ initialized = " just initialized above"
639+ )]
640+ assert_eq! (ptr . read (), 42 );
641+ }
642+
643+ #[safety:: batch_checked(
644+ aligned = " arrays are properly aligned" ,
645+ valid_for_reads = " the arrays are owned by this function, and contain the copy type f32" ,
646+ )]
647+ unsafe {
648+ float32x4x4_t (
649+ vld1q_f32 (a . as_ptr ()),
650+ vld1q_f32 (b . as_ptr ()),
651+ vld1q_f32 (c . as_ptr ()),
652+ vld1q_f32 (d . as_ptr ()),
653+ )
654+ }
655+ ```
656+
657+ Atomic discharging saves us from visual unsafe granularity, and focus on semantic unsafe
658+ granularity, because any use of ` checked ` is only valid for single unsafe operation.
659+
660+ ``` rust
661+ #[safety:: checked(... )] // ❌ hard error
662+ unsafe { char :: from_u32_unchecked (* ptr . cast :: <u32 >()) }
663+
664+ #[safety:: batch_checked(... )] // ✅
665+ unsafe { char :: from_u32_unchecked (* ptr . cast :: <u32 >()) }
666+
667+ unsafe {
668+ #[safety:: checked(... )] // ✅ dereferencing raw pointer is an unsafe operation in future possibilities
669+ let int_value = * ptr . cast :: <u32 >();
670+ #[safety:: checked(... )] // ✅
671+ char :: from_u32_unchecked (int_value )
672+ }
673+ ```
674+
675+ we could have ` #[deny(clippy::batch_checked)] ` to prohibit any use of ` #[safety::batch_checked] ` in
676+ crates if rigid atomic discharging is required.
677+
613678# Future possibilities
614679[ future-possibilities ] : #future-possibilities
615680
0 commit comments