Skip to content

Commit a3947c8

Browse files
committed
SE-0458: Require types to be marked @safe/@unsafe if their storage is unsafe
1 parent 86c1028 commit a3947c8

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

proposals/0458-strict-memory-safety.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,35 @@ There are a number of compiler flags that intentionally disable some safety-rela
331331
* `-strict-concurrency=` for anything other than "complete", because the memory safety model requires strict concurrency to eliminate thread safety issues.
332332
* `-disable-access-control`, which allows one to break invariants of a type that can lead to memory-safety issues, such as breaking the invariant of `Range` that the lower bound not exceed the upper bound.
333333

334+
### Types with unsafe storage
335+
336+
Types that wrap unsafe types will often encapsulate the unsafe behavior to provide safe interfaces. However, this requires deliberate design and implementation, potentially involving adding specific preconditions. When strict safety checking is enabled, a type whose storage is unsafe will be diagnosed as involving unsafe code. This diagnostic can be suppressed by marking the type as `@safe` or `@unsafe`, in the same manner as any other declaration that has unsafe types or conformances in its signature:
337+
338+
```swift
339+
// @safe is required to suppress a diagnostic about the 'buffer' property's use
340+
// of an unsafe type.
341+
@safe
342+
struct ImmortalBufferWrapper<Element> : Collection {
343+
let buffer: UnsafeBufferPointer<Element>
344+
345+
@unsafe init(_ withImmortalBuffer: UnsafeBufferPointer<Element>) {
346+
self.buffer = unsafe buffer
347+
}
348+
349+
subscript(index: Index) -> Element {
350+
precondition(index >= 0 && index < buffer.count)
351+
return unsafe buffer[index]
352+
}
353+
354+
/* Also: Index, startIndex, endIndex, index(after:) */
355+
}
356+
```
357+
358+
A type has unsafe storage if:
359+
360+
* Any stored instance property (for `actor`, `class`, and `struct` types) or associated value (for cases of `enum` types) have a type that involves an unsafe type or conformance.
361+
* Any stored instance property uses one of the unsafe language features (such as `unowned(unsafe)`).
362+
334363
### Unsafe overrides
335364

336365
Overriding a safe method within an `@unsafe` one could introduce unsafety, so it will produce a diagnostic in the strict safety mode:
@@ -704,6 +733,7 @@ We could introduce an optional `message` argument to the `@unsafe` attribute, wh
704733

705734
* **Revision 2 (following first review)**
706735
* Specified that variables of unsafe type passed in to uses of `@safe` declarations (e.g., calls, property accesses) are not diagnosed as themselves being unsafe. This makes means that expressions like `unsafeBufferePointer.count` will be considered safe.
736+
* Require types whose storage involves an unsafe type or conformance to be marked as `@safe` or `@unsafe`, much like other declarations that have unsafe types or conformances in their signature.
707737
* Add an Alternatives Considered section on prohibiting unsafe conformances and overrides.
708738

709739
## Acknowledgments

0 commit comments

Comments
 (0)