@@ -15,19 +15,19 @@ requirement into a single, check-off reminder.
1515The following snippet [ compiles] today if we enable enough nightly features, but we expect Clippy
1616and Rust-Analyzer to enforce tag checks and provide first-class IDE support.
1717
18- [ compiles ] : https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=34c1b3d4c13685bae6da6eb299fded95
18+ [ compiles ] : https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=6b7b341b8879bfdecb80ae72a8011a6d
1919
2020``` rust
2121#[safety:: requires( // 💡 define safety tags on an unsafe function
22- ValidPtr = " src must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads" ,
23- Aligned = " src must be properly aligned, even if T has size 0" ,
24- Initialized = " src must point to a properly initialized value of type T"
22+ valid_ptr = " src must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads" ,
23+ aligned = " src must be properly aligned, even if T has size 0" ,
24+ initialized = " src must point to a properly initialized value of type T"
2525)]
2626pub unsafe fn read <T >(ptr : * const T ) { }
2727
2828fn main () {
2929 #[safety:: checked( // 💡 discharge safety tags on an unsafe call
30- ValidPtr , Aligned , Initialized = " optional reason"
30+ valid_ptr, aligned, initialized = " optional reason"
3131 )]
3232 unsafe { read (& ()) };
3333}
@@ -152,11 +152,11 @@ understand them and Clippy to emit good diagnostic messages.
152152
153153``` rust
154154#[safety:: requires( // defsite or definition
155- ValidPtr = " definition1" , Aligned = " definition2" , Initialized = " definition3"
156- )]
155+ valid_ptr = " definition1" , aligned = " definition2" , initialized = " definition3"
156+ )]
157157pub unsafe fn read <T >(ptr : * const T ) -> T { ... }
158158
159- #[safety:: checked( ValidPtr , Aligned , Initialized )] // callsite or discharge
159+ #[safety:: checked( valid_ptr, aligned, initialized )] // callsite or discharge
160160unsafe { read (ptr ) };
161161```
162162
@@ -165,12 +165,12 @@ We can also attach comments for a tag to clarify how safety requirements are met
165165``` rust
166166for _ in 0 .. n {
167167 unsafe {
168- #[safety:: checked(ValidPtr , Aligned , Initialized =
168+ #[safety:: checked(valid_ptr, aligned, initialized =
169169 " addr range p..p+n is properly initialized from aligned memory"
170170 )]
171171 c ^= p . read ();
172172
173- #[safety:: checked(InBounded , ValidNum =
173+ #[safety:: checked(in_bound, valid_num =
174174 " `n` won't exceed isize::MAX here, so `p.add(n)` is fine"
175175 )]
176176 p = p . add (1 );
@@ -192,16 +192,16 @@ unsafe { ptr::read(ptr) }
192192```
193193
194194``` rust
195- warning : `ValidPtr `, `Aligned `, `Initialized ` tags are missing . Add them to `#[safety:: checked]`
195+ warning : `valid_ptr `, `aligned `, `initialized ` tags are missing . Add them to `#[safety:: checked]`
196196 once these invariants are confirmed to be satisfied .
197197 - -> file . rs: xxx : xxx
198198 |
199199LLL | unsafe { ptr :: read (ptr ) }
200200 | ^^^^^^^^^^^^^^^^^^^^^^^^^ This unsafe call requires these safety tags .
201201 |
202- = NOTE : ValidPtr = " definition1"
203- = NOTE : Aligned = " definition2"
204- = NOTE : Initialized = " definition3"
202+ = NOTE : valid_ptr = " definition1"
203+ = NOTE : aligned = " definition2"
204+ = NOTE : initialized = " definition3"
205205```
206206
207207The process of verifying whether a tag is checked is referred to as tag discharge.
@@ -210,19 +210,19 @@ Now consider forwarding invariants of unsafe callees onto the unsafe caller for
210210propogation:
211211
212212``` rust
213- #[safety:: requires(ValidPtr = " ..." , Aligned = " ..." , Initialized = " ..." )]
213+ #[safety:: requires(valid_ptr = " ..." , aligned = " ..." , initialized = " ..." )]
214214unsafe fn propogation <T >(ptr : * const T ) -> T {
215- #[safety:: checked(ValidPtr , Aligned , Initialized )]
215+ #[safety:: checked(valid_ptr, aligned, initialized )]
216216 unsafe { read (ptr ) }
217217}
218218```
219219
220220Tags defined on an unsafe function must be ** fully** discharged at callsites. No partial discharge:
221221
222222``` rust
223- #[safety:: requires(ValidPtr = " ..." , Initialized = " ..." )]
223+ #[safety:: requires(valid_ptr = " ..." , initialized = " ..." )]
224224unsafe fn delegation <T >(ptr : * const T ) -> T {
225- #[safety:: checked(Aligned )] // 💥 warning: Tags are not fully discharged.
225+ #[safety:: checked(aligned )] // 💥 warning: Tags are not fully discharged.
226226 unsafe { read (ptr ) }
227227}
228228```
@@ -231,21 +231,21 @@ For such partial unsafe delegations, please fully discharge tags on the callee a
231231tags on the caller.
232232
233233``` rust
234- #[safety:: requires(ValidPtr = " ..." , Initialized = " ..." )]
234+ #[safety:: requires(valid_ptr = " ..." , initialized = " ..." )]
235235unsafe fn delegation <T >(ptr : * const T ) -> T {
236236 let align = mem :: align_of :: <T >();
237237 let addr = ptr as usize ;
238238 let aligned_addr = (addr + align - 1 ) & ! (align - 1 );
239239
240240 #[safety:: checked(
241- Aligned = " alignment of ptr has be adjusted" ,
242- ValidPtr , Initialized = " delegated to the caller"
241+ aligned = " alignment of ptr has be adjusted" ,
242+ validPtr, initialized = " delegated to the caller"
243243 )]
244244 unsafe { read (ptr ) }
245245}
246246```
247247
248- The tags ` ValidPtr ` and ` Initialized = "delegated to the caller"` are grouped together . We do not
248+ ` valid_ptr ` and ` initialized ` are grouped together to share "delegated to the caller". We do not
249249introduce new syntax for grouping tags but instead suggest visually grouping them for clarity. When
250250` rustfmt ` automatically formats ` ValidPtr ` to its own line, the only workaround is to set
251251` attr_fn_like_width = 0 ` in the ` rustfmt.toml ` configuration file. For further discussion on this
@@ -256,12 +256,12 @@ invariants, and define the new tag on `delegation` function. This practice exten
256256delegation of multiple tag discharges:
257257
258258``` rust
259- #[safety:: requires(MyInvariant = " Invariants of A and C, but could be a more contextual name." )]
259+ #[safety:: requires(my_invariant = " Invariants of A and C, but could be a more contextual name." )]
260260unsafe fn delegation () {
261261 unsafe {
262- #[safety:: checked(A = " delegated to the caller's MyInvariant" , B )]
262+ #[safety:: checked(a = " delegated to the caller's MyInvariant" , b )]
263263 foo ();
264- #[safety:: checked(C = " delegated to the caller's MyInvariant" , D )]
264+ #[safety:: checked(c = " delegated to the caller's MyInvariant" , d )]
265265 bar ();
266266 }
267267}
@@ -305,6 +305,9 @@ NOTE:
305305Since tag definitions duplicate safety comments, we propose ` rustdoc ` can recognize
306306` #[safety::requires] ` attributes and render them into safety docs.
307307
308+ By convention, tag names are written in ` snake_case ` . ` rustdoc ` will replace all underscores (` _ ` )
309+ with spaces and capitalize the first letter.
310+
308311For ` ptr::read ` , replace the existing comments with safety tags:
309312
310313``` rust
@@ -321,22 +324,22 @@ pub const unsafe fn read<T>(src: *const T) -> T { ... }
321324/// # Safety
322325/// Behavior is undefined if any of the following conditions are violated:
323326#[safety:: requires(
324- ValidPtr = " `src` must be [valid] for reads" ;
325- Aligned = " `src` must be properly aligned. Use [`read_unaligned`] if this is not the case" ;
326- Initialized = " `src` must point to a properly initialized value of type `T`"
327+ valid_ptr = " `src` must be [valid] for reads" ;
328+ aligned = " `src` must be properly aligned. Use [`read_unaligned`] if this is not the case" ;
329+ initialized = " `src` must point to a properly initialized value of type `T`"
327330)]
328331/// # Examples
329332pub const unsafe fn read <T >(src : * const T ) -> T { ... }
330333```
331334
332- Each ` Tag = "desc"` item is rendered as `` ` Tag` : desc ` ` list item.
335+ Each ` TagName = "desc"` item is rendered as ` Tag name : desc ` list item.
333336
334337``` rust
335338/// # Safety
336339/// Behavior is undefined if any of the following conditions are violated:
337- /// * `ValidPtr` : `src` must be [valid] for reads.
338- /// * ` Aligned` : `src` must be properly aligned. Use [`read_unaligned`] if this is not the case.
339- /// * ` Initialized` : `src` must point to a properly initialized value of type `T`.
340+ /// * Valid ptr : `src` must be [valid] for reads.
341+ /// * Aligned: `src` must be properly aligned. Use [`read_unaligned`] if this is not the case.
342+ /// * Initialized: `src` must point to a properly initialized value of type `T`.
340343/// # Examples
341344pub const unsafe fn read <T >(src : * const T ) -> T { ... }
342345```
@@ -399,8 +402,8 @@ Treat `#[safety::requires]` tool attributes on unsafe functions as `#[doc]` attr
399402tag names and definitions to render as item list:
400403
401404``` rust
402- #[safety:: requires(Tag1 = " definition1" )]
403- #[safety:: requires(Tag2 = " definition2" )]
405+ #[safety:: requires(tag1 = " definition1" )]
406+ #[safety:: requires(tag2 = " definition2" )]
404407```
405408
406409will be rendered if in markdown syntax
@@ -522,16 +525,16 @@ Our proposed syntax looks closer to structured comments:
522525
523526``` rust
524527#[safety:: checked(
525- ValidPtr , Align , Initialized = " `self.head_tail()` returns two slices to live elements." ,
526- NotOwned = " because we incremented..." ,
528+ valid_ptr, align, initialized = " `self.head_tail()` returns two slices to live elements." ,
529+ not_owned = " because we incremented..." ,
527530)]
528531unsafe { ptr :: read (elem ) }
529532```
530533
531534``` rust
532535// SAFETY
533- // - ValidPtr, Aligned, Initialized : `self.head_tail()` returns two slices to live elements.
534- // - NotOwned : because we incremented...
536+ // - Valid ptr, aligned, initialized : `self.head_tail()` returns two slices to live elements.
537+ // - Not owned : because we incremented...
535538unsafe { ptr :: read (elem ) }
536539```
537540
@@ -571,15 +574,15 @@ description of an unsafe operation, but they are never type checked. An example:
571574
572575``` rust
573576#[safety:: requires(
574- ValidPtr = {
577+ valid_ptr = {
575578 args = [ " p" , " T" , " len" ],
576579 desc = " pointer `{p}` must be valid for \
577580 reading and writing the `sizeof({T})*{n}` memory from it"
578581 }
579582)]
580583unsafe fn foo <T >(ptr : * const T ) -> T { ... }
581584
582- #[safety:: checked(ValidPtr (p))] // p will not be type-checked
585+ #[safety:: checked(valid_ptr (p))] // p will not be type-checked
583586unsafe { bar (p ) }
584587```
585588
@@ -607,23 +610,6 @@ following cases:
607610But we believe safety requirements are almost mostly imposed by unsafe functions, so tagging a
608611struct, enum, or union is neither needed nor permitted.
609612
610- ## Tag naming convention
611-
612- There are two primary conventions for naming tags: ` PascalCase ` (also known as ` UpperCamelCase ` ) and
613- ` snake_case ` .
614-
615- We might consider recommending just one convention for consistency, but it's challenging to
616- determine whether a tag functions more like a type-level construct (semantically akin to an
617- uninhabited enum) or a value-level construct (such as a function, especially if tags can take
618- arguments).
619-
620- To accommodate both styles, we could provide an option that allows users to unify their code style
621- or lint against the alternative convention:
622-
623- ``` rust
624- #![safety:: tag_naming_convention = " PascalCase" ] // in root module
625- ```
626-
627613# Future possibilities
628614[ future-possibilities ] : #future-possibilities
629615
@@ -632,17 +618,17 @@ or lint against the alternative convention:
632618If safety tags become standard practice or are widely accepted, tag checks could be integrated into
633619rustc, allowing ` cargo check ` to perform these checks.
634620
635- ## Discharge One Tag from ` any = { Option1, Option2 } `
621+ ## Discharge One Tag from ` any = { option1, option2 } `
636622
637623Sometimes it’s useful to declare a set of safety tags on an unsafe function while discharging only
638624one of them.
639625
640- For instance, ` ptr::read ` could expose the grouped tag ` any { DropCheck, CopyType } ` and then
641- discharge either ` DropCheck ` or ` CopyType ` at the call site, depending on the concrete type ` T ` .
626+ For instance, ` ptr::read ` could expose the grouped tag ` any { drop_check, copy_type } ` and then
627+ discharge either ` drop_check ` or ` copy_type ` at the call site, depending on the concrete type ` T ` .
642628
643629Another instance is ` <*const T>::as_ref ` , whose safety doc states that the caller must guarantee
644630“the pointer is either null or safely convertible to a reference”. This can be expressed as
645- ` #[safety::requires(any = { Null, ValidPtr2Ref })] ` , allowing the caller to discharge whichever
631+ ` #[safety::requires(any = { null, valid_ptr_to_ref })] ` , allowing the caller to discharge whichever
646632tag applies.
647633
648634## Entity References and Code Review Enhancement
@@ -668,7 +654,7 @@ fn try_fold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
668654 guard . consumed += 1 ;
669655
670656 #[safety:: ref (try_fold)] // 💡
671- #[safety:: checked(ValidPtr , Aligned , Initialized , DropCheck =
657+ #[safety:: checked(valid_ptr, aligned, initialized, drop_check =
672658 " Because we incremented `guard.consumed`, the deque \
673659 effectively forgot the element, so we can take ownership."
674660 )]
@@ -680,6 +666,7 @@ fn try_fold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
680666 guard . consumed += 1 ;
681667
682668 #[safety:: ref (try_fold)] // 💡 No longer to write SAFETY: Same as above.
669+ #[safety:: checked(... )]
683670 unsafe { ptr :: read (elem ) }
684671 })
685672 . try_fold (init , & mut f )
@@ -696,17 +683,19 @@ fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R {
696683 guard . consumed += 1 ;
697684
698685 #[safety:: ref (try_fold)] // 💡 No longer to write SAFETY: See `try_fold`'s safety comment.
686+ #[safety:: checked(... )]
699687 unsafe { ptr :: read (elem ) }
700688 })
701689 . try_rfold (init , & mut f )? ;
702690
703691 head . iter (). map (| elem | {
704- guard . consumed += 1 ;
692+ guard . consumed += 1 ;
705693
706- #[safety:: ref (try_fold)] // 💡 No longer to write SAFETY: Same as above.
707- unsafe { ptr :: read (elem ) }
708- })
709- . try_rfold (init , & mut f )
694+ #[safety:: ref (try_fold)] // 💡 No longer to write SAFETY: Same as above.
695+ #[safety:: checked(... )]
696+ unsafe { ptr :: read (elem ) }
697+ })
698+ . try_rfold (init , & mut f )
710699}
711700```
712701
0 commit comments