Skip to content

Commit 1ccf19c

Browse files
committed
[cxx-interop] Treat un-instantiated templated types as unsafe
When determining whether a C++ method is safe to be imported, we look at its return type to see if it stores any pointers in its fields. If the type is templated, we might not have its definition available yet. Unfortunately we cannot instantiate it on the spot, since the Clang AST would be read and written at the same time. Let's stay on the safe side and treat such methods as unsafe. rdar://107609381 (cherry picked from commit c813254)
1 parent c4e30e1 commit 1ccf19c

File tree

4 files changed

+60
-14
lines changed

4 files changed

+60
-14
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6395,7 +6395,9 @@ static bool hasIteratorAPIAttr(const clang::Decl *decl) {
63956395
static bool hasPointerInSubobjects(const clang::CXXRecordDecl *decl) {
63966396
// Probably a class template that has not yet been specialized:
63976397
if (!decl->getDefinition())
6398-
return false;
6398+
// If the definition is unknown, there is no way to determine if the type
6399+
// stores pointers. Stay on the safe side and assume that it does.
6400+
return true;
63996401

64006402
auto checkType = [](clang::QualType t) {
64016403
if (t->isPointerType())
@@ -6689,9 +6691,10 @@ bool IsSafeUseOfCxxDecl::evaluate(Evaluator &evaluator,
66896691
return false;
66906692
}
66916693

6692-
// Mark this as safe to help our diganostics down the road.
66936694
if (!cxxRecordReturnType->getDefinition()) {
6694-
return true;
6695+
// This is a templated type that has not been instantiated yet. We do
6696+
// not know if it is safe. Assume that it isn't.
6697+
return false;
66956698
}
66966699

66976700
if (!cxxRecordReturnType->hasUserDeclaredCopyConstructor() &&

test/Interop/Cxx/class/Inputs/type-classification.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,32 @@ struct HasMethodThatReturnsIteratorBox {
213213
IteratorBox getIteratorBox() const;
214214
};
215215

216+
template <typename T>
217+
struct TemplatedPointerBox {
218+
T *ptr;
219+
};
220+
221+
struct HasMethodThatReturnsTemplatedPointerBox {
222+
TemplatedPointerBox<int> getTemplatedPointerBox() const;
223+
};
224+
225+
template <typename T>
226+
struct TemplatedBox {
227+
T value;
228+
};
229+
230+
struct HasMethodThatReturnsTemplatedBox {
231+
TemplatedBox<int> getIntBox() const;
232+
TemplatedBox<int *> getIntPtrBox() const;
233+
};
234+
235+
template <typename T>
236+
struct __attribute__((swift_attr("import_iterator"))) TemplatedIterator {
237+
T idx;
238+
};
239+
240+
struct HasMethodThatReturnsTemplatedIterator {
241+
TemplatedIterator<int *> getIterator() const;
242+
};
243+
216244
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_TYPE_CLASSIFICATION_H

test/Interop/Cxx/class/type-classification-module-interface.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,18 @@
3535
// CHECK: func __getIteratorBoxUnsafe() -> IteratorBox
3636
// CHECK-SKIP-UNSAFE-NOT: func __getIteratorBoxUnsafe() -> IteratorBox
3737
// CHECK: }
38+
39+
// CHECK: struct HasMethodThatReturnsTemplatedPointerBox {
40+
// CHECK: func __getTemplatedPointerBoxUnsafe() -> TemplatedPointerBox<Int32>
41+
// CHECK-SKIP-UNSAFE-NOT: func __getTemplatedPointerBoxUnsafe() -> TemplatedPointerBox<Int32>
42+
// CHECK: }
43+
44+
// CHECK: struct HasMethodThatReturnsTemplatedBox {
45+
// FIXME: This is unfortunate, we should be able to recognize that TemplatedBox<Int32> does not store any pointers as fields.
46+
// CHECK: func __getIntBoxUnsafe() -> TemplatedBox<Int32>
47+
// CHECK: func __getIntPtrBoxUnsafe()
48+
// CHECK: }
49+
50+
// CHECK: struct HasMethodThatReturnsTemplatedIterator {
51+
// CHECK: func __getIteratorUnsafe()
52+
// CHECK: }

test/Interop/Cxx/templates/Inputs/large-class-templates.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ struct ValExpr {
2828
using type = typename E::type;
2929
E expr;
3030

31-
ValExpr<SliceExpr<E, 1>> test1() { return {SliceExpr<E, 1>{expr}}; }
32-
ValExpr<SliceExpr<E, 2>> test2() { return {SliceExpr<E, 2>{expr}}; }
33-
ValExpr<SliceExpr<E, 3>> test3() { return {SliceExpr<E, 3>{expr}}; }
34-
ValExpr<SliceExpr<E, 4>> test4() { return {SliceExpr<E, 4>{expr}}; }
35-
ValExpr<SliceExpr<E, 5>> test5() { return {SliceExpr<E, 5>{expr}}; }
36-
ValExpr<SliceExpr<E, 6>> test6() { return {SliceExpr<E, 6>{expr}}; }
37-
ValExpr<SliceExpr<E, 7>> test7() { return {SliceExpr<E, 7>{expr}}; }
38-
ValExpr<SliceExpr<E, 8>> test8() { return {SliceExpr<E, 8>{expr}}; }
39-
ValExpr<SliceExpr<E, 9>> test9() { return {SliceExpr<E, 8>{expr}}; }
40-
ValExpr<SliceExpr<E, 11>> test11() { return {SliceExpr<E, 11>{expr}}; }
41-
ValExpr<SliceExpr<E, 12>> test12() { return {SliceExpr<E, 12>{expr}}; }
31+
ValExpr<SliceExpr<E, 1>> test1() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 1>{expr}}; }
32+
ValExpr<SliceExpr<E, 2>> test2() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 2>{expr}}; }
33+
ValExpr<SliceExpr<E, 3>> test3() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 3>{expr}}; }
34+
ValExpr<SliceExpr<E, 4>> test4() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 4>{expr}}; }
35+
ValExpr<SliceExpr<E, 5>> test5() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 5>{expr}}; }
36+
ValExpr<SliceExpr<E, 6>> test6() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 6>{expr}}; }
37+
ValExpr<SliceExpr<E, 7>> test7() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 7>{expr}}; }
38+
ValExpr<SliceExpr<E, 8>> test8() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 8>{expr}}; }
39+
ValExpr<SliceExpr<E, 9>> test9() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 8>{expr}}; }
40+
ValExpr<SliceExpr<E, 11>> test11() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 11>{expr}}; }
41+
ValExpr<SliceExpr<E, 12>> test12() __attribute__((swift_attr("import_unsafe"))) { return {SliceExpr<E, 12>{expr}}; }
4242
};
4343

4444
// This class template is exponentially slow to *fully* instantiate (and the

0 commit comments

Comments
 (0)