[cxx-interop] noexcept specifier before function attributes (#74780)

In #74516 the `SWIFT_NOEXCEPT` specifier is added to the imported Swift
functions in C++ mode, but it is added after the function attributes. It seems
that the tests only do `-fsyntax-only`, which seems not to catch an error like
"expected function body after function declarator" when the header is
used without that flag.

Flip the attributes and the specifier around in the printer, and flip
them in all the tests.

The tests were using `%check-in-clang`, but it only checks importing as
an objective-c-header. Add a parallel `%check-in-clang-cxx` to test also
in C++. It uses C++17 because of some details in the imported headers and
disables a warning about variadic macros that was promoted to an error
and was blocking passing the tests. The clang-importer-sdk gets the
minimal set of files to compile the two modified tests as C++. The files
are mostly empty, except `cstddef` that imports the equivalent C header.
Some modifications were needed in `ctypes.h` because the header was
using features only available in C and not C++.
This commit is contained in:
Daniel Rodríguez Troitiño
2024-06-27 22:49:03 -07:00
committed by GitHub
parent b1fc313f22
commit 00e866ae53
11 changed files with 31 additions and 8 deletions

View File

@@ -1440,8 +1440,8 @@ private:
assert(FD->getAttrs().hasAttribute<CDeclAttr>() && "not a cdecl function");
os << "SWIFT_EXTERN ";
printFunctionDeclAsCFunctionDecl(FD, FD->getCDeclName(), resultTy);
printFunctionClangAttributes(FD, funcTy);
os << " SWIFT_NOEXCEPT";
printFunctionClangAttributes(FD, funcTy);
printAvailability(FD);
os << ";\n";
}

View File

@@ -0,0 +1,6 @@
#ifndef _LIBCPP_CSTDDEF
#define _LIBCPP_CSTDDEF
#include <stddef.h>
#endif

View File

