diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index ccef3f30caaa3..cc6e169a25f0a 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1500,6 +1500,24 @@ namespace { // bridging, i.e. if the imported typealias should name a bridged type // 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()), diff --git a/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h b/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h new file mode 100644 index 0000000000000..9ac3ee1dcac9a --- /dev/null +++ b/test/Interop/Cxx/templates/Inputs/ForwardDeclaredSpecialization.h @@ -0,0 +1,63 @@ +#ifndef FORWARD_DECLARED_SPECIALIZATION_H +#define FORWARD_DECLARED_SPECIALIZATION_H + +// Basic template definition +template +struct BasicTemplate { + T value; +}; + +// Case 1: Forward-declared specialization (should NOT import) +template <> +struct BasicTemplate; +typedef BasicTemplate ForwardDeclaredInt; + +// Case 2: Complete specialization (should import successfully) +template <> +struct BasicTemplate { + double value; + double getValue() const { return value; } +}; +typedef BasicTemplate CompleteDouble; + +// Case 3: Specialization defined after typedef (should import) +template <> +struct BasicTemplate; +typedef BasicTemplate FloatTypedef; + +template <> +struct BasicTemplate { + float value; +}; + +// Case 4: For comparison - forward-declared non-templated struct (have same behavior) +struct ForwardDeclaredStruct; +typedef ForwardDeclaredStruct ForwardDeclaredStructType; + +// Case 5: Complete non-templated struct (imports successfully) +struct CompleteStruct { + int value; +}; +typedef CompleteStruct CompleteStructType; + +// Template for partial specialization test +template +struct PartialTemplate { + T first; + U second; +}; + +// Case 6: Forward-declared partial specialization (should NOT import - same as explicit) +template +struct PartialTemplate; // Forward declaration only +typedef PartialTemplate ForwardDeclaredPartial; + +// Case 7: Complete partial specialization (should import successfully) +template +struct PartialTemplate { + T* ptr; + double value; +}; +typedef PartialTemplate CompletePartial; + +#endif diff --git a/test/Interop/Cxx/templates/Inputs/module.modulemap b/test/Interop/Cxx/templates/Inputs/module.modulemap index 88d4bdd22085f..720ea7fc9da7f 100644 --- a/test/Interop/Cxx/templates/Inputs/module.modulemap +++ b/test/Interop/Cxx/templates/Inputs/module.modulemap @@ -182,3 +182,8 @@ module VariableTemplate { header "variable-template.h" requires cplusplus } + +module ForwardDeclaredSpecialization { + header "ForwardDeclaredSpecialization.h" + requires cplusplus +} diff --git a/test/Interop/Cxx/templates/forward-declared-specialization.swift b/test/Interop/Cxx/templates/forward-declared-specialization.swift new file mode 100644 index 0000000000000..3f3080e048feb --- /dev/null +++ b/test/Interop/Cxx/templates/forward-declared-specialization.swift @@ -0,0 +1,32 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default + +import ForwardDeclaredSpecialization + +func testForwardDeclaredSpecialization(_ param: ForwardDeclaredInt) { + // expected-error@-1 {{cannot find type 'ForwardDeclaredInt' in scope}} +} + +func testCompleteSpecialization(_ param: CompleteDouble) { + let _ = param.getValue() +} + +func testSpecializationDefinedAfter(_ param: FloatTypedef) { + let _ = param.value +} + +func testForwardDeclaredStruct(_ param: ForwardDeclaredStructType) { + // expected-error@-1 {{cannot find type 'ForwardDeclaredStructType' in scope}} +} + +func testCompleteStruct(_ param: CompleteStructType) { + let _ = param.value +} + +func testForwardDeclaredPartial(_ param: ForwardDeclaredPartial) { + // expected-error@-1 {{cannot find type 'ForwardDeclaredPartial' in scope}} +} + +func testCompletePartial(_ param: CompletePartial) { + let _ = param.ptr + let _ = param.value +}