Skip to content

Commit 29e5549

Browse files
committed
[6.2][cxx-interop] Prevent crash when importing a std::optional of nonescapable
When we tried to create a std::optional of a nonescapable type in Swift, the compiler would run into an assertion failure. This is because std::optional has an anonymous union where one of its members would be of this nonescapable type. Turns out that we were not handling anonymous unions with nonescapable members correctly. Fields of anonymous unions are injected to the parent as IndirectFieldDecl, so we need to handle these indirect fields the same way we handle "normal" fields. rdar://156704699
1 parent 3ba22e2 commit 29e5549

File tree

2 files changed

+81
-23
lines changed

2 files changed

+81
-23
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,8 +2377,18 @@ namespace {
23772377
}
23782378

23792379
auto *vd = cast<VarDecl>(member);
2380-
if (!isNonEscapable) {
2381-
if (const auto *fd = dyn_cast<clang::FieldDecl>(nd))
2380+
auto getFieldDecl =
2381+
[](const clang::NamedDecl *decl) -> const clang::FieldDecl * {
2382+
if (const clang::FieldDecl *fd = dyn_cast<clang::FieldDecl>(decl))
2383+
return fd;
2384+
if (const clang::IndirectFieldDecl *ind =
2385+
dyn_cast<clang::IndirectFieldDecl>(decl))
2386+
return ind->getAnonField();
2387+
return nullptr;
2388+
};
2389+
2390+
if (!isNonEscapable && !decl->isAnonymousStructOrUnion()) {
2391+
if (const auto *fd = getFieldDecl(nd)) {
23822392
if (evaluateOrDefault(
23832393
Impl.SwiftContext.evaluator,
23842394
ClangTypeEscapability({fd->getType().getTypePtr(), &Impl}),
@@ -2391,6 +2401,7 @@ namespace {
23912401
decl->getLocation());
23922402
return nullptr;
23932403
}
2404+
}
23942405
}
23952406
members.push_back(vd);
23962407
}

test/Interop/Cxx/class/nonescapable-errors.swift

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Test {
1414
//--- Inputs/nonescapable.h
1515
#include "swift/bridging"
1616
#include <vector>
17+
#include <optional>
1718

1819
struct SWIFT_NONESCAPABLE View {
1920
View() : member(nullptr) {}
@@ -99,54 +100,87 @@ struct SWIFT_ESCAPABLE Invalid {
99100
View v;
100101
};
101102

103+
struct SWIFT_NONESCAPABLE NonEscapable {};
104+
105+
template<typename T>
106+
struct HasAnonUnion {
107+
union {
108+
int known;
109+
T unknown;
110+
};
111+
};
112+
113+
template<typename T>
114+
struct HasAnonStruct {
115+
struct {
116+
int known;
117+
T unknown;
118+
};
119+
};
120+
121+
template<typename T>
122+
struct SWIFT_NONESCAPABLE NonEscapableHasAnonUnion {
123+
union {
124+
int known;
125+
T unknown;
126+
};
127+
};
128+
129+
using HasAnonUnionNonEscapable = HasAnonUnion<NonEscapable>;
130+
using HasAnonStructNonEscapable = HasAnonStruct<NonEscapable>;
131+
using NonEscapableHasAnonUnionNonEscapable = NonEscapableHasAnonUnion<NonEscapable>;
132+
using NonEscapableOptional = std::optional<NonEscapable>;
133+
102134
//--- test.swift
103135
import Test
104136
import CxxStdlib
105137

106138
// CHECK: error: cannot find type 'Invalid' in scope
107139
// CHECK: note: escapable record 'Invalid' cannot have non-escapable field 'v'
140+
// CHECK-NO-LIFETIMES: error: cannot find type 'Invalid' in scope
141+
// CHECK-NO-LIFETIMES: note: escapable record 'Invalid' cannot have non-escapable field 'v'
108142
public func importInvalid(_ x: Invalid) {
109143
}
110144

111145
// CHECK: error: a function with a ~Escapable result needs a parameter to depend on
112-
// CHECK-NO-LIFETIMES: test.swift:11:32: error: a function cannot return a ~Escapable result
146+
// CHECK-NO-LIFETIMES: test.swift:13:32: error: a function cannot return a ~Escapable result
113147
public func noAnnotations() -> View {
114-
// CHECK: nonescapable.h:16:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
115-
// CHECK-NO-LIFETIMES: nonescapable.h:16:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
148+
// CHECK: nonescapable.h:17:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
149+
// CHECK-NO-LIFETIMES: nonescapable.h:17:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
116150
f(nil)
117-
// CHECK: nonescapable.h:20:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
118-
// CHECK-NO-LIFETIMES: nonescapable.h:20:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
151+
// CHECK: nonescapable.h:21:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
152+
// CHECK-NO-LIFETIMES: nonescapable.h:21:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
119153
// No duplicate warning for f2:
120-
// CHECK-NOT: nonescapable.h:20
154+
// CHECK-NOT: nonescapable.h:21
121155
f2(nil, nil)
122-
// CHECK: nonescapable.h:24:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
123-
// CHECK-NO-LIFETIMES: nonescapable.h:24:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
124-
// CHECK-NO-LIFETIMES: nonescapable.h:24:6: error: a function cannot return a ~Escapable result
156+
// CHECK: nonescapable.h:25:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
157+
// CHECK-NO-LIFETIMES: nonescapable.h:25:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
158+
// CHECK-NO-LIFETIMES: nonescapable.h:25:6: error: a function cannot return a ~Escapable result
125159
g(nil)
126160
h1(nil)
127-
// CHECK-NO-LIFETIMES: nonescapable.h:34:21: error: a function cannot return a ~Escapable result
128-
h2(nil)
129161
// CHECK-NO-LIFETIMES: nonescapable.h:35:21: error: a function cannot return a ~Escapable result
162+
h2(nil)
163+
// CHECK-NO-LIFETIMES: nonescapable.h:36:21: error: a function cannot return a ~Escapable result
130164
h3(nil)
131165
i1()
132-
// CHECK: nonescapable.h:39:39: error: template parameter 'Missing' does not exist
133-
// CHECK-NO-LIFETIMES: nonescapable.h:39:39: error: template parameter 'Missing' does not exist
166+
// CHECK: nonescapable.h:40:39: error: template parameter 'Missing' does not exist
167+
// CHECK-NO-LIFETIMES: nonescapable.h:40:39: error: template parameter 'Missing' does not exist
134168
i2()
135-
// CHECK: nonescapable.h:45:33: error: template parameter 'S' expected to be a type parameter
136-
// CHECK-NO-LIFETIMES: nonescapable.h:45:33: error: template parameter 'S' expected to be a type parameter
169+
// CHECK: nonescapable.h:46:33: error: template parameter 'S' expected to be a type parameter
170+
// CHECK-NO-LIFETIMES: nonescapable.h:46:33: error: template parameter 'S' expected to be a type parameter
137171
j1()
138-
// CHECK-NO-LIFETIMES: nonescapable.h:63:41: error: a function cannot return a ~Escapable result
139-
j2()
140172
// CHECK-NO-LIFETIMES: nonescapable.h:64:41: error: a function cannot return a ~Escapable result
173+
j2()
174+
// CHECK-NO-LIFETIMES: nonescapable.h:65:41: error: a function cannot return a ~Escapable result
141175
j3()
142176
k1();
143-
// CHECK-NO-LIFETIMES: nonescapable.h:70:15: error: a function cannot return a ~Escapable result
177+
// CHECK-NO-LIFETIMES: nonescapable.h:71:15: error: a function cannot return a ~Escapable result
144178
k2();
145-
// CHECK-NO-LIFETIMES: nonescapable.h:71:22: error: a function cannot return a ~Escapable result
179+
// CHECK-NO-LIFETIMES: nonescapable.h:72:22: error: a function cannot return a ~Escapable result
146180
k3();
147181
l1();
148-
// CHECK: nonescapable.h:77:12: error: a function with a ~Escapable result needs a parameter to depend on
149-
// CHECK-NO-LIFETIMES: nonescapable.h:77:12: error: a function cannot return a ~Escapable result
182+
// CHECK: nonescapable.h:78:12: error: a function with a ~Escapable result needs a parameter to depend on
183+
// CHECK-NO-LIFETIMES: nonescapable.h:78:12: error: a function cannot return a ~Escapable result
150184
l2();
151185
return View()
152186
}
@@ -162,6 +196,19 @@ public func test3(_ x: inout View) {
162196
// CHECK-NO-LIFETIMES: note: return type unavailable (cannot import)
163197
// CHECK-NO-LIFETIMES: pointer to non-escapable type 'View' cannot be imported
164198
}
199+
200+
public func anonymousUnions() {
201+
_ = HasAnonUnionNonEscapable()
202+
// CHECK: error: cannot find 'HasAnonUnionNonEscapable' in scope
203+
// CHECK-NO-LIFETIMES: error: cannot find 'HasAnonUnionNonEscapable' in scope
204+
_ = HasAnonStructNonEscapable()
205+
// CHECK: error: cannot find 'HasAnonStructNonEscapable' in scope
206+
// CHECK-NO-LIFETIMES: error: cannot find 'HasAnonStructNonEscapable' in scope
207+
_ = NonEscapableHasAnonUnionNonEscapable()
208+
_ = NonEscapableOptional()
209+
// CHECK-NO-LIFETIMES: error: an initializer cannot return a ~Escapable result
210+
}
211+
165212
// CHECK-NOT: error
166213
// CHECK-NOT: warning
167214
// CHECK-NO-LIFETIMES-NOT: error

0 commit comments

Comments
 (0)