@@ -242,7 +242,10 @@ typedef OpaqueTypedefForFP2 (*FunctionPointerReturningOpaqueTypedef2)(void);
size_t returns_size_t();
// This will probably never be serializable.
#if !defined(__cplusplus)
// C++ error: unnamed struct cannot be defined in the result type of a function
typedef struct { int x; int y; } *(*UnserializableFunctionPointer)(void);
#endif
//===---
// Unions
@@ -308,7 +311,10 @@ typedef struct ModRM {
// Arrays
//===---
void useArray(char x[4], char y[], char z[][8]);
#if !defined(__cplusplus)
// error: static array size is a C99 feature, not permitted in C++
void staticBoundsArray(const char x[static 4]);
#endif
void useBigArray(char max_size[4096], char max_size_plus_one[4097]);
void useBigArray2d(char max_size[][4096], char max_size_plus_one[][4097]);

View File

@@ -2,6 +2,7 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -parse-as-library -emit-objc-header-path %t/swift.h
// RUN: %FileCheck %s < %t/swift.h
// RUN: %check-in-clang %t/swift.h
// RUN: %check-in-clang-cxx %t/swift.h
// REQUIRES: objc_interop
@@ -12,7 +13,7 @@ import Foundation
// CHECK-NOT: @import Foundation;
// CHECK: @class Bee;
// CHECK-LABEL: Bee * _Nonnull fwd_declares_bee(void) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: Bee * _Nonnull fwd_declares_bee(void) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
@_cdecl("fwd_declares_bee")
public func fwdDeclaresBee() -> Bee { fatalError() }

View File

@@ -4,18 +4,19 @@
// RUN: %FileCheck %s < %t/cdecl.h
// RUN: %check-in-clang %t/cdecl.h
// RUN: %check-in-clang -fno-modules -Qunused-arguments %t/cdecl.h -include ctypes.h -include CoreFoundation.h
// RUN: %check-in-clang-cxx -fno-modules -Qunused-arguments %t/cdecl.h -include ctypes.h -include CoreFoundation.h
// REQUIRES: objc_interop
// CHECK: /// What a nightmare!
// CHECK-LABEL: SWIFT_EXTERN double (^ _Nonnull block_nightmare(SWIFT_NOESCAPE float (^ _Nonnull x)(NSInteger)))(char) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN double (^ _Nonnull block_nightmare(SWIFT_NOESCAPE float (^ _Nonnull x)(NSInteger)))(char) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
/// What a nightmare!
@_cdecl("block_nightmare")
public func block_nightmare(x: @convention(block) (Int) -> Float)
-> @convention(block) (CChar) -> Double { return { _ in 0 } }
// CHECK-LABEL: SWIFT_EXTERN double (^ _Nonnull block_recurring_nightmare(float (^ _Nonnull x)(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(double))))(SWIFT_NOESCAPE char (^ _Nonnull)(unsigned char)) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN double (^ _Nonnull block_recurring_nightmare(float (^ _Nonnull x)(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(double))))(SWIFT_NOESCAPE char (^ _Nonnull)(unsigned char)) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
@_cdecl("block_recurring_nightmare")
public func block_recurring_nightmare(x: @escaping @convention(block) (@convention(block) (Double) -> Int) -> Float)
-> @convention(block) (_ asdfasdf: @convention(block) (CUnsignedChar) -> CChar) -> Double {
@@ -26,12 +27,12 @@ public func block_recurring_nightmare(x: @escaping @convention(block) (@conventi
@_cdecl("foo_bar")
func foo(x: Int, bar y: Int) {}
// CHECK-LABEL: SWIFT_EXTERN double (* _Nonnull function_pointer_nightmare(float (* _Nonnull x)(NSInteger)))(char) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN double (* _Nonnull function_pointer_nightmare(float (* _Nonnull x)(NSInteger)))(char) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
@_cdecl("function_pointer_nightmare")
func function_pointer_nightmare(x: @convention(c) (Int) -> Float)
-> @convention(c) (CChar) -> Double { return { _ in 0 } }
// CHECK-LABEL: SWIFT_EXTERN double (* _Nonnull function_pointer_recurring_nightmare(float (* _Nonnull x)(NSInteger (* _Nonnull)(double))))(char (* _Nonnull)(unsigned char)) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN double (* _Nonnull function_pointer_recurring_nightmare(float (* _Nonnull x)(NSInteger (* _Nonnull)(double))))(char (* _Nonnull)(unsigned char)) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
@_cdecl("function_pointer_recurring_nightmare")
public func function_pointer_recurring_nightmare(x: @escaping @convention(c) (@convention(c) (Double) -> Int) -> Float)
-> @convention(c) (@convention(c) (CUnsignedChar) -> CChar) -> Double {
@@ -45,11 +46,11 @@ func keywordArgNames(auto: Int, union: Int) {}
@objc
class C {}
// CHECK-LABEL: SWIFT_EXTERN C * _Null_unspecified return_iuo(void) SWIFT_WARN_UNUSED_RESULT SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN C * _Null_unspecified return_iuo(void) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
@_cdecl("return_iuo")
func returnIUO() -> C! { return C() }
// CHECK-LABEL: SWIFT_EXTERN void return_never(void) SWIFT_NORETURN SWIFT_NOEXCEPT;
// CHECK-LABEL: SWIFT_EXTERN void return_never(void) SWIFT_NOEXCEPT SWIFT_NORETURN;
@_cdecl("return_never")
func returnNever() -> Never { fatalError() }

View File

@@ -9,3 +9,12 @@ config.substitutions.insert(0, ('%check-in-clang',
'-F %%clang-importer-sdk-path/frameworks '
'-I %%clang-include-dir '
'-isysroot %r/Inputs/clang-importer-sdk' % config.test_source_root) )
config.substitutions.insert(0, ('%check-in-clang-cxx',
'%%clang -fsyntax-only -x objective-c++-header -std=c++17 '
'-fobjc-arc -fmodules -fmodules-validate-system-headers '
'-Weverything -Werror -Wno-unused-macros -Wno-incomplete-module '
'-Wno-auto-import -Wno-c++98-compat-pedantic '
'-F %%clang-importer-sdk-path/frameworks '
'-I %%clang-include-dir '
'-isysroot %r/Inputs/clang-importer-sdk' % config.test_source_root) )