diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index ee7888c5f2e9f..b75b8a3c47b1f 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -257,6 +257,7 @@ NOTE(record_field_not_imported, none, "field %0 unavailable (cannot import)", (c NOTE(invoked_func_not_imported, none, "function %0 unavailable (cannot import)", (const clang::NamedDecl*)) NOTE(record_method_not_imported, none, "method %0 unavailable (cannot import)", (const clang::NamedDecl*)) NOTE(objc_property_not_imported, none, "property %0 unavailable (cannot import)", (const clang::NamedDecl*)) +NOTE(unsupported_return_type, none, "C++ function %0 is unavailable: return type is unavailable in Swift", (const clang::NamedDecl*)) NOTE(placeholder_for_forward_declared_interface_member_access_failure, none, "class '%0' will be imported as an opaque placeholder class and may be " diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 89789d64e7840..59e50a328f5ba 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -5622,13 +5622,7 @@ importName(const clang::NamedDecl *D, Type ClangImporter::importFunctionReturnType( const clang::FunctionDecl *clangDecl, DeclContext *dc) { - bool isInSystemModule = - cast(dc->getModuleScopeContext())->isSystemModule(); - bool allowNSUIntegerAsInt = - Impl.shouldAllowNSUIntegerAsInt(isInSystemModule, clangDecl); - if (auto imported = - Impl.importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt) - .getType()) + if (auto imported = Impl.importFunctionReturnType(clangDecl, dc).getType()) return imported; return dc->getASTContext().getNeverType(); } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index cf15e538d4db5..0edc1076b2f69 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3048,13 +3048,16 @@ namespace { if (auto recordType = dyn_cast( decl->getReturnType().getCanonicalType())) { - Impl.addImportDiagnostic( - decl, Diagnostic(diag::reference_passed_by_value, - Impl.SwiftContext.AllocateCopy( - recordType->getDecl()->getNameAsString()), - "the return"), - decl->getLocation()); - return recordHasReferenceSemantics(recordType->getDecl()); + if (recordHasReferenceSemantics(recordType->getDecl())) { + Impl.addImportDiagnostic( + decl, + Diagnostic(diag::reference_passed_by_value, + Impl.SwiftContext.AllocateCopy( + recordType->getDecl()->getNameAsString()), + "the return"), + decl->getLocation()); + return true; + } } return false; @@ -3391,6 +3394,14 @@ namespace { func->setAccess(AccessLevel::Public); } + if (!isa(decl) && !importedType) { + if (!Impl.importFunctionReturnType(decl, result->getDeclContext())) { + Impl.addImportDiagnostic( + decl, Diagnostic(diag::unsupported_return_type, decl), + decl->getSourceRange().getBegin()); + return nullptr; + } + } result->setIsObjC(false); result->setIsDynamic(false); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 2fd3508e4e9fd..3c355c8b2c4ed 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2074,6 +2074,15 @@ applyImportTypeAttrs(ImportTypeAttrs attrs, Type type, return type; } +ImportedType ClangImporter::Implementation::importFunctionReturnType( + const clang::FunctionDecl *clangDecl, DeclContext *dc) { + bool isInSystemModule = + cast(dc->getModuleScopeContext())->isSystemModule(); + bool allowNSUIntegerAsInt = + shouldAllowNSUIntegerAsInt(isInSystemModule, clangDecl); + return importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt); +} + ImportedType ClangImporter::Implementation::importFunctionReturnType( DeclContext *dc, const clang::FunctionDecl *clangDecl, bool allowNSUIntegerAsInt) { diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 27aef3e217a22..7cf17144a3853 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1340,6 +1340,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation const clang::FunctionDecl *clangDecl, bool allowNSUIntegerAsInt); + ImportedType importFunctionReturnType(const clang::FunctionDecl *clangDecl, + DeclContext *dc); + /// Import the parameter list for a function /// /// \param clangDecl The underlying declaration, if any; should only be diff --git a/test/Interop/Cxx/class/returns-unavailable-class.swift b/test/Interop/Cxx/class/returns-unavailable-class.swift new file mode 100644 index 0000000000000..7e448d1d0f9fd --- /dev/null +++ b/test/Interop/Cxx/class/returns-unavailable-class.swift @@ -0,0 +1,65 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %target-swift-ide-test -print-module -module-to-print=CxxModule -I %t/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s + +// RUN: %target-swift-frontend -typecheck -verify -I %t/Inputs -enable-experimental-cxx-interop %t/test.swift + +// RUN: not %target-swift-frontend -typecheck -I %t/Inputs -enable-experimental-cxx-interop %t/test.swift 2>&1 | %FileCheck --check-prefix=NOTE %s + + +//--- Inputs/module.modulemap +module CxxTypes { + header "types.h" + requires cplusplus +} + +module CxxModule { + header "header.h" + requires cplusplus +} + +//--- Inputs/types.h + +template +class TemplateInTypesModule { +public: + T x, y; +}; + +//--- Inputs/header.h + +#pragma clang module import CxxTypes + +class Struct { +public: + int x, y; + + TemplateInTypesModule returnsClassInTypesModules() const; + + void takesClassInTypesModules(TemplateInTypesModule) const; + void takesClassInTypesModulesRef(const TemplateInTypesModule &) const; +}; + +// CHECK: struct Struct { +// CHECK-NEXT: init() +// CHECK-NEXT: init(x: Int32, y: Int32) +// CHECK-NEXT: var x: Int32 +// CHECK-NEXT: var y: Int32 +// CHECK-NEXT: } + +// CHECK-NOT: funcWithClass + +TemplateInTypesModule funcWithClassInTypesModules(); +void funcWithClassInTypesModulesParam(TemplateInTypesModule); +void funcWithClassInTypesModulesParamRef(const TemplateInTypesModule &); + +//--- test.swift + +import CxxModule + +func test() { + funcWithClassInTypesModules() // expected-error {{cannot find 'funcWithClassInTypesModules' in scope}} + Struct().returnsClassInTypesModules() // expected-error {{value of type 'Struct' has no member 'returnsClassInTypesModules'}} +} + +// NOTE: note: C++ function 'funcWithClassInTypesModules' is unavailable: return type is unavailable in Swift