[libcxx-commits] [libcxx] [libc++] Add warning groups to all our diagnose_if uses (PR #128759)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 6 04:54:42 PDT 2026


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/128759

>From febc806d9ccd72e99f05fc1f3d6098e756084aa4 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 25 Feb 2025 19:52:57 +0100
Subject: [PATCH] [libc++] Add warning groups to diagnose_if when available

---
 libcxx/include/__atomic/check_memory_order.h  | 17 +++++++-------
 libcxx/include/__configuration/attributes.h   |  7 ------
 libcxx/include/__filesystem/path.h            |  2 +-
 libcxx/include/__hash_table                   | 22 ++++++++++++-------
 libcxx/include/__tree                         | 12 +++++-----
 libcxx/include/map                            | 10 ++++-----
 libcxx/include/module.modulemap.in            |  1 +
 libcxx/include/set                            | 10 ++++-----
 libcxx/include/unordered_map                  |  6 +++--
 libcxx/include/unordered_set                  |  6 +++--
 .../non_const_comparator.verify.cpp           | 10 ++++-----
 .../unord/non_const_comparator.verify.cpp     | 19 ++++++++--------
 .../strings/basic.string/nonnull.verify.cpp   |  3 ---
 .../strings/string.view/nonnull.verify.cpp    |  3 ---
 14 files changed, 61 insertions(+), 67 deletions(-)

diff --git a/libcxx/include/__atomic/check_memory_order.h b/libcxx/include/__atomic/check_memory_order.h
index 536f764a61902..da9e3a8ecd1c1 100644
--- a/libcxx/include/__atomic/check_memory_order.h
+++ b/libcxx/include/__atomic/check_memory_order.h
@@ -15,20 +15,21 @@
 #  pragma GCC system_header
 #endif
 
+#define _LIBCPP_DIAGNOSE_ATOMIC_MEMORY_ORDERING_IF(condition)                                                          \
+  _LIBCPP_DIAGNOSE_IF(                                                                                                 \
+      condition, "memory order argument to atomic operation is invalid", "warning", "atomic-memory-ordering")
+
 #define _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m)                                                                          \
-  _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_consume || __m == memory_order_acquire || __m == memory_order_acq_rel,  \
-                           "memory order argument to atomic operation is invalid")
+  _LIBCPP_DIAGNOSE_ATOMIC_MEMORY_ORDERING_IF(                                                                          \
+      __m == memory_order_consume || __m == memory_order_acquire || __m == memory_order_acq_rel)
 
 #define _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m)                                                                           \
-  _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || __m == memory_order_acq_rel,                                 \
-                           "memory order argument to atomic operation is invalid")
+  _LIBCPP_DIAGNOSE_ATOMIC_MEMORY_ORDERING_IF(__m == memory_order_release || __m == memory_order_acq_rel)
 
 #define _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__m, __f)                                                                  \
-  _LIBCPP_DIAGNOSE_WARNING(__f == memory_order_release || __f == memory_order_acq_rel,                                 \
-                           "memory order argument to atomic operation is invalid")
+  _LIBCPP_DIAGNOSE_ATOMIC_MEMORY_ORDERING_IF(__f == memory_order_release || __f == memory_order_acq_rel)
 
 #define _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__m)                                                                           \
-  _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || __m == memory_order_acq_rel,                                 \
-                           "memory order argument to atomic operation is invalid")
+  _LIBCPP_DIAGNOSE_ATOMIC_MEMORY_ORDERING_IF(__m == memory_order_release || __m == memory_order_acq_rel)
 
 #endif // _LIBCPP___ATOMIC_CHECK_MEMORY_ORDER_H
diff --git a/libcxx/include/__configuration/attributes.h b/libcxx/include/__configuration/attributes.h
index c543ba9cb9e25..a30ad26404508 100644
--- a/libcxx/include/__configuration/attributes.h
+++ b/libcxx/include/__configuration/attributes.h
@@ -255,13 +255,6 @@
 #endif
 
 #if __has_attribute(__diagnose_if__)
