mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #78422 from swiftlang/gaborh/cxx-span-overload-importer
[cxx-interop] Generate safe overloads for non-escapable spans
This commit is contained in:
@@ -566,7 +566,8 @@ void importer::getNormalInvocationArguments(
|
||||
}
|
||||
}
|
||||
|
||||
if (LangOpts.hasFeature(Feature::SafeInteropWrappers))
|
||||
if (LangOpts.hasFeature(Feature::SafeInteropWrappers) &&
|
||||
!LangOpts.EnableCXXInterop)
|
||||
invocationArgStrs.push_back("-fexperimental-bounds-safety-attributes");
|
||||
|
||||
// Set C language options.
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjCCommon.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
@@ -71,10 +72,12 @@
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#define DEBUG_TYPE "Clang module importer"
|
||||
|
||||
@@ -130,6 +133,7 @@ createFuncOrAccessor(ClangImporter::Implementation &impl, SourceLoc funcLoc,
|
||||
impl.importSwiftAttrAttributes(decl);
|
||||
if (hasBoundsAnnotation)
|
||||
impl.importBoundsAttributes(decl);
|
||||
impl.importSpanAttributes(decl);
|
||||
|
||||
return decl;
|
||||
}
|
||||
@@ -8698,11 +8702,7 @@ public:
|
||||
|
||||
void printCountedBy(const clang::CountAttributedType *CAT,
|
||||
size_t pointerIndex) {
|
||||
if (!firstParam) {
|
||||
out << ", ";
|
||||
} else {
|
||||
firstParam = false;
|
||||
}
|
||||
printSeparator();
|
||||
clang::Expr *countExpr = CAT->getCountExpr();
|
||||
bool isSizedBy = CAT->isCountInBytes();
|
||||
out << ".";
|
||||
@@ -8720,9 +8720,76 @@ public:
|
||||
out, {}, {ctx.getLangOpts()}); // TODO: map clang::Expr to Swift Expr
|
||||
out << "\")";
|
||||
}
|
||||
|
||||
void printNonEscaping(int idx) {
|
||||
printSeparator();
|
||||
out << ".nonescaping(pointer: " << idx << ")";
|
||||
}
|
||||
|
||||
void printTypeMapping(const llvm::StringMap<std::string> &mapping) {
|
||||
printSeparator();
|
||||
out << "typeMappings: [";
|
||||
if (mapping.empty()) {
|
||||
out << ":]";
|
||||
return;
|
||||
}
|
||||
llvm::interleaveComma(mapping, out, [&](const auto &entry) {
|
||||
out << '"' << entry.getKey() << "\" : \"" << entry.getValue() << '"';
|
||||
});
|
||||
out << "]";
|
||||
}
|
||||
|
||||
private:
|
||||
void printSeparator() {
|
||||
if (!firstParam) {
|
||||
out << ", ";
|
||||
} else {
|
||||
firstParam = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void ClangImporter::Implementation::importSpanAttributes(FuncDecl *MappedDecl) {
|
||||
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
|
||||
return;
|
||||
auto ClangDecl =
|
||||
dyn_cast_or_null<clang::FunctionDecl>(MappedDecl->getClangDecl());
|
||||
if (!ClangDecl)
|
||||
return;
|
||||
|
||||
llvm::SmallString<128> MacroString;
|
||||
bool attachMacro = false;
|
||||
{
|
||||
llvm::raw_svector_ostream out(MacroString);
|
||||
llvm::StringMap<std::string> typeMapping;
|
||||
|
||||
SwiftifyInfoPrinter printer(getClangASTContext(), out);
|
||||
for (auto [index, param] : llvm::enumerate(ClangDecl->parameters())) {
|
||||
auto paramTy = param->getType();
|
||||
const auto *decl = paramTy->getAsTagDecl();
|
||||
if (!decl || !decl->isInStdNamespace())
|
||||
continue;
|
||||
if (decl->getName() != "span")
|
||||
continue;
|
||||
if (param->hasAttr<clang::NoEscapeAttr>()) {
|
||||
printer.printNonEscaping(index + 1);
|
||||
clang::PrintingPolicy policy(param->getASTContext().getLangOpts());
|
||||
policy.SuppressTagKeyword = true;
|
||||
auto param = MappedDecl->getParameters()->get(index);
|
||||
typeMapping.insert(std::make_pair(
|
||||
paramTy.getAsString(policy),
|
||||
param->getInterfaceType()->getDesugaredType()->getString()));
|
||||
attachMacro = true;
|
||||
}
|
||||
}
|
||||
printer.printTypeMapping(typeMapping);
|
||||
}
|
||||
|
||||
if (attachMacro)
|
||||
importNontrivialAttribute(MappedDecl, MacroString);
|
||||
}
|
||||
|
||||
void ClangImporter::Implementation::importBoundsAttributes(
|
||||
FuncDecl *MappedDecl) {
|
||||
assert(SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers));
|
||||
|
||||
@@ -1746,6 +1746,7 @@ public:
|
||||
|
||||
void importSwiftAttrAttributes(Decl *decl);
|
||||
void importBoundsAttributes(FuncDecl *MappedDecl);
|
||||
void importSpanAttributes(FuncDecl *MappedDecl);
|
||||
|
||||
/// Find the lookup table that corresponds to the given Clang module.
|
||||
///
|
||||
|
||||
@@ -167,6 +167,18 @@ func isRawPointerType(text: String) -> Bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove std. or std.__1. prefix
|
||||
func getUnqualifiedStdName(_ type: String) -> String? {
|
||||
if (type.hasPrefix("std.")) {
|
||||
var ty = type.dropFirst(4)
|
||||
if (ty.hasPrefix("__1.")) {
|
||||
ty = ty.dropFirst(4)
|
||||
}
|
||||
return String(ty)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSafePointerName(mut: Mutability, generateSpan: Bool, isRaw: Bool) -> TokenSyntax {
|
||||
switch (mut, generateSpan, isRaw) {
|
||||
case (.Immutable, true, true): return "RawSpan"
|
||||
@@ -314,9 +326,10 @@ struct CxxSpanThunkBuilder: BoundsCheckedThunkBuilder {
|
||||
"unable to desugar type with name '\(typeName)'", node: node)
|
||||
}
|
||||
|
||||
let parsedDesugaredType = TypeSyntax("\(raw: desugaredType)")
|
||||
types[index] = TypeSyntax(IdentifierTypeSyntax(name: "Span",
|
||||
genericArgumentClause: parsedDesugaredType.as(IdentifierTypeSyntax.self)!.genericArgumentClause))
|
||||
let parsedDesugaredType = TypeSyntax("\(raw: getUnqualifiedStdName(desugaredType)!)")
|
||||
let genericArg = TypeSyntax(parsedDesugaredType.as(IdentifierTypeSyntax.self)!
|
||||
.genericArgumentClause!.arguments.first!.argument)!
|
||||
types[index] = TypeSyntax("Span<\(raw: try getTypeName(genericArg).text)>")
|
||||
return try base.buildFunctionSignature(types, variant)
|
||||
}
|
||||
|
||||
@@ -696,9 +709,11 @@ public struct SwiftifyImportMacro: PeerMacro {
|
||||
for (idx, param) in signature.parameterClause.parameters.enumerated() {
|
||||
let typeName = try getTypeName(param.type).text;
|
||||
if let desugaredType = typeMappings[typeName] {
|
||||
if desugaredType.starts(with: "span") {
|
||||
result.append(CxxSpan(pointerIndex: idx + 1, nonescaping: false,
|
||||
original: param, typeMappings: typeMappings))
|
||||
if let unqualifiedDesugaredType = getUnqualifiedStdName(desugaredType) {
|
||||
if unqualifiedDesugaredType.starts(with: "span<") {
|
||||
result.append(CxxSpan(pointerIndex: idx + 1, nonescaping: false,
|
||||
original: param, typeMappings: typeMappings))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,6 @@ inline SpanOfInt initSpan(int arr[], size_t size) {
|
||||
|
||||
inline struct SpanBox getStructSpanBox() { return {iarray, iarray, sarray, sarray}; }
|
||||
|
||||
void funcWithSafeWrapper(SpanOfInt s [[clang::noescape]]) {}
|
||||
|
||||
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_SPAN_H
|
||||
|
||||
17
test/Interop/Cxx/stdlib/std-span-interface.swift
Normal file
17
test/Interop/Cxx/stdlib/std-span-interface.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature Span -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=StdSpan -source-filename=x -enable-experimental-cxx-interop -Xcc -std=c++20 -module-cache-path %t > %t/interface.swift
|
||||
// RUN: %FileCheck %s < %t/interface.swift
|
||||
|
||||
// REQUIRES: swift_feature_SafeInteropWrappers
|
||||
// REQUIRES: swift_feature_Span
|
||||
|
||||
// FIXME swift-ci linux tests do not support std::span
|
||||
// UNSUPPORTED: OS=linux-gnu
|
||||
|
||||
#if !BRIDGING_HEADER
|
||||
import StdSpan
|
||||
#endif
|
||||
import CxxStdlib
|
||||
|
||||
// CHECK: func funcWithSafeWrapper(_ s: SpanOfInt)
|
||||
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
|
||||
@@ -7,7 +7,7 @@ public struct SpanOfInt {
|
||||
init(_ x: Span<CInt>) {}
|
||||
}
|
||||
|
||||
@_SwiftifyImport(.nonescaping(pointer: 1), typeMappings: ["SpanOfInt" : "span<CInt>"])
|
||||
@_SwiftifyImport(.nonescaping(pointer: 1), typeMappings: ["SpanOfInt" : "std.span<CInt>"])
|
||||
func myFunc(_ span: SpanOfInt, _ secondSpan: SpanOfInt) {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user