[libcxx-dev] Sequence container swap noexcept specifiers not-to-spec
Tim Song via libcxx-dev
libcxx-dev at lists.llvm.org
Thu Mar 4 09:02:24 PST 2021
On Thu, Mar 4, 2021 at 10:12 AM Louis Dionne via libcxx-dev
<libcxx-dev at lists.llvm.org> wrote:
>
>
>
> On Feb 20, 2021, at 14:12, Christopher Di Bella <cjdb.ns at gmail.com> wrote:
>
> I've noticed that our sequence containers' noexcept specifiers for swap aren't to spec. Is this intentional, or some gross oversight?
>
> Example from <vector>
>
> void swap(vector&)
> #if _LIBCPP_STD_VER >= 14
> _NOEXCEPT;
> #else
> _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
> __is_nothrow_swappable<allocator_type>::value);
> #endif
>
> To me, this looks like it's saying that swap is unconditionally noexcept in C++17 and C++20, and possibly the opposite of [vector.capacity]/12 otherwise?
>
> [vector.capacity]/12 notes:
>
> constexpr void swap(vector& x)
> noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
> allocator_traits<Allocator>::is_always_equal::value);
>
> If this is an oversight, I'll file a bug and patch ASAP. If it's intentional, is it explicitly documented somewhere to explain the deviation? This was a surprise when writing tests for std::ranges::swap's noexcept status.
>
>
> Based on https://en.cppreference.com/w/cpp/container/vector/swap, it seems to me like what we want here is:
>
> void swap(vector&)
> #if _LIBCPP_STD_VER < 17
> _NOEXCEPT
> #else
> _NOEXCEPT_((std::allocator_traits<Allocator>::propagate_on_container_swap::value ||
> std::allocator_traits<Allocator>::is_always_equal::value))
> #endif
>
> In other words, mark it as unconditionally noexcept (as a conforming extension) pre-C++17, and implement the noexcept specification per the spec in C++17 and above. Do you agree? If so, I think it would be great to submit a patch and add tests for all the places where this is broken. I would be verrrrry grateful if you were willing to do that, I’ll review it.
>
> Louis
I don't think this is an oversight. The conditional noexcept on swap
in the standard is entirely due to the Lakos rule (swapping containers
with non-propagating unequal allocators is undefined), so the
unconditional noexcept is a permissible strengthening. The
__is_nothrow_swappable check pre-17 is presumably to support
allocators with throwing swaps, which were banned by LWG2016.
If a change is desirable, I would suggest treating LWG2016 as a DR and
using unconditional noexcept across the board.
More information about the libcxx-dev
mailing list