diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index b33024d299a..e390c7f644d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -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( + 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) { diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index dafb869c49b..904e3ced760 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -71,6 +71,25 @@ struct TemplatedConstructorWithExtraArg { TemplatedConstructorWithExtraArg(T value, U other) { } }; +struct TemplatedCopyConstructor { + int x = 0; + + TemplatedCopyConstructor(int x) : x(x) {} + + template + TemplatedCopyConstructor(const T &value) : x(value.x) {} +}; + +struct TemplatedCopyConstructorWithExtraArg { + int x = 0; + + TemplatedCopyConstructorWithExtraArg(int x) : x(x) {} + + template + TemplatedCopyConstructorWithExtraArg(const T &value, int add = 0) + : x(value.x + add) {} +}; + struct __attribute__((swift_attr("import_unsafe"))) HasUserProvidedCopyConstructor { int numCopies; diff --git a/test/Interop/Cxx/class/constructors-copy-module-interface.swift b/test/Interop/Cxx/class/constructors-copy-module-interface.swift index 609c390fda7..042c10e7d1d 100644 --- a/test/Interop/Cxx/class/constructors-copy-module-interface.swift +++ b/test/Interop/Cxx/class/constructors-copy-module-interface.swift @@ -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 diff --git a/test/Interop/Cxx/class/constructors-typechecker.swift b/test/Interop/Cxx/class/constructors-typechecker.swift index 16509750a32..8ce10b1ca75 100644 --- a/test/Interop/Cxx/class/constructors-typechecker.swift +++ b/test/Interop/Cxx/class/constructors-typechecker.swift @@ -2,6 +2,8 @@ import Constructors +func takesCopyable(_ 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)