Skip to content

Remove the experimental LifetimeDependenceDiagnoseTrivial feature. #78283

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
Dec 19, 2024

Conversation

atrick
Copy link
Contributor

@atrick atrick commented Dec 19, 2024

This was never used to generate a .swiftinterface, so can be safely removed. It
was used to guard compiler fixes that might break older .swiftinterface
files. Now, we guard the same fixes by checking the source file type.

This depends on fixing Span initialization from CxxSpan.

Briefly, some versions of Span in the standard library violated trivial
lifetimes; versions of the compiler built at that time simply ignored
dependencies on trivial values. For now, disable trivial dependencies to allow
newer compilers to build against those older standard libraries. This check is
only relevant for ~6 mo (until July 2025).
CxxSpan is trivial, but not immortal.

This initializer is diagnosed with an error after enabling trivial dependence
enforcement. Correct this with an _overrideLifetime call. This could be avoided
if we had a another way to tell the compiler that CxxSpan.__dataUnsafe()
produced a pointer with the same effective lifetime as the CxxSpan.
A trivial value that is marked dependent on the access scope of another trivial
variable is escaping of its use is outside the access scope.
This was never used to generate a .swiftinterface, so can be safely removed. It
was used to guard compiler fixes that might break older .swiftinterface
files. Now, we guard the same fixes by checking the source file type.
@atrick
Copy link
Contributor Author

atrick commented Dec 19, 2024

@Xazax-hun please take a look at the Span initializer fix

@atrick atrick requested review from Xazax-hun and removed request for Xazax-hun December 19, 2024 01:19
@atrick
Copy link
Contributor Author

atrick commented Dec 19, 2024

@swift-ci test

@atrick
Copy link
Contributor Author

atrick commented Dec 19, 2024

@swift-ci benchmark

@atrick
Copy link
Contributor Author

atrick commented Dec 19, 2024

@Xazax-hun this appears to fix: rdar://136668965 (Borrow diagnostics not triggered for foreign types)

@Xazax-hun
Copy link
Contributor

this appears to fix: rdar://136668965 (Borrow diagnostics not triggered for foreign types)

This is wonderful news, thanks a lot for looking into it!

@unsafe
@lifetime(borrow span)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I am not sure this would work for the purposes we want to use this conversion for.

The planned usage looks like this. imagine the following C++ function:

using SpanOfInt = std::span<int>;
SpanOfInt foo(const Bar& b [[clang::lifetimebound]]);

We plan to import it like this:

@_disfavoredOverload
func foo(b: borrwing Bar) -> SpanOfInt 

And we plan to generate a safe wrapper using Swift's span something like this:

@lifetime(bar)
func foo(b: borrowing Bar) -> Span<int> {
  Span(_unsafeCxxSpan: foo(b))
}

Note that, we expect the Swift span to be used after the lifetime of the corresponding C++ span ends. I'd expect this to be OK as the C++ span does not actually own the buffer. So we want to inherit/copy the dependencies of the C++ span to the Swift span. Unfortunately, we cannot do that as the C++ span is escapable. This is why my initial feeling was to just make the Swift span immortal and leave it to the safe wrapper to propagate the correct lifetimes.

What do you think, what would be the proper way to make this scenario work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Xazax-hun We have two options for ceating such wrappers:

  1. Add @_unsafeNonescapableResult to the Span initializer:
@_unsafeNonescapableResult
Span.init<T: CxxSpan<Element>>(_unsafeCxxSpan span: borrowing T)`

This is ok if you never expect programmers to access this initializer. You're placing the responsibilty for safety entirely on the wrapper.

  1. Add _overrideLifetime to the wrapper:
@lifetime(bar)
func foo(b: borrowing Bar) -> Span<int> {
  let cxxSpan = cxx_foo(b)
  let swiftSpan = Span(_unsafeCxxSpan: cxxSpan)
   // The lexical variable scope of cxxSpan covers the final use if `swiftSpan` below:
  return _overrideLifetime(swiftSpan, borrowing: b)
}

@atrick atrick merged commit c347b66 into swiftlang:main Dec 19, 2024
6 checks passed
@atrick atrick deleted the remove-trivial-feature branch December 19, 2024 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants