Skip to content

Commit 8462105

Browse files
authored
Merge pull request swiftlang#78947 from swiftlang/gaborh/lifetimebound-this
2 parents 71015c6 + 06e5ead commit 8462105

File tree

8 files changed

+73
-20
lines changed

8 files changed

+73
-20
lines changed

lib/ClangImporter/ImportDecl.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -8789,7 +8789,8 @@ class SwiftifyInfoPrinter {
87898789

87908790
void printLifetimeboundReturn(int idx, bool borrow) {
87918791
printSeparator();
8792-
out << ".lifetimeDependence(dependsOn: " << (idx + 1);
8792+
out << ".lifetimeDependence(dependsOn: ";
8793+
printParamOrReturn(idx);
87938794
out << ", pointer: .return, type: ";
87948795
out << (borrow ? ".borrow" : ".copy");
87958796
out << ")";
@@ -8818,7 +8819,9 @@ class SwiftifyInfoPrinter {
88188819
}
88198820

88208821
void printParamOrReturn(ssize_t pointerIndex) {
8821-
if (pointerIndex == -1)
8822+
if (pointerIndex == -2)
8823+
out << ".self";
8824+
else if (pointerIndex == -1)
88228825
out << ".return";
88238826
else
88248827
out << ".param(" << pointerIndex + 1 << ")";
@@ -8859,15 +8862,21 @@ void ClangImporter::Implementation::importSpanAttributes(FuncDecl *MappedDecl) {
88598862
->getDesugaredType()
88608863
->getString()));
88618864
}
8865+
bool lifetimeDependenceOn = MappedDecl->getASTContext().LangOpts.hasFeature(
8866+
Feature::LifetimeDependence);
8867+
if (SwiftDeclConverter::getImplicitObjectParamAnnotation<
8868+
clang::LifetimeBoundAttr>(ClangDecl) &&
8869+
lifetimeDependenceOn && returnIsSpan) {
8870+
printer.printLifetimeboundReturn(-2, true);
8871+
attachMacro = true;
8872+
}
88628873
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
88638874
auto paramTy = param->getType();
88648875
const auto *decl = paramTy->getAsTagDecl();
88658876
auto swiftParam = MappedDecl->getParameters()->get(index);
88668877
bool isSpan =
88678878
decl && decl->isInStdNamespace() && decl->getName() == "span";
8868-
if (param->hasAttr<clang::LifetimeBoundAttr>() &&
8869-
MappedDecl->getASTContext().LangOpts.hasFeature(
8870-
Feature::LifetimeDependence) &&
8879+
if (param->hasAttr<clang::LifetimeBoundAttr>() && lifetimeDependenceOn &&
88718880
(isSpan || returnIsSpan)) {
88728881
printer.printLifetimeboundReturn(
88738882
index, !isSpan && swiftParam->getInterfaceType()->isEscapable());

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

+28-8
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import SwiftSyntaxMacros
1010
enum SwiftifyExpr: Hashable {
1111
case param(_ index: Int)
1212
case `return`
13+
case `self`
1314
}
1415

1516
extension SwiftifyExpr: CustomStringConvertible {
1617
var description: String {
1718
switch self {
1819
case .param(let index): return ".param(\(index))"
1920
case .return: return ".return"
21+
case .self: return ".self"
2022
}
2123
}
2224
}
@@ -26,7 +28,7 @@ enum DependenceType {
2628
}
2729

2830
struct LifetimeDependence {
29-
let dependsOn: Int
31+
let dependsOn: SwiftifyExpr
3032
let type: DependenceType
3133
}
3234

@@ -48,6 +50,8 @@ func tryGetParamName(_ funcDecl: FunctionDeclSyntax, _ expr: SwiftifyExpr) -> To
4850
case .param(let i):
4951
let funcParam = getParam(funcDecl, i - 1)
5052
return funcParam.secondName ?? funcParam.firstName
53+
case .`self`:
54+
return .keyword(.self)
5155
default: return nil
5256
}
5357
}
@@ -59,6 +63,8 @@ func getSwiftifyExprType(_ funcDecl: FunctionDeclSyntax, _ expr: SwiftifyExpr) -
5963
return funcParam.type
6064
case .return:
6165
return funcDecl.signature.returnClause!.type
66+
case .self:
67+
return TypeSyntax(IdentifierTypeSyntax(name: TokenSyntax("Self")))
6268
}
6369
}
6470

