diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 50180e3960e8a..87b776b35282b 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -62,8 +62,9 @@ #include "clang/AST/DeclObjCCommon.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" -#include "clang/AST/StmtVisitor.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" @@ -9119,6 +9120,24 @@ namespace { }; } // namespace +namespace { +// Searches for template instantiations that are not behind type aliases. +// FIXME: make sure the generated code compiles for template +// instantiations that are not behind type aliases. +struct UnaliasedInstantiationVisitor + : clang::RecursiveASTVisitor { + bool hasUnaliasedInstantiation = false; + + bool TraverseTypedefType(const clang::TypedefType *) { return true; } + + bool + VisitTemplateSpecializationType(const clang::TemplateSpecializationType *) { + hasUnaliasedInstantiation = true; + return false; + } +}; +} // namespace + // Don't try to transform any Swift types that _SwiftifyImport doesn't know how // to handle. static bool SwiftifiableCountedByPointerType(Type swiftType) { @@ -9173,6 +9192,13 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) { if (ClangDecl->getNumParams() != MappedDecl->getParameters()->size()) return; + { + UnaliasedInstantiationVisitor visitor; + visitor.TraverseType(ClangDecl->getType()); + if (visitor.hasUnaliasedInstantiation) + return; + } + llvm::SmallString<128> MacroString; // We only attach the macro if it will produce an overload. Any __counted_by // will produce an overload, since UnsafeBufferPointer is still an improvement diff --git a/test/Interop/Cxx/stdlib/Inputs/std-span.h b/test/Interop/Cxx/stdlib/Inputs/std-span.h index d49773165ccaf..2657dec2ccbdc 100644 --- a/test/Interop/Cxx/stdlib/Inputs/std-span.h +++ b/test/Interop/Cxx/stdlib/Inputs/std-span.h @@ -165,12 +165,20 @@ inline SpanOfInt MixedFuncWithMutableSafeWrapper7(int * __counted_by(len) p, int return SpanOfInt(p, len); } +template +struct S {}; + struct SpanWithoutTypeAlias { std::span bar() [[clang::lifetimebound]]; void foo(std::span s [[clang::noescape]]); + void otherTemplatedType(ConstSpanOfInt copy [[clang::noescape]], S); + void otherTemplatedType2(ConstSpanOfInt copy [[clang::noescape]], S *); }; inline void func(ConstSpanOfInt copy [[clang::noescape]]) {} inline void mutableKeyword(SpanOfInt copy [[clang::noescape]]) {} +inline void spanWithoutTypeAlias(std::span s [[clang::noescape]]) {} +inline void mutableSpanWithoutTypeAlias(std::span s [[clang::noescape]]) {} + #endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_SPAN_H diff --git a/test/Interop/Cxx/stdlib/std-span-interface.swift b/test/Interop/Cxx/stdlib/std-span-interface.swift index 4c812467a23ab..2a11fd0dd0f84 100644 --- a/test/Interop/Cxx/stdlib/std-span-interface.swift +++ b/test/Interop/Cxx/stdlib/std-span-interface.swift @@ -3,7 +3,7 @@ // RUN: %FileCheck %s < %t/interface.swift // Make sure we trigger typechecking and SIL diagnostics -// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature Lifetimes -cxx-interoperability-mode=default -strict-memory-safety -warnings-as-errors -Xcc -std=c++20 %s +// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature Lifetimes -cxx-interoperability-mode=default -strict-memory-safety -warnings-as-errors -verify -Xcc -std=c++20 %s // REQUIRES: swift_feature_SafeInteropWrappers // REQUIRES: swift_feature_Lifetimes @@ -34,15 +34,10 @@ import CxxStdlib // CHECK-NEXT: } // CHECK: struct SpanWithoutTypeAlias { // CHECK-NEXT: init() -// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop -// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) -// CHECK-NEXT: @_lifetime(borrow self) -// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public mutating func bar() -> Span // CHECK-NEXT: mutating func bar() -> std.{{.*}}span<__cxxConst, _C{{.*}}_{{.*}}> -// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop -// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) -// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public mutating func foo(_ s: Span) // CHECK-NEXT: mutating func foo(_ s: std.{{.*}}span<__cxxConst, _C{{.*}}_{{.*}}>) +// CHECK-NEXT: mutating func otherTemplatedType(_ copy: ConstSpanOfInt, _: S) +// CHECK-NEXT: mutating func otherTemplatedType2(_ copy: ConstSpanOfInt, _: UnsafeMutablePointer>!) // CHECK-NEXT: } // CHECK: /// This is an auto-generated wrapper for safer interop @@ -150,7 +145,7 @@ func callMethodWithSafeWrapper(_ x: inout X, s: Span) { } func callFooBar(_ x: inout SpanWithoutTypeAlias, _ s: ConstSpanOfInt) { - let _: Span = x.bar() + let _: Span = x.bar() // expected-error {{cannot convert value of type}} unsafe x.foo(s) } @@ -242,3 +237,11 @@ func callMixedFuncWithSafeWrapper7(_ p: UnsafeBufferPointer) { func callMutableKeyword(_ span: inout MutableSpan) { mutableKeyword(&span) } + +func callSpanWithoutTypeAlias(_ span: Span) { + spanWithoutTypeAlias(span) // expected-error {{cannot convert value of type}} +} + +func callMutableSpanWithoutTypeAlias(_ span: consuming MutableSpan) { + mutableSpanWithoutTypeAlias(&span) // expected-error {{cannot convert value of type}} +}