Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<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(
ClangType, ImportTypeKind::Typedef,
ImportDiagnosticAdder(Impl, Decl, Decl->getLocation()),
Expand Down Expand Up @@ -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<int>;
//
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,11 @@ struct PartialTemplate<T*, double> {
};
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
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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)
}