diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 5401f80def4c8..19349241cc00b 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1501,23 +1501,6 @@ namespace { // or the original C type. clang::QualType ClangType = Decl->getUnderlyingType(); - // Prevent import of typedefs to forward-declared explicit template - // specializations, which would trigger assertion in Clang. - if (auto *templateSpec = dyn_cast( - importer::desugarIfElaborated(ClangType).getTypePtr())) { - if (auto *recordType = - templateSpec->desugar()->getAs()) { - if (auto *spec = dyn_cast( - recordType->getDecl())) { - if (spec->getSpecializationKind() == - clang::TSK_ExplicitSpecialization && - !spec->isCompleteDefinition()) { - return nullptr; - } - } - } - } - SwiftType = Impl.importTypeIgnoreIUO( ClangType, ImportTypeKind::Typedef, ImportDiagnosticAdder(Impl, Decl, Decl->getLocation()), @@ -3346,6 +3329,15 @@ namespace { decl->getName() == "_Expr" || decl->getName() == "__val_expr")) return nullptr; + // Don't even try to specialize/import this template if it's + // a forward-declared specialization like this: + // + // template <> struct MyTemplate; + // + if (decl->getSpecializationKind() == clang::TSK_ExplicitSpecialization && + !decl->isCompleteDefinition()) + return nullptr; + // `decl->getDefinition()` can return nullptr before the call to sema and // return its definition afterwards. clang::Sema &clangSema = Impl.getClangSema(); diff --git a/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h b/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h index 9ac3ee1dcac9a..06381ded6e4ab 100644 --- a/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h +++ b/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h @@ -60,4 +60,11 @@ struct PartialTemplate { }; typedef PartialTemplate CompletePartial; +// Some functions that use forward-declared specializations +void TakesIncompleteSpecialization(BasicTemplate); +BasicTemplate ReturnsIncompleteSpecialization(); + +void TakesPtrToIncompleteSpecialization(BasicTemplate *); +BasicTemplate *ReturnsPtrToIncompleteSpecialization(); + #endif diff --git a/test/Interop/Cxx/templates/forward-declared-specialization.swift b/test/Interop/Cxx/templates/forward-declared-specialization.swift index 3f3080e048feb..d93caeb754820 100644 --- a/test/Interop/Cxx/templates/forward-declared-specialization.swift +++ b/test/Interop/Cxx/templates/forward-declared-specialization.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default -suppress-remarks -suppress-notes import ForwardDeclaredSpecialization @@ -30,3 +30,17 @@ func testCompletePartial(_ param: CompletePartial) { let _ = param.ptr let _ = param.value } + +func testFunctionsUsingIncompleteSpec() { + let inc = ReturnsIncompleteSpecialization() + // expected-error@-1 {{return type is unavailable in Swift}} + // expected-warning@-2 {{constant 'inc' inferred to have type 'Never', which is an enum with no cases}} + TakesIncompleteSpecialization(inc) + // expected-error@-1 {{cannot find 'TakesIncompleteSpecialization' in scope}} +} + +func testFunctionsUsingPtrToIncompleteSpec(_ ptr: OpaquePointer) { + let incPtr = ReturnsPtrToIncompleteSpecialization() + TakesPtrToIncompleteSpecialization(incPtr) + TakesPtrToIncompleteSpecialization(ptr) +}