-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[cxx-interop] Generate safe overloads for non-escapable spans #78422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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.")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will it always be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not anticipate a change in this, it is the same namespace for the last decade or so. But it is true that we are somewhat closely coupled to this implementation detail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we make this adjustment on the C++ side where we can reason about things like inline namespaces? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be reasonable to skip inline namespaces in the Swift names, especially since these names do leak into the diagnostics occasionally. It would be more user friendly. I am not sure if this could ever create name collisions, hopefully not. But I'd address this in a separate PR. How closely coupled are the compiler and the standard library? In case this code supposed to work with older compiler versions, we'd want to keep the skipping logic here. |
||
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)) | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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>) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw some crashes in Clang when this option was used in C++ mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine for now, but we should dig into these crashes to see what's going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-fbounds-safety
support for C++ in Clang is currently experimental, but-fexperimental-bounds-safety-attributes
is used for C/C++ interop also, so that one shouldn't crash. It is a relatively new flag though, so there might be some gaps. CC @patrykstefanski for awareness.