[llvm-branch-commits] [libcxx] release/22.x: [libc++] Annotate filesystem::path with [[clang::lifetimebound]] (#175507) (PR #177595)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jan 23 06:34:13 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: None (llvmbot)
<details>
<summary>Changes</summary>
Backport 8b5185984e57df12878ea026febb414769c54b03
Requested by: @<!-- -->ldionne
---
Full diff: https://github.com/llvm/llvm-project/pull/177595.diff
2 Files Affected:
- (modified) libcxx/include/__filesystem/path.h (+17-15)
- (added) libcxx/test/libcxx/input.output/filesystems/class.path/lifetimebound.verify.cpp (+39)
``````````diff
diff --git a/libcxx/include/__filesystem/path.h b/libcxx/include/__filesystem/path.h
index 4fd3acad4d430..4957761c0ef7e 100644
--- a/libcxx/include/__filesystem/path.h
+++ b/libcxx/include/__filesystem/path.h
@@ -449,7 +449,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
return *this;
}
- _LIBCPP_HIDE_FROM_ABI path& assign(string_type&& __s) noexcept {
+ _LIBCPP_HIDE_FROM_ABI path& assign(string_type&& __s) noexcept _LIBCPP_LIFETIMEBOUND {
__pn_ = std::move(__s);
return *this;
}
@@ -460,14 +460,14 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
}
template <class _Source>
- _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> assign(const _Source& __src) {
+ _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> assign(const _Source& __src) _LIBCPP_LIFETIMEBOUND {
__pn_.clear();
_SourceCVT<_Source>::__append_source(__pn_, __src);
return *this;
}
template <class _InputIt>
- _LIBCPP_HIDE_FROM_ABI path& assign(_InputIt __first, _InputIt __last) {
+ _LIBCPP_HIDE_FROM_ABI path& assign(_InputIt __first, _InputIt __last) _LIBCPP_LIFETIMEBOUND {
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
__pn_.clear();
_PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
@@ -501,12 +501,12 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
}
template <class _Source>
- _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) {
+ _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) _LIBCPP_LIFETIMEBOUND {
return operator/=(path(__src));
}
template <class _InputIt>
- _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) {
+ _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) _LIBCPP_LIFETIMEBOUND {
return operator/=(path(__first, __last));
}
# else
@@ -530,7 +530,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
}
template <class _Source>
- _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) {
+ _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) _LIBCPP_LIFETIMEBOUND {
using _Traits = __is_pathable<_Source>;
using _CVT = _PathCVT<_SourceChar<_Source> >;
bool __source_is_absolute = filesystem::__is_separator(_Traits::__first_or_null(__src));
@@ -543,7 +543,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
}
template <class _InputIt>
- _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) {
+ _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) _LIBCPP_LIFETIMEBOUND {
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
using _CVT = _PathCVT<_ItVal>;
@@ -594,13 +594,13 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
}
template <class _Source>
- _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> concat(const _Source& __x) {
+ _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> concat(const _Source& __x) _LIBCPP_LIFETIMEBOUND {
_SourceCVT<_Source>::__append_source(__pn_, __x);
return *this;
}
template <class _InputIt>
- _LIBCPP_HIDE_FROM_ABI path& concat(_InputIt __first, _InputIt __last) {
+ _LIBCPP_HIDE_FROM_ABI path& concat(_InputIt __first, _InputIt __last) _LIBCPP_LIFETIMEBOUND {
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
_PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
return *this;
@@ -609,26 +609,26 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
// modifiers
_LIBCPP_HIDE_FROM_ABI void clear() noexcept { __pn_.clear(); }
- _LIBCPP_HIDE_FROM_ABI path& make_preferred() {
+ _LIBCPP_HIDE_FROM_ABI path& make_preferred() _LIBCPP_LIFETIMEBOUND {
# if defined(_LIBCPP_WIN32API)
std::replace(__pn_.begin(), __pn_.end(), L'/', L'\\');
# endif
return *this;
}
- _LIBCPP_HIDE_FROM_ABI path& remove_filename() {
+ _LIBCPP_HIDE_FROM_ABI path& remove_filename() _LIBCPP_LIFETIMEBOUND {
auto __fname = __filename();
if (!__fname.empty())
__pn_.erase(__fname.data() - __pn_.data());
return *this;
}
- _LIBCPP_HIDE_FROM_ABI path& replace_filename(const path& __replacement) {
+ _LIBCPP_HIDE_FROM_ABI path& replace_filename(const path& __replacement) _LIBCPP_LIFETIMEBOUND {
remove_filename();
return (*this /= __replacement);
}
- path& replace_extension(const path& __replacement = path());
+ path& replace_extension(const path& __replacement = path()) _LIBCPP_LIFETIMEBOUND;
friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept {
return __lhs.__compare(__rhs.__pn_) == 0;
@@ -667,9 +667,11 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
_LIBCPP_HIDE_FROM_ABI void __reserve(size_t __s) { __pn_.reserve(__s); }
// native format observers
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept { return __pn_; }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept _LIBCPP_LIFETIMEBOUND { return __pn_; }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept { return __pn_.c_str(); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept _LIBCPP_LIFETIMEBOUND {
+ return __pn_.c_str();
+ }
_LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; }
diff --git a/libcxx/test/libcxx/input.output/filesystems/class.path/lifetimebound.verify.cpp b/libcxx/test/libcxx/input.output/filesystems/class.path/lifetimebound.verify.cpp
new file mode 100644
index 0000000000000..3e5aa5e57e259
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/filesystems/class.path/lifetimebound.verify.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// ADDITIONAL_COMPILE_FLAGS: -Wno-unused-variable
+
+#include <filesystem>
+
+// clang-format off
+
+namespace fs = std::filesystem;
+
+fs::path& test() {
+ fs::path p;
+ char arr[] = "Banane";
+
+ auto&& v1 = fs::path().native(); // expected-warning {{temporary bound to local reference 'v1' will be destroyed at the end of the full-expression}}
+ auto v2 = fs::path().c_str(); // expected-warning {{temporary whose address is used as value of local variable 'v2' will be destroyed at the end of the full-expression}}
+
+ return p.assign(""); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.assign(std::string()); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.assign(std::begin(arr), std::end(arr)); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+
+ return p.append(""); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.append(std::begin(arr), std::end(arr)); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+
+ return p.concat(""); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.concat(std::begin(arr), std::end(arr)); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+
+ return p.make_preferred(); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.remove_filename(); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.replace_filename(""); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+ return p.replace_extension(); // expected-warning {{reference to stack memory associated with local variable 'p' returned}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/177595
More information about the llvm-branch-commits
mailing list