From 43cef148cb8ddb519a27d08a07c5f308cb6e8279 Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Fri, 19 Sep 2025 10:35:01 +0100 Subject: [PATCH] [cxx-interop] Do not consider std::span::size and co unsafe Since these APIs operate on unsafes we consider them unsafe by default. This PR adds APINotes to override these defaults as these APIs will not touch the underlying buffer. This should slightly reduce the number of `unsafe`s in user code. rdar://159839254 --- stdlib/public/Cxx/std/CMakeLists.txt | 6 +++++- stdlib/public/Cxx/std/std.apinotes | 17 +++++++++++++++++ stdlib/public/Cxx/std/std_span.apinotes | 14 ++++++++++++++ stdlib/public/Cxx/std/std_string_view.apinotes | 14 ++++++++++++++ test/Interop/Cxx/class/safe-interop-mode.swift | 3 ++- 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 stdlib/public/Cxx/std/std_span.apinotes create mode 100644 stdlib/public/Cxx/std/std_string_view.apinotes diff --git a/stdlib/public/Cxx/std/CMakeLists.txt b/stdlib/public/Cxx/std/CMakeLists.txt index 536c167ec59cd..4a87a99aa4ac1 100644 --- a/stdlib/public/Cxx/std/CMakeLists.txt +++ b/stdlib/public/Cxx/std/CMakeLists.txt @@ -6,9 +6,13 @@ add_custom_command_target(unused_var CUSTOM_TARGET_NAME CxxStdlib-apinotes COMMAND ${CMAKE_COMMAND} "-E" "make_directory" "${output_dir}" COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_SOURCE_DIR}/std.apinotes" "${output_dir}" + COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_SOURCE_DIR}/std_span.apinotes" "${output_dir}" + COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_SOURCE_DIR}/std_string_view.apinotes" "${output_dir}" COMMENT "Copying CxxStdlib API Notes to ${output_dir}" OUTPUT "${output_dir}/std.apinotes" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/std.apinotes") + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/std.apinotes" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/std_span.apinotes" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/std_string_view.apinotes") swift_install_in_component(FILES std.apinotes DESTINATION "lib/swift/apinotes" diff --git a/stdlib/public/Cxx/std/std.apinotes b/stdlib/public/Cxx/std/std.apinotes index eab6f835c9c26..5b15211f5e717 100644 --- a/stdlib/public/Cxx/std/std.apinotes +++ b/stdlib/public/Cxx/std/std.apinotes @@ -17,3 +17,20 @@ Namespaces: Methods: - Name: data SwiftName: __dataUnsafe() + - Name: size + SwiftSafety: safe + - Name: size_bytes + SwiftSafety: safe + - Name: empty + SwiftSafety: safe + - Name: basic_string_view + Methods: + - Name: size + SwiftSafety: safe + - Name: max_size + SwiftSafety: safe + - Name: length + SwiftSafety: safe + - Name: empty + SwiftSafety: safe + \ No newline at end of file diff --git a/stdlib/public/Cxx/std/std_span.apinotes b/stdlib/public/Cxx/std/std_span.apinotes new file mode 100644 index 0000000000000..d813f0fe784f2 --- /dev/null +++ b/stdlib/public/Cxx/std/std_span.apinotes @@ -0,0 +1,14 @@ +Name: std_span +Namespaces: +- Name: std + Tags: + - Name: span + Methods: + - Name: data + SwiftName: __dataUnsafe() + - Name: size + SwiftSafety: safe + - Name: size_bytes + SwiftSafety: safe + - Name: empty + SwiftSafety: safe diff --git a/stdlib/public/Cxx/std/std_string_view.apinotes b/stdlib/public/Cxx/std/std_string_view.apinotes new file mode 100644 index 0000000000000..ca5d034c32ee6 --- /dev/null +++ b/stdlib/public/Cxx/std/std_string_view.apinotes @@ -0,0 +1,14 @@ +Name: std_string_view +Namespaces: +- Name: std + Tags: + - Name: basic_string_view + Methods: + - Name: size + SwiftSafety: safe + - Name: max_size + SwiftSafety: safe + - Name: length + SwiftSafety: safe + - Name: empty + SwiftSafety: safe diff --git a/test/Interop/Cxx/class/safe-interop-mode.swift b/test/Interop/Cxx/class/safe-interop-mode.swift index 16b47fde34ffd..2b9187a7a263e 100644 --- a/test/Interop/Cxx/class/safe-interop-mode.swift +++ b/test/Interop/Cxx/class/safe-interop-mode.swift @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: split-file %s %t -// RUN: %target-swift-frontend -typecheck -verify -I %swift_src_root/lib/ClangImporter/SwiftBridging -Xcc -std=c++20 -I %t/Inputs %t/test.swift -strict-memory-safety -enable-experimental-feature LifetimeDependence -cxx-interoperability-mode=default -diagnostic-style llvm 2>&1 +// RUN: %target-swift-frontend -typecheck -verify -I %swift_src_root/lib/ClangImporter/SwiftBridging -Xcc -iapinotes-modules -Xcc %swift_src_root/stdlib/public/Cxx/std -Xcc -std=c++20 -I %t/Inputs %t/test.swift -strict-memory-safety -enable-experimental-feature LifetimeDependence -cxx-interoperability-mode=default -diagnostic-style llvm 2>&1 // REQUIRES: objc_interop // REQUIRES: swift_feature_LifetimeDependence @@ -134,6 +134,7 @@ func useUnsafeTuple(x: UnsafeTuple) { func useCppSpan(x: SpanOfInt) { // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} + _ = x.size() } func useCppSpan2(x: SpanOfIntAlias) {