Skip to content

Remove diagnostic: lifetime_dependence_on_bitwise_copyable #73831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===--- AccessUtils.swift - Utilities for analyzing memory accesses ------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// TODO: Move this to AccessUtils.swift when FunctionTest is available.
//
//===----------------------------------------------------------------------===//

let getAccessBaseTest = FunctionTest("swift_get_access_base") {
function, arguments, context in
let address = arguments.takeValue()
print("Address: \(address)")
let base = address.accessBase
print("Base: \(base)")
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors

swift_compiler_sources(Optimizer
AccessUtilsTest.swift
AddressUtils.swift
BorrowedFromUpdater.swift
BorrowUtils.swift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ extension BridgedTestArguments {
public func registerOptimizerTests() {
// Register each test.
registerFunctionTests(
getAccessBaseTest,
argumentConventionsTest,
borrowIntroducersTest,
enclosingValuesTest,
Expand Down
4 changes: 2 additions & 2 deletions SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,8 @@ extension AddressUseDefWalker {
} else {
return walkUp(address: ia.base, path: path.push(.anyIndexedElement, index: 0))
}
case let mdi as MarkDependenceInst:
return walkUp(address: mdi.operands[0].value, path: path)
case is MarkDependenceInst, is MarkUninitializedInst:
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
case is MoveOnlyWrapperToCopyableAddrInst,
is CopyableToMoveOnlyWrapperAddrInst:
return walkUp(address: (def as! Instruction).operands[0].value, path: path)
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7985,8 +7985,6 @@ ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
"expected nil or self as return values in an initializer with "
"lifetime dependent specifiers",
())
ERROR(lifetime_dependence_on_bitwise_copyable, none,
"invalid lifetime dependence on BitwiseCopyable type", ())
ERROR(lifetime_dependence_cannot_be_applied_to_tuple_elt, none,
"lifetime dependence specifiers cannot be applied to tuple elements", ())
ERROR(lifetime_dependence_method_escapable_bitwisecopyable_self, none,
Expand Down
20 changes: 6 additions & 14 deletions lib/AST/LifetimeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,24 +207,16 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd) {
Type paramType,
ValueOwnership ownership) {
auto loc = specifier.getLoc();

// Diagnose when we have lifetime dependence on a type that is
// BitwiseCopyable & Escapable.
// ~Escapable types are non-trivial in SIL and we should not raise this
// error.
// TODO: Diagnose ~Escapable types are always non-trivial in SIL.
if (paramType->isEscapable()) {
if (isBitwiseCopyable(paramType, mod, ctx)) {
diags.diagnose(loc, diag::lifetime_dependence_on_bitwise_copyable);
return true;
}
}

auto parsedLifetimeKind = specifier.getParsedLifetimeDependenceKind();
auto lifetimeKind =
getLifetimeDependenceKindFromDecl(parsedLifetimeKind, paramType);
bool isCompatible = isLifetimeDependenceCompatibleWithOwnership(
bool isCompatible = true;
// Lifetime dependence always propagates through temporary BitwiseCopyable
// values, even if the dependence is scoped.
if (!isBitwiseCopyable(paramType, mod, ctx)) {
isCompatible = isLifetimeDependenceCompatibleWithOwnership(
lifetimeKind, ownership, afd);
}
if (parsedLifetimeKind == ParsedLifetimeDependenceKind::Scope &&
!isCompatible) {
diags.diagnose(
Expand Down
9 changes: 5 additions & 4 deletions lib/SIL/Utils/MemAccessUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2087,13 +2087,14 @@ struct AccessUseTestVisitor : public AccessUseVisitor {
}
};

static FunctionTest AccessPathBaseTest("accesspath-base", [](auto &function,
auto &arguments,
auto &test) {
static FunctionTest AccessPathBaseTest("accesspath", [](auto &function,
auto &arguments,
auto &test) {
auto value = arguments.takeValue();
function.print(llvm::outs());
llvm::outs() << "Access path base: " << value;
llvm::outs() << "Access path for: " << value;
auto accessPathWithBase = AccessPathWithBase::compute(value);
llvm::outs() << " base: " << accessPathWithBase.base;
AccessUseTestVisitor visitor;
visitAccessPathBaseUses(visitor, accessPathWithBase, &function);
});
Expand Down
6 changes: 2 additions & 4 deletions test/ModuleInterface/Inputs/lifetime_dependence.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
public struct AnotherView : ~Escapable {
@usableFromInline let _ptr: UnsafeRawBufferPointer
@usableFromInline let _count: Int
@_unsafeNonescapableResult
internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) {
internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) -> dependsOn(ptr) Self {
self._ptr = ptr
self._count = count
}
Expand All @@ -11,9 +10,8 @@ public struct AnotherView : ~Escapable {
public struct BufferView : ~Escapable {
@usableFromInline let _ptr: UnsafeRawBufferPointer
@usableFromInline let _count: Int
@_unsafeNonescapableResult
@usableFromInline
internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) {
internal init(_ ptr: UnsafeRawBufferPointer, _ count: Int) -> dependsOn(ptr) Self {
self._ptr = ptr
self._count = count
}
Expand Down
7 changes: 3 additions & 4 deletions test/Parse/explicit_lifetime_dependence_specifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import Builtin

struct BufferView : ~Escapable {
let ptr: UnsafeRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer) {
init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self {
self.ptr = ptr
}
// TODO: -> dependsOn(ptr) Self
@_unsafeNonescapableResult
init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) {
if (i % 2 == 0) {
Expand Down Expand Up @@ -45,8 +45,7 @@ struct BufferView : ~Escapable {

struct MutableBufferView : ~Escapable, ~Copyable {
let ptr: UnsafeMutableRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeMutableRawBufferPointer) {
init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self {
self.ptr = ptr
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/SIL/Parser/lifetime_dependence.sil
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Swift

struct BufferView : ~Escapable {
@_hasStorage let ptr: UnsafeRawBufferPointer { get }
@_unsafeNonescapableResult @inlinable init(_ ptr: UnsafeRawBufferPointer)
@inlinable init(_ ptr: UnsafeRawBufferPointer) -> _scope(ptr) Self
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Int>) -> _scope(a) Self
}

Expand Down
30 changes: 16 additions & 14 deletions test/SIL/explicit_lifetime_dependence_specifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ import Builtin

struct BufferView : ~Escapable {
let ptr: UnsafeRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer) {
init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self {
self.ptr = ptr
}
// TODO: -> dependsOn(ptr) Self
@_unsafeNonescapableResult
init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) {
if (i % 2 == 0) {
return nil
}
self.ptr = ptr
}
@_unsafeNonescapableResult
init(independent ptr: UnsafeRawBufferPointer) {
self.ptr = ptr
}
// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySiGhYlstcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array<Int>, @thin BufferView.Type) -> _scope(1) @owned BufferView {
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Int>) -> dependsOn(a) Self {
self.ptr = ptr
Expand All @@ -38,8 +42,7 @@ struct BufferView : ~Escapable {

struct MutableBufferView : ~Escapable, ~Copyable {
let ptr: UnsafeMutableRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeMutableRawBufferPointer) {
init(_ ptr: UnsafeMutableRawBufferPointer) -> dependsOn(ptr) Self {
self.ptr = ptr
}
}
Expand All @@ -57,28 +60,28 @@ func testBasic() {

// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView {
func derive(_ x: borrowing BufferView) -> dependsOn(scoped x) BufferView {
return BufferView(x.ptr)
return BufferView(independent: x.ptr)
}

// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView {
func consumeAndCreate(_ x: consuming BufferView) -> dependsOn(x) BufferView {
return BufferView(x.ptr)
return BufferView(independent: x.ptr)
}

// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat1yAA10BufferViewVADYls_ADYlstF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> _scope(0, 1) @owned BufferView {
func deriveThisOrThat1(_ this: borrowing BufferView, _ that: borrowing BufferView) -> dependsOn(scoped this, that) BufferView {
if (Int.random(in: 1..<100) == 0) {
return BufferView(this.ptr)
return BufferView(independent: this.ptr)
}
return BufferView(that.ptr)
return BufferView(independent: that.ptr)
}

// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat2yAA10BufferViewVADYls_ADnYlitF : $@convention(thin) (@guaranteed BufferView, @owned BufferView) -> _inherit(1) _scope(0) @owned BufferView {
func deriveThisOrThat2(_ this: borrowing BufferView, _ that: consuming BufferView) -> dependsOn(scoped this) dependsOn(that) BufferView {
if (Int.random(in: 1..<100) == 0) {
return BufferView(this.ptr)
return BufferView(independent: this.ptr)
}
return BufferView(that.ptr)
return BufferView(independent: that.ptr)
}

func use(_ x: borrowing BufferView) {}
Expand All @@ -101,19 +104,18 @@ struct Wrapper : ~Escapable {

struct Container : ~Escapable {
let ptr: UnsafeRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer) {
init(_ ptr: UnsafeRawBufferPointer) -> dependsOn(ptr) Self {
self.ptr = ptr
}
}

// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getConsumingViewyAA06BufferG0VAA9ContainerVnYliF : $@convention(thin) (@owned Container) -> _inherit(0) @owned BufferView {
func getConsumingView(_ x: consuming Container) -> dependsOn(x) BufferView {
return BufferView(x.ptr)
return BufferView(independent: x.ptr)
}

// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getBorrowingViewyAA06BufferG0VAA9ContainerVYlsF : $@convention(thin) (@guaranteed Container) -> _scope(0) @owned BufferView {
func getBorrowingView(_ x: borrowing Container) -> dependsOn(scoped x) BufferView {
return BufferView(x.ptr)
return BufferView(independent: x.ptr)
}

16 changes: 9 additions & 7 deletions test/SIL/implicit_lifetime_dependence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
struct BufferView : ~Escapable {
let ptr: UnsafeRawBufferPointer
let c: Int
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self {
self.ptr = ptr
self.c = c
}
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
init(independent ptr: UnsafeRawBufferPointer, _ c: Int) {
self.ptr = ptr
self.c = c
}
Expand All @@ -31,8 +35,7 @@ struct BufferView : ~Escapable {
struct MutableBufferView : ~Escapable, ~Copyable {
let ptr: UnsafeMutableRawBufferPointer
let c: Int
@_unsafeNonescapableResult
init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) {
init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) -> dependsOn(ptr) Self {
self.ptr = ptr
self.c = c
}
Expand All @@ -54,12 +57,12 @@ func derive(_ x: borrowing BufferView) -> BufferView {
}

func derive(_ unused: Int, _ x: borrowing BufferView) -> BufferView {
return BufferView(x.ptr, x.c)
return BufferView(independent: x.ptr, x.c)
}

// CHECK: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView {
func consumeAndCreate(_ x: consuming BufferView) -> BufferView {
return BufferView(x.ptr, x.c)
return BufferView(independent: x.ptr, x.c)
}

func use(_ x: borrowing BufferView) {}
Expand Down Expand Up @@ -135,8 +138,7 @@ struct GenericBufferView<Element> : ~Escapable {
count: count)
}
// unsafe private API
@_unsafeNonescapableResult
init(baseAddress: Pointer, count: Int) {
init(baseAddress: Pointer, count: Int) -> dependsOn(baseAddress) Self {
precondition(count >= 0, "Count must not be negative")
self.baseAddress = baseAddress
self.count = count
Expand Down
1 change: 1 addition & 0 deletions test/SIL/lifetime_dependence_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extension P {
}

public struct View: ~Escapable {
// TODO: dependsOn(immortal)
@_unsafeNonescapableResult
init() { }
}
Expand Down
1 change: 1 addition & 0 deletions test/SIL/type_lowering_unit.sil
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ extension GSNCInt: Copyable where T: Copyable {}

struct GSNEInt<T: ~Escapable>: ~Escapable {
var x: Int
// TODO: dependsOn(immortal)
@_unsafeNonescapableResult
init() { x = 0 }
}
Expand Down
29 changes: 25 additions & 4 deletions test/SILOptimizer/accessbase_unit.sil
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ class C {}
// CHECK: Class [[BOX]] = argument of bb0
// CHECK: Field: var value: T Index: 0
// CHECK-LABEL: end running test {{.*}} on test_phi_nested_access: compute_access_storage with
// CHECK-LABEL: begin running test 3 of 3 on test_phi_nested_access: accesspath-base
// CHECK: Access path base: %6 = argument of bb1
// CHECK-LABEL: begin running test 3 of 3 on test_phi_nested_access: accesspath
// CHECK: Access path for: %6 = argument of bb1
// CHECK: Exact Use: end_access %2
// CHECK-LABEL: end running test 3 of 3 on test_phi_nested_access: accesspath-base
// CHECK-LABEL: end running test 3 of 3 on test_phi_nested_access: accesspath
sil @test_phi_nested_access : $@convention(method) (@guaranteed Box<C>) -> () {
bb1(%box : $Box<C>):
%value_addr = ref_element_addr %box : $Box<C>, #Box.value
Expand All @@ -42,7 +42,7 @@ bb1(%box : $Box<C>):
exit(%phi : $Builtin.RawPointer):
specify_test "get_access_base @argument"
specify_test "compute_access_storage @argument"
specify_test "accesspath-base @argument"
specify_test "accesspath @argument"
%retval = tuple ()
return %retval : $()
}
Expand All @@ -65,3 +65,24 @@ sil @test_access_global : $@convention(thin) () -> () {
%retval = tuple ()
return %retval : $()
}

// CHECK-LABEL: begin running test {{.*}} on test_mark_uninitialized_inst: get_access_base
// CHECK: Address: %{{.*}} = mark_uninitialized [var] [[ALLOC:%.*]] : $*C
// CHECK: Base: [[ALLOC]] = alloc_stack [var_decl] $C
// CHECK-LABEL: end running test {{.*}} on test_mark_uninitialized_inst: get_access_base
// CHECK-LABEL: begin running test {{.*}} on test_mark_uninitialized_inst: swift_get_access_base
// CHECK: Address: %{{.*}} = mark_uninitialized [var] [[ALLOC:%.*]] : $*C
// CHECK: Base: stack - [[ALLOC]] = alloc_stack [var_decl] $C
// CHECK-LABEL: end running test {{.*}} on test_mark_uninitialized_inst: swift_get_access_base
sil [ossa] @test_mark_uninitialized_inst : $@convention(thin) (@owned C) -> () {
bb0(%0 : @owned $C):
%1 = alloc_stack [var_decl] $C, let
%2 = mark_uninitialized [var] %1 : $*C
specify_test "get_access_base %2"
specify_test "swift_get_access_base %2"
assign %0 to %2 : $*C
destroy_addr %2 : $*C
dealloc_stack %1 : $*C
%9999 = tuple()
return %9999 : $()
}
Loading