Skip to content

Commit b7158ea

Browse files
committed
[cxx-interop] add SWIFT_NONCOPYABLE annotation
1 parent 0296448 commit b7158ea

File tree

5 files changed

+53
-0
lines changed

5 files changed

+53
-0
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7076,6 +7076,14 @@ static bool hasIteratorAPIAttr(const clang::Decl *decl) {
70767076
});
70777077
}
70787078

7079+
static bool hasNonCopyableAttr(const clang::RecordDecl *decl) {
7080+
return decl->hasAttrs() && llvm::any_of(decl->getAttrs(), [](auto *attr) {
7081+
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
7082+
return swiftAttr->getAttribute() == "~Copyable";
7083+
return false;
7084+
});
7085+
}
7086+
70797087
/// Recursively checks that there are no pointers in any fields or base classes.
70807088
/// Does not check C++ records with specific API annotations.
70817089
static bool hasPointerInSubobjects(const clang::CXXRecordDecl *decl) {
@@ -7295,6 +7303,10 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
72957303
return CxxRecordSemanticsKind::MissingLifetimeOperation;
72967304
}
72977305

7306+
if (hasNonCopyableAttr(cxxDecl) && hasMoveTypeOperations(cxxDecl)) {
7307+
return CxxRecordSemanticsKind::MoveOnly;
7308+
}
7309+
72987310
if (hasOwnedValueAttr(cxxDecl)) {
72997311
return CxxRecordSemanticsKind::Owned;
73007312
}

lib/ClangImporter/bridging

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@
153153
#define SWIFT_UNCHECKED_SENDABLE \
154154
__attribute__((swift_attr("@Sendable")))
155155

156+
/// Specifies that a specific c++ type such class or struct should be imported
157+
/// as a non-copyable Swift value type.
158+
#define SWIFT_NONCOPYABLE \
159+
__attribute__((swift_attr("~Copyable")))
160+
156161
#else // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
157162

158163
// Empty defines for compilers that don't support `attribute(swift_attr)`.
@@ -166,6 +171,7 @@
166171
#define SWIFT_COMPUTED_PROPERTY
167172
#define SWIFT_MUTATING
168173
#define SWIFT_UNCHECKED_SENDABLE
174+
#define SWIFT_NONCOPYABLE
169175

170176
#endif // #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
171177

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,15 @@ struct HasMethodThatReturnsIteratorBox {
251251
IteratorBox getIteratorBox() const;
252252
};
253253

254+
struct __attribute__((swift_attr("~Copyable"))) StructCopyableMovableAnnotatedNonCopyable {
255+
inline StructCopyableMovableAnnotatedNonCopyable() {}
256+
StructCopyableMovableAnnotatedNonCopyable(const StructCopyableMovableAnnotatedNonCopyable &) = default;
257+
StructCopyableMovableAnnotatedNonCopyable(StructCopyableMovableAnnotatedNonCopyable &&) = default;
258+
StructCopyableMovableAnnotatedNonCopyable &
259+
operator=(const StructCopyableMovableAnnotatedNonCopyable &) = default;
260+
StructCopyableMovableAnnotatedNonCopyable &
261+
operator=(StructCopyableMovableAnnotatedNonCopyable &&) = default;
262+
~StructCopyableMovableAnnotatedNonCopyable() = default;
263+
};
264+
254265
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_TYPE_CLASSIFICATION_H
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Test various aspects of the C++ `nodiscard` keyword.
2+
3+
// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-experimental-cxx-interop
4+
5+
import TypeClassification
6+
7+
func test() {
8+
let x = StructCopyableMovableAnnotatedNonCopyable()
9+
let v = copy x // expected-error {{'copy' cannot be applied to noncopyable types}}
10+
_ = v
11+
}
12+
13+
test()

test/Interop/Cxx/ergonomics/swift-bridging-annotations.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ class SWIFT_UNCHECKED_SENDABLE UnsafeSendable {
8484
public:
8585
};
8686

87+
class SWIFT_NONCOPYABLE NonCopyableCopyable {
88+
public:
89+
NonCopyableCopyable(const NonCopyableCopyable &other) = default;
90+
NonCopyableCopyable(NonCopyableCopyable &&other);
91+
~NonCopyableCopyable();
92+
private:
93+
int x;
94+
};
95+
8796

8897
// CHECK: struct SelfContained {
8998

@@ -106,3 +115,5 @@ public:
106115
// CHECK: struct ConformsTo : Proto {
107116

108117
// CHECK: struct UnsafeSendable : @unchecked Sendable {
118+
119+
// CHECK: struct NonCopyableCopyable

0 commit comments

Comments
 (0)