diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 6bffbf3c3ef1c..7079888ec18db 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2282,6 +2282,7 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType( } clang::QualType returnType = desugarIfElaborated(clangDecl->getReturnType()); + returnType = desugarIfBoundsAttributed(returnType); // In C interop mode, the return type of library builtin functions // like 'memcpy' from headers like 'string.h' drops // any nullability specifiers from their return type, and preserves it on the @@ -2388,6 +2389,7 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType( ImportDiagnosticAdder addDiag(*this, clangDecl, clangDecl->getSourceRange().getBegin()); clang::QualType returnType = desugarIfElaborated(clangDecl->getReturnType()); + returnType = desugarIfBoundsAttributed(returnType); ImportedType importedType = importer::findOptionSetEnum(returnType, *this); @@ -2454,6 +2456,7 @@ ClangImporter::Implementation::importParameterType( ArrayRef genericParams, llvm::function_ref addImportDiagnosticFn) { auto paramTy = desugarIfElaborated(param->getType()); + paramTy = desugarIfBoundsAttributed(paramTy); ImportTypeKind importKind = paramIsCompletionHandler ? ImportTypeKind::CompletionHandlerParameter diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 1951b9acb935d..657d152398578 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -2102,6 +2102,22 @@ inline clang::QualType desugarIfElaborated(clang::QualType type) { return type; } +inline clang::QualType desugarIfBoundsAttributed(clang::QualType type) { + if (auto BAT = dyn_cast(type)) + return BAT->desugar(); + if (auto VT = dyn_cast(type)) + return VT->desugar(); + if (auto AT = dyn_cast(type)) + switch (AT->getAttrKind()) { + case clang::attr::PtrUnsafeIndexable: + case clang::attr::PtrSingle: + return AT->desugar(); + default: + break; + } + return type; +} + /// Option set enums are sometimes imported as typedefs which assign a name to /// the type, but are unavailable in Swift. /// diff --git a/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift b/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift new file mode 100644 index 0000000000000..4c726d8f6af88 --- /dev/null +++ b/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift @@ -0,0 +1,68 @@ +// REQUIRES: swift_feature_SafeInteropWrappers + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers %t/template.swift -dump-macro-expansions -emit-ir -o %t/out -verify +// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -cxx-interoperability-mode=default -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Template -source-filename=x | %FileCheck %s + +// CHECK: func cb_template(_ p: UnsafePointer, _ size: Int{{.*}}) -> UnsafePointer +// CHECK: func eb_template(_ p: UnsafePointer, _ end: UnsafePointer) -> UnsafePointer +// CHECK: func s_template(_ p: UnsafePointer) -> UnsafePointer +// CHECK: func ui_template(_ p: UnsafePointer) -> UnsafePointer + +//--- Inputs/module.modulemap +module Template { + header "template.h" + requires cplusplus +} + +//--- Inputs/template.h +#include +#include + +template +inline const T* __counted_by(size) cb_template(const T* __counted_by(size) p __noescape, int size) { return p; } + +template +inline const T* __ended_by(end) eb_template(const T* __ended_by(end) p __noescape, const T* end) { return p; } + +template +inline const T* __single s_template(const T* __single p) { return p; } + +template +inline const T* __unsafe_indexable ui_template(const T* __unsafe_indexable p) { return p; } + +// FIXME: parse null_terminated in templated contexts +// template +// inline const T* __null_terminated nt_template(const T* __null_terminated p) {} + +//--- template.swift +import Template + +// make sure the original functions are still available when parsing bounds attributes +func testOriginalCB(p: UnsafePointer, len: CInt) { + let _ = cb_template(p, len) +} +func testOriginalEB(p: UnsafePointer, end: UnsafePointer) { + let _ = eb_template(p, end) +} +func testOriginalS(s: UnsafePointer) { + let _ = s_template(s) +} +func testOriginalUI(s: UnsafePointer) { + let _ = ui_template(s) +} + + // FIXME: generate safe overloads for templated functions (rdar://151481042) +func testSafeOverloadCB(s: Span) { + // expected-error@+3{{generic parameter 'T' could not be inferred}} + // expected-error@+2{{cannot convert value of type 'Span'}} + // expected-error@+1{{missing argument for parameter #2 in call}} + cb_template(s) +} +func testSafeOverloadEB(s: Span) { + // expected-error@+3{{generic parameter 'T' could not be inferred}} + // expected-error@+2{{cannot convert value of type 'Span'}} + // expected-error@+1{{missing argument for parameter #2 in call}} + eb_template(s) +}