@@ -84,6 +90,8 @@ struct CxxSpan: ParamInfo {
8490
case .return:
8591
return CxxSpanReturnThunkBuilder(base: base, signature: funcDecl.signature,
8692
typeMappings: typeMappings, node: original)
93+
case .self:
94+
return base
8795
}
8896
}
8997
}
@@ -118,6 +126,8 @@ struct CountedBy: ParamInfo {
118126
base: base, countExpr: count,
119127
signature: funcDecl.signature,
120128
nonescaping: nonescaping, isSizedBy: sizedBy)
129+
case .self:
130+
return base
121131
}
122132
}
123133
}
@@ -315,8 +325,9 @@ struct FunctionCallBuilder: BoundsCheckedThunkBuilder {
315325
}.map { (i: Int, e: FunctionParameterSyntax) in
316326
e.with(\.type, (argTypes[i] ?? e.type)!)
317327
}
318-
let last = newParams.popLast()!
319-
newParams.append(last.with(\.trailingComma, nil))
328+
if let last = newParams.popLast() {
329+
newParams.append(last.with(\.trailingComma, nil))
330+
}
320331

321332
var sig = base.signature.with(\.parameterClause.parameters, FunctionParameterListSyntax(newParams))
322333
if returnType != nil {
@@ -755,9 +766,10 @@ public struct SwiftifyImportMacro: PeerMacro {
755766
let pointerParamIndex: Int = try getIntLiteralValue(pointerParamIndexArg.expression)
756767
return .param(pointerParamIndex)
757768
case "return": return .return
769+
case "self": return .`self`
758770
default:
759771
throw DiagnosticError(
760-
"expected 'param' or 'return', got '\(enumName)'",
772+
"expected 'param', 'return', or 'self', got '\(enumName)'",
761773
node: expr)
762774
}
763775
}
@@ -823,7 +835,11 @@ public struct SwiftifyImportMacro: PeerMacro {
823835
static func parseLifetimeDependence(_ enumConstructorExpr: FunctionCallExprSyntax) throws -> (SwiftifyExpr, LifetimeDependence) {
824836
let argumentList = enumConstructorExpr.arguments
825837
let pointer: SwiftifyExpr = try parseSwiftifyExpr(try getArgumentByName(argumentList, "pointer"))
826-
let dependsOn: Int = try getIntLiteralValue(try getArgumentByName(argumentList, "dependsOn"))
838+
let dependsOnArg = try getArgumentByName(argumentList, "dependsOn")
839+
let dependsOn: SwiftifyExpr = try parseSwiftifyExpr(dependsOnArg)
840+
if dependsOn == .`return` {
841+
throw DiagnosticError("lifetime cannot depend on the return value", node: dependsOnArg)
842+
}
827843
let type = try getArgumentByName(argumentList, "type")
828844
let depType: DependenceType
829845
switch try parseEnumName(type) {
@@ -917,8 +933,9 @@ public struct SwiftifyImportMacro: PeerMacro {
917933
let (expr, dependence) = try parseLifetimeDependence(enumConstructorExpr)
918934
lifetimeDependencies[expr, default: []].append(dependence)
919935
// We assume pointers annotated with lifetimebound do not escape.
920-
if dependence.type == DependenceType.copy {
921-
nonescapingPointers.insert(dependence.dependsOn)
936+
let fromIdx = paramOrReturnIndex(dependence.dependsOn)
937+
if dependence.type == DependenceType.copy && fromIdx != 0 {
938+
nonescapingPointers.insert(fromIdx)
922939
}
923940
// The escaping is controlled when a parameter is the target of a lifetimebound.
924941
// So we want to do the transformation to Swift's Span.
@@ -987,13 +1004,16 @@ public struct SwiftifyImportMacro: PeerMacro {
9871004
"multiple _SwiftifyInfos referring to return value: \(pointerInfo) and \(ret!)", node: pointerInfo.original)
9881005
}
9891006
ret = pointerInfo
1007+
case .self:
1008+
throw DiagnosticError("do not annotate self", node: pointerInfo.original)
9901009
}
9911010
}
9921011
}
9931012

9941013
static func paramOrReturnIndex(_ expr: SwiftifyExpr) -> Int {
9951014
switch expr {
9961015
case .param(let i): return i
1016+
case .`self`: return 0
9971017
case .return: return -1
9981018
}
9991019
}
@@ -1029,7 +1049,7 @@ public struct SwiftifyImportMacro: PeerMacro {
10291049
DeclReferenceExprSyntax(baseName: TokenSyntax("borrow"))))
10301050
}
10311051
args.append(LabeledExprSyntax(expression:
1032-
DeclReferenceExprSyntax(baseName: TokenSyntax(tryGetParamName(funcDecl, .param(dependence.dependsOn)))!),
1052+
DeclReferenceExprSyntax(baseName: TokenSyntax(tryGetParamName(funcDecl, dependence.dependsOn))!),
10331053
trailingComma: .commaToken()))
10341054
}
10351055
args[args.count - 1] = args[args.count - 1].with(\.trailingComma, nil)