-#  define _LIBCPP_DIAGNOSE_WARNING(...) __attribute__((__diagnose_if__(__VA_ARGS__, "warning")))
-#else
-#  define _LIBCPP_DIAGNOSE_WARNING(...)
-#endif
-
-#if __has_attribute(__diagnose_if__) && !defined(_LIBCPP_APPLE_CLANG_VER) &&                                           \
-    (!defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 2001)
 #  define _LIBCPP_DIAGNOSE_IF(...) __attribute__((__diagnose_if__(__VA_ARGS__)))
 #else
 #  define _LIBCPP_DIAGNOSE_IF(...)
diff --git a/libcxx/include/__filesystem/path.h b/libcxx/include/__filesystem/path.h
index a63c4ee611ebf..a77439b632f0d 100644
--- a/libcxx/include/__filesystem/path.h
+++ b/libcxx/include/__filesystem/path.h
@@ -513,7 +513,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path {
     return *this;
   }
 
-  // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
+  // FIXME: Use _LIBCPP_DIAGNOSE_IF to produce a diagnostic when __src
   // is known at compile time to be "/' since the user almost certainly intended
   // to append a separator instead of overwriting the path with "/"
   template <class _Source>
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 0ce4cf3edd6fd..9c3472c75fca2 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -596,15 +596,21 @@ struct __enforce_unordered_container_requirements {
   typedef int type;
 };
 
+#define _LIBCPP_DIAGNOSE_UNORDERED_CONTAINER_REQUIREMENTS(_Key, _Hash, _Equal)                                         \
+  _LIBCPP_DIAGNOSE_IF(                                                                                                 \
+      !__is_invocable_v<_Equal const&, _Key const&, _Key const&>,                                                      \
+      "the specified comparator type does not provide a viable const call operator",                                   \
+      "warning",                                                                                                       \
+      "discard-qual")                                                                                                  \
+  _LIBCPP_DIAGNOSE_IF(                                                                                                 \
+      !__is_invocable_v<_Hash const&, _Key const&>,                                                                    \
+      "the specified hash functor does not provide a viable const call operator",                                      \
+      "warning",                                                                                                       \
+      "discard-qual")
+
 template <class _Key, class _Hash, class _Equal>
-#ifndef _LIBCPP_CXX03_LANG
-_LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Equal const&, _Key const&, _Key const&>,
-                         "the specified comparator type does not provide a viable const call operator")
-_LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Hash const&, _Key const&>,
-                         "the specified hash functor does not provide a viable const call operator")
-#endif
-    typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
-    __diagnose_unordered_container_requirements(int);
+typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
+__diagnose_unordered_container_requirements(int);
 
 // This dummy overload is used so that the compiler won't emit a spurious
 // "no matching function for call to __diagnose_unordered_xxx" diagnostic
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index dafeff3e2e019..b46716e87f9e4 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -894,12 +894,12 @@ struct __specialized_algorithm<
 };
 #endif
 
