diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 3f422f48d5b87..cf05fcd56ccf4 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7368,12 +7368,6 @@ static bool hasDestroyTypeOperations(const clang::CXXRecordDecl *decl) { } static bool hasCustomCopyOrMoveConstructor(const clang::CXXRecordDecl *decl) { - // std::pair and std::tuple might have copy and move constructors, but that - // doesn't mean they are safe to use from Swift, e.g. std::pair - if (decl->isInStdNamespace() && - (decl->getName() == "pair" || decl->getName() == "tuple")) { - return false; - } return decl->hasUserDeclaredCopyConstructor() || decl->hasUserDeclaredMoveConstructor(); } @@ -7489,6 +7483,13 @@ CxxRecordAsSwiftType::evaluate(Evaluator &evaluator, } bool anySubobjectsSelfContained(const clang::CXXRecordDecl *decl) { + // std::pair and std::tuple might have copy and move constructors, or base + // classes with copy and move constructors, but they are not self-contained + // types, e.g. `std::pair`. + if (decl->isInStdNamespace() && + (decl->getName() == "pair" || decl->getName() == "tuple")) + return false; + if (!decl->getDefinition()) return false; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 8b782a8750e79..cc33d2a20703d 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2959,9 +2959,7 @@ namespace { if (notInstantiated) return nullptr; } - if (!clangSema.isCompleteType( - decl->getLocation(), - Impl.getClangASTContext().getRecordType(decl))) { + if (!decl->getDefinition()) { // If we got nullptr definition now it means the type is not complete. // We don't import incomplete types. return nullptr; diff --git a/test/Interop/Cxx/stdlib/Inputs/module.modulemap b/test/Interop/Cxx/stdlib/Inputs/module.modulemap index 3092b15d76a42..187111acca6a2 100644 --- a/test/Interop/Cxx/stdlib/Inputs/module.modulemap +++ b/test/Interop/Cxx/stdlib/Inputs/module.modulemap @@ -1,26 +1,31 @@ module StdVector { header "std-vector.h" requires cplusplus + export * } module StdMap { header "std-map.h" requires cplusplus + export * } module StdOptional { header "std-optional.h" requires cplusplus + export * } module StdSet { header "std-set.h" requires cplusplus + export * } module StdPair { header "std-pair.h" requires cplusplus + export * } module MsvcUseVecIt { @@ -32,4 +37,11 @@ module MsvcUseVecIt { module StdUniquePtr { header "std-unique-ptr.h" requires cplusplus + export * +} + +module StdFunction { + header "std-function.h" + requires cplusplus + export * } diff --git a/test/Interop/Cxx/stdlib/Inputs/std-function.h b/test/Interop/Cxx/stdlib/Inputs/std-function.h new file mode 100644 index 0000000000000..1486f3a3e20de --- /dev/null +++ b/test/Interop/Cxx/stdlib/Inputs/std-function.h @@ -0,0 +1,16 @@ +#ifndef TEST_INTEROP_CXX_STDLIB_INPUTS_STD_FUNCTION_H +#define TEST_INTEROP_CXX_STDLIB_INPUTS_STD_FUNCTION_H + +#include + +using FunctionIntToInt = std::function; + +FunctionIntToInt getIdentityFunction() { + return [](int x) { return x; }; +} + +bool isEmptyFunction(FunctionIntToInt f) { return !(bool)f; } + +int invokeFunction(FunctionIntToInt f, int x) { return f(x); } + +#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_FUNCTION_H diff --git a/test/Interop/Cxx/stdlib/Inputs/std-pair.h b/test/Interop/Cxx/stdlib/Inputs/std-pair.h index 8fc2604600e32..ff0c213b8a778 100644 --- a/test/Interop/Cxx/stdlib/Inputs/std-pair.h +++ b/test/Interop/Cxx/stdlib/Inputs/std-pair.h @@ -35,7 +35,7 @@ struct __attribute__((swift_attr("import_iterator"))) Iterator {}; using PairUnsafeStructInt = std::pair; using PairIteratorInt = std::pair; -struct HasMethodThatReturnsUnsafePair { +struct __attribute__((swift_attr("import_owned"))) HasMethodThatReturnsUnsafePair { PairUnsafeStructInt getUnsafePair() const { return {}; } PairIteratorInt getIteratorPair() const { return {}; } }; diff --git a/test/Interop/Cxx/stdlib/use-std-function.swift b/test/Interop/Cxx/stdlib/use-std-function.swift new file mode 100644 index 0000000000000..271a89b8f8982 --- /dev/null +++ b/test/Interop/Cxx/stdlib/use-std-function.swift @@ -0,0 +1,29 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop) +// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift) + +// REQUIRES: executable_test + +import StdlibUnittest +import StdFunction + +var StdFunctionTestSuite = TestSuite("StdFunction") + +StdFunctionTestSuite.test("init empty") { + let f = FunctionIntToInt() + expectTrue(isEmptyFunction(f)) + + let copied = f + expectTrue(isEmptyFunction(copied)) +} + +StdFunctionTestSuite.test("call") { + let f = getIdentityFunction() + expectEqual(123, f(123)) +} + +StdFunctionTestSuite.test("retrieve and pass back as parameter") { + let res = invokeFunction(getIdentityFunction(), 456) + expectEqual(456, res) +} + +runAllTests() diff --git a/test/Interop/Cxx/stdlib/use-std-pair-typechecker.swift b/test/Interop/Cxx/stdlib/use-std-pair-typechecker.swift index c24bc9337d109..7c366c2afc884 100644 --- a/test/Interop/Cxx/stdlib/use-std-pair-typechecker.swift +++ b/test/Interop/Cxx/stdlib/use-std-pair-typechecker.swift @@ -1,7 +1,12 @@ -// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-experimental-cxx-interop +// RUN: not %target-swift-frontend %s -typecheck -I %S/Inputs -enable-experimental-cxx-interop 2>&1 | %FileCheck %s import StdPair let u = HasMethodThatReturnsUnsafePair() -u.getUnsafePair() // expected-error {{value of type 'HasMethodThatReturnsUnsafePair' has no member 'getUnsafePair'}} -u.getIteratorPair() // expected-error {{value of type 'HasMethodThatReturnsUnsafePair' has no member 'getIteratorPair'}} +u.getUnsafePair() +// CHECK: error: value of type 'HasMethodThatReturnsUnsafePair' has no member 'getUnsafePair' +// CHECK: note: C++ method 'getUnsafePair' may return an interior pointer + +u.getIteratorPair() +// CHECK: error: value of type 'HasMethodThatReturnsUnsafePair' has no member 'getIteratorPair' +// CHECK: note: C++ method 'getIteratorPair' may return an interior pointer