Skip to content

[Swiftify] Update availability for CxxSpan<->Span, fix lifetimebound on parameters with reference type #81634

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 1 commit into from
May 22, 2025

Conversation

hnrklssn
Copy link
Contributor

@hnrklssn hnrklssn commented May 20, 2025

Update availability for CxxSpan<->Span, fix lifetimebound on parameters with reference type

Because swift-ide-test doesn't care about typechecking, std-span-interface.swift passed despite containing 2 separate errors. This updates the test file to properly exercise the entire compilation pipeline for the macro expansions, by running swift-frontend -emit-module and calling each macro expansion.

The first issue was that CxxSpan initializers taking [Mutable]Span still had their availability set to Swift 6.2+, even after back-deploying caused [Mutable]Span to have availability back to Swift 5.0. Since _SwiftifyImport expansions copy the availbility of Span, this resulted in the macro expansions calling unavailable initializers. Interestingly enough, this manifested itself in the form of a tripped assert in SIL verification, because although we do now typecheck the expansions from _SwiftifyImport, the compilation can still keep going after shouldEmitFunctionBody returns false: the macro expansion declaration is still there, but is now missing its definition, despite not being external.

The second issue was when parameters with C++ reference types were annotated with [[clang::lifetimebound]]. For parameters with a type that is Escapable, this is normally done using @lifetime(borrow foo). However C++ reference parameters are imported as inout, which requires the @lifetime(&foo) syntax.

rdar://151493400
rdar://151678415

@hnrklssn
Copy link
Contributor Author

@swift-ci please smoke test

@atrick
Copy link
Contributor

atrick commented May 20, 2025

when parameters with C++ reference types were annotated with [[clang::lifetimebound]]. C++ reference parameters are imported as inout, but lifetimebound results in the macro expansion having a lifetime dependence on the parameter. For parameters with a type that is Escapable, this is done using @Lifetime(borrow foo). However, you can't borrow an inout paramter. For parameters with a type that is ~Escapable it's done using @Lifetime(copy foo), which works with inout. When the parameter is inout Escapable however, neither annotation works. Because of this we now ignore lifetimebound on parameters with an Escapable type when they are imported as inout.

This might be the right change. But I want to make sure it's understood that you can borrow in 'inout' parameter. The syntax is now @lifetime(&parameter). For example:

struct NE : ~Escapable {
  @lifetime(immortal)
  init() {}
}

struct E {
  @lifetime(&self)
  mutating func getNE() -> NE { NE() }
}

@lifetime(&e)
func foo(e: inout E) -> NE {
  e.getNE()
}

If you're talking about the output of an 'inout' parameter that depends on its own input value, then it only makes sense to copy its input lifetime.

@lifetime(ne1: copy ne1, copy ne2)
func bar(ne1: inout NE, ne2: NE, z: Bool) {
  if z {
    ne1 = ne2
  } /* else { ne1 = ne1 } */
}

on parameters with reference type

Because swift-ide-test doesn't care about typechecking,
std-span-interface.swift passed despite containing 2 separate errors.
This updates the test file to properly exercise the entire compilation
pipeline for the macro expansions, by running swift-frontend
-emit-module and calling each macro expansion.

The first issue was that CxxSpan initializers taking [Mutable]Span still
had their availability set to Swift 6.2+, even after back-deploying
caused [Mutable]Span to have availability back to Swift 5.0. Since
_SwiftifyImport expansions copy the availbility of Span, this resulted
in the macro expansions calling unavailable initializers.
Interestingly enough, this manifested itself in the form of a tripped
assert in SIL verification, because although we do now typecheck the
expansions from _SwiftifyImport, the compilation can still keep going
after `shouldEmitFunctionBody` returns false: the macro expansion
declaration is still there, but is now missing its definition, despite
not being external.

The second issue was when parameters with C++ reference types were
annotated with `[[clang::lifetimebound]]`. For parameters with a
type that is `Escapable`, this is normally done using
`@lifetime(borrow foo)`. However C++ reference parameters are
imported as `inout`, which requires the `@lifetime(&foo)` syntax.

rdar://151493400
rdar://151670224
@hnrklssn hnrklssn force-pushed the swiftify-span-typecheck branch from 68ff41a to e0fab79 Compare May 21, 2025 00:12
@hnrklssn
Copy link
Contributor Author

when parameters with C++ reference types were annotated with [[clang::lifetimebound]]. C++ reference parameters are imported as inout, but lifetimebound results in the macro expansion having a lifetime dependence on the parameter. For parameters with a type that is Escapable, this is done using @Lifetime(borrow foo). However, you can't borrow an inout paramter. For parameters with a type that is ~Escapable it's done using @Lifetime(copy foo), which works with inout. When the parameter is inout Escapable however, neither annotation works. Because of this we now ignore lifetimebound on parameters with an Escapable type when they are imported as inout.

This might be the right change. But I want to make sure it's understood that you can borrow in 'inout' parameter. The syntax is now @lifetime(&parameter). For example:

struct NE : ~Escapable {
  @lifetime(immortal)
  init() {}
}

struct E {
  @lifetime(&self)
  mutating func getNE() -> NE { NE() }
}

@lifetime(&e)
func foo(e: inout E) -> NE {
  e.getNE()
}

If you're talking about the output of an 'inout' parameter that depends on its own input value, then it only makes sense to copy its input lifetime.

