Skip to content

Commit 5cfd426

Browse files
committed
[cxx-interop] Make sure to create empty initializers for C++ structs
The existing synthesis mechanism had a bug: `cxxRecordDecl->hasDefaultConstructor()` returns true for C++ types with an implicit default constructor, for instance, `pthread_mutexattr_t`. rdar://113708880
1 parent f02ca3b commit 5cfd426

File tree

2 files changed

+44
-26
lines changed

2 files changed

+44
-26
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,32 +2381,6 @@ namespace {
23812381
hasMemberwiseInitializer = false;
23822382
}
23832383

2384-
if (hasZeroInitializableStorage &&
2385-
!(cxxRecordDecl && cxxRecordDecl->hasDefaultConstructor())) {
2386-
// Add default constructor for the struct if compiling in C mode.
2387-
// If we're compiling for C++:
2388-
// 1. If a default constructor is declared, don't synthesize one.
2389-
// 2. If a default constructor is deleted, don't try to synthesize one.
2390-
// 3. If there is no default constructor, synthesize a C-like default
2391-
// constructor that zero-initializes the backing memory of the
2392-
// struct. This is important to maintain source compatibility when a
2393-
// client enables C++ interop in an existing project that uses C
2394-
// interop and might rely on the fact that C structs have a default
2395-
// constructor available in Swift.
2396-
ConstructorDecl *defaultCtor =
2397-
synthesizer.createDefaultConstructor(result);
2398-
ctors.push_back(defaultCtor);
2399-
if (cxxRecordDecl) {
2400-
auto attr = AvailableAttr::createPlatformAgnostic(
2401-
defaultCtor->getASTContext(),
2402-
"This zero-initializes the backing memory of the struct, which "
2403-
"is unsafe for some C++ structs. Consider adding an explicit "
2404-
"default initializer for this C++ struct.",
2405-
"", PlatformAgnosticAvailabilityKind::Deprecated);
2406-
defaultCtor->getAttrs().add(attr);
2407-
}
2408-
}
2409-
24102384
bool forceMemberwiseInitializer = false;
24112385
if (cxxRecordDecl && cxxRecordDecl->isInStdNamespace() &&
24122386
cxxRecordDecl->getIdentifier() &&
@@ -2447,6 +2421,44 @@ namespace {
24472421
}
24482422
}
24492423

2424+
// Add default constructor for the struct if compiling in C mode.
2425+
// If we're compiling for C++:
2426+
// 1. If a default constructor is declared, don't synthesize one.
2427+
// 2. If a default constructor is deleted, don't try to synthesize one.
2428+
// 3. If there is no default constructor, synthesize a C-like default
2429+
// constructor that zero-initializes the backing memory of the
2430+
// struct. This is important to maintain source compatibility when a
2431+
// client enables C++ interop in an existing project that uses C
2432+
// interop and might rely on the fact that C structs have a default
2433+
// constructor available in Swift.
2434+
bool needsEmptyInitializer = true;
2435+
if (cxxRecordDecl) {
2436+
if (auto structResult = dyn_cast<StructDecl>(result)) {
2437+
for (auto member : structResult->getMembers()) {
2438+
if (auto constructorDecl = dyn_cast<ConstructorDecl>(member)) {
2439+
if (constructorDecl->getParameters()->size() == 0) {
2440+
needsEmptyInitializer = false;
2441+
break;
2442+
}
2443+
}
2444+
}
2445+
}
2446+
}
2447+
if (hasZeroInitializableStorage && needsEmptyInitializer) {
2448+
ConstructorDecl *defaultCtor =
2449+
synthesizer.createDefaultConstructor(result);
2450+
ctors.push_back(defaultCtor);
2451+
if (cxxRecordDecl) {
2452+
auto attr = AvailableAttr::createPlatformAgnostic(
2453+
defaultCtor->getASTContext(),
2454+
"This zero-initializes the backing memory of the struct, which "
2455+
"is unsafe for some C++ structs. Consider adding an explicit "
2456+
"default initializer for this C++ struct.",
2457+
"", PlatformAgnosticAvailabilityKind::Deprecated);
2458+
defaultCtor->getAttrs().add(attr);
2459+
}
2460+
}
2461+
24502462
if (auto structResult = dyn_cast<StructDecl>(result)) {
24512463
structResult->setHasUnreferenceableStorage(hasUnreferenceableStorage);
24522464
if (isNonTrivialPtrAuth) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-objc-interop -enable-experimental-cxx-interop
2+
// REQUIRES: OS=macosx
3+
4+
import Darwin
5+
6+
_ = pthread_mutexattr_t() // expected-warning {{'init()' is deprecated: This zero-initializes the backing memory of the struct}}

0 commit comments

Comments
 (0)