diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 17dc9aa1a7194..8d6c763018baa 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -5881,6 +5881,8 @@ namespace { result->setMemberLoader(&Impl, 0); + Impl.swiftifyProtocol(result); + return result; } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index e17f4d8d20d6e..fef4067233d05 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1827,6 +1827,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation void addOptionSetTypealiases(NominalTypeDecl *nominal); void swiftify(AbstractFunctionDecl *MappedDecl); + void swiftifyProtocol(NominalTypeDecl *MappedDecl); /// Find the lookup table that corresponds to the given Clang module. /// diff --git a/lib/ClangImporter/SwiftifyDecl.cpp b/lib/ClangImporter/SwiftifyDecl.cpp index 7be08be0032a9..06a96050849b1 100644 --- a/lib/ClangImporter/SwiftifyDecl.cpp +++ b/lib/ClangImporter/SwiftifyDecl.cpp @@ -16,6 +16,7 @@ #include "ImporterImpl.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/ParameterList.h" @@ -30,13 +31,42 @@ using namespace swift; using namespace importer; #define DEBUG_TYPE "safe-interop-wrappers" -#define DLOG(x) LLVM_DEBUG(llvm::dbgs() << x) + +#define DLOG(x) LLVM_DEBUG(LogIndentTracker::indent(DBGS) << x) + +#ifndef NDEBUG +#define DBGS llvm::dbgs() << "[swiftify:" << __LINE__ << "] " +#define DUMP(x) DLOG(""); x->dump() +#define DLOG_SCOPE(x) DLOG(x); LogIndentTracker Scope +#else +#define DLOG_SCOPE(x) do {} while(false); +#endif + namespace { +#ifndef NDEBUG +struct LogIndentTracker { + static thread_local uint8_t LogIndent; + static llvm::raw_ostream &indent(llvm::raw_ostream &out) { + for (uint8_t i = 0; i < LogIndent; i++) + out << "| "; + return out; + } + + LogIndentTracker() { + LogIndent++; + } + ~LogIndentTracker() { + LogIndent--; + } +}; +thread_local uint8_t LogIndentTracker::LogIndent = 0; +#endif + ValueDecl *getKnownSingleDecl(ASTContext &SwiftContext, StringRef DeclName) { SmallVector decls; SwiftContext.lookupInSwiftModule(DeclName, decls); - assert(decls.size() < 2); + ASSERT(decls.size() < 2); if (decls.size() != 1) return nullptr; return decls[0]; } @@ -151,6 +181,7 @@ class SwiftifyInfoPrinter { out << "\""; } +protected: void printSeparator() { if (!firstParam) { out << ", "; @@ -159,6 +190,7 @@ class SwiftifyInfoPrinter { } } +private: void printParamOrReturn(ssize_t pointerIndex) { if (pointerIndex == SELF_PARAM_INDEX) out << ".self"; @@ -186,8 +218,7 @@ struct CountedByExpressionValidator case clang::BuiltinType::ULong: case clang::BuiltinType::LongLong: case clang::BuiltinType::ULongLong: - // These integer literals are printed with a suffix that isn't valid Swift - // syntax + DLOG("Ignoring count parameter with non-portable integer literal"); return false; default: return true; @@ -226,7 +257,10 @@ struct CountedByExpressionValidator SUPPORTED_BINOP(Or) #undef SUPPORTED_BINOP - bool VisitStmt(const clang::Stmt *) { return false; } + bool VisitStmt(const clang::Stmt *) { + DLOG("Ignoring count parameter with unsupported expression\n"); + return false; + } }; @@ -245,16 +279,24 @@ static bool SwiftifiableSizedByPointerType(const clang::ASTContext &ctx, if (nonnullType->isOpaquePointer()) return true; PointerTypeKind PTK; - if (!nonnullType->getAnyPointerElementType(PTK)) + if (!nonnullType->getAnyPointerElementType(PTK)) { + DLOG("Ignoring sized_by on non-pointer type\n"); return false; + } if (PTK == PTK_UnsafeRawPointer || PTK == PTK_UnsafeMutableRawPointer) return true; - if (PTK != PTK_UnsafePointer && PTK != PTK_UnsafeMutablePointer) + if (PTK != PTK_UnsafePointer && PTK != PTK_UnsafeMutablePointer) { + DLOG("Ignoring sized_by on Autoreleasing pointer\n"); + CONDITIONAL_ASSERT(PTK == PTK_AutoreleasingUnsafeMutablePointer); return false; + } // We have a pointer to a type with a size. Verify that it is char-sized. auto PtrT = CAT->getAs(); auto PointeeT = PtrT->getPointeeType(); - return ctx.getTypeSizeInChars(PointeeT).isOne(); + bool isByteSized ctx.getTypeSizeInChars(PointeeT).isOne(); + if (!isByteSized) + DLOG("Ignoring sized_by on non-byte-sized pointer\n"); + return isByteSized; } static bool SwiftifiableCAT(const clang::ASTContext &ctx, const clang::CountAttributedType *CAT, @@ -277,6 +319,7 @@ struct UnaliasedInstantiationVisitor bool VisitTemplateSpecializationType(const clang::TemplateSpecializationType *) { hasUnaliasedInstantiation = true; + DLOG("Signature contains raw template, skipping"); return false; } }; @@ -296,13 +339,26 @@ static StringRef getAttributeName(const clang::CountAttributedType *CAT) { llvm_unreachable("CountAttributedType cannot be ended_by"); } } + +template +static bool getImplicitObjectParamAnnotation(const clang::ObjCMethodDecl* D) { + return false; // Only C++ methods have implicit params +} + +static size_t getNumParams(const clang::ObjCMethodDecl* D) { + return D->param_size(); +} +static size_t getNumParams(const clang::FunctionDecl* D) { + return D->getNumParams(); +} } // namespace +template static bool swiftifyImpl(ClangImporter::Implementation &Self, SwiftifyInfoPrinter &printer, const AbstractFunctionDecl *MappedDecl, - const clang::FunctionDecl *ClangDecl) { - DLOG("Checking " << *ClangDecl << " for bounds and lifetime info\n"); + const T *ClangDecl) { + DLOG_SCOPE("Checking '" << *ClangDecl << "' for bounds and lifetime info\n"); // FIXME: for private macro generated functions we do not serialize the // SILFunction's body anywhere triggering assertions. @@ -310,13 +366,6 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, ClangDecl->getAccess() == clang::AS_private) return false; - { - UnaliasedInstantiationVisitor visitor; - visitor.TraverseType(ClangDecl->getType()); - if (visitor.hasUnaliasedInstantiation) - return false; - } - clang::ASTContext &clangASTContext = Self.getClangASTContext(); // We only attach the macro if it will produce an overload. Any __counted_by @@ -332,12 +381,13 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, swiftReturnTy = ctorDecl->getResultInterfaceType(); else ABORT("Unexpected AbstractFunctionDecl subclass."); + clang::QualType clangReturnTy = ClangDecl->getReturnType(); bool returnIsStdSpan = printer.registerStdSpanTypeMapping( - swiftReturnTy, ClangDecl->getReturnType()); - auto *CAT = ClangDecl->getReturnType()->getAs(); + swiftReturnTy, clangReturnTy); + auto *CAT = clangReturnTy->getAs(); if (SwiftifiableCAT(clangASTContext, CAT, swiftReturnTy)) { printer.printCountedBy(CAT, SwiftifyInfoPrinter::RETURN_VALUE_INDEX); - DLOG(" Found bounds info '" << clang::QualType(CAT, 0) << "' on return value\n"); + DLOG("Found bounds info '" << clang::QualType(CAT, 0) << "' on return value\n"); attachMacro = true; } auto dependsOnClass = [](const ParamDecl *fromParam) { @@ -345,12 +395,14 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, }; bool returnHasLifetimeInfo = false; if (getImplicitObjectParamAnnotation(ClangDecl)) { - DLOG(" Found lifetimebound attribute on implicit 'this'\n"); + DLOG("Found lifetimebound attribute on implicit 'this'\n"); if (!dependsOnClass( MappedDecl->getImplicitSelfDecl(/*createIfNeeded*/ true))) { printer.printLifetimeboundReturn(SwiftifyInfoPrinter::SELF_PARAM_INDEX, true); returnHasLifetimeInfo = true; + } else { + DLOG("lifetimebound ignored because it depends on class with refcount\n"); } } @@ -361,13 +413,15 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, size_t swiftNumParams = MappedDecl->getParameters()->size() - (ClangDecl->isVariadic() ? 1 : 0); ASSERT((MappedDecl->isImportAsInstanceMember() == isClangInstanceMethod) == - (ClangDecl->getNumParams() == swiftNumParams)); + (getNumParams(ClangDecl) == swiftNumParams)); size_t selfParamIndex = MappedDecl->isImportAsInstanceMember() ? MappedDecl->getSelfIndex() - : ClangDecl->getNumParams(); + : getNumParams(ClangDecl); for (auto [index, clangParam] : llvm::enumerate(ClangDecl->parameters())) { - auto clangParamTy = clangParam->getType(); + clang::QualType clangParamTy = clangParam->getType(); + DLOG_SCOPE("Checking parameter '" << *clangParam << "' with type '" + << clangParamTy << "'\n"); int mappedIndex = index < selfParamIndex ? index : index > selfParamIndex ? index - 1 : SwiftifyInfoPrinter::SELF_PARAM_INDEX; @@ -383,17 +437,15 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, auto *CAT = clangParamTy->getAs(); if (CAT && mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX) { Self.diagnose(HeaderLoc(clangParam->getLocation()), - diag::warn_clang_ignored_bounds_on_self, - getAttributeName(CAT)); - auto swiftName = ClangDecl->getAttr(); + diag::warn_clang_ignored_bounds_on_self, getAttributeName(CAT)); + auto swiftName = ClangDecl->template getAttr(); ASSERT(swiftName && "free function mapped to instance method without swift_name??"); Self.diagnose(HeaderLoc(swiftName->getLocation()), - diag::note_swift_name_instance_method); + diag::note_swift_name_instance_method); } else if (SwiftifiableCAT(clangASTContext, CAT, swiftParamTy)) { printer.printCountedBy(CAT, mappedIndex); - DLOG(" Found bounds info '" << clangParamTy << "' on parameter '" - << *clangParam << "'\n"); + DLOG("Found bounds info '" << clangParamTy << "'\n"); attachMacro = paramHasBoundsInfo = true; } bool paramIsStdSpan = @@ -401,14 +453,13 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, paramHasBoundsInfo |= paramIsStdSpan; bool paramHasLifetimeInfo = false; - if (clangParam->hasAttr()) { - DLOG(" Found noescape attribute on parameter '" << *clangParam << "'\n"); + if (clangParam->template hasAttr()) { + DLOG("Found noescape attribute\n"); printer.printNonEscaping(mappedIndex); paramHasLifetimeInfo = true; } if (clangParam->template hasAttr()) { - DLOG(" Found lifetimebound attribute on parameter '" << *clangParam - << "'\n"); + DLOG("Found lifetimebound attribute\n"); if (!dependsOnClass(swiftParam)) { // If this parameter has bounds info we will tranform it into a Span, // so then it will no longer be Escapable. @@ -419,22 +470,64 @@ static bool swiftifyImpl(ClangImporter::Implementation &Self, printer.printLifetimeboundReturn(mappedIndex, willBeEscapable); paramHasLifetimeInfo = true; returnHasLifetimeInfo = true; + } else { + DLOG("lifetimebound ignored because it depends on class with refcount\n"); } } if (paramIsStdSpan && paramHasLifetimeInfo) { - DLOG(" Found both std::span and lifetime info for parameter '" - << *clangParam << "'\n"); + DLOG("Found both std::span and lifetime info\n"); attachMacro = true; } } if (returnIsStdSpan && returnHasLifetimeInfo) { - DLOG(" Found both std::span and lifetime info for return value\n"); + DLOG("Found both std::span and lifetime info for return value\n"); attachMacro = true; } } return attachMacro; } +class SwiftifyProtocolInfoPrinter : public SwiftifyInfoPrinter { +private: + ClangImporter::Implementation &ImporterImpl; + +public: + SwiftifyProtocolInfoPrinter(ClangImporter::Implementation &ImporterImpl, + clang::ASTContext &ctx, ASTContext &SwiftContext, + llvm::raw_ostream &out, + MacroDecl &SwiftifyImportDecl) + : SwiftifyInfoPrinter(ctx, SwiftContext, out, SwiftifyImportDecl), + ImporterImpl(ImporterImpl) {} + + bool printMethod(const FuncDecl *Method) { + // don't emit .method() if we know it's going to be empty + auto ClangDecl = dyn_cast_or_null(Method->getClangDecl()); + if (!ClangDecl) + return false; + + printSeparator(); + out << ".method(signature: \""; + printMethodSignature(Method); + out << "\", paramInfo: ["; + // reset firstParam inside paramInfo array. At this point firstParam will + // always be false, so no need to save the current value. + ASSERT(!firstParam); + firstParam = true; + bool hadAttributes = swiftifyImpl(ImporterImpl, *this, Method, ClangDecl); + firstParam = false; + out << "])"; + return hadAttributes; + } + +private: + void printMethodSignature(const FuncDecl *Method) { + auto options = + PrintOptions::printForDiagnostics(AccessLevel::Private, true); + StreamPrinter printer(out); + Method->print(printer, options); + } +}; + void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) { if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers) || SwiftContext.ClangImporterOpts.DisableSafeInteropWrappers) @@ -443,9 +536,23 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) { if (!ClangDecl) return; + DLOG_SCOPE( + "Checking '" << *ClangDecl << "' (imported as '" + << MappedDecl->getName().getBaseName().userFacingName() + << "')\n"); + + { + UnaliasedInstantiationVisitor visitor; + visitor.TraverseType(ClangDecl->getType()); + if (visitor.hasUnaliasedInstantiation) + return; + } + MacroDecl *SwiftifyImportDecl = dyn_cast_or_null(getKnownSingleDecl(SwiftContext, "_SwiftifyImport")); - if (!SwiftifyImportDecl) + if (!SwiftifyImportDecl) { + DLOG("_SwiftifyImport macro not found"); return; + } llvm::SmallString<128> MacroString; { @@ -453,8 +560,10 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) { out << "@_SwiftifyImport"; SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out, *SwiftifyImportDecl); - if (!swiftifyImpl(*this, printer, MappedDecl, ClangDecl)) + if (!swiftifyImpl(*this, printer, MappedDecl, ClangDecl)) { + DLOG("No relevant bounds or lifetime info found\n"); return; + } printer.printAvailability(); printer.printTypeMapping(); } @@ -479,3 +588,48 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) { } } +void ClangImporter::Implementation::swiftifyProtocol( + NominalTypeDecl *MappedDecl) { + if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers) || + SwiftContext.ClangImporterOpts.DisableSafeInteropWrappers) + return; + if (!isa(MappedDecl)) + return; + + MacroDecl *SwiftifyImportDecl = dyn_cast_or_null( + getKnownSingleDecl(SwiftContext, "_SwiftifyImportProtocol")); + if (!SwiftifyImportDecl) { + DLOG("_SwiftifyImportProtocol macro not found"); + return; + } + + DLOG_SCOPE("Checking '" << MappedDecl->getName() + << "' protocol for methods with bounds and lifetime info\n"); + llvm::SmallString<128> MacroString; + { + llvm::raw_svector_ostream out(MacroString); + out << "@_SwiftifyImportProtocol"; + + bool hasBoundsAttributes = false; + SwiftifyProtocolInfoPrinter printer(*this, getClangASTContext(), + SwiftContext, out, *SwiftifyImportDecl); + for (Decl *SwiftMember : + cast(MappedDecl)->getAllMembers()) { + FuncDecl *SwiftDecl = dyn_cast(SwiftMember); + if (!SwiftDecl) + continue; + hasBoundsAttributes |= printer.printMethod(SwiftDecl); + } + + if (!hasBoundsAttributes) { + DLOG("No relevant bounds or lifetime info found\n"); + return; + } + printer.printAvailability(); + printer.printTypeMapping(); + } + + DLOG("Attaching safe interop macro: " << MacroString << "\n"); + importNontrivialAttribute(MappedDecl, MacroString); +} + diff --git a/lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift b/lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift index ea5af950daf3a..461807dbe4847 100644 --- a/lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift +++ b/lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift @@ -1808,11 +1808,21 @@ public struct SwiftifyImportProtocolMacro: ExtensionMacro { } let overloads = try arguments.map { let (method, args) = try parseProtocolMacroParam($0, methods: methods) - let function = try constructOverloadFunction( + let hasVisibilityModifier = method.modifiers.contains { modifier in + let modName = modifier.name.trimmed.text + return modName == "public" || modName == "internal" || modName == "open" + || modName == "private" || modName == "filePrivate" + } + let result = try constructOverloadFunction( forDecl: method, leadingTrivia: Trivia(), args: args, spanAvailability: spanAvailability, typeMappings: typeMappings) - return MemberBlockItemSyntax(decl: function) + guard let newMethod = result.as(FunctionDeclSyntax.self)? + .with(\.modifiers, method.modifiers + + (hasVisibilityModifier ? [] : [DeclModifierSyntax(name: .identifier("public"))])) else { + throw RuntimeError("expected FunctionDeclSyntax but got \(result.kind) for \(method.description)") + } + return MemberBlockItemSyntax(decl: newMethod) } return [ExtensionDeclSyntax(extensionKeyword: .identifier("extension"), extendedType: type, diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 9e57b5a012a13..6df797d829003 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -1360,6 +1360,7 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) { return macroSourceFile->getBufferID(); } + static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr, bool passParentContext, MacroRole role, @@ -1370,7 +1371,11 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, dc = attachedTo->getDeclContext(); } else if (role == MacroRole::Conformance || role == MacroRole::Extension) { // Conformance macros always expand to extensions at file-scope. - dc = attachedTo->getDeclContext()->getParentSourceFile(); + dc = attachedTo->getDeclContext(); + if (!isa(dc->getModuleScopeContext())) + dc = dc->getParentSourceFile(); + else // decls imported from clang do not have a SourceFile + ASSERT(isa(dc) && !isa(dc)); } else { dc = attachedTo->getInnermostDeclContext(); } diff --git a/test/Interop/ObjC/swiftify-import/counted-by-protocol.swift b/test/Interop/ObjC/swiftify-import/counted-by-protocol.swift new file mode 100644 index 0000000000000..efe843e4d6037 --- /dev/null +++ b/test/Interop/ObjC/swiftify-import/counted-by-protocol.swift @@ -0,0 +1,133 @@ +// REQUIRES: swift_feature_SafeInteropWrappers + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/CountedByProtocol.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/counted-by-protocol.swift -verify -Xcc -Wno-nullability-completeness +// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/CountedByProtocol.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/counted-by-protocol.swift -dump-macro-expansions 2> %t/expansions.out +// RUN: %diff %t/expansions.out %t/expansions.expected + +//--- Inputs/module.modulemap +module CountedByProtocolClang { + header "counted-by-protocol.h" + export * +} + +//--- Inputs/counted-by-protocol.h +#pragma once + +#define __counted_by(x) __attribute__((__counted_by__(x))) + +int foo(int len, int * __counted_by(len) p); +@protocol CountedByProtocol + - (void) simple:(int)len :(int * __counted_by(len))p; + - (void) shared:(int)len :(int * __counted_by(len))p1 :(int * __counted_by(len))p2; + - (void) complexExpr:(int)len :(int) offset :(int * __counted_by(len - offset))p; + - (void) nullUnspecified:(int)len :(int * __counted_by(len) _Null_unspecified)p; + - (void) nonnull:(int)len :(int * __counted_by(len) _Nonnull)p; + - (void) nullable:(int)len :(int * __counted_by(len) _Nullable)p; + - (int * __counted_by(len)) returnPointer:(int)len; + + + (void) staticMethod:(int)len :(int * __counted_by(len))p; +@end + +__attribute__((swift_attr("@_SwiftifyImportProtocol(.method(signature: \"func swiftAttr(_ len: Int32, _ p: UnsafeMutablePointer!)\", paramInfo: [.countedBy(pointer: .param(2), count: \"len\")]))"))) +@protocol SwiftAttrProtocol + - (void)swiftAttr:(int)len :(int *)p; +@end + +//--- expansions.expected +@__swiftmacro_So17CountedByProtocol015_SwiftifyImportC0fMe_.swift +------------------------------ +extension CountedByProtocol { + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func simple(_ p: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p.count)! + return unsafe simple(len, p.baseAddress!) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func shared(_ p1: UnsafeMutableBufferPointer, _ p2: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p1.count)! + if p2.count != len { + fatalError("bounds check failure in shared: expected \(len) but got \(p2.count)") + } + return unsafe shared(len, p1.baseAddress!, p2.baseAddress!) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func complexExpr(_ len: Int32, _ offset: Int32, _ p: UnsafeMutableBufferPointer) { + let _pCount = p.count + if _pCount != len - offset { + fatalError("bounds check failure in complexExpr: expected \(len - offset) but got \(_pCount)") + } + return unsafe complexExpr(len, offset, p.baseAddress!) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func nullUnspecified(_ p: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p.count)! + return unsafe nullUnspecified(len, p.baseAddress!) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func nonnull(_ p: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p.count)! + return unsafe nonnull(len, p.baseAddress!) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func nullable(_ p: UnsafeMutableBufferPointer?) { + let len = Int32(exactly: unsafe p?.count ?? 0)! + return unsafe nullable(len, p?.baseAddress) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func returnPointer(_ len: Int32) -> UnsafeMutableBufferPointer { + return unsafe UnsafeMutableBufferPointer(start: unsafe returnPointer(len), count: Int(len)) + } + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload + static public func staticMethod(_ p: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p.count)! + return unsafe staticMethod(len, p.baseAddress!) + } +} +------------------------------ +@__swiftmacro_So17SwiftAttrProtocol015_SwiftifyImportC0fMe_.swift +------------------------------ +extension SwiftAttrProtocol { + /// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public + func swiftAttr(_ p: UnsafeMutableBufferPointer) { + let len = Int32(exactly: p.count)! + return unsafe swiftAttr(len, p.baseAddress!) + } +} +------------------------------ +@__swiftmacro_So3foo15_SwiftifyImportfMp_.swift +------------------------------ +/// This is an auto-generated wrapper for safer interop +@_alwaysEmitIntoClient @_disfavoredOverload public func foo(_ p: UnsafeMutableBufferPointer) -> Int32 { + let len = Int32(exactly: p.count)! + return unsafe foo(len, p.baseAddress!) +} +------------------------------ +//--- counted-by-protocol.swift +import CountedByProtocolClang + +@inlinable +public func call(p: UnsafeMutableBufferPointer, x: CInt, y: CInt, a: CountedByProtocol, b: SwiftAttrProtocol) { + a.simple(p) + a.shared(p, p) + a.complexExpr(x, y, p) + a.nullUnspecified(p) + a.nonnull(p) + a.nullable(p) + let _: UnsafeMutableBufferPointer = a.returnPointer(x) + let r2 = a.returnPointer(x) + let _: UnsafeMutablePointer? = r2 // make sure the original is the favored overload + b.swiftAttr(p) + let _ = foo(p) +} diff --git a/test/Macros/SwiftifyImport/CountedBy/Protocol.swift b/test/Macros/SwiftifyImport/CountedBy/Protocol.swift index 38729d224b9d9..3623caa797a71 100644 --- a/test/Macros/SwiftifyImport/CountedBy/Protocol.swift +++ b/test/Macros/SwiftifyImport/CountedBy/Protocol.swift @@ -42,7 +42,7 @@ protocol OverloadedProtocol { ------------------------------ extension SimpleProtocol { /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public func myFunc(_ ptr: UnsafeBufferPointer) { let len = CInt(exactly: ptr.count)! return unsafe myFunc(ptr.baseAddress!, len) @@ -53,7 +53,7 @@ extension SimpleProtocol { ------------------------------ extension SpanProtocol { /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public func foo(_ ptr: Span) { let len = CInt(exactly: ptr.count)! return unsafe ptr.withUnsafeBufferPointer { _ptrPtr in @@ -61,7 +61,7 @@ extension SpanProtocol { } } /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_lifetime(borrow self) @_disfavoredOverload +@_alwaysEmitIntoClient @_lifetime(borrow self) @_disfavoredOverload public func bar(_ len: CInt) -> Span { return unsafe _swiftifyOverrideLifetime(Span(_unsafeStart: unsafe bar(len), count: Int(len)), copying: ()) } @@ -71,7 +71,7 @@ extension SpanProtocol { ------------------------------ extension MixedProtocol { /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public /// Some doc comment func foo(_ ptr: Span) { let len = CInt(exactly: ptr.count)! @@ -80,7 +80,7 @@ extension MixedProtocol { } } /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public func bar(_ ptr: UnsafeBufferPointer) { let len = CInt(exactly: ptr.count)! return unsafe bar(ptr.baseAddress!, len) @@ -91,13 +91,13 @@ extension MixedProtocol { ------------------------------ extension OverloadedProtocol { /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public func foo(_ ptr: UnsafeBufferPointer) { let len1 = CInt(exactly: ptr.count)! return unsafe foo(ptr.baseAddress!, len1) } /// This is an auto-generated wrapper for safer interop -@_alwaysEmitIntoClient @_disfavoredOverload +@_alwaysEmitIntoClient @_disfavoredOverload public func foo(bar: UnsafeBufferPointer) { let len2 = CInt(exactly: bar.count)! return unsafe foo(bar: bar.baseAddress!, len2)