Skip to content

Commit da489e1

Browse files
committed
[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 (cherry picked from commit 8859b62)
1 parent 22544f3 commit da489e1

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,9 +1885,11 @@ bool isFragileClangNode(const ClangNode &node) {
18851885
if (auto *typedefDecl = dyn_cast<clang::TypedefNameDecl>(decl))
18861886
return isFragileClangType(typedefDecl->getUnderlyingType());
18871887
if (auto *rd = dyn_cast<clang::RecordDecl>(decl)) {
1888-
if (!isa<clang::CXXRecordDecl>(rd))
1888+
auto cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(rd);
1889+
if (!cxxRecordDecl)
18891890
return false;
1890-
return !rd->getDeclContext()->isExternCContext();
1891+
return !cxxRecordDecl->isCLike() &&
1892+
!cxxRecordDecl->getDeclContext()->isExternCContext();
18911893
}
18921894
return true;
18931895
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module MyCLibrary {
2+
header "my_c_header.h"
3+
export *
4+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct MyCStruct {
2+
int x;
3+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// Build a Swift library that uses symbols from a C library without enabling C++ interop.
5+
// 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
6+
7+
// Make sure the module interface can be type-checked with C++ interop enabled.
8+
// RUN: %target-swift-frontend -typecheck-module-from-interface -cxx-interoperability-mode=default %t/artifacts/UsesCLibrary.swiftinterface -I %S/Inputs
9+
10+
// Make sure we can build a Swift executable that uses the library and enables C++ interop.
11+
// RUN: %target-swift-frontend -typecheck -cxx-interoperability-mode=default -module-name Main %t/main.swift -I %t/artifacts -I %S/Inputs
12+
13+
//--- uses-c-library.swift
14+
15+
import MyCLibrary
16+
17+
public func getMyCStruct() -> MyCStruct {
18+
return MyCStruct()
19+
}
20+
21+
//--- main.swift
22+
23+
import UsesCLibrary
24+
25+
let _ = getMyCStruct()

0 commit comments

Comments
 (0)