Skip to content

Fix lifetime dependence demangling and add a new Sema diagnostic #72684

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 4 commits into from
Mar 29, 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
2 changes: 1 addition & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ Types
C-TYPE is mangled according to the Itanium ABI, and prefixed with the length.
Non-ASCII identifiers are preserved as-is; we do not use Punycode.

function-signature ::= params-type params-type async? sendable? throws? differentiable? function-isolation? // results and parameters
function-signature ::= params-type params-type async? sendable? throws? differentiable? function-isolation? self-lifetime-dependence? // results and parameters

params-type ::= type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type
// with optional inout convention, shared convention. parameters don't have labels,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7889,6 +7889,10 @@ ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
"invalid lifetime dependence on bitwise copyable 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,
"cannot infer lifetime dependence on a self which is BitwiseCopyable & "
"Escapable",
())

//===----------------------------------------------------------------------===//
// MARK: Transferring
Expand Down
8 changes: 4 additions & 4 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,7 @@ NodePointer Demangler::popFunctionType(Node::Kind kind, bool hasClangType) {
ClangType = demangleClangType();
}
addChild(FuncType, ClangType);
addChild(FuncType, popNode(Node::Kind::SelfLifetimeDependence));
addChild(FuncType, popNode(Node::Kind::GlobalActorFunctionType));
addChild(FuncType, popNode(Node::Kind::IsolatedAnyFunctionType));
addChild(FuncType, popNode(Node::Kind::TransferringResultFunctionType));
Expand All @@ -1570,7 +1571,6 @@ NodePointer Demangler::popFunctionType(Node::Kind kind, bool hasClangType) {
}));
addChild(FuncType, popNode(Node::Kind::ConcurrentFunctionType));
addChild(FuncType, popNode(Node::Kind::AsyncAnnotation));
addChild(FuncType, popNode(Node::Kind::SelfLifetimeDependence));

FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ArgumentTuple));
FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ReturnType));
Expand Down Expand Up @@ -1603,6 +1603,9 @@ NodePointer Demangler::popFunctionParamLabels(NodePointer Type) {
return nullptr;

unsigned FirstChildIdx = 0;
if (FuncType->getChild(FirstChildIdx)->getKind() ==
Node::Kind::SelfLifetimeDependence)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind()
== Node::Kind::GlobalActorFunctionType)
++FirstChildIdx;
Expand All @@ -1629,9 +1632,6 @@ NodePointer Demangler::popFunctionParamLabels(NodePointer Type) {
if (FuncType->getChild(FirstChildIdx)->getKind() ==
Node::Kind::ParamLifetimeDependence)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind() ==
Node::Kind::SelfLifetimeDependence)
++FirstChildIdx;
auto ParameterType = FuncType->getChild(FirstChildIdx);

assert(ParameterType->getKind() == Node::Kind::ArgumentTuple);
Expand Down
14 changes: 14 additions & 0 deletions lib/Sema/LifetimeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ std::optional<LifetimeDependenceInfo>
LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
auto *dc = afd->getDeclContext();
auto &ctx = dc->getASTContext();
auto *mod = afd->getModuleContext();

if (!ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
return std::nullopt;
Expand Down Expand Up @@ -431,6 +432,19 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {

if (afd->getKind() != DeclKind::Constructor && afd->hasImplicitSelfDecl()) {
Type selfTypeInContext = dc->getSelfTypeInContext();
if (selfTypeInContext->isEscapable()) {
if (ctx.LangOpts.hasFeature(Feature::BitwiseCopyable)) {
auto *bitwiseCopyableProtocol =
ctx.getProtocol(KnownProtocolKind::BitwiseCopyable);
if (bitwiseCopyableProtocol &&
mod->checkConformance(selfTypeInContext, bitwiseCopyableProtocol)) {
diags.diagnose(
returnLoc,
diag::lifetime_dependence_method_escapable_bitwisecopyable_self);
return std::nullopt;
}
}
}
auto kind = getLifetimeDependenceKindFromType(selfTypeInContext);
auto selfOwnership = afd->getImplicitSelfDecl()->getValueOwnership();
if (!isLifetimeDependenceCompatibleWithOwnership(kind, selfOwnership,
Expand Down
10 changes: 5 additions & 5 deletions test/SIL/implicit_lifetime_dependence.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %target-swift-frontend %s \
// RUN: -emit-sil \
// RUN: -emit-sil -disable-availability-checking \
// RUN: -enable-experimental-feature NonescapableTypes \
// RUN: -enable-experimental-feature NoncopyableGenerics | %FileCheck %s
// REQUIRES: asserts
Expand Down Expand Up @@ -82,13 +82,13 @@ struct Wrapper : ~Escapable {
self._view = view
}
// TODO: Investigate why it was mangled as Yli and not YLi before
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyYLiF : $@convention(method) (@guaranteed Wrapper) -> _inherit(0) @owned BufferView {
borrowing func getView1() -> BufferView {
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyKYLiF : $@convention(method) (@guaranteed Wrapper) -> _inherit(0) (@owned BufferView, @error any Error) {
borrowing func getView1() throws -> BufferView {
return _view
}

// CHECK:sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYLiF : $@convention(method) (@owned Wrapper) -> _inherit(0) @owned BufferView {
consuming func getView2() -> BufferView {
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYaKYLiF : $@convention(method) @async (@owned Wrapper) -> _inherit(0) (@owned BufferView, @error any Error) {
consuming func getView2() async throws -> BufferView {
return _view
}
}
Expand Down
16 changes: 15 additions & 1 deletion test/Sema/explicit_lifetime_dependence_specifiers1.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -enable-experimental-feature NoncopyableGenerics
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature BitwiseCopyable
// REQUIRES: asserts

struct Container {
Expand Down Expand Up @@ -218,3 +218,17 @@ func derive(_ x: BufferView) -> dependsOn(x) BufferView { // expected-note{{'der
func derive(_ x: BufferView) -> dependsOn(scoped x) BufferView { // expected-error{{invalid redeclaration of 'derive'}}
return BufferView(x.ptr)
}

struct RawBufferView {
let ptr: UnsafeRawBufferPointer
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer) {
self.ptr = ptr
}
}

extension RawBufferView {
mutating func zeroBufferView() throws -> BufferView { // expected-error{{cannot infer lifetime dependence on a self which is BitwiseCopyable & Escapable}}
return BufferView(ptr)
}
}
11 changes: 8 additions & 3 deletions test/Sema/implicit_lifetime_dependence.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -enable-experimental-feature NoncopyableGenerics
// RUN: %target-typecheck-verify-swift -enable-experimental-feature NonescapableTypes -enable-experimental-feature NoncopyableGenerics
// REQUIRES: asserts

struct BufferView : ~Escapable, ~Copyable {
let ptr: UnsafeRawBufferPointer
let ptr: UnsafeRawBufferPointer?
let c: Int
@_unsafeNonescapableResult
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
init(_ ptr: UnsafeRawBufferPointer?, _ c: Int) {
self.ptr = ptr
self.c = c
}
Expand All @@ -23,3 +23,8 @@ struct ImplicitInit3 : ~Escapable, ~Copyable { // expected-error{{cannot infer l
let mbv1: BufferView
let mbv2: BufferView
}

func foo() -> BufferView { // expected-error{{cannot infer lifetime dependence , no parameters found that are ~Escapable or Escapable with a borrowing ownership}}
return BufferView(nil, 0)
}