Add _LIBCPP_DIAGNOSE_WARNING and _LIBCPP_DIAGNOSE_ERROR macros.

Clang recently added a `diagnose_if(cond, msg, type)` attribute
which can be used to generate diagnostics when `cond` is a constant
expression that evaluates to true. Otherwise no attribute has no
effect.

This patch adds _LIBCPP_DIAGNOSE_ERROR/WARNING macros which
use this new attribute. Additionally this patch implements
a diagnostic message when a non-const-callable comparator is
given to a container.

Note: For now the warning version of the diagnostic is useless
within libc++ since warning diagnostics are suppressed by the
system header pragma. I'm going to work on fixing this.

llvm-svn: 291961
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: b1e7a12ee89ffcf50d0b18f8c6da7423604ea9d8
diff --git a/include/__config b/include/__config
index 5cb699b..fec9642 100644
--- a/include/__config
+++ b/include/__config
@@ -1006,6 +1006,16 @@
 #endif
 #endif
 
+#if __has_attribute(diagnose_if) && !defined(_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS)
+# define _LIBCPP_DIAGNOSE_WARNING(...) \
+    __attribute__((__diagnose_if__(__VA_ARGS__, "warning")))
+# define _LIBCPP_DIAGNOSE_ERROR(...) \
+    __attribute__((__diagnose_if__(__VA_ARGS__, "error")))
+#else
+# define _LIBCPP_DIAGNOSE_WARNING(...)
+# define _LIBCPP_DIAGNOSE_ERROR(...)
+#endif
+
 #endif // __cplusplus
 
 #endif // _LIBCPP_CONFIG
diff --git a/include/__tree b/include/__tree
index dd32f70..3bc0207 100644
--- a/include/__tree
+++ b/include/__tree
@@ -41,6 +41,10 @@
 struct __value_type;
 #endif
 
+template <class _Key, class _CP, class _Compare,
+    bool = is_empty<_Compare>::value && !__libcpp_is_final<_Compare>::value>
+class __map_value_compare;
+
 template <class _Allocator> class __map_node_destructor;
 template <class _TreeIterator> class _LIBCPP_TEMPLATE_VIS __map_iterator;
 template <class _TreeIterator> class _LIBCPP_TEMPLATE_VIS __map_const_iterator;
@@ -955,6 +959,30 @@
 
 };
 
+#ifndef _LIBCPP_CXX03_LANG
+template <class _Tp, class _Compare, class _Allocator>
+struct __diagnose_tree_helper {
+  static constexpr bool __trigger_diagnostics()
+      _LIBCPP_DIAGNOSE_WARNING(!__is_const_comparable<_Compare, _Tp>::value,
+            "the specified comparator type does not provide a const call operator")
+  { return true; }
+};
+
+template <class _Key, class _Value, class _KeyComp, class _Alloc>
+struct __diagnose_tree_helper<
+    __value_type<_Key, _Value>,
+    __map_value_compare<_Key, __value_type<_Key, _Value>, _KeyComp>,
+    _Alloc
+>
+{
+  static constexpr bool __trigger_diagnostics()
+      _LIBCPP_DIAGNOSE_WARNING(!__is_const_comparable<_KeyComp, _Key>::value,
+            "the specified comparator type does not provide a const call operator")
+  { return true; }
+};
+
+#endif
+
 template <class _Tp, class _Compare, class _Allocator>
 class __tree
 {
@@ -1787,7 +1815,11 @@
 {
     static_assert((is_copy_constructible<value_compare>::value),
                  "Comparator must be copy-constructible.");
-    destroy(__root());
+#ifndef _LIBCPP_CXX03_LANG
+    static_assert((__diagnose_tree_helper<_Tp, _Compare, _Allocator>::
+                     __trigger_diagnostics()), "");
+#endif
+  destroy(__root());
 }
 
 template <class _Tp, class _Compare, class _Allocator>
diff --git a/include/map b/include/map
index 9555aad..ecd9d92 100644
--- a/include/map
+++ b/include/map
@@ -453,9 +453,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Key, class _CP, class _Compare,
-          bool = is_empty<_Compare>::value && !__libcpp_is_final<_Compare>::value
-         >
+template <class _Key, class _CP, class _Compare, bool _IsSmall>
 class __map_value_compare
     : private _Compare
 {
diff --git a/include/type_traits b/include/type_traits
index 7862955..8812d3d 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -4715,6 +4715,15 @@
 
 #endif
 
+template <class _Comp, class _ValueType, class = void>
+struct __is_const_comparable : false_type {};
+
+template <class _Comp, class _ValueType>
+struct __is_const_comparable<_Comp, _ValueType, typename __void_t<
+    decltype(_VSTD::declval<_Comp const&>()(_VSTD::declval<_ValueType const&>(),
+                                            _VSTD::declval<_ValueType const&>()))
+  >::type> : true_type {};
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_TYPE_TRAITS