On Wed, 4 Mar 2026 at 14:46, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> 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.

Yes, so we simplified it to just using a static_assert.

You also said you'd prefer to use aligned-new unconditionally, but I
still think we should avoid the possible extra overhead of
aligned_alloc and only do that when malloc isn't OK for the type.



>>
>>
>>  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