-template <class _Tp, class _Compare>
-#ifndef _LIBCPP_CXX03_LANG
-_LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Compare const&, _Tp const&, _Tp const&>,
-                         "the specified comparator type does not provide a viable const call operator")
-#endif
-int __diagnose_non_const_comparator();
+#define _LIBCPP_DIAGNOSE_NON_CONST_COMPARATOR(_Compare, _Tp)                                                           \
+  _LIBCPP_DIAGNOSE_IF(                                                                                                 \
+      !__is_invocable_v<_Compare const&, _Tp const&, _Tp const&>,                                                      \
+      "the specified comparator type does not provide a viable const call operator",                                   \
+      "warning",                                                                                                       \
+      "discard-qual")
 
 template <class _Tp, class _Compare, class _Allocator>
 class __tree {
diff --git a/libcxx/include/map b/libcxx/include/map
index 8efe18fa3f839..f9c1528d0043c 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1092,9 +1092,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 map(const map& __m, const allocator_type& __alloc)
       : __tree_(__m.__tree_, __alloc) {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~map() {
-    static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), "");
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~map()
+      _LIBCPP_DIAGNOSE_NON_CONST_COMPARATOR(key_compare, key_type) {}
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() _NOEXCEPT {
     return __tree_.begin();
@@ -1876,9 +1875,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 multimap(const multimap& __m, const allocator_type& __a)
       : __tree_(__m.__tree_, __a) {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~multimap() {
-    static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), "");
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~multimap()
+      _LIBCPP_DIAGNOSE_NON_CONST_COMPARATOR(key_compare, key_type) {}
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() _NOEXCEPT {
     return __tree_.begin();
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 39b4e0bb986c6..ed8b052333021 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2413,6 +2413,7 @@ module std {
   module tree                 {
     header "__tree"
     export std.memory.unique_ptr
+    export std_core.type_traits.invoke
   }
   module std_mbstate_t {
     header "__std_mbstate_t.h"
diff --git a/libcxx/include/set b/libcxx/include/set
index 0409131ac6981..993e854a78a98 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -709,9 +709,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 set& operator=(set&& __s) = default;
 #  endif // _LIBCPP_CXX03_LANG
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~set() {
-    static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), "");
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~set()
+      _LIBCPP_DIAGNOSE_NON_CONST_COMPARATOR(key_compare, key_type) {}
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() _NOEXCEPT {
     return __tree_.begin();
@@ -1268,9 +1267,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 multiset& operator=(multiset&& __s) = default;
 #  endif // _LIBCPP_CXX03_LANG
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~multiset() {
-    static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), "");
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 ~multiset()
+      _LIBCPP_DIAGNOSE_NON_CONST_COMPARATOR(key_compare, key_type) {}
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() _NOEXCEPT {
     return __tree_.begin();
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 8cefba01fb5f6..9e39db76b21f2 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -1024,7 +1024,8 @@ public:
   unordered_map(initializer_list<value_type> __il, size_type __n, const hasher& __hf, const allocator_type& __a)
       : unordered_map(__il, __n, __hf, key_equal(), __a) {}
 #  endif
-  _LIBCPP_HIDE_FROM_ABI ~unordered_map() {
+  _LIBCPP_HIDE_FROM_ABI ~unordered_map()
+      _LIBCPP_DIAGNOSE_UNORDERED_CONTAINER_REQUIREMENTS(key_type, hasher, key_equal) {
     static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), "");
   }
 
@@ -1818,7 +1819,8 @@ public:
   unordered_multimap(initializer_list<value_type> __il, size_type __n, const hasher& __hf, const allocator_type& __a)
       : unordered_multimap(__il, __n, __hf, key_equal(), __a) {}
 #  endif
-  _LIBCPP_HIDE_FROM_ABI ~unordered_multimap() {
+  _LIBCPP_HIDE_FROM_ABI ~unordered_multimap()
+      _LIBCPP_DIAGNOSE_UNORDERED_CONTAINER_REQUIREMENTS(key_type, hasher, key_equal) {
     static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), "");
   }
 
diff --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index d54d59403b038..60b661072ce08 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -726,7 +726,8 @@ public:
       : unordered_set(__il, __n, __hf, key_equal(), __a) {}
 #    endif
 #  endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI ~unordered_set() {
+  _LIBCPP_HIDE_FROM_ABI ~unordered_set()
+      _LIBCPP_DIAGNOSE_UNORDERED_CONTAINER_REQUIREMENTS(key_type, hasher, key_equal) {
     static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), "");
   }
 
@@ -1340,7 +1341,8 @@ public:
       : unordered_multiset(__il, __n, __hf, key_equal(), __a) {}
 #    endif
 #  endif // _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI ~unordered_multiset() {
+  _LIBCPP_HIDE_FROM_ABI ~unordered_multiset()
+      _LIBCPP_DIAGNOSE_UNORDERED_CONTAINER_REQUIREMENTS(key_type, hasher, key_equal) {
     static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), "");
   }
 
