mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[cxx-interop] Check the presence of copy constructor correctly
This removes a longstanding workaround in the import logic for C++ structs: Swift assumed that if a C++ struct has no copy constructor that is explicitly deleted, then the struct is copyable. This is not actually correct. This replaces the workaround with a proper check for the presence of a C++ copy constructor. rdar://136838485
This commit is contained in:
@@ -7619,18 +7619,22 @@ static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
if (decl->isInStdNamespace() && decl->getIdentifier() &&
|
||||
decl->getName() == "_Optional_construct_base")
|
||||
return true;
|
||||
// Hack for std::vector::const_iterator from libstdc++, which uses an extra
|
||||
// parameter on its copy constructor, which has a defaulted enable_if value.
|
||||
auto namespaceContext = dyn_cast_or_null<clang::NamespaceDecl>(
|
||||
decl->getEnclosingNamespaceContext());
|
||||
if (namespaceContext && namespaceContext->getIdentifier() &&
|
||||
namespaceContext->getName() == "__gnu_cxx" && decl->getIdentifier() &&
|
||||
decl->getName() == "__normal_iterator")
|
||||
return true;
|
||||
|
||||
// If we have no way of copying the type we can't import the class
|
||||
// at all because we cannot express the correct semantics as a swift
|
||||
// struct.
|
||||
if (llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isCopyConstructor() &&
|
||||
(ctor->isDeleted() || ctor->getAccess() != clang::AS_public);
|
||||
}))
|
||||
return false;
|
||||
|
||||
// TODO: this should probably check to make sure we actually have a copy ctor.
|
||||
return true;
|
||||
return llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
|
||||
return ctor->isCopyConstructor() && !ctor->isDeleted() &&
|
||||
ctor->getAccess() == clang::AccessSpecifier::AS_public;
|
||||
});
|
||||
}
|
||||
|
||||
static bool hasMoveTypeOperations(const clang::CXXRecordDecl *decl) {
|
||||
|
||||
@@ -71,6 +71,25 @@ struct TemplatedConstructorWithExtraArg {
|
||||
TemplatedConstructorWithExtraArg(T value, U other) { }
|
||||
};
|
||||
|
||||
struct TemplatedCopyConstructor {
|
||||
int x = 0;
|
||||
|
||||
TemplatedCopyConstructor(int x) : x(x) {}
|
||||
|
||||
template <class T>
|
||||
TemplatedCopyConstructor(const T &value) : x(value.x) {}
|
||||
};
|
||||
|
||||
struct TemplatedCopyConstructorWithExtraArg {
|
||||
int x = 0;
|
||||
|
||||
TemplatedCopyConstructorWithExtraArg(int x) : x(x) {}
|
||||
|
||||
template <class T>
|
||||
TemplatedCopyConstructorWithExtraArg(const T &value, int add = 0)
|
||||
: x(value.x + add) {}
|
||||
};
|
||||
|
||||
struct __attribute__((swift_attr("import_unsafe")))
|
||||
HasUserProvidedCopyConstructor {
|
||||
int numCopies;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// RUN: %target-swift-ide-test -print-module -module-to-print=Constructors -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
|
||||
|
||||
// CHECK: struct TemplatedCopyConstructor
|
||||
// CHECK: struct TemplatedCopyConstructorWithExtraArg
|
||||
|
||||
// Make sure we don't import non-copyable types because we will have no way to
|
||||
// represent and copy/move these in swift with correct semantics.
|
||||
// CHECK-NOT: DeletedCopyConstructor
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import Constructors
|
||||
|
||||
func takesCopyable<T: Copyable>(_ x: T.Type) {}
|
||||
|
||||
let explicit = ExplicitDefaultConstructor()
|
||||
|
||||
let implicit = ImplicitDefaultConstructor()
|
||||
@@ -12,3 +14,8 @@ let onlyCopyAndMove = CopyAndMoveConstructor() // expected-warning {{'init()' is
|
||||
let deletedExplicitly = DefaultConstructorDeleted() // expected-error {{missing argument for parameter 'a' in call}}
|
||||
|
||||
let withArg = ConstructorWithParam(42)
|
||||
|
||||
let _ = TemplatedCopyConstructor(123)
|
||||
let _ = TemplatedCopyConstructorWithExtraArg(123)
|
||||
takesCopyable(TemplatedCopyConstructor.self)
|
||||
takesCopyable(TemplatedCopyConstructorWithExtraArg.self)
|
||||
|
||||
Reference in New Issue
Block a user