Skip to content

Commit 7d7a6c6

Browse files
committed
[cxx-interop] Detect IndirectFields nested in non-importable anon-unions
This patch to the Clang Importer avoids an assert by detecting when an IndirectField belongs to an anonymous union that is not importable. How it does this is by determining if an IndirectFieldDecl's anonymous parent field is non-importable (based on isCxxRecordImportable) and if so skips importing the IndirectFieldDecl. This avoids the mentioned assert because makeIndirectFieldAccessors expects a FieldDecl of __Unnamed_union___Anonymous_field that is only populated when the top-level union is imported from an IndirectFieldDecl's parent. IndirectFieldDecls for the members of an anonymous union are dependent on their parent and should not be imported if their parent can not also be imported. This corner case can happen in cases when an anonymous union contains an ARC pointer, which results in a non-trivial but also inaccessible dtor.
1 parent c417464 commit 7d7a6c6

File tree

5 files changed

+55
-0
lines changed

5 files changed

+55
-0
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,6 +3516,20 @@ namespace {
35163516
Impl.ImportedDecls.end())
35173517
continue;
35183518

3519+
// If we encounter an IndirectFieldDecl, ensure that its parent is
3520+
// importable before attempting to import it because they are dependent
3521+
// when it comes to getter/setter generation.
3522+
if (const auto *ind = dyn_cast<clang::IndirectFieldDecl>(nd)) {
3523+
const clang::CXXRecordDecl *parentUnion =
3524+
(ind->getChainingSize() >= 2)
3525+
? dyn_cast<clang::CXXRecordDecl>(
3526+
ind->getAnonField()->getParent())
3527+
: nullptr;
3528+
if (parentUnion && parentUnion->isAnonymousStructOrUnion() &&
3529+
parentUnion->isUnion() && !isCxxRecordImportable(parentUnion))
3530+
continue;
3531+
}
3532+
35193533
auto member = Impl.importDecl(nd, getActiveSwiftVersion());
35203534
if (!member) {
35213535
if (!isa<clang::TypeDecl>(nd) && !isa<clang::FunctionDecl>(nd)) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@class C;
2+
@interface C
3+
{}
4+
@end
5+
6+
struct S {
7+
union {
8+
C *t;
9+
char c;
10+
};
11+
S(const S &s) {}
12+
~S() { }
13+
int f() { return 42; }
14+
};
15+
16+
S *getSPtr();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module AnonymousUnionPartlyInvalid {
2+
header "anonymous-union-partly-invalid.h"
3+
requires cplusplus
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=AnonymousUnionPartlyInvalid -I %S/Inputs -source-filename=x -enable-cxx-interop -enable-objc-interop | %FileCheck %s
2+
3+
// CHECK: class C {
4+
// CHECK-NEXT: }
5+
// CHECK-NEXT: struct S {
6+
// CHECK-NEXT: mutating func f() -> Int32
7+
// CHECK-NEXT: }
8+
// CHECK-NEXT: func getSPtr() -> UnsafeMutablePointer<S>!
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %swift -I %S/Inputs -enable-cxx-interop -enable-objc-interop -emit-ir %s | %FileCheck %s
2+
3+
import AnonymousUnionPartlyInvalid
4+
5+
let sPtr = getSPtr()
6+
let a = sPtr![0].f()
7+
8+
// CHECK: i32 @main
9+
// CHECK-NEXT: entry:
10+
// CHECK-NEXT: bitcast
11+
// CHECK-NEXT: call %struct.S
12+
// CHECK-NEXT: ptrtoint %struct.S
13+

0 commit comments

Comments
 (0)