diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index a939a5e8a95b8..4a4674d6598d4 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -881,8 +881,15 @@ ClangTypeConverter::convertClangDecl(Type type, const clang::Decl *clangDecl) { if (auto clangTypeDecl = dyn_cast(clangDecl)) { auto qualType = ctx.getTypeDeclType(clangTypeDecl); - if (type->isForeignReferenceType()) + if (type->isForeignReferenceType()) { qualType = ctx.getPointerType(qualType); + auto nonNullAttr = new (ctx) clang::TypeNonNullAttr( + ctx, + clang::AttributeCommonInfo( + clang::SourceRange(), clang::AttributeCommonInfo::AT_TypeNonNull, + clang::AttributeCommonInfo::Form::Implicit())); + qualType = ctx.getAttributedType(nonNullAttr, qualType, qualType); + } return qualType.getUnqualifiedType(); } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 7079888ec18db..d34af23dd356b 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2458,6 +2458,13 @@ ClangImporter::Implementation::importParameterType( auto paramTy = desugarIfElaborated(param->getType()); paramTy = desugarIfBoundsAttributed(paramTy); + // If this type has a _Nullable/_Nonnull attribute, drop it, since we already + // have that information in optionalityOfParam. + if (auto attributedTy = dyn_cast(paramTy)) { + if (attributedTy->getImmediateNullability()) + clang::AttributedType::stripOuterNullability(paramTy); + } + ImportTypeKind importKind = paramIsCompletionHandler ? ImportTypeKind::CompletionHandlerParameter : ImportTypeKind::Parameter; @@ -2486,6 +2493,17 @@ ClangImporter::Implementation::importParameterType( pointerKind)); return std::nullopt; } + switch (optionalityOfParam) { + case OTK_Optional: + swiftParamTy = OptionalType::get(swiftParamTy); + break; + case OTK_ImplicitlyUnwrappedOptional: + swiftParamTy = OptionalType::get(swiftParamTy); + isParamTypeImplicitlyUnwrapped = true; + break; + case OTK_None: + break; + } } else if (isa(paramTy) && isa(paramTy->getPointeeType())) { // We don't support universal reference, bail. @@ -2734,8 +2752,6 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( } bool knownNonNull = !nonNullArgs.empty() && nonNullArgs[index]; - // Specialized templates need to match the args/result exactly. - knownNonNull |= clangDecl->isFunctionTemplateSpecialization(); // Check nullability of the parameter. OptionalTypeKind optionalityOfParam = diff --git a/stdlib/public/Cxx/CxxSpan.swift b/stdlib/public/Cxx/CxxSpan.swift index 1da23193b0cb2..fcd202d87c5a2 100644 --- a/stdlib/public/Cxx/CxxSpan.swift +++ b/stdlib/public/Cxx/CxxSpan.swift @@ -66,7 +66,7 @@ public protocol CxxSpan { associatedtype Size: BinaryInteger init() - init(_ unsafePointer : UnsafePointer, _ count: Size) + init(_ unsafePointer: UnsafePointer!, _ count: Size) func size() -> Size func __dataUnsafe() -> UnsafePointer? @@ -136,7 +136,7 @@ public protocol CxxMutableSpan { associatedtype Size: BinaryInteger init() - init(_ unsafeMutablePointer : UnsafeMutablePointer, _ count: Size) + init(_ unsafeMutablePointer: UnsafeMutablePointer!, _ count: Size) func size() -> Size func __dataUnsafe() -> UnsafeMutablePointer? diff --git a/stdlib/public/Cxx/cxxshim/libcxxshim.h b/stdlib/public/Cxx/cxxshim/libcxxshim.h index 102bc1548faa5..52df8cc647914 100644 --- a/stdlib/public/Cxx/cxxshim/libcxxshim.h +++ b/stdlib/public/Cxx/cxxshim/libcxxshim.h @@ -1,2 +1,4 @@ template -To __swift_interopStaticCast(From from) { return static_cast(from); } \ No newline at end of file +To _Nonnull __swift_interopStaticCast(From _Nonnull from) { + return static_cast(from); +} diff --git a/test/Interop/Cxx/stdlib/use-std-span-typechecker.swift b/test/Interop/Cxx/stdlib/use-std-span-typechecker.swift index 51b6444ea1921..7b868bb347748 100644 --- a/test/Interop/Cxx/stdlib/use-std-span-typechecker.swift +++ b/test/Interop/Cxx/stdlib/use-std-span-typechecker.swift @@ -15,7 +15,5 @@ arr.withUnsafeBufferPointer { ubpointer in arr.withUnsafeBufferPointer { ubpointer in // FIXME: this crashes the compiler once we import span's templated ctors as Swift generics. let _ = ConstSpanOfInt(ubpointer.baseAddress, ubpointer.count) - // expected-error@-1 {{value of optional type 'UnsafePointer?' must be unwrapped to a value of type 'UnsafePointer'}} - // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} - // expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} + // expected-warning@-1 {{'init(_:_:)' is deprecated: use 'init(_:)' instead.}} } diff --git a/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift b/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift index 4c726d8f6af88..f09d490ebfd0c 100644 --- a/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift +++ b/test/Interop/Cxx/swiftify-import/bounds-attrs-in-template.swift @@ -5,10 +5,10 @@ // 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 +// 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 { diff --git a/test/Interop/Cxx/templates/Inputs/function-templates.h b/test/Interop/Cxx/templates/Inputs/function-templates.h index 7121752bec13a..a2a9d8da0a774 100644 --- a/test/Interop/Cxx/templates/Inputs/function-templates.h +++ b/test/Interop/Cxx/templates/Inputs/function-templates.h @@ -120,7 +120,9 @@ template bool constLvalueReferenceToBool(const T &t) { return t; } template void forwardingReference(T &&) {} -template void PointerTemplateParameter(T*){} +template bool pointerTemplateParameter(T *t) { return t; } +template bool pointerTemplateParameterNonnull(T *_Nonnull t) { return t; } +template bool pointerTemplateParameterNullable(T *_Nullable t) { return t; } template void callFunction(F f) { f(); } template void callFunctionWithParam(F f, T t) { f(t); } diff --git a/test/Interop/Cxx/templates/defaulted-template-type-parameter-module-interface.swift b/test/Interop/Cxx/templates/defaulted-template-type-parameter-module-interface.swift index 45cbddf4d0531..7d7f7c70895db 100644 --- a/test/Interop/Cxx/templates/defaulted-template-type-parameter-module-interface.swift +++ b/test/Interop/Cxx/templates/defaulted-template-type-parameter-module-interface.swift @@ -21,6 +21,6 @@ // TODO-CHECK: func defaultedTemplatePointerTypeParam(_ t: UnsafeMutablePointer) // TODO-CHECK: func defaultedTemplatePointerPointerTypeParam(_ t: UnsafeMutablePointer!) -// CHECK: func defaultedTemplatePointerTypeParam(_ t: UnsafeMutablePointer) +// CHECK: func defaultedTemplatePointerTypeParam(_ t: UnsafeMutablePointer!) // We don't support references to dependent types (rdar://89034440). // CHECK-NOT: defaultedTemplatePointerReferenceTypeParam diff --git a/test/Interop/Cxx/templates/function-template-module-interface.swift b/test/Interop/Cxx/templates/function-template-module-interface.swift index 34f92bead4074..38cc7f1906630 100644 --- a/test/Interop/Cxx/templates/function-template-module-interface.swift +++ b/test/Interop/Cxx/templates/function-template-module-interface.swift @@ -20,7 +20,10 @@ // CHECK: func lvalueReference(_ ref: inout T) // CHECK: func constLvalueReference(_: T) -// CHECK: func PointerTemplateParameter(_: UnsafeMutablePointer) + +// CHECK: func pointerTemplateParameter(_ t: UnsafeMutablePointer!) -> Bool +// CHECK: func pointerTemplateParameterNonnull(_ t: UnsafeMutablePointer) -> Bool +// CHECK: func pointerTemplateParameterNullable(_ t: UnsafeMutablePointer?) -> Bool // CHECK: enum Orbiters { // CHECK: static func galileo(_: T) diff --git a/test/Interop/Cxx/templates/function-template.swift b/test/Interop/Cxx/templates/function-template.swift index d718040390e8d..e78a4d2aabc22 100644 --- a/test/Interop/Cxx/templates/function-template.swift +++ b/test/Interop/Cxx/templates/function-template.swift @@ -39,6 +39,26 @@ FunctionTemplateTestSuite.test("constLvalueReferenceToBool where T == Bool") expectFalse(constLvalueReferenceToBool(false)) } +var nilPtr: UnsafeMutablePointer? = nil +var nilPtrIOU: UnsafeMutablePointer! = nil +var nonNilPtr: UnsafeMutablePointer = .init(bitPattern: 123)! + +FunctionTemplateTestSuite.test("pointerTemplateParameter") { + expectFalse(pointerTemplateParameter(nilPtr)) + expectFalse(pointerTemplateParameter(nilPtrIOU)) + expectTrue(pointerTemplateParameter(nonNilPtr)) +} + +FunctionTemplateTestSuite.test("pointerTemplateParameterNonnull") { + expectTrue(pointerTemplateParameterNonnull(nonNilPtr)) +} + +FunctionTemplateTestSuite.test("pointerTemplateParameterNullable") { + expectFalse(pointerTemplateParameterNullable(nilPtr)) + expectFalse(pointerTemplateParameterNullable(nilPtrIOU)) + expectTrue(pointerTemplateParameterNullable(nonNilPtr)) +} + // TODO: Generics, Any, and Protocols should be tested here but need to be // better supported in ClangTypeConverter first. diff --git a/test/Interop/Cxx/templates/template-instantiation-irgen.swift b/test/Interop/Cxx/templates/template-instantiation-irgen.swift index e2f90959410b1..fe334652aa1ec 100644 --- a/test/Interop/Cxx/templates/template-instantiation-irgen.swift +++ b/test/Interop/Cxx/templates/template-instantiation-irgen.swift @@ -46,8 +46,8 @@ func takesPtrToStruct(x: UnsafePointer) { takesValue(x) } func takesPtrToClass(x: UnsafePointer) { takesValue(x) } // CHECK: define {{.*}} void @{{.*}}takesPtrToClass{{.*}} -// FIXME: this crashes because this round-trips to UnsafePointer -// func takesPtrToFRT(x: UnsafePointer) { takesValue(x) } +func takesPtrToFRT(x: UnsafePointer) { takesValue(x) } +// CHECK: define {{.*}} void @{{.*}}takesPtrToFRT{{.*}} func takesMutPtrToStruct(x: UnsafeMutablePointer) { takesValue(x) } // CHECK: define {{.*}} void @{{.*}}takesMutPtrToStruct{{.*}} @@ -55,12 +55,11 @@ func takesMutPtrToStruct(x: UnsafeMutablePointer) { takesValue(x) } func takesMutPtrToClass(x: UnsafeMutablePointer) { takesValue(x) } // CHECK: define {{.*}} void @{{.*}}takesMutPtrToClass{{.*}} -// FIXME: this crashes because this round-trips to UnsafeMutablePointer -// func takesMutPtrToFRT(x: UnsafeMutablePointer) { takesValue(x) } +func takesMutPtrToFRT(x: UnsafeMutablePointer) { takesValue(x) } +// CHECK: define {{.*}} void @{{.*}}takesMutPtrToFRT{{.*}} func takesCPtr() { - // FIXME: optional pointers are not yet supported but they should be; this crashes - // takesValue(intPtr) + takesValue(intPtr) // It's fine if we dereference it, though takesValue(intPtr!) @@ -92,9 +91,6 @@ func takesSwiftClosureTakingCxxClass() { takesValue({(x: CxxClass) in takesValue func takesTakesCxxClass() { takesValue(takesCxxClass) } func takesSwiftClosureReturningFRT() { takesValue({() -> FRT in FRT()}) } +func takesSwiftClosureTakingFRT() { takesValue({(x: FRT) in takesValue(x)}) } -// FIXME: this crashes due to pointer round-tripping -// func takesSwiftClosureTakingFRT() { takesValue({(x: FRT) in takesValue(x)}) } - -// FIXME: this crashes due to pointer round-tripping -// func takesTakesFRT() { takesValue(takesFRT) } +func takesTakesFRT() { takesValue(takesFRT) }