Skip to content

Commit 6e56c24

Browse files
authored
Merge pull request #83973 from susmonteiro/nonescapable-std-optional
[cxx-interop] Prevent crash when importing a std::optional of nonescapable
2 parents 9805bd8 + 1bfa16a commit 6e56c24

File tree

2 files changed

+99
-29
lines changed

2 files changed

+99
-29
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,8 +2413,18 @@ namespace {
24132413
}
24142414

24152415
auto *vd = cast<VarDecl>(member);
2416-
if (!isNonEscapable) {
2417-
if (const auto *fd = dyn_cast<clang::FieldDecl>(nd))
2416+
auto getFieldDecl =
2417+
[](const clang::NamedDecl *decl) -> const clang::FieldDecl * {
2418+
if (const clang::FieldDecl *fd = dyn_cast<clang::FieldDecl>(decl))
2419+
return fd;
2420+
if (const clang::IndirectFieldDecl *ind =
2421+
dyn_cast<clang::IndirectFieldDecl>(decl))
2422+
return ind->getAnonField();
2423+
return nullptr;
2424+
};
2425+
2426+
if (!isNonEscapable && !decl->isAnonymousStructOrUnion()) {
2427+
if (const auto *fd = getFieldDecl(nd)) {
24182428
if (evaluateOrDefault(
24192429
Impl.SwiftContext.evaluator,
24202430
ClangTypeEscapability({fd->getType().getTypePtr(), &Impl}),
@@ -2427,6 +2437,7 @@ namespace {
24272437
decl->getLocation());
24282438
return nullptr;
24292439
}
2440+
}
24302441
}
24312442
members.push_back(vd);
24322443
}

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

Lines changed: 86 additions & 27 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) {}
@@ -115,64 +116,107 @@ struct SWIFT_ESCAPABLE Invalid {
115116
View v;
116117
};
117118

119+
struct SWIFT_NONESCAPABLE NonEscapable {};
120+
121+
template<typename T>
122+
struct HasAnonUnion {
123+
union {
124+
int known;
125+
T unknown;
126+
};
127+
};
128+
129+
template<typename T>
130+
struct HasAnonStruct {
131+
struct {
132+
int known;
133+
T unknown;
134+
};
135+
};
136+
137+
template<typename T>
138+
struct SWIFT_NONESCAPABLE NonEscapableHasAnonUnion {
139+
union {
140+
int known;
141+
T unknown;
142+
};
143+
};
144+
145+
using HasAnonUnionNonEscapable = HasAnonUnion<NonEscapable>;
146+
using HasAnonStructNonEscapable = HasAnonStruct<NonEscapable>;
147+
using NonEscapableHasAnonUnionNonEscapable = NonEscapableHasAnonUnion<NonEscapable>;
148+
using NonEscapableOptional = std::optional<NonEscapable>;
149+
118150
//--- test.swift
119151
import Test
120152
import CxxStdlib
121153

122154
// CHECK: error: cannot find type 'Invalid' in scope
123155
// CHECK: note: escapable record 'Invalid' cannot have non-escapable field 'v'
156+
// CHECK-NO-LIFETIMES: error: cannot find type 'Invalid' in scope
157+
// CHECK-NO-LIFETIMES: note: escapable record 'Invalid' cannot have non-escapable field 'v'
124158
public func importInvalid(_ x: Invalid) {
125159
}
126160

