Merge pull request #86002 from j-hui/migrate-incomplete-template-spec-check

This commit is contained in:
John Hui
2025-12-12 07:52:00 -08:00
committed by GitHub
3 changed files with 31 additions and 18 deletions

View File

@@ -1501,23 +1501,6 @@ namespace {
// or the original C type. // or the original C type.
clang::QualType ClangType = Decl->getUnderlyingType(); 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<clang::TemplateSpecializationType>(
importer::desugarIfElaborated(ClangType).getTypePtr())) {
if (auto *recordType =
templateSpec->desugar()->getAs<clang::RecordType>()) {
if (auto *spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(
recordType->getDecl())) {
if (spec->getSpecializationKind() ==
clang::TSK_ExplicitSpecialization &&
!spec->isCompleteDefinition()) {
return nullptr;
}
}
}
}
SwiftType = Impl.importTypeIgnoreIUO( SwiftType = Impl.importTypeIgnoreIUO(
ClangType, ImportTypeKind::Typedef, ClangType, ImportTypeKind::Typedef,
ImportDiagnosticAdder(Impl, Decl, Decl->getLocation()), ImportDiagnosticAdder(Impl, Decl, Decl->getLocation()),
@@ -3346,6 +3329,15 @@ namespace {
decl->getName() == "_Expr" || decl->getName() == "__val_expr")) decl->getName() == "_Expr" || decl->getName() == "__val_expr"))
return nullptr; return nullptr;
// Don't even try to specialize/import this template if it's
// a forward-declared specialization like this:
//
// template <> struct MyTemplate<int>;
//
if (decl->getSpecializationKind() == clang::TSK_ExplicitSpecialization &&
!decl->isCompleteDefinition())
return nullptr;
// `decl->getDefinition()` can return nullptr before the call to sema and // `decl->getDefinition()` can return nullptr before the call to sema and
// return its definition afterwards. // return its definition afterwards.
clang::Sema &clangSema = Impl.getClangSema(); clang::Sema &clangSema = Impl.getClangSema();

View File

@@ -60,4 +60,11 @@ struct PartialTemplate<T*, double> {
}; };
typedef PartialTemplate<int*, double> CompletePartial; typedef PartialTemplate<int*, double> CompletePartial;
// Some functions that use forward-declared specializations
void TakesIncompleteSpecialization(BasicTemplate<int>);
BasicTemplate<int> ReturnsIncompleteSpecialization();
void TakesPtrToIncompleteSpecialization(BasicTemplate<int> *);
BasicTemplate<int> *ReturnsPtrToIncompleteSpecialization();
#endif #endif

View File

@@ -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 import ForwardDeclaredSpecialization
@@ -30,3 +30,17 @@ func testCompletePartial(_ param: CompletePartial) {
let _ = param.ptr let _ = param.ptr
let _ = param.value 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)
}