On Wed, Mar 4, 2026 at 12:56 PM Jonathan Wakely <[email protected]> wrote:

> As Bug 122300 shows, we have at least one target where the
> static_assert added by r16-4422-g1b18a9e53960f3 fails. This patch
> resurrects the original proposal for using aligned new that I posted in
> https://gcc.gnu.org/pipermail/libstdc++/2025-October/063904.html
>
> Instead of just asserting that the memory from operator new will be
> sufficiently aligned, check whether it will be and use aligned new if
> needed. We don't just use aligned new unconditionally, because that can
> add overhead on targets where malloc already meets the requirements.
>
> libstdc++-v3/ChangeLog:
>
>         PR libstdc++/122300
>         * src/c++17/fs_path.cc (path::_List::_Impl): Remove
>         static_asserts.
>         (path::_List::_Impl::required_alignment)
>         (path::_List::_Impl::use_aligned_new): New static data members.
>         (path::_List::_Impl::create_unchecked): Check use_aligned_new
>         and use aligned new if needed.
>         (path::_List::_Impl::alloc_size): New static member function.
>         (path::_List::_Impl_deleter::operator): Check use_aligned_new
>         and use aligned delete if needed.
> ---
>
> Tested x86_64-linux and bootstrapped pru-unknown-elf, confirming that it
> fixes the failed static_assert during bootstrap.
>
Looks good. Remember discussing these changes with the original patch?
we didn't knew if any target was affected.

>
>  libstdc++-v3/src/c++17/fs_path.cc | 27 +++++++++++++++++++++------
>  1 file changed, 21 insertions(+), 6 deletions(-)
>
> diff --git a/libstdc++-v3/src/c++17/fs_path.cc
> b/libstdc++-v3/src/c++17/fs_path.cc
> index 9d8d38266789..c217dc278018 100644
> --- a/libstdc++-v3/src/c++17/fs_path.cc
> +++ b/libstdc++-v3/src/c++17/fs_path.cc
> @@ -260,9 +260,12 @@ struct path::_List::_Impl
>
>    // We use the two least significant bits to store a _Type value so
>    // require memory aligned to at least 4 bytes:
> -  static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 4);
> -  // Require memory suitably aligned for an _Impl and its value types:
> -  static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(value_type));
> +  static constexpr size_t required_alignment
> +    = std::max(size_t(4), alignof(value_type));
> +
> +  // Only use aligned new if needed, because it might be less efficient.
> +  static constexpr bool use_aligned_new
> +    = __STDCPP_DEFAULT_NEW_ALIGNMENT__ < required_alignment;
>
>    // Clear the lowest two bits from the pointer (i.e. remove the _Type
> value)
>    static _Impl* notype(_Impl* p)
> @@ -297,9 +300,18 @@ struct path::_List::_Impl
>    static unique_ptr<_Impl, _Impl_deleter>
>    create_unchecked(int n)
>    {
> -    void* p = ::operator new(sizeof(_Impl) + n * sizeof(value_type));
> +    const auto bytes = alloc_size(n);
> +    void* p;
> +    if constexpr (use_aligned_new)
> +      p = ::operator new(bytes, align_val_t{required_alignment});
> +    else
> +      p = ::operator new(bytes);
>      return std::unique_ptr<_Impl, _Impl_deleter>(::new(p) _Impl{n});
>    }
> +
> +  // The number of bytes that must be allocated for _Impl with capacity n.
> +  static size_t
> +  alloc_size(int n) { return sizeof(_Impl) + n * sizeof(value_type); }
>  };
>
>  // Destroy and deallocate an _Impl.
> @@ -309,9 +321,12 @@ path::_List::_Impl_deleter::operator()(_Impl* p)
> const noexcept
>    p = _Impl::notype(p);
>    if (p)
>      {
> -      const auto n = p->_M_capacity;
> +      const auto bytes = _Impl::alloc_size(p->_M_capacity);
>        p->~_Impl();
> -      ::operator delete(p, sizeof(_Impl) + n * sizeof(_Impl::value_type));
> +      if constexpr (_Impl::use_aligned_new)
> +       ::operator delete(p, bytes,
> align_val_t{_Impl::required_alignment});
> +      else
> +       ::operator delete(p, bytes);
>      }
>  }
>
> --
> 2.53.0
>
>

Reply via email to