https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/177595
Backport 8b5185984e57df12878ea026febb414769c54b03 Requested by: @ldionne >From 579da2d4c18d127c93682d7bb5b56c050cf9c114 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Tue, 13 Jan 2026 10:35:59 +0100 Subject: [PATCH] [libc++] Annotate filesystem::path with [[clang::lifetimebound]] (#175507) Fixes #175379 (cherry picked from commit 8b5185984e57df12878ea026febb414769c54b03) --- libcxx/include/__filesystem/path.h | 32 ++++++++------- .../class.path/lifetimebound.verify.cpp | 39 +++++++++++++++++++ 2 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 libcxx/test/libcxx/input.output/filesystems/class.path/lifetimebound.verify.cpp 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}} +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
