Skip to content

Commit 23f8942

Browse files
committed
tag: snake_case naming convention and render to Snake case
1 parent 4c8a256 commit 23f8942

File tree

1 file changed

+56
-67
lines changed

1 file changed

+56
-67
lines changed

text/0000-safety-tags.md

Lines changed: 56 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ requirement into a single, check-off reminder.
1515
The following snippet [compiles] today if we enable enough nightly features, but we expect Clippy
1616
and 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
)]
2626
pub unsafe fn read<T>(ptr: *const T) { }
2727

2828
fn 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+
)]
157157
pub 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
160160
unsafe { 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
166166
for _ 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
|
199199
LLL | 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

207207
The 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
210210
propogation:
211211

212212
```rust
213-
#[safety::requires(ValidPtr = "...", Aligned = "...", Initialized = "...")]
213+
#[safety::requires(valid_ptr = "...", aligned = "...", initialized = "...")]
214214
unsafe 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

220220
Tags 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 = "...")]
224224
unsafe 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
231231
tags on the caller.
232232

233233
```rust
234-
#[safety::requires(ValidPtr = "...", Initialized = "...")]
234+
#[safety::requires(valid_ptr = "...", initialized = "...")]
235235
unsafe 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
249249
introduce 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
256256
delegation 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.")]
260260
unsafe 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:
305305
Since 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+
308311
For `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
329332
pub 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
341344
pub 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
399402
tag 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

406409
will 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
)]
528531
unsafe { 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...
535538
unsafe { 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
)]
580583
unsafe 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
583586
unsafe { bar(p) }
584587
```
585588

@@ -607,23 +610,6 @@ following cases:
607610
But we believe safety requirements are almost mostly imposed by unsafe functions, so tagging a
608611
struct, 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:
632618
If safety tags become standard practice or are widely accepted, tag checks could be integrated into
633619
rustc, 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

637623
Sometimes it’s useful to declare a set of safety tags on an unsafe function while discharging only
638624
one 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

643629
Another 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
646632
tag 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

Comments
 (0)