stdlib/public/core/SwiftifyImport.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
public enum _SwiftifyExpr {
22
case param(_ index: Int)
33
case `return`
4+
case `self`
45
}
56

67
public enum _DependenceType {
@@ -41,7 +42,7 @@ public enum _SwiftifyInfo {
4142
case nonescaping(pointer: _SwiftifyExpr)
4243
/// Can express lifetime dependencies between inputs and outputs of a function.
4344
/// 'dependsOn' is the input on which the output 'pointer' depends.
44-
case lifetimeDependence(dependsOn: Int, pointer: _SwiftifyExpr, type: _DependenceType)
45+
case lifetimeDependence(dependsOn: _SwiftifyExpr, pointer: _SwiftifyExpr, type: _DependenceType)
4546
}
4647

4748
/// Generates a safe wrapper for function with Unsafe[Mutable][Raw]Pointer[?] or std::span arguments.

test/Interop/Cxx/stdlib/Inputs/std-span.h

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ inline SpanOfInt initSpan(int arr[], size_t size) {
5454
return SpanOfInt(arr, size);
5555
}
5656

57+
struct DependsOnSelf {
58+
std::vector<int> v;
59+
__attribute__((swift_name("get()")))
60+
ConstSpanOfInt get() [[clang::lifetimebound]] { return ConstSpanOfInt(v.data(), v.size()); }
61+
};
62+
5763
inline struct SpanBox getStructSpanBox() { return {iarray, iarray, sarray, sarray}; }
5864

5965
inline void funcWithSafeWrapper(ConstSpanOfInt s [[clang::noescape]]) {}

test/Interop/Cxx/stdlib/std-span-interface.swift

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import StdSpan
1414
#endif
1515
import CxxStdlib
1616

17+
// CHECK: struct DependsOnSelf {
18+
// CHECK: @lifetime(borrow self)
19+
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func get() -> Span<CInt>
20+
// CHECK-NEXT: mutating func get() -> ConstSpanOfInt
21+
1722
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
1823
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: borrowing ConstSpanOfInt) -> ConstSpanOfInt
1924
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt

test/Macros/SwiftifyImport/CxxSpan/LifetimeboundSpan.swift

+14-4
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,27 @@ import StdSpan
1313

1414
public struct VecOfInt {}
1515

