Skip to content

Commit b33ab5f

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 b33ab5f

File tree

2 files changed

+42
-26
lines changed

2 files changed

+42
-26
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 36 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() &&
@@ -2437,6 +2411,42 @@ namespace {
24372411
ctors.push_back(valueCtor);
24382412
}
24392413

2414+
// Add default constructor for the struct if compiling in C mode.
2415+
// If we're compiling for C++:
2416+
// 1. If a default constructor is declared, don't synthesize one.
2417+
// 2. If a default constructor is deleted, don't try to synthesize one.
2418+
// 3. If there is no default constructor, synthesize a C-like default
2419+
// constructor that zero-initializes the backing memory of the
2420+
// struct. This is important to maintain source compatibility when a
2421+
// client enables C++ interop in an existing project that uses C
2422+
// interop and might rely on the fact that C structs have a default
2423+
// constructor available in Swift.
2424+
bool needsEmptyInitializer = true;
2425+
if (cxxRecordDecl) {
2426+
if (auto structResult = dyn_cast<StructDecl>(result)) {
2427+
for (auto constructorDecl : ctors) {
2428+
if (constructorDecl->getParameters()->size() == 0) {
2429+
needsEmptyInitializer = false;
2430+
break;
2431+
}
2432+
}
2433+
}
2434+
}
2435+
if (hasZeroInitializableStorage && needsEmptyInitializer) {
2436+
ConstructorDecl *defaultCtor =
2437+
synthesizer.createDefaultConstructor(result);
2438+
ctors.push_back(defaultCtor);
2439+
if (cxxRecordDecl) {
2440+
auto attr = AvailableAttr::createPlatformAgnostic(
2441+
defaultCtor->getASTContext(),
2442+
"This zero-initializes the backing memory of the struct, which "
2443+
"is unsafe for some C++ structs. Consider adding an explicit "
2444+
"default initializer for this C++ struct.",
2445+
"", PlatformAgnosticAvailabilityKind::Deprecated);
2446+
defaultCtor->getAttrs().add(attr);
2447+
}
2448+
}
2449+
24402450
// Do not allow Swift to construct foreign reference types (at least, not
24412451
// yet).
24422452
if (isa<StructDecl>(result)) {
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)