From 00e4c6d805a084c4310d4e27bb87892411bf659a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 8 Aug 2025 10:17:33 +0800 Subject: [PATCH 1/2] [libc++] Fix uses of non-empty transparent comparator with in `` The `__get_value()` member function was removed in LLVM 21, but the calls in `` weren't removed. This patch completes the removal and adds regression test cases. --- libcxx/include/map | 4 ++-- .../associative/map/map.ops/count0.pass.cpp | 4 ++++ .../associative/map/map.ops/equal_range0.pass.cpp | 7 +++++++ .../associative/map/map.ops/find0.pass.cpp | 5 +++++ .../associative/map/map.ops/lower_bound0.pass.cpp | 5 +++++ .../associative/map/map.ops/upper_bound0.pass.cpp | 5 +++++ .../multimap/multimap.ops/count0.pass.cpp | 4 ++++ .../multimap/multimap.ops/equal_range0.pass.cpp | 7 +++++++ .../multimap/multimap.ops/find0.pass.cpp | 5 +++++ .../multimap/multimap.ops/lower_bound0.pass.cpp | 5 +++++ .../multimap/multimap.ops/upper_bound0.pass.cpp | 5 +++++ libcxx/test/support/is_transparent.h | 13 +++++++++++++ 12 files changed, 67 insertions(+), 2 deletions(-) diff --git a/libcxx/include/map b/libcxx/include/map index 6378218945ca0..9f98abef9afe0 100644 --- a/libcxx/include/map +++ b/libcxx/include/map @@ -691,12 +691,12 @@ public: # if _LIBCPP_STD_VER >= 14 template _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const { - return __comp_(__x, __y.__get_value().first); + return __comp_(__x, __y.first); } template _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const { - return __comp_(__x.__get_value().first, __y); + return __comp_(__x.first, __y); } # endif }; diff --git a/libcxx/test/std/containers/associative/map/map.ops/count0.pass.cpp b/libcxx/test/std/containers/associative/map/map.ops/count0.pass.cpp index c7ba765178969..62491e2bc4438 100644 --- a/libcxx/test/std/containers/associative/map/map.ops/count0.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.ops/count0.pass.cpp @@ -33,6 +33,10 @@ int main(int, char**) { typedef std::map M; assert(M().count(C2Int{5}) == 0); } + { + using M = std::map; + assert(M().count(C2Int{5}) == 0); + } return 0; } diff --git a/libcxx/test/std/containers/associative/map/map.ops/equal_range0.pass.cpp b/libcxx/test/std/containers/associative/map/map.ops/equal_range0.pass.cpp index 75724bdb387ce..57ce9339f6323 100644 --- a/libcxx/test/std/containers/associative/map/map.ops/equal_range0.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.ops/equal_range0.pass.cpp @@ -40,6 +40,13 @@ int main(int, char**) { P result = example.equal_range(C2Int{5}); assert(result.first == result.second); } + { + using M = std::map; + using P = std::pair; + M example; + P result = example.equal_range(C2Int{5}); + assert(result.first == result.second); + } return 0; } diff --git a/libcxx/test/std/containers/associative/map/map.ops/find0.pass.cpp b/libcxx/test/std/containers/associative/map/map.ops/find0.pass.cpp index 9825d6c5879b1..3f09d5608772d 100644 --- a/libcxx/test/std/containers/associative/map/map.ops/find0.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.ops/find0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.find(C2Int{5}) == example.end()); } + { + using M = std::map; + M example; + assert(example.find(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/std/containers/associative/map/map.ops/lower_bound0.pass.cpp b/libcxx/test/std/containers/associative/map/map.ops/lower_bound0.pass.cpp index fe7fe381a86eb..308a2ed1e3af0 100644 --- a/libcxx/test/std/containers/associative/map/map.ops/lower_bound0.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.ops/lower_bound0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.lower_bound(C2Int{5}) == example.end()); } + { + using M = std::map; + M example; + assert(example.lower_bound(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/std/containers/associative/map/map.ops/upper_bound0.pass.cpp b/libcxx/test/std/containers/associative/map/map.ops/upper_bound0.pass.cpp index 525aa673ea74b..332b71a84e9fb 100644 --- a/libcxx/test/std/containers/associative/map/map.ops/upper_bound0.pass.cpp +++ b/libcxx/test/std/containers/associative/map/map.ops/upper_bound0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.upper_bound(C2Int{5}) == example.end()); } + { + using M = std::map; + M example; + assert(example.upper_bound(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.ops/count0.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.ops/count0.pass.cpp index 233d1a11e1d6c..36f0ac2647ba3 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.ops/count0.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.ops/count0.pass.cpp @@ -33,6 +33,10 @@ int main(int, char**) { typedef std::multimap M; assert(M().count(C2Int{5}) == 0); } + { + using M = std::multimap; + assert(M().count(C2Int{5}) == 0); + } return 0; } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.ops/equal_range0.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.ops/equal_range0.pass.cpp index 0bead6c7938db..a362c03e26385 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.ops/equal_range0.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.ops/equal_range0.pass.cpp @@ -40,6 +40,13 @@ int main(int, char**) { P result = example.equal_range(C2Int{5}); assert(result.first == result.second); } + { + using M = std::multimap; + using P = std::pair; + M example; + P result = example.equal_range(C2Int{5}); + assert(result.first == result.second); + } return 0; } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.ops/find0.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.ops/find0.pass.cpp index 701d4e314e7a8..ccb0900e76835 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.ops/find0.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.ops/find0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.find(C2Int{5}) == example.end()); } + { + using M = std::multimap; + M example; + assert(example.find(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.ops/lower_bound0.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.ops/lower_bound0.pass.cpp index 79f994847f131..4b4853062001f 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.ops/lower_bound0.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.ops/lower_bound0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.lower_bound(C2Int{5}) == example.end()); } + { + using M = std::multimap; + M example; + assert(example.lower_bound(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.ops/upper_bound0.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.ops/upper_bound0.pass.cpp index 62f52416b9156..f2ae94577b6c1 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.ops/upper_bound0.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.ops/upper_bound0.pass.cpp @@ -36,6 +36,11 @@ int main(int, char**) { M example; assert(example.upper_bound(C2Int{5}) == example.end()); } + { + using M = std::multimap; + M example; + assert(example.upper_bound(C2Int{5}) == example.end()); + } return 0; } diff --git a/libcxx/test/support/is_transparent.h b/libcxx/test/support/is_transparent.h index 700c894a8b60f..350ef97f31877 100644 --- a/libcxx/test/support/is_transparent.h +++ b/libcxx/test/support/is_transparent.h @@ -36,6 +36,19 @@ struct transparent_less_not_referenceable using is_transparent = void () const &; // it's a type; a weird one, but a type }; +// Prevent regression when empty base class optimization is not suitable. +// See https://github.com/llvm/llvm-project/issues/152543. +struct transparent_less_nonempty { + template + constexpr auto operator()(T&& t, U&& u) const // + noexcept(noexcept(std::forward(t) < std::forward(u))) // + -> decltype /**/ (std::forward(t) < std::forward(u)) { + return /*--------*/ std::forward(t) < std::forward(u); + } + struct is_transparent { + } pad_; // making this comparator non-empty +}; + struct transparent_less_no_type { template From b187fdf728bcfca0cc1dbb7a26323865892affd5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 8 Aug 2025 15:45:59 +0800 Subject: [PATCH 2/2] Simpify `transparent_less_nonempty` --- libcxx/test/support/is_transparent.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libcxx/test/support/is_transparent.h b/libcxx/test/support/is_transparent.h index 350ef97f31877..4b2a458f574aa 100644 --- a/libcxx/test/support/is_transparent.h +++ b/libcxx/test/support/is_transparent.h @@ -40,10 +40,8 @@ struct transparent_less_not_referenceable // See https://github.com/llvm/llvm-project/issues/152543. struct transparent_less_nonempty { template - constexpr auto operator()(T&& t, U&& u) const // - noexcept(noexcept(std::forward(t) < std::forward(u))) // - -> decltype /**/ (std::forward(t) < std::forward(u)) { - return /*--------*/ std::forward(t) < std::forward(u); + constexpr bool operator()(T&& t, U&& u) const { + return std::forward(t) < std::forward(u); } struct is_transparent { } pad_; // making this comparator non-empty