mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[cxx-interop] Allow using C-like structs in public Swift interfaces
When compiling with C++ interop enabled, we enable extra safety checks to prevent library authors from accidentally exposing ABI-fragile C++ symbols in resilient Swift interfaces. The heuristic we use is overly strict, and it prevents the compiler from being able to typecheck various modules from their interfaces when C++ interop is enabled. Darwin and System are two of such modules. The underlying challenge is that there isn't a good distinction between C structs and C++ structs: whenever parsing a header file in C++ language mode, Clang assumes that every struct is a C++ struct. This relaxes the heuristic to allow exposing C-like structs in resilient interfaces. rdar://140203932
This commit is contained in:
@@ -1885,9 +1885,11 @@ bool isFragileClangNode(const ClangNode &node) {
|
||||
if (auto *typedefDecl = dyn_cast<clang::TypedefNameDecl>(decl))
|
||||
return isFragileClangType(typedefDecl->getUnderlyingType());
|
||||
if (auto *rd = dyn_cast<clang::RecordDecl>(decl)) {
|
||||
if (!isa<clang::CXXRecordDecl>(rd))
|
||||
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(rd);
|
||||
if (!cxxRecordDecl)
|
||||
return false;
|
||||
return !rd->getDeclContext()->isExternCContext();
|
||||
return !cxxRecordDecl->isCLike() &&
|
||||
!cxxRecordDecl->getDeclContext()->isExternCContext();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module MyCLibrary {
|
||||
header "my_c_header.h"
|
||||
export *
|
||||
}
|
||||
3
test/Interop/Cxx/library-evolution/Inputs/my_c_header.h
Normal file
3
test/Interop/Cxx/library-evolution/Inputs/my_c_header.h
Normal file
@@ -0,0 +1,3 @@
|
||||
struct MyCStruct {
|
||||
int x;
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Build a Swift library that uses symbols from a C library without enabling C++ interop.
|
||||
// RUN: %target-build-swift %t/uses-c-library.swift -emit-module -emit-library -enable-library-evolution -module-name UsesCLibrary -emit-module-path %t/artifacts/UsesCLibrary.swiftmodule -emit-module-interface-path %t/artifacts/UsesCLibrary.swiftinterface -I %S/Inputs
|
||||
|
||||
// Make sure the module interface can be type-checked with C++ interop enabled.
|
||||
// RUN: %target-swift-frontend -typecheck-module-from-interface -cxx-interoperability-mode=default %t/artifacts/UsesCLibrary.swiftinterface -I %S/Inputs
|
||||
|
||||
// Make sure we can build a Swift executable that uses the library and enables C++ interop.
|
||||
// RUN: %target-swift-frontend -typecheck -cxx-interoperability-mode=default -module-name Main %t/main.swift -I %t/artifacts -I %S/Inputs
|
||||
|
||||
//--- uses-c-library.swift
|
||||
|
||||
import MyCLibrary
|
||||
|
||||
public func getMyCStruct() -> MyCStruct {
|
||||
return MyCStruct()
|
||||
}
|
||||
|
||||
//--- main.swift
|
||||
|
||||
import UsesCLibrary
|
||||
|
||||
let _ = getMyCStruct()
|
||||
Reference in New Issue
Block a user