Skip to content

Commit fdea6ba

Browse files
authored
[Swiftify][ClangImporter] Import noescape attribute for parameters (#78713)
This passes along the noescape attribute to @_SwiftifyImport as .noescape(pointer: .param(X)). This allows importing parameters as Span, MutableSpan and RawSpan.
1 parent c1915c8 commit fdea6ba

File tree

8 files changed

+110
-1
lines changed

8 files changed

+110
-1
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8912,6 +8912,9 @@ void ClangImporter::Implementation::importBoundsAttributes(
89128912
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
89138913
if (auto CAT = param->getType()->getAs<clang::CountAttributedType>()) {
89148914
printer.printCountedBy(CAT, index);
8915+
if (param->hasAttr<clang::NoEscapeAttr>()) {
8916+
printer.printNonEscaping(index);
8917+
}
89158918
}
89168919
}
89178920
if (auto CAT =
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#define __counted_by(x) __attribute__((__counted_by__(x)))
4+
#define __noescape __attribute__((noescape))
5+
6+
void simple(int len, int * __counted_by(len) __noescape p);
7+
8+
void swiftAttr(int len, int *p) __attribute__((
9+
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"), .nonescaping(pointer: .param(2)))")));
10+
11+
void shared(int len, int * __counted_by(len) __noescape p1, int * __counted_by(len) __noescape p2);
12+
13+
void complexExpr(int len, int offset, int * __counted_by(len - offset) __noescape p);
14+
15+
void nullUnspecified(int len, int * __counted_by(len) _Null_unspecified __noescape p);
16+
17+
void nonnull(int len, int * __counted_by(len) _Nonnull __noescape p);
18+
19+
//void nullable(int len, int * __counted_by(len) _Nullable p);
20+
21+
int * __counted_by(len) __noescape returnPointer(int len);
22+

test/Interop/C/swiftify-import/Inputs/module.modulemap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ module CountedByClang {
22
header "counted-by.h"
33
export *
44
}
5+
module CountedByNoEscapeClang {
6+
header "counted-by-noescape.h"
7+
export *
8+
}
59
module SizedByClang {
610
header "sized-by.h"
711
export *
812
}
13+
module SizedByNoEscapeClang {
14+
header "sized-by-noescape.h"
15+
export *
16+
}
917

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#define __sized_by(x) __attribute__((__sized_by__(x)))
4+
#define __noescape __attribute__((noescape))
5+
6+
void simple(int len, const void * __sized_by(len) __noescape p);
7+
8+
void swiftAttr(int len, const void *p) __attribute__((swift_attr(
9+
"@_SwiftifyImport(.sizedBy(pointer: .param(2), size: \"len\"), .nonescaping(pointer: .param(2)))")));
10+
11+
void shared(int len, const void * __sized_by(len) __noescape p1, const void * __sized_by(len) __noescape p2);
12+
13+
void complexExpr(int len, int offset, const void * __sized_by(len - offset) __noescape p);
14+
15+
void nullUnspecified(int len, const void * __sized_by(len) __noescape _Null_unspecified p);
16+
17+
void nonnull(int len, const void * __sized_by(len) __noescape _Nonnull p);
18+
19+
// Nullable ~Escapable types not supported yet
20+
//void nullable(int len, const void * __sized_by(len) __noescape _Nullable p);
21+
22+
const void * __sized_by(len) __noescape _Nonnull returnPointer(int len);
23+
24+
typedef struct foo opaque_t;
25+
void opaque(int len, opaque_t * __sized_by(len) __noescape p);
26+

test/Interop/C/swiftify-import/Inputs/sized-by.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ void nonnull(int len, void * __sized_by(len) _Nonnull p);
1717

1818
void nullable(int len, void * __sized_by(len) _Nullable p);
1919

20+
void * __sized_by(len) returnPointer(int len);
21+
2022
typedef struct foo opaque_t;
2123
void opaque(int len, opaque_t * __sized_by(len) p);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
// REQUIRES: swift_feature_Span
3+
4+
// RUN: %target-swift-ide-test -print-module -module-to-print=CountedByNoEscapeClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature Span | %FileCheck %s
5+
6+
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
7+
// RUN: %empty-directory(%t)
8+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/CountedByNoEscape.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
9+
10+
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __counted_by __noescape parameters.
11+
12+
import CountedByNoEscapeClang
13+
14+
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: MutableSpan<Int{{.*}}>)
15+
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: MutableSpan<Int{{.*}}>)
16+
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: MutableSpan<Int{{.*}}>)
17+
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
18+
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: MutableSpan<Int{{.*}}>, _ p2: MutableSpan<Int{{.*}}>)
19+
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: MutableSpan<Int{{.*}}>)
20+
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: MutableSpan<Int{{.*}}>)
21+
22+
@inlinable
23+
public func callReturnPointer() {
24+
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
25+
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
26+
}
27+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
// REQUIRES: swift_feature_Span
3+
4+
// RUN: %target-swift-ide-test -print-module -module-to-print=SizedByNoEscapeClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature Span | %FileCheck %s
5+
6+
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
7+
// RUN: %empty-directory(%t)
8+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/SizedByNoEscape.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
9+
10+
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __noescape parameters.
11+
import SizedByNoEscapeClang
12+
13+
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
14+
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
15+
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
16+
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
17+
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
18+
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
19+
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
20+
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)

test/Interop/C/swiftify-import/sized-by.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
66
// RUN: %empty-directory(%t)
7-
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/CountedBy.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
7+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/SizedBy.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s
88

99
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by parameters.
1010
import SizedByClang
@@ -14,6 +14,7 @@ import SizedByClang
1414
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableRawBufferPointer)
1515
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableRawBufferPointer?)
1616
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: UnsafeRawBufferPointer)
17+
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableRawBufferPointer
1718
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableRawBufferPointer, _ p2: UnsafeMutableRawBufferPointer)
1819
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableRawBufferPointer)
1920
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableRawBufferPointer)

0 commit comments

Comments
 (0)