16-
@_SwiftifyImport(.lifetimeDependence(dependsOn: 1, pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
16+
@_SwiftifyImport(.lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
1717
func myFunc(_ span: SpanOfInt) -> SpanOfInt {
1818
}
1919

20-
@_SwiftifyImport(.lifetimeDependence(dependsOn: 1, pointer: .return, type: .borrow), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
20+
@_SwiftifyImport(.lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .borrow), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
2121
func myFunc2(_ vec: borrowing VecOfInt) -> SpanOfInt {
2222
}
2323

24-
@_SwiftifyImport(.lifetimeDependence(dependsOn: 1, pointer: .return, type: .copy), .lifetimeDependence(dependsOn: 2, pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
24+
@_SwiftifyImport(.lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy), .lifetimeDependence(dependsOn: .param(2), pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
2525
func myFunc3(_ span1: SpanOfInt, _ span2: SpanOfInt) -> SpanOfInt {
2626
}
2727

28-
@_SwiftifyImport(.lifetimeDependence(dependsOn: 1, pointer: .return, type: .borrow), .lifetimeDependence(dependsOn: 2, pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
28+
@_SwiftifyImport(.lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .borrow), .lifetimeDependence(dependsOn: .param(2), pointer: .return, type: .copy), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
2929
func myFunc4(_ vec: borrowing VecOfInt, _ span: SpanOfInt) -> SpanOfInt {
3030
}
3131

32+
struct X {
33+
@_SwiftifyImport(.lifetimeDependence(dependsOn: .self, pointer: .return, type: .borrow), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
34+
func myFunc5() -> SpanOfInt {}
35+
}
36+
3237
// CHECK: @_alwaysEmitIntoClient @lifetime(span)
3338
// CHECK-NEXT: func myFunc(_ span: Span<CInt>) -> Span<CInt> {
3439
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc(SpanOfInt(span)))
@@ -48,3 +53,8 @@ func myFunc4(_ vec: borrowing VecOfInt, _ span: SpanOfInt) -> SpanOfInt {
4853
// CHECK-NEXT: func myFunc4(_ vec: borrowing VecOfInt, _ span: Span<CInt>) -> Span<CInt> {
4954
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc4(vec, SpanOfInt(span)))
5055
// CHECK-NEXT: }
56+
57+
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow self)
58+
// CHECK-NEXT: func myFunc5() -> Span<CInt> {
59+
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc5())
60+
// CHECK-NEXT: }

test/abi/macOS/arm64/stdlib.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -802,14 +802,15 @@ Added: _$ss7RawSpanVN
802802
// _SwiftifyInfo enum for _SwiftifyImports macro
803803
Added: _$ss13_SwiftifyExprO5paramyABSicABmFWC
804804
Added: _$ss13_SwiftifyExprO6returnyA2BmFWC
805+
Added: _$ss13_SwiftifyExprO4selfyA2BmFWC
805806
Added: _$ss13_SwiftifyExprOMa
806807
Added: _$ss13_SwiftifyExprOMn
807808
Added: _$ss13_SwiftifyExprON
808809
Added: _$ss13_SwiftifyInfoO11nonescapingyABs01_A4ExprO_tcABmFWC
809810
Added: _$ss13_SwiftifyInfoO7endedByyABs01_A4ExprO_SitcABmFWC
810811
Added: _$ss13_SwiftifyInfoO7sizedByyABs01_A4ExprO_SStcABmFWC
811812
Added: _$ss13_SwiftifyInfoO9countedByyABs01_A4ExprO_SStcABmFWC
812-
Added: _$ss13_SwiftifyInfoO18lifetimeDependenceyABSi_s01_A4ExprOs01_D4TypeOtcABmFWC
813+
Added: _$ss13_SwiftifyInfoO18lifetimeDependenceyABs01_A4ExprO_AEs01_D4TypeOtcABmFWC
813814
Added: _$ss13_SwiftifyInfoOMa
814815
Added: _$ss13_SwiftifyInfoOMn
815816
Added: _$ss13_SwiftifyInfoON

test/abi/macOS/x86_64/stdlib.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -803,14 +803,15 @@ Added: _$ss7RawSpanVN
803803
// _SwiftifyInfo enum for _SwiftifyImports macro
804804
Added: _$ss13_SwiftifyExprO5paramyABSicABmFWC
805805
Added: _$ss13_SwiftifyExprO6returnyA2BmFWC
806+
Added: _$ss13_SwiftifyExprO4selfyA2BmFWC
806807
Added: _$ss13_SwiftifyExprOMa
807808
Added: _$ss13_SwiftifyExprOMn
808809
Added: _$ss13_SwiftifyExprON
809810
Added: _$ss13_SwiftifyInfoO11nonescapingyABs01_A4ExprO_tcABmFWC
810811
Added: _$ss13_SwiftifyInfoO7endedByyABs01_A4ExprO_SitcABmFWC
811812
Added: _$ss13_SwiftifyInfoO7sizedByyABs01_A4ExprO_SStcABmFWC
812813
Added: _$ss13_SwiftifyInfoO9countedByyABs01_A4ExprO_SStcABmFWC
813-
Added: _$ss13_SwiftifyInfoO18lifetimeDependenceyABSi_s01_A4ExprOs01_D4TypeOtcABmFWC
814+
Added: _$ss13_SwiftifyInfoO18lifetimeDependenceyABs01_A4ExprO_AEs01_D4TypeOtcABmFWC
814815
Added: _$ss13_SwiftifyInfoOMa
815816
Added: _$ss13_SwiftifyInfoOMn
816817
Added: _$ss13_SwiftifyInfoON

0 commit comments

Comments
 (0)