[libcxx-commits] [libcxx] [libc++] Require the exact assignment expression to be trivial in `__uninitialized_allocator_copy_impl` (PR #196648)
Yuxuan Chen via libcxx-commits
libcxx-commits at lists.llvm.org
Sat May 9 13:18:53 PDT 2026
================
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <new>
+#include <type_traits>
+#include <vector>
+
+class Optional {
+public:
+ Optional() = default;
+ Optional(const Optional&) = default;
+ Optional& operator=(const Optional&) = default;
+ Optional(Optional&&) {}
+
+ template <class Arg>
+ Optional& operator=(Arg&& rhs) {
+ assert(value_ != Poison);
+ value_ = rhs.value_;
+ return *this;
+ }
+
+ bool hasValue() const { return value_ == HasValue; }
+
+private:
+ static constexpr std::uint32_t Poison = 0xBEBEBEBE;
+ static constexpr std::uint32_t NoValue = 0;
+ static constexpr std::uint32_t HasValue = 1;
+
+ std::uint32_t value_ = NoValue;
+};
+
+static_assert(std::is_trivially_copy_constructible<Optional>::value, "");
+static_assert(std::is_trivially_copy_assignable<Optional>::value, "");
+static_assert(!std::is_trivially_assignable<Optional&, Optional&>::value, "");
+
+template <class T>
+struct PoisoningAllocator {
+ using value_type = T;
+ PoisoningAllocator() = default;
+ template <class U>
+ PoisoningAllocator(const PoisoningAllocator<U>&) noexcept {}
+ T* allocate(std::size_t n) {
+ void* p = ::operator new(n * sizeof(T));
+ std::memset(p, 0xBE, n * sizeof(T));
+ return static_cast<T*>(p);
+ }
+ void deallocate(T* p, std::size_t) noexcept { ::operator delete(p); }
+};
+
+template <class T, class U>
+bool operator==(const PoisoningAllocator<T>&, const PoisoningAllocator<U>&) noexcept {
+ return true;
+}
+template <class T, class U>
+bool operator!=(const PoisoningAllocator<T>&, const PoisoningAllocator<U>&) noexcept {
+ return false;
+}
+
+int main(int, char**) {
----------------
yuxuanchen1997 wrote:
I added the constexpr path, but after testing it against the old implementation I don’t think it actually covers this bug because `__uninitialized_allocator_copy_impl` already has a constant-evaluation branch [here](https://github.com/llvm/llvm-project/blob/45e5bfb456409d171db3a8f7fa8a553dc7bde0d8/libcxx/include/__memory/uninitialized_algorithms.h#L495). What we are fixing is specifically in the non-constexpr `std::copy` path.
https://github.com/llvm/llvm-project/pull/196648
More information about the libcxx-commits
mailing list