127161
// CHECK: error: a function with a ~Escapable result needs a parameter to depend on
128-
// CHECK-NO-LIFETIMES: test.swift:11:32: error: a function cannot return a ~Escapable result
162+
// CHECK-NO-LIFETIMES: test.swift:13:32: error: a function cannot return a ~Escapable result
129163
public func noAnnotations() -> View {
130-
// CHECK: nonescapable.h:24:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
131-
// CHECK-NO-LIFETIMES: nonescapable.h:24:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
164+
// CHECK: nonescapable.h:25:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
165+
// CHECK-NO-LIFETIMES: nonescapable.h:25:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
132166
f(nil)
133-
// CHECK: nonescapable.h:28:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
134-
// CHECK-NO-LIFETIMES: nonescapable.h:28:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
167+
// CHECK: nonescapable.h:29:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
168+
// CHECK-NO-LIFETIMES: nonescapable.h:29:7: warning: the returned type 'Owner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
135169
// No duplicate warning for f2:
136-
// CHECK-NOT: nonescapable.h:28
170+
// CHECK-NOT: nonescapable.h:29
137171
f2(nil, nil)
138-
// CHECK: nonescapable.h:32:19: warning: the returned type 'TemplatedIntOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
139-
// CHECK-NO-LIFETIMES: nonescapable.h:32:19: warning: the returned type 'TemplatedIntOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
172+
// CHECK: nonescapable.h:33:19: warning: the returned type 'TemplatedIntOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
173+
// CHECK-NO-LIFETIMES: nonescapable.h:33:19: warning: the returned type 'TemplatedIntOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
140174
// No duplicate warning for f3:
141-
// CHECK-NOT: nonescapable.h:32
175+
// CHECK-NOT: nonescapable.h:33
142176
f3(nil)
143-
// CHECK: nonescapable.h:36:21: warning: the returned type 'TemplatedFloatOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
144-
// CHECK-NO-LIFETIMES: nonescapable.h:36:21: warning: the returned type 'TemplatedFloatOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
177+
// CHECK: nonescapable.h:37:21: warning: the returned type 'TemplatedFloatOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
178+
// CHECK-NO-LIFETIMES: nonescapable.h:37:21: warning: the returned type 'TemplatedFloatOwner' is annotated as escapable; it cannot have lifetime dependencies [#ClangDeclarationImport]
145179
// No duplicate warning for f4:
146-
// CHECK-NOT: nonescapable.h:34
180+
// CHECK-NOT: nonescapable.h:35
147181
f4(nil)
148-
// CHECK: nonescapable.h:40:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
149-
// CHECK-NO-LIFETIMES: nonescapable.h:40:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
150-
// CHECK-NO-LIFETIMES: nonescapable.h:40:6: error: a function cannot return a ~Escapable result
182+
// CHECK: nonescapable.h:41:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
183+
// CHECK-NO-LIFETIMES: nonescapable.h:41:6: warning: the returned type 'View' is annotated as non-escapable; its lifetime dependencies must be annotated [#ClangDeclarationImport]
184+
// CHECK-NO-LIFETIMES: nonescapable.h:41:6: error: a function cannot return a ~Escapable result
151185
g(nil)
152186
h1(nil)
153-
// CHECK-NO-LIFETIMES: nonescapable.h:50:21: error: a function cannot return a ~Escapable result
154-
h2(nil)
155187
// CHECK-NO-LIFETIMES: nonescapable.h:51:21: error: a function cannot return a ~Escapable result
188+
h2(nil)
189+
// CHECK-NO-LIFETIMES: nonescapable.h:52:21: error: a function cannot return a ~Escapable result
156190
h3(nil)
157191
i1()
158-
// CHECK: nonescapable.h:55:39: error: template parameter 'Missing' does not exist
159-
// CHECK-NO-LIFETIMES: nonescapable.h:55:39: error: template parameter 'Missing' does not exist
192+
// CHECK: nonescapable.h:56:39: error: template parameter 'Missing' does not exist
193+
// CHECK-NO-LIFETIMES: nonescapable.h:56:39: error: template parameter 'Missing' does not exist
160194
i2()
161-
// CHECK: nonescapable.h:61:33: error: template parameter 'S' expected to be a type parameter
162-
// CHECK-NO-LIFETIMES: nonescapable.h:61:33: error: template parameter 'S' expected to be a type parameter
195+
// CHECK: nonescapable.h:62:33: error: template parameter 'S' expected to be a type parameter
196+
// CHECK: nonescapable.h:80:41: error: a function with a ~Escapable result needs a parameter to depend on
197+
// CHECK: note: '@_lifetime(immortal)' can be used to indicate that values produced
198+
// CHECK-NO-LIFETIMES: nonescapable.h:62:33: error: template parameter 'S' expected to be a type parameter
163199
j1()
164-
// CHECK-NO-LIFETIMES: nonescapable.h:79:41: error: a function cannot return a ~Escapable result
165-
j2()
166200
// CHECK-NO-LIFETIMES: nonescapable.h:80:41: error: a function cannot return a ~Escapable result
201+
j2()
202+
// CHECK: nonescapable.h:81:41: error: a function with a ~Escapable result needs a parameter to depend on
203+
// CHECK-NO-LIFETIMES: nonescapable.h:81:41: error: a function cannot return a ~Escapable result
204+
// CHECK: note: '@_lifetime(immortal)' can be used to indicate that values produced
167205
j3()
168206
k1();
169-
// CHECK-NO-LIFETIMES: nonescapable.h:86:15: error: a function cannot return a ~Escapable result
207+
// CHECK: nonescapable.h:87:15: error: a function with a ~Escapable result needs a parameter to depend on
208+
// CHECK: nonescapable.h:87:15: note: '@_lifetime(immortal)' can be used to indicate that values produced
209+
// CHECK-NO-LIFETIMES: nonescapable.h:87:15: error: a function cannot return a ~Escapable result
210+
170211
k2();
171-
// CHECK-NO-LIFETIMES: nonescapable.h:87:22: error: a function cannot return a ~Escapable result
212+
// CHECK: nonescapable.h:88:22: error: a function with a ~Escapable result needs a parameter to depend on
213+
// CHECK-NO-LIFETIMES: nonescapable.h:88:22: error: a function cannot return a ~Escapable result
214+
// CHECK: note: '@_lifetime(immortal)' can be used to indicate that values produced
172215
k3();
173216
l1();
174-
// CHECK: nonescapable.h:93:12: error: a function with a ~Escapable result needs a parameter to depend on
175-
// CHECK-NO-LIFETIMES: nonescapable.h:93:12: error: a function cannot return a ~Escapable result
217+
// CHECK: nonescapable.h:94:12: error: a function with a ~Escapable result needs a parameter to depend on
218+
// CHECK: nonescapable.h:94:12: note: '@_lifetime(immortal)' can be used to indicate that values produced by this initializer have no lifetime dependencies
219+
// CHECK-NO-LIFETIMES: nonescapable.h:94:12: error: a function cannot return a ~Escapable result
176220
l2();
177221
return View()
178222
}
@@ -188,6 +232,21 @@ public func test3(_ x: inout View) {
188232
// CHECK-NO-LIFETIMES: note: return type unavailable (cannot import)
189233
// CHECK-NO-LIFETIMES: pointer to non-escapable type 'View' cannot be imported
190234
}
235+
236+
public func anonymousUnions() {
237+
_ = HasAnonUnionNonEscapable()
238+
// CHECK: error: cannot find 'HasAnonUnionNonEscapable' in scope
239+
// CHECK-NO-LIFETIMES: error: cannot find 'HasAnonUnionNonEscapable' in scope
240+
_ = HasAnonStructNonEscapable()
241+
// CHECK: error: cannot find 'HasAnonStructNonEscapable' in scope
242+
// CHECK-NO-LIFETIMES: error: cannot find 'HasAnonStructNonEscapable' in scope
243+
_ = NonEscapableHasAnonUnionNonEscapable()
244+
_ = NonEscapableOptional()
245+
// CHECK: error: cannot infer the lifetime dependence scope on an initializer with a ~Escapable parameter, specify '@_lifetime(borrow {{.*}})' or '@_lifetime(copy {{.*}})'
246+
// CHECK-NO-LIFETIMES: error: an initializer cannot return a ~Escapable result
247+
// CHECK-NO-LIFETIMES: error: an initializer cannot return a ~Escapable result
248+
}
249+
191250
// CHECK-NOT: error
192251
// CHECK-NOT: warning
193252
// CHECK-NO-LIFETIMES-NOT: error

0 commit comments

Comments
 (0)