Skip to content

<algorithm>: Stable sorting algorithms don't accept element types of large alignments by default #5800

@frederick-vs-ja

Description

@frederick-vs-ja

Describe the bug

Currently, _Optimistic_temporary_buffer used for stable sorting algorithms relies on _Aligned_storage_t, which doesn't accept overaligned element types by default due to ABI compatibility issues.

_Aligned_storage_t<sizeof(_Ty), alignof(_Ty)> _Stack_space[_Optimistic_count];

STL/stl/inc/type_traits

Lines 1246 to 1266 in eb024e0

template <size_t _Len, size_t _Align>
struct _Aligned<_Len, _Align, double, false> {
#ifdef _ENABLE_EXTENDED_ALIGNED_STORAGE
struct type {
alignas(_Align) char _Space[_Len];
};
#else // ^^^ defined(_ENABLE_EXTENDED_ALIGNED_STORAGE) / !defined(_ENABLE_EXTENDED_ALIGNED_STORAGE) vvv
#ifndef _DISABLE_EXTENDED_ALIGNED_STORAGE
static_assert(_Always_false<_Aligned>,
"You've instantiated std::aligned_storage<Len, Align> with an extended alignment (in other "
"words, Align > alignof(max_align_t)). Before VS 2017 15.8, the member \"type\" would "
"non-conformingly have an alignment of only alignof(max_align_t). VS 2017 15.8 was fixed to "
"handle this correctly, but the fix inherently changes layout and breaks binary compatibility "
"(*only* for uses of aligned_storage with extended alignments). "
"To suppress this error, please define either "
"(1) _ENABLE_EXTENDED_ALIGNED_STORAGE to confirm that you want a type with an extended alignment, or "
"(2) _DISABLE_EXTENDED_ALIGNED_STORAGE to get the old non-conforming behavior.");
#endif // ^^^ !defined(_DISABLE_EXTENDED_ALIGNED_STORAGE) ^^^
using type = _Align_type<max_align_t, _Len>;
#endif // ^^^ !defined(_ENABLE_EXTENDED_ALIGNED_STORAGE) ^^^
};

Command-line test case

Godbolt link

#include <algorithm>
#include <array>
#include <iterator>

struct alignas(32) large_element {
    std::array<unsigned char, 32> elems;

    friend auto operator<=>(const large_element&, const large_element&) = default;
};

int main() {
    large_element arr[42]{};

    std::stable_sort(std::begin(arr), std::end(arr));
    std::stable_partition(std::begin(arr), std::end(arr), [](const auto&) { return true; });
    std::inplace_merge(std::begin(arr), std::begin(arr), std::end(arr));

    std::ranges::stable_sort(arr);
    std::ranges::stable_partition(arr, [](const auto&) { return true; });
    std::ranges::inplace_merge(arr, std::ranges::begin(arr));
}

Expected behavior

This program correctly compiles and runs.

STL version

Probably all versions with default error set for aligned_storage_t.

Additional context

As _Optimistic_temporary_buffer is only internally used and only used on the stack, perhaps it's safe to change the size and/or the alignment of the buffer with its name changed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions