Skip to content

Commit 91d7cc4

Browse files
authored
Merge pull request #78761 from swiftlang/gaborh/span-lifetimebound-end-to-end
[cxx-interop] Make ClangImporter support lifetimebound annotated spans
2 parents 795d629 + 042b108 commit 91d7cc4

File tree

4 files changed

+73
-16
lines changed

4 files changed

+73
-16
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8794,6 +8794,14 @@ class SwiftifyInfoPrinter {
87948794
out << ")";
87958795
}
87968796

8797+
void printLifetimeboundReturn(int idx, bool borrow) {
8798+
printSeparator();
8799+
out << ".lifetimeDependence(dependsOn: " << (idx + 1);
8800+
out << ", pointer: .return, type: ";
8801+
out << (borrow ? ".borrow" : ".copy");
8802+
out << ")";
8803+
}
8804+
87978805
void printTypeMapping(const llvm::StringMap<std::string> &mapping) {
87988806
printSeparator();
87998807
out << "typeMappings: [";
@@ -8839,23 +8847,44 @@ void ClangImporter::Implementation::importSpanAttributes(FuncDecl *MappedDecl) {
88398847
llvm::raw_svector_ostream out(MacroString);
88408848
llvm::StringMap<std::string> typeMapping;
88418849

8850+
auto registerSwiftifyMacro =
8851+
[&typeMapping, &attachMacro](ParamDecl *swiftParam,
8852+
const clang::ParmVarDecl *param) {
8853+
typeMapping.insert(std::make_pair(
8854+
swiftParam->getInterfaceType()->getString(),
8855+
swiftParam->getInterfaceType()->getDesugaredType()->getString()));
8856+
attachMacro = true;
8857+
};
88428858
SwiftifyInfoPrinter printer(getClangASTContext(), out);
8859+
auto retDecl = ClangDecl->getReturnType()->getAsTagDecl();
8860+
bool returnIsSpan =
8861+
retDecl && retDecl->isInStdNamespace() && retDecl->getName() == "span";
8862+
if (returnIsSpan) {
8863+
typeMapping.insert(
8864+
std::make_pair(MappedDecl->getResultInterfaceType()->getString(),
8865+
MappedDecl->getResultInterfaceType()
8866+
->getDesugaredType()
8867+
->getString()));
8868+
}
88438869
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
88448870
auto paramTy = param->getType();
88458871
const auto *decl = paramTy->getAsTagDecl();
8846-
if (!decl || !decl->isInStdNamespace())
8847-
continue;
8848-
if (decl->getName() != "span")
8872+
auto swiftParam = MappedDecl->getParameters()->get(index);
8873+
bool isSpan =
8874+
decl && decl->isInStdNamespace() && decl->getName() == "span";
8875+
if (param->hasAttr<clang::LifetimeBoundAttr>() &&
8876+
MappedDecl->getASTContext().LangOpts.hasFeature(
8877+
Feature::LifetimeDependence) &&
8878+
(isSpan || returnIsSpan)) {
8879+
printer.printLifetimeboundReturn(
8880+
index, !isSpan && swiftParam->getInterfaceType()->isEscapable());
8881+
registerSwiftifyMacro(swiftParam, param);
8882+
}
8883+
if (!isSpan)
88498884
continue;
88508885
if (param->hasAttr<clang::NoEscapeAttr>()) {
88518886
printer.printNonEscaping(index);
8852-
clang::PrintingPolicy policy(param->getASTContext().getLangOpts());
8853-
policy.SuppressTagKeyword = true;
8854-
auto param = MappedDecl->getParameters()->get(index);
8855-
typeMapping.insert(std::make_pair(
8856-
paramTy.getAsString(policy),
8857-
param->getInterfaceType()->getDesugaredType()->getString()));
8858-
attachMacro = true;
8887+
registerSwiftifyMacro(swiftParam, param);
88598888
}
88608889
}
88618890
printer.printTypeMapping(typeMapping);

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ func replaceBaseType(_ type: TypeSyntax, _ base: TypeSyntax) -> TypeSyntax {
189189
return base
190190
}
191191

192+
// The generated type names for template instantiations sometimes contain
193+
// a `_const` suffix for diambiguation purposes. We need to remove that.
194+
func dropConstSuffix(_ typeName: String) -> String {
195+
if typeName.hasSuffix("_const") {
196+
return String(typeName.dropLast("_const".count))
197+
}
198+
return typeName
199+
}
200+
192201
func getPointerMutability(text: String) -> Mutability? {
193202
switch text {
194203
case "UnsafePointer": return .Immutable
@@ -372,7 +381,8 @@ struct CxxSpanThunkBuilder: ParamPointerBoundsThunkBuilder {
372381
let parsedDesugaredType = TypeSyntax("\(raw: getUnqualifiedStdName(desugaredType)!)")
373382
let genericArg = TypeSyntax(parsedDesugaredType.as(IdentifierTypeSyntax.self)!
374383
.genericArgumentClause!.arguments.first!.argument)!
375-
types[index] = replaceBaseType(param.type, TypeSyntax("Span<\(raw: try getTypeName(genericArg).text)>"))
384+
types[index] = replaceBaseType(param.type,
385+
TypeSyntax("Span<\(raw: dropConstSuffix(try getTypeName(genericArg).text))>"))
376386
return try base.buildFunctionSignature(types, returnType)
377387
}
378388

@@ -407,7 +417,7 @@ struct CxxSpanReturnThunkBuilder: BoundsCheckedThunkBuilder {
407417
let genericArg = TypeSyntax(parsedDesugaredType.as(IdentifierTypeSyntax.self)!
408418
.genericArgumentClause!.arguments.first!.argument)!
409419
let newType = replaceBaseType(signature.returnClause!.type,
410-
TypeSyntax("Span<\(raw: try getTypeName(genericArg).text)>"))
420+
TypeSyntax("Span<\(raw: dropConstSuffix(try getTypeName(genericArg).text))>"))
411421
return try base.buildFunctionSignature(argTypes, newType)
412422
}
413423

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
#define TEST_INTEROP_CXX_STDLIB_INPUTS_STD_SPAN_H
33

44
#include <cstddef>
5-
#include <string>
65
#include <span>
6+
#include <string>
7+
#include <vector>
78

89
using ConstSpanOfInt = std::span<const int>;
910
using SpanOfInt = std::span<int>;
1011
using ConstSpanOfString = std::span<const std::string>;
1112
using SpanOfString = std::span<std::string>;
13+
using VecOfInt = std::vector<int>;
1214

1315
static int iarray[]{1, 2, 3};
1416
static std::string sarray[]{"", "ab", "abc"};
@@ -54,6 +56,15 @@ inline SpanOfInt initSpan(int arr[], size_t size) {
5456

5557
inline struct SpanBox getStructSpanBox() { return {iarray, iarray, sarray, sarray}; }
5658

57-
void funcWithSafeWrapper(SpanOfInt s [[clang::noescape]]) {}
59+
inline void funcWithSafeWrapper(ConstSpanOfInt s [[clang::noescape]]) {}
60+
61+
inline ConstSpanOfInt funcWithSafeWrapper2(ConstSpanOfInt s
62+
[[clang::lifetimebound]]) {
63+
return s;
64+
}
65+
inline ConstSpanOfInt funcWithSafeWrapper3(const VecOfInt &v
66+
[[clang::lifetimebound]]) {
67+
return ConstSpanOfInt(v.data(), v.size());
68+
}
5869

5970
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_SPAN_H
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature Span -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=StdSpan -source-filename=x -enable-experimental-cxx-interop -Xcc -std=c++20 -module-cache-path %t > %t/interface.swift
2+
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature LifetimeDependence -enable-experimental-feature Span -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=StdSpan -source-filename=x -enable-experimental-cxx-interop -Xcc -std=c++20 -module-cache-path %t > %t/interface.swift
33
// RUN: %FileCheck %s < %t/interface.swift
44

55
// REQUIRES: swift_feature_SafeInteropWrappers
66
// REQUIRES: swift_feature_Span
7+
// REQUIRES: swift_feature_LifetimeDependence
78

89
// FIXME swift-ci linux tests do not support std::span
910
// UNSUPPORTED: OS=linux-gnu
@@ -13,5 +14,11 @@ import StdSpan
1314
#endif
1415
import CxxStdlib
1516

16-
// CHECK: func funcWithSafeWrapper(_ s: SpanOfInt)
17+
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
18+
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: borrowing ConstSpanOfInt) -> ConstSpanOfInt
19+
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt
1720
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
21+
// CHECK-NEXT: @lifetime(s)
22+
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: borrowing Span<CInt>) -> Span<CInt>
23+
// CHECK-NEXT: @lifetime(borrow v)
24+
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>

0 commit comments

Comments
 (0)