diff --git a/libcxx/test/libcxx/containers/associative/non_const_comparator.verify.cpp b/libcxx/test/libcxx/containers/associative/non_const_comparator.verify.cpp
index cb7a044abd8c0..8c338be91110e 100644
--- a/libcxx/test/libcxx/containers/associative/non_const_comparator.verify.cpp
+++ b/libcxx/test/libcxx/containers/associative/non_const_comparator.verify.cpp
@@ -27,22 +27,20 @@ void f() {
   static_assert(!std::__is_invocable_v<BadCompare const&, int const&, int const&>, "");
   static_assert(std::__is_invocable_v<BadCompare&, int const&, int const&>, "");
 
-  // expected-warning at set:* 2 {{the specified comparator type does not provide a viable const call operator}}
-  // expected-warning at map:* 2 {{the specified comparator type does not provide a viable const call operator}}
   {
     using C = std::set<int, BadCompare>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}}
   }
   {
     using C = std::multiset<long, BadCompare>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}}
   }
   {
     using C = std::map<int, int, BadCompare>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}}
   }
   {
     using C = std::multimap<long, int, BadCompare>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}}
   }
 }
diff --git a/libcxx/test/libcxx/containers/unord/non_const_comparator.verify.cpp b/libcxx/test/libcxx/containers/unord/non_const_comparator.verify.cpp
index c3418302d0315..c3a58a5c72299 100644
--- a/libcxx/test/libcxx/containers/unord/non_const_comparator.verify.cpp
+++ b/libcxx/test/libcxx/containers/unord/non_const_comparator.verify.cpp
@@ -12,6 +12,8 @@
 // Test that libc++ generates a warning diagnostic when the container is
 // provided a non-const callable comparator or a non-const hasher.
 
+// ADDITIONAL_COMPILE_FLAGS: -Wno-comment
+
 #include <__type_traits/invoke.h>
 #include <unordered_set>
 #include <unordered_map>
@@ -34,25 +36,24 @@ void f() {
   static_assert(!std::__is_invocable_v<BadEqual const&, int const&, int const&>, "");
   static_assert(std::__is_invocable_v<BadEqual&, int const&, int const&>, "");
 
-  // expected-warning at unordered_set:* 2 {{the specified comparator type does not provide a viable const call operator}}
-  // expected-warning at unordered_map:* 2 {{the specified comparator type does not provide a viable const call operator}}
-  // expected-warning at unordered_set:* 2 {{the specified hash functor does not provide a viable const call operator}}
-  // expected-warning at unordered_map:* 2 {{the specified hash functor does not provide a viable const call operator}}
-
   {
     using C = std::unordered_set<int, BadHash, BadEqual>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}} \
+            expected-warning {{the specified hash functor does not provide a viable const call operator}}
   }
   {
     using C = std::unordered_multiset<long, BadHash, BadEqual>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}} \
+            expected-warning {{the specified hash functor does not provide a viable const call operator}}
   }
   {
     using C = std::unordered_map<int, int, BadHash, BadEqual>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}} \
+            expected-warning {{the specified hash functor does not provide a viable const call operator}}
   }
   {
     using C = std::unordered_multimap<long, int, BadHash, BadEqual>;
-    C s;
+    C s; // expected-warning {{the specified comparator type does not provide a viable const call operator}} \
+            expected-warning {{the specified hash functor does not provide a viable const call operator}}
   }
 }
diff --git a/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp b/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
index bdb3189b7fd35..9db3c0be6392f 100644
--- a/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/nonnull.verify.cpp
@@ -10,9 +10,6 @@
 
 // Ensure that APIs which take a CharT* are diagnosing passing a nullptr to them
 
-// AppleClang doesn't have diagnose_if with diagnostic flags
-// UNSUPPORTED: apple-clang-21
-
 // ADDITIONAL_COMPILE_FLAGS: -Wno-unused-result
 
 #include <string>
diff --git a/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp b/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp
index cac8ca81b1a1b..4f699d9d1b3fc 100644
--- a/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp
+++ b/libcxx/test/libcxx/strings/string.view/nonnull.verify.cpp
@@ -10,9 +10,6 @@
 
 // Ensure that APIs which take a CharT* are diagnosing passing a nullptr to them
 
-// AppleClang doesn't have diagnose_if with diagnostic flags
-// UNSUPPORTED: apple-clang-21
-
 // ADDITIONAL_COMPILE_FLAGS: -Wno-unused-result
 
 #include <string_view>



More information about the libcxx-commits mailing list