[libcxx-commits] [libcxx] [libc++] Make sure that __desugars_to isn't tripped up by reference_wrapper and cv-refs (PR #132092)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 20 10:37:59 PDT 2025


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/132092

>From 72990d44832ffe0de57b71912f6088cab2d5fa29 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 19 Mar 2025 16:14:24 -0400
Subject: [PATCH 1/3] [libc++] Make sure that __desugars_to isn't tripped up by
 reference_wrapper and cv-refs

Previously, any cv-ref qualification on an operation would cause
__desugars_to to report false, which would lead to unnecessary
pessimizations. The same holds for reference_wrapper.

In practice, cv-ref qualifications on the operation itself are not
relevant to determining whether an operation desugars to something
else or not.

Fixes #129312
---
 .../include/__functional/reference_wrapper.h  |  6 +++
 libcxx/include/__type_traits/desugars_to.h    | 18 +++++++++
 .../type_traits/desugars_to.compile.pass.cpp  | 40 +++++++++++++++++++
 .../refwrap/desugars_to.compile.pass.cpp      | 23 +++++++++++
 4 files changed, 87 insertions(+)
 create mode 100644 libcxx/test/libcxx/type_traits/desugars_to.compile.pass.cpp
 create mode 100644 libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp

diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index d6cd6428f22db..3678b5553c444 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -15,6 +15,7 @@
 #include <__config>
 #include <__functional/weak_result_type.h>
 #include <__memory/addressof.h>
+#include <__type_traits/desugars_to.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_const.h>
@@ -149,6 +150,11 @@ void ref(const _Tp&&) = delete;
 template <class _Tp>
 void cref(const _Tp&&) = delete;
 
+// Let desugars-to pass through std::reference_wrapper
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, reference_wrapper<_Operation>, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
diff --git a/libcxx/include/__type_traits/desugars_to.h b/libcxx/include/__type_traits/desugars_to.h
index 452c70bfbad66..ed8b5ab8d318a 100644
--- a/libcxx/include/__type_traits/desugars_to.h
+++ b/libcxx/include/__type_traits/desugars_to.h
@@ -52,6 +52,24 @@ struct __totally_ordered_less_tag {};
 template <class _CanonicalTag, class _Operation, class... _Args>
 inline const bool __desugars_to_v = false;
 
+// For the purpose of determining whether something desugars to something else,
+// we disregard the cv-refs of the operation itself.
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, _Operation const, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, _Operation volatile, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, _Operation const volatile, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, _Operation&, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+template <class _CanonicalTag, class _Operation, class... _Args>
+inline const bool __desugars_to_v<_CanonicalTag, _Operation&&, _Args...> =
+    __desugars_to_v<_CanonicalTag, _Operation, _Args...>;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H
diff --git a/libcxx/test/libcxx/type_traits/desugars_to.compile.pass.cpp b/libcxx/test/libcxx/type_traits/desugars_to.compile.pass.cpp
new file mode 100644
index 0000000000000..780d9372d8387
--- /dev/null
+++ b/libcxx/test/libcxx/type_traits/desugars_to.compile.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__type_traits/desugars_to.h>
+
+struct Tag {};
+struct Operation {};
+template <>
+bool const std::__desugars_to_v<Tag, Operation> = true;
+
+void tests() {
+  // Make sure that __desugars_to is false by default
+  {
+    struct Foo {};
+    static_assert(!std::__desugars_to_v<Tag, Foo>, "");
+  }
+
+  // Make sure that __desugars_to bypasses cv and ref qualifiers on the operation
+  {
+    static_assert(std::__desugars_to_v<Tag, Operation>, ""); // no quals
+    static_assert(std::__desugars_to_v<Tag, Operation const>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation volatile>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation const volatile>, "");
+
+    static_assert(std::__desugars_to_v<Tag, Operation&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation const&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation volatile&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation const volatile&>, "");
+
+    static_assert(std::__desugars_to_v<Tag, Operation&&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation const&&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation volatile&&>, "");
+    static_assert(std::__desugars_to_v<Tag, Operation const volatile&&>, "");
+  }
+}
diff --git a/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
new file mode 100644
index 0000000000000..30e5654c0824f
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <functional>
+
+// reference_wrapper
+
+// Ensure that std::reference_wrapper does not inhibit optimizations based on the
+// std::__desugars_to internal helper.
+
+#include <functional>
+
+static_assert(std::__desugars_to_v<std::__equal_tag, std::equal_to<void>, int, int>,
+              "something is wrong with the test");
+
+// make sure we pass through reference_wrapper
+static_assert(std::__desugars_to_v<std::__equal_tag, std::reference_wrapper<std::equal_to<void> >, int, int>, "");
+static_assert(std::__desugars_to_v<std::__equal_tag, std::reference_wrapper<std::equal_to<void> const>, int, int>, "");

>From 918e2696cdb14807fa5c6b921f4130eda77905d9 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 20 Mar 2025 13:36:36 -0400
Subject: [PATCH 2/3] Decouple test from std::equal_to

---
 .../refwrap/desugars_to.compile.pass.cpp             | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
index 30e5654c0824f..c98d688b41084 100644
--- a/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
@@ -15,9 +15,13 @@
 
 #include <functional>
 
-static_assert(std::__desugars_to_v<std::__equal_tag, std::equal_to<void>, int, int>,
-              "something is wrong with the test");
+struct Operation {};
+struct Tag {};
+template <>
+bool const std::__desugars_to_v<Tag, Operation> = true;
+
+static_assert(std::__desugars_to_v<Tag, Operation>, "something is wrong with the test");
 
 // make sure we pass through reference_wrapper
-static_assert(std::__desugars_to_v<std::__equal_tag, std::reference_wrapper<std::equal_to<void> >, int, int>, "");
-static_assert(std::__desugars_to_v<std::__equal_tag, std::reference_wrapper<std::equal_to<void> const>, int, int>, "");
+static_assert(std::__desugars_to_v<Tag, std::reference_wrapper<Operation> >, "");
+static_assert(std::__desugars_to_v<Tag, std::reference_wrapper<Operation const> >, "");

>From 691272c6dbbd71703ead367f9d7e1a59e3073c31 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 20 Mar 2025 13:37:47 -0400
Subject: [PATCH 3/3] Fix modules issues

---
 .../function.objects/refwrap/desugars_to.compile.pass.cpp        | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
index c98d688b41084..96e3e76aac685 100644
--- a/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/function.objects/refwrap/desugars_to.compile.pass.cpp
@@ -14,6 +14,7 @@
 // std::__desugars_to internal helper.
 
 #include <functional>
+#include <__type_traits/desugars_to.h>
 
 struct Operation {};
 struct Tag {};



More information about the libcxx-commits mailing list