From 6351bac4fb50fae9d7fbe50735a5aa5d855e0629 Mon Sep 17 00:00:00 2001 From: Paul Dreik Date: Wed, 22 Jul 2026 17:36:21 +0200 Subject: [PATCH 1/6] compliance fixes for vector --- include/__psychicstd_contiguous_iterator | 22 ++++++++++++++------ include/compare | 8 ++++---- include/new | 4 ++++ include/vector | 8 ++++---- tests/test_compare.cpp | 11 ++++++++++ tests/test_new.cpp | 3 +++ tests/test_vector.cpp | 26 ++++++++++++++++++++++++ 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/include/__psychicstd_contiguous_iterator b/include/__psychicstd_contiguous_iterator index 75a42aa3..516eb064 100644 --- a/include/__psychicstd_contiguous_iterator +++ b/include/__psychicstd_contiguous_iterator @@ -27,21 +27,31 @@ template struct __vec_iter { constexpr T& operator*() const noexcept { return *ptr_; } constexpr T* operator->() const noexcept { return ptr_; } constexpr T& operator[](ptrdiff_t n) const noexcept { return ptr_[n]; } - constexpr __vec_iter& operator++() noexcept { return ++ptr_, *this; } + constexpr __vec_iter& operator++() noexcept { + ++ptr_; + return *this; + } constexpr __vec_iter operator++(int) noexcept { auto t = *this; - return ++ptr_, t; + ++ptr_; + return t; + } + constexpr __vec_iter& operator--() noexcept { + --ptr_; + return *this; } - constexpr __vec_iter& operator--() noexcept { return --ptr_, *this; } constexpr __vec_iter operator--(int) noexcept { auto t = *this; - return --ptr_, t; + --ptr_; + return t; } constexpr __vec_iter& operator+=(ptrdiff_t n) noexcept { - return ptr_ += n, *this; + ptr_ += n; + return *this; } constexpr __vec_iter& operator-=(ptrdiff_t n) noexcept { - return ptr_ -= n, *this; + ptr_ -= n; + return *this; } constexpr __vec_iter operator+(ptrdiff_t n) const noexcept { return __vec_iter{ptr_ + n}; diff --git a/include/compare b/include/compare index 8254d5e0..6b15f90c 100644 --- a/include/compare +++ b/include/compare @@ -196,12 +196,12 @@ constexpr bool is_lteq(partial_ordering v) noexcept { return v <= 0; } constexpr bool is_gteq(partial_ordering v) noexcept { return v >= 0; } // three_way_comparable concept -template +template concept three_way_comparable = requires(const __psychicstd_detail::remove_reference_t& a, - const __psychicstd_detail::remove_reference_t& b) { - a <=> b; - b <=> a; + const __psychicstd_detail::remove_reference_t& b) { + static_cast(a <=> b); + static_cast(b <=> a); }; template diff --git a/include/new b/include/new index 2cbfb38f..76a030d6 100644 --- a/include/new +++ b/include/new @@ -2,6 +2,10 @@ #include #include +namespace std { +enum class align_val_t : size_t {}; +} + // placement new is a language built-in; the header just declares the // signatures. global operator new/delete are provided by the runtime // (libstdc++/libc). diff --git a/include/vector b/include/vector index 1a3a533a..d0d0a212 100644 --- a/include/vector +++ b/include/vector @@ -27,8 +27,8 @@ public: using difference_type = ptrdiff_t; using reference = T&; using const_reference = const T&; - using pointer = T*; - using const_pointer = const T*; + using pointer = typename allocator_traits::pointer; + using const_pointer = typename allocator_traits::const_pointer; using iterator = __vec_iter; using const_iterator = __vec_iter; using reverse_iterator = std::reverse_iterator; @@ -401,7 +401,7 @@ public: } constexpr vector& operator=(const vector& o) { - if (this == &o) + if (this == std::addressof(o)) return *this; using traits = allocator_traits; if constexpr (traits::propagate_on_container_copy_assignment::value) { @@ -421,7 +421,7 @@ public: constexpr vector& operator=(vector&& o) noexcept( allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) { - if (this == &o) + if (this == std::addressof(o)) return *this; using traits = allocator_traits; if constexpr (traits::propagate_on_container_move_assignment::value) { diff --git a/tests/test_compare.cpp b/tests/test_compare.cpp index 474d7e39..cd529101 100644 --- a/tests/test_compare.cpp +++ b/tests/test_compare.cpp @@ -1,6 +1,17 @@ #include "psyassert.h" #include +struct strongly_ordered { + int value; + constexpr auto operator<=>(const strongly_ordered&) const = default; +}; + +struct not_ordered {}; + +static_assert( + std::three_way_comparable); +static_assert(!std::three_way_comparable); + int main() { psyassert(std::strong_ordering::equal == 0); psyassert((std::strong_ordering::less <=> 0) == std::strong_ordering::less); diff --git a/tests/test_new.cpp b/tests/test_new.cpp index 142b687a..91339f0e 100644 --- a/tests/test_new.cpp +++ b/tests/test_new.cpp @@ -2,6 +2,9 @@ #include int main() { + auto alignment = std::align_val_t{64}; + psyassert(static_cast(alignment) == 64); + auto* p = ::operator new(8); psyassert(p != nullptr); ::operator delete(p); diff --git a/tests/test_vector.cpp b/tests/test_vector.cpp index 84fd942e..e5f67c31 100644 --- a/tests/test_vector.cpp +++ b/tests/test_vector.cpp @@ -31,6 +31,26 @@ struct resize_value { } }; +struct operator_hijacker { + template friend void operator&(T&&) = delete; + template friend void operator,(T&&, U&&) = delete; +}; + +template struct fancy_pointer { + using element_type = T; + template using rebind = fancy_pointer; +}; + +template struct fancy_allocator { + using value_type = T; + using pointer = fancy_pointer; + using const_pointer = fancy_pointer; +}; + +using fancy_vector = std::vector>; +static_assert(__is_same(fancy_vector::pointer, fancy_pointer)); +static_assert(__is_same(fancy_vector::const_pointer, fancy_pointer)); + int main() { std::vector zeroes(32); for (char c : zeroes) @@ -80,4 +100,10 @@ int main() { psyassert(resize_value::moves < 512); for (const auto& item : resized_with_value) psyassert(item.n == 42); + + std::vector hijackers; + std::vector other_hijackers; + hijackers = other_hijackers; + hijackers = static_cast(other_hijackers); + hijackers.insert(hijackers.begin(), hijackers.begin(), hijackers.end()); } From cd8ca4897fa0aaadfb94df6e370989a2d4639771 Mon Sep 17 00:00:00 2001 From: Paul Dreik Date: Wed, 22 Jul 2026 18:03:09 +0200 Subject: [PATCH 2/6] Improve C++20 string compliance Add constexpr string operations, allocator-aware pointer handling, required bounds errors, and safe self-referential modifiers. Cover the new behavior with focused system and psychicstd tests. --- include/__psychicstd_char_traits | 33 +- include/memory | 17 +- include/string | 642 ++++++++++++++++++++----------- tests/test_string.cpp | 35 ++ 4 files changed, 500 insertions(+), 227 deletions(-) diff --git a/include/__psychicstd_char_traits b/include/__psychicstd_char_traits index b280b1f7..a0349562 100644 --- a/include/__psychicstd_char_traits +++ b/include/__psychicstd_char_traits @@ -25,10 +25,25 @@ template struct char_traits { size_t n) noexcept { if (!n) return dst; + if (__builtin_is_constant_evaluated()) { + for (size_t i = 0; i < n; ++i) + dst[i] = src[i]; + return dst; + } return (char_type*)__builtin_memcpy(dst, src, n * sizeof(char_type)); } static constexpr char_type* move(char_type* dst, const char_type* src, size_t n) noexcept { + if (__builtin_is_constant_evaluated()) { + if (dst < src) { + for (size_t i = 0; i < n; ++i) + dst[i] = src[i]; + } else if (dst > src) { + for (size_t i = n; i-- > 0;) + dst[i] = src[i]; + } + return dst; + } return (char_type*)__builtin_memmove(dst, src, n * sizeof(char_type)); } static constexpr const char_type* find(const char_type* s, size_t n, @@ -89,10 +104,12 @@ template <> struct char_traits { #pragma GCC diagnostic ignored "-Wrestrict" #endif static constexpr char* copy(char* d, const char* s, size_t n) noexcept { - if (n) { - return (char*)__builtin_memcpy(d, s, n); + if (__builtin_is_constant_evaluated()) { + for (size_t i = 0; i < n; ++i) + d[i] = s[i]; + return d; } - return d; + return n ? (char*)__builtin_memcpy(d, s, n) : d; } #ifndef __clang__ #pragma GCC diagnostic pop @@ -102,6 +119,16 @@ template <> struct char_traits { #pragma GCC diagnostic ignored "-Wrestrict" #endif static constexpr char* move(char* d, const char* s, size_t n) noexcept { + if (__builtin_is_constant_evaluated()) { + if (d < s) { + for (size_t i = 0; i < n; ++i) + d[i] = s[i]; + } else if (d > s) { + for (size_t i = n; i-- > 0;) + d[i] = s[i]; + } + return d; + } return (char*)__builtin_memmove(d, s, n); } #ifndef __clang__ diff --git a/include/memory b/include/memory index a3aa4137..802f92d1 100644 --- a/include/memory +++ b/include/memory @@ -20,6 +20,17 @@ inline void* align(size_t alignment, size_t size, void*& ptr, } namespace __detail { +template struct __pointer_element; +template