Skip to content

[Swiftify][ClangImporter] Import noescape attribute for parameters #78713

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 2 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8912,6 +8912,9 @@ void ClangImporter::Implementation::importBoundsAttributes(
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
if (auto CAT = param->getType()->getAs<clang::CountAttributedType>()) {
printer.printCountedBy(CAT, index);
if (param->hasAttr<clang::NoEscapeAttr>()) {
printer.printNonEscaping(index);
}
}
}
if (auto CAT =
Expand Down
22 changes: 22 additions & 0 deletions test/Interop/C/swiftify-import/Inputs/counted-by-noescape.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#define __counted_by(x) __attribute__((__counted_by__(x)))
#define __noescape __attribute__((noescape))

void simple(int len, int * __counted_by(len) __noescape p);

void swiftAttr(int len, int *p) __attribute__((
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"), .nonescaping(pointer: .param(2)))")));

void shared(int len, int * __counted_by(len) __noescape p1, int * __counted_by(len) __noescape p2);

void complexExpr(int len, int offset, int * __counted_by(len - offset) __noescape p);

void nullUnspecified(int len, int * __counted_by(len) _Null_unspecified __noescape p);

void nonnull(int len, int * __counted_by(len) _Nonnull __noescape p);

//void nullable(int len, int * __counted_by(len) _Nullable p);

int * __counted_by(len) __noescape returnPointer(int len);

8 changes: 8 additions & 0 deletions test/Interop/C/swiftify-import/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ module CountedByClang {
header "counted-by.h"
export *
}
module CountedByNoEscapeClang {
header "counted-by-noescape.h"
export *
}
module SizedByClang {
header "sized-by.h"
export *
}
module SizedByNoEscapeClang {
header "sized-by-noescape.h"
export *
}

26 changes: 26 additions & 0 deletions test/Interop/C/swiftify-import/Inputs/sized-by-noescape.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#define __sized_by(x) __attribute__((__sized_by__(x)))
#define __noescape __attribute__((noescape))

void simple(int len, const void * __sized_by(len) __noescape p);

void swiftAttr(int len, const void *p) __attribute__((swift_attr(
"@_SwiftifyImport(.sizedBy(pointer: .param(2), size: \"len\"), .nonescaping(pointer: .param(2)))")));

void shared(int len, const void * __sized_by(len) __noescape p1, const void * __sized_by(len) __noescape p2);

void complexExpr(int len, int offset, const void * __sized_by(len - offset) __noescape p);

void nullUnspecified(int len, const void * __sized_by(len) __noescape _Null_unspecified p);

void nonnull(int len, const void * __sized_by(len) __noescape _Nonnull p);

// Nullable ~Escapable types not supported yet
//void nullable(int len, const void * __sized_by(len) __noescape _Nullable p);

const void * __sized_by(len) __noescape _Nonnull returnPointer(int len);

typedef struct foo opaque_t;
void opaque(int len, opaque_t * __sized_by(len) __noescape p);

2 changes: 2 additions & 0 deletions test/Interop/C/swiftify-import/Inputs/sized-by.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ void nonnull(int len, void * __sized_by(len) _Nonnull p);

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

void * __sized_by(len) returnPointer(int len);

typedef struct foo opaque_t;
void opaque(int len, opaque_t * __sized_by(len) p);
27 changes: 27 additions & 0 deletions test/Interop/C/swiftify-import/counted-by-noescape.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_Span

// 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

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

// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __counted_by __noescape parameters.

import CountedByNoEscapeClang

// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: MutableSpan<Int{{.*}}>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: MutableSpan<Int{{.*}}>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: MutableSpan<Int{{.*}}>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: MutableSpan<Int{{.*}}>, _ p2: MutableSpan<Int{{.*}}>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: MutableSpan<Int{{.*}}>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: MutableSpan<Int{{.*}}>)

@inlinable
public func callReturnPointer() {
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
}

20 changes: 20 additions & 0 deletions test/Interop/C/swiftify-import/sized-by-noescape.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_Span

// 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

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

// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __noescape parameters.
import SizedByNoEscapeClang

// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)
3 changes: 2 additions & 1 deletion test/Interop/C/swiftify-import/sized-by.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

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

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