@lifetime(ne1: copy ne1, copy ne2)
func bar(ne1: inout NE, ne2: NE, z: Bool) {
  if z {
    ne1 = ne2
  } /* else { ne1 = ne1 } */
}

Thanks, that worked perfectly it seems!

@hnrklssn
Copy link
Contributor Author

@swift-ci please smoke test

@hnrklssn hnrklssn changed the title [Swiftify] Update availability for CxxSpan<->Span, ignore lifetimebound [Swiftify] Update availability for CxxSpan<->Span, fix lifetimebound on parameters with reference type May 21, 2025
@hnrklssn
Copy link
Contributor Author

@swift-ci please smoke test

Copy link
Contributor

@j-hui j-hui left a comment

Choose a reason for hiding this comment

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

LGTM

@hnrklssn
Copy link
Contributor Author

@swift-ci please smoke test macos

@hnrklssn hnrklssn merged commit 262a53f into swiftlang:main May 22, 2025
3 checks passed
hnrklssn added a commit to hnrklssn/swift that referenced this pull request May 29, 2025
…on parameters with reference type (swiftlang#81634)

Update availability for CxxSpan<->Span, fix lifetimebound on parameters
with reference type

Because swift-ide-test doesn't care about typechecking,
std-span-interface.swift passed despite containing 2 separate errors.
This updates the test file to properly exercise the entire compilation
pipeline for the macro expansions, by running swift-frontend
-emit-module and calling each macro expansion.

The first issue was that CxxSpan initializers taking [Mutable]Span still
had their availability set to Swift 6.2+, even after back-deploying
caused [Mutable]Span to have availability back to Swift 5.0. Since
_SwiftifyImport expansions copy the availbility of Span, this resulted
in the macro expansions calling unavailable initializers. Interestingly
enough, this manifested itself in the form of a tripped assert in SIL
verification, because although we do now typecheck the expansions from
_SwiftifyImport, the compilation can still keep going after
`shouldEmitFunctionBody` returns false: the macro expansion declaration
is still there, but is now missing its definition, despite not being
external.

The second issue was when parameters with C++ reference types were
annotated with `[[clang::lifetimebound]]`. For parameters with a type
that is `Escapable`, this is normally done using `@lifetime(borrow
foo)`. However C++ reference parameters are imported as `inout`, which
requires the `@lifetime(&foo)` syntax.

rdar://151493400
rdar://151678415
(cherry picked from commit 262a53f)
hnrklssn added a commit to hnrklssn/swift that referenced this pull request May 29, 2025
…on parameters with reference type (swiftlang#81634)

Update availability for CxxSpan<->Span, fix lifetimebound on parameters
with reference type

Because swift-ide-test doesn't care about typechecking,
std-span-interface.swift passed despite containing 2 separate errors.
This updates the test file to properly exercise the entire compilation
pipeline for the macro expansions, by running swift-frontend
-emit-module and calling each macro expansion.

The first issue was that CxxSpan initializers taking [Mutable]Span still
had their availability set to Swift 6.2+, even after back-deploying
caused [Mutable]Span to have availability back to Swift 5.0. Since
_SwiftifyImport expansions copy the availbility of Span, this resulted
in the macro expansions calling unavailable initializers. Interestingly
enough, this manifested itself in the form of a tripped assert in SIL
verification, because although we do now typecheck the expansions from
_SwiftifyImport, the compilation can still keep going after
`shouldEmitFunctionBody` returns false: the macro expansion declaration
is still there, but is now missing its definition, despite not being
external.

The second issue was when parameters with C++ reference types were
annotated with `[[clang::lifetimebound]]`. For parameters with a type
that is `Escapable`, this is normally done using `@lifetime(borrow
foo)`. However C++ reference parameters are imported as `inout`, which
requires the `@lifetime(&foo)` syntax.

rdar://151493400
rdar://151678415
(cherry picked from commit 262a53f)
hnrklssn added a commit to hnrklssn/swift that referenced this pull request May 31, 2025
…on parameters with reference type (swiftlang#81634)

Update availability for CxxSpan<->Span, fix lifetimebound on parameters
with reference type

Because swift-ide-test doesn't care about typechecking,
std-span-interface.swift passed despite containing 2 separate errors.
This updates the test file to properly exercise the entire compilation
pipeline for the macro expansions, by running swift-frontend
-emit-module and calling each macro expansion.

The first issue was that CxxSpan initializers taking [Mutable]Span still
had their availability set to Swift 6.2+, even after back-deploying
caused [Mutable]Span to have availability back to Swift 5.0. Since
_SwiftifyImport expansions copy the availbility of Span, this resulted
in the macro expansions calling unavailable initializers. Interestingly
enough, this manifested itself in the form of a tripped assert in SIL
verification, because although we do now typecheck the expansions from
_SwiftifyImport, the compilation can still keep going after
`shouldEmitFunctionBody` returns false: the macro expansion declaration
is still there, but is now missing its definition, despite not being
external.

The second issue was when parameters with C++ reference types were
annotated with `[[clang::lifetimebound]]`. For parameters with a type
that is `Escapable`, this is normally done using `@lifetime(borrow
foo)`. However C++ reference parameters are imported as `inout`, which
requires the `@lifetime(&foo)` syntax.

rdar://151493400
rdar://151678415
(cherry picked from commit 262a53f)
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.

3 participants