-
Notifications
You must be signed in to change notification settings - Fork 10.5k
PrintAsClang: Print a C block in the compatibility header for @cdecl
functions
#80917
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
Changes from all commits
d5b3132
e65a1fb
02933b5
bcbdfee
a55b190
20e1ac6
1b0a3d2
3623c1d
5e7887d
0f98021
f6dd432
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/// Similar test to cdecl-official but gated to objc-interop compatibility | ||
|
||
// RUN: %empty-directory(%t) | ||
// RUN: split-file %S/cdecl-official.swift %t --leading-lines | ||
|
||
/// Generate cdecl.h | ||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) \ | ||
// RUN: %t/Lib.swift -emit-module -verify -o %t -emit-module-doc \ | ||
// RUN: -emit-clang-header-path %t/cdecl.h \ | ||
// RUN: -enable-experimental-feature CDecl | ||
|
||
/// Check cdecl.h directly | ||
// RUN: %check-in-clang %t/cdecl.h | ||
// RUN: %check-in-clang-cxx %t/cdecl.h | ||
|
||
/// Build an Objective-C client against cdecl.h | ||
// RUN: %clang -c %t/Client.c -fmodules -I %t \ | ||
// RUN: -F %S/../Inputs/clang-importer-sdk-path/frameworks \ | ||
// RUN: -I %clang-include-dir -Werror \ | ||
// RUN: -isysroot %S/../Inputs/clang-importer-sdk | ||
|
||
// REQUIRES: swift_feature_CDecl | ||
// REQUIRES: objc_interop |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// RUN: %empty-directory(%t) | ||
// RUN: split-file %s %t --leading-lines | ||
|
||
/// Generate cdecl.h | ||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) \ | ||
// RUN: %t/Lib.swift -emit-module -verify -o %t -emit-module-doc \ | ||
// RUN: -emit-clang-header-path %t/cdecl.h \ | ||
// RUN: -enable-experimental-feature CDecl | ||
|
||
/// Check cdecl.h directly | ||
// RUN: %FileCheck %s --input-file %t/cdecl.h | ||
// RUN: %check-in-clang-c %t/cdecl.h -Wnullable-to-nonnull-conversion | ||
|
||
/// Build a client against cdecl.h | ||
// RUN: %clang-no-modules -c %t/Client.c -I %t \ | ||
// RUN: -F %S/../Inputs/clang-importer-sdk-path/frameworks \ | ||
// RUN: -I %clang-include-dir -Werror \ | ||
// RUN: -isysroot %S/../Inputs/clang-importer-sdk | ||
|
||
// REQUIRES: swift_feature_CDecl | ||
|
||
//--- Lib.swift | ||
|
||
// CHECK-NOT: assume_nonnull | ||
|
||
// CHECK: #if defined(__cplusplus) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strongly recommend adding test cases that require an import and then testing the imports you get. Remember, to be compatible with non-clang compilers, official cdecl needs to not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, C includes with require some new logic to the printing component. |
||
// CHECK: extern "C" { | ||
// CHECK: #endif | ||
|
||
/// My documentation | ||
@cdecl("simple") | ||
func a_simple(x: Int, bar y: Int) -> Int { return x } | ||
// CHECK-LABEL: // My documentation | ||
// CHECK-LABEL: SWIFT_EXTERN ptrdiff_t simple(ptrdiff_t x, ptrdiff_t y) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT; | ||
|
||
@cdecl("primitiveTypes") | ||
public func b_primitiveTypes(i: Int, ci: CInt, l: CLong, c: CChar, f: Float, d: Double, b: Bool) {} | ||
// CHECK-LABEL: SWIFT_EXTERN void primitiveTypes(ptrdiff_t i, int ci, long l, char c, float f, double d, bool b) SWIFT_NOEXCEPT; | ||
|
||
@cdecl("has_keyword_arg_names") | ||
func c_keywordArgNames(auto: Int, union: Int) {} | ||
// CHECK-LABEL: SWIFT_EXTERN void has_keyword_arg_names(ptrdiff_t auto_, ptrdiff_t union_) SWIFT_NOEXCEPT; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add test cases for various pointer types: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, I'm taking note of these. I plan on adding more test and type-checking around the types accepted by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already get the desired behavior so I've added tests for pointer types and nullability to this PR. |
||
|
||
@cdecl("return_never") | ||
func d_returnNever() -> Never { fatalError() } | ||
// CHECK-LABEL: SWIFT_EXTERN void return_never(void) SWIFT_NOEXCEPT SWIFT_NORETURN; | ||
|
||
/// Pointer types | ||
// CHECK: /// Pointer types | ||
|
||
@cdecl("pointers") | ||
func f_pointers(_ x: UnsafeMutablePointer<Int>, | ||
y: UnsafePointer<Int>, | ||
z: UnsafeMutableRawPointer, | ||
w: UnsafeRawPointer, | ||
u: OpaquePointer) {} | ||
// CHECK: SWIFT_EXTERN void pointers(ptrdiff_t * _Nonnull x, ptrdiff_t const * _Nonnull y, void * _Nonnull z, void const * _Nonnull w, void * _Nonnull u) SWIFT_NOEXCEPT; | ||
|
||
@cdecl("nullable_pointers") | ||
func g_nullablePointers(_ x: UnsafeMutableRawPointer, | ||
y: UnsafeMutableRawPointer?, | ||
z: UnsafeMutableRawPointer!) {} | ||
// CHECK: SWIFT_EXTERN void nullable_pointers(void * _Nonnull x, void * _Nullable y, void * _Null_unspecified z) SWIFT_NOEXCEPT; | ||
|
||
// CHECK: #if defined(__cplusplus) | ||
// CHECK-NEXT: } | ||
// CHECK-NEXT: #endif | ||
|
||
//--- Client.c | ||
|
||
#include "cdecl.h" | ||
|
||
int main() { | ||
ptrdiff_t x = simple(42, 43); | ||
primitiveTypes(1, 2, 3, 'a', 1.0f, 2.0, true); | ||
has_keyword_arg_names(1, 2); | ||
return_never(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/// Ensure we print @cdecl and @_cdecl only once. | ||
|
||
// RUN: %empty-directory(%t) | ||
|
||
/// Generate cdecl.h | ||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) \ | ||
// RUN: %s -emit-module -verify -o %t -emit-module-doc \ | ||
// RUN: -emit-objc-header-path %t/cdecl.h \ | ||
// RUN: -disable-objc-attr-requires-foundation-module \ | ||
// RUN: -enable-experimental-feature CDecl | ||
|
||
/// Check cdecl.h directly | ||
// RUN: %FileCheck %s --input-file %t/cdecl.h | ||
// RUN: %check-in-clang %t/cdecl.h | ||
// RUN: %check-in-clang-c %t/cdecl.h -Wnullable-to-nonnull-conversion | ||
// RUN: %check-in-clang-cxx %t/cdecl.h | ||
|
||
// REQUIRES: swift_feature_CDecl | ||
// REQUIRES: objc_interop | ||
|
||
@cdecl("cFunc") | ||
func cFunc() { } | ||
// CHECK: cFunc | ||
// CHECK-NOT: cFunc | ||
|
||
/// The class would break C parsing if printed in wrong block | ||
@objc | ||
class ObjCClass {} | ||
|
||
@_cdecl("objcFunc") | ||
func objcFunc() -> ObjCClass! { return ObjCClass() } | ||
// CHECK: objcFunc | ||
// CHECK-NOT: objcFunc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you’re in C++ or ObjC mode, are there going to be two sets of imports? Do both of them actually get printed? What if there’s overlap between them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept the logic collecting imports as part of the boilerplate when I set up the C block but not the imports printing part. I don't expect it to collect anything at this point and it's unclear to me if we'll need to print imports for C in the future. Maybe for imported
@cdecl enums
or eventually some form of@cdecl struct
, but even then we may have to print a local copy as we wouldn't know what header to import. Do you see other scenarios where we'd need imports for C?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imports come up when a declaration uses a type from another (C) library. For instance, suppose you have this header:
And you write this Swift file:
The ToasterKit generated header will need to use
CTTimeSetting
, which means it has to import the header it came from:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes perfect sense. I've added imported types to the pitch already and plan on adding support for C includes in a future PR.