mirror of
https://github.com/apple/swift.git
synced 2026-10-28 21:15:56 +01:00
'@unsafe' requires uses to be acknowledged with the 'unsafe' keyword only when strict memory safety checking is enabled. Add '@unsafe(always)', which requires it in every language mode and diagnoses an error rather than a warning, for constructs that are very hard to use correctly: ones where nearly every use is incorrect, so writing one should be a deliberate act. The motivating case is C++ interop, where an API whose lifetime dependencies cannot be inferred is imported '@unsafe' today and can then be used with no acknowledgement at all outside of strict memory safety checking. This covers the attribute itself and its enforcement at use sites: expressions and for-in loops. Declaration-level checks (overrides, protocol witnesses, unsafe storage and superclasses) follow separately. Notes: - A plain '@unsafe' declaration whose signature involves an always-unsafe type does not launder the stronger requirement. - Compiler-synthesized code cannot be annotated by hand, so an always-unsafe use there falls back to the merely-unsafe behavior instead of erroring. - Interfaces strip 'unsafe' markers from inlinable bodies, so the diagnostics degrade to warnings when type-checking a .swiftinterface. - '@unsafe(always)' is printed into module interfaces behind a '$AlwaysUnsafeAttribute' feature check, falling back to '@unsafe' for compilers that predate the spelling.
31 lines
1.1 KiB
Swift
31 lines
1.1 KiB
Swift
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name always_unsafe
|
|
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name always_unsafe
|
|
// RUN: %FileCheck %s --input-file %t.swiftinterface --match-full-lines
|
|
|
|
// Older compilers don't understand the argument of '@unsafe(always)', so the
|
|
// interface falls back to plain '@unsafe' for them.
|
|
|
|
// CHECK: #if compiler(>=5.3) && $AlwaysUnsafeAttribute
|
|
// CHECK: @unsafe(always) public func alwaysUnsafeFunc()
|
|
// CHECK: #else
|
|
// CHECK: @unsafe public func alwaysUnsafeFunc()
|
|
// CHECK: #endif
|
|
@unsafe(always)
|
|
public func alwaysUnsafeFunc() { }
|
|
|
|
// A plain '@unsafe' needs no compatibility guard.
|
|
// CHECK-NOT: $AlwaysUnsafeAttribute
|
|
// CHECK: @unsafe public func unsafeFunc()
|
|
@unsafe
|
|
public func unsafeFunc() { }
|
|
|
|
// The 'unsafe' marker is deliberately stripped from inlinable bodies printed
|
|
// into an interface, so the printed body contains a bare call. Verifying the
|
|
// interface therefore must not be a hard error.
|
|
// CHECK: @inlinable public func inlinableUse() {
|
|
// CHECK-NEXT: alwaysUnsafeFunc()
|
|
@inlinable
|
|
public func inlinableUse() {
|
|
unsafe alwaysUnsafeFunc()
|
|
}
|