CaseyCarter created this revision.
CaseyCarter added reviewers: mclow.lists, EricWF.

I'm breaking this up into independent bite-sized ~500 line reviews instead of a 
single 5200 line monster in hopes that we can turnaround changes quickly.

This first piece implements the new bullet for `common_type`, and all of 
`common_reference` and `basic_common_reference`. I've conservatively hidden 
everything behind `_LIBCPP_STD_VER > 17`, although it could be made available 
in C++11 mode with some edits.


https://reviews.llvm.org/D49118

Files:
  include/type_traits
  test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.pass.cpp
  test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp

Index: test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp
===================================================================
--- test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp
+++ test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp
@@ -83,13 +83,16 @@
 template <class T1, class T2>
 using TernaryOp = typename TernaryOpImp<T1, T2>::type;
 
+// (4.1)
 // -- If sizeof...(T) is zero, there shall be no member type.
 void test_bullet_one() {
   static_assert(no_common_type<>::value, "");
 }
 
-// If sizeof...(T) is one, let T0 denote the sole type constituting the pack T.
-// The member typedef-name type shall denote the same type as decay_t<T0>.
+// (4.2)
+// -- If sizeof...(T) is one, let T0 denote the sole type constituting the pack
+//    T. The member typedef-name type shall denote the same type, if any, as
+//    common_type_t<T0, T0>; otherwise there shall be no member type.
 void test_bullet_two() {
   static_assert(std::is_same<CommonType<void>, void>::value, "");
   static_assert(std::is_same<CommonType<int>, int>::value, "");
@@ -110,11 +113,11 @@
   static_assert(std::is_same<CommonType<T, U>, CommonType<DT, DU>>::value, "");
 }
 
-// (3.3)
+// (4.3)
 // -- If sizeof...(T) is two, let the first and second types constituting T be
 //    denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
 //    as decay_t<T1> and decay_t<T2>, respectively.
-// (3.3.1)
+// (4.3.1)
 //    -- If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C
 //       denote the same type, if any, as common_type_t<D1, D2>.
 void test_bullet_three_one() {
@@ -148,16 +151,19 @@
   }
 }
 
-// (3.3)
+// (4.3)
 // -- If sizeof...(T) is two, let the first and second types constituting T be
 //    denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
 //    as decay_t<T1> and decay_t<T2>, respectively.
-// (3.3.1)
+// (4.3.1)
 //    -- If [...]
-// (3.3.2)
-//    -- Otherwise, let C denote the same type, if any, as
+// (4.3.2)
+//    -- [Note: [...]
+// (4.3.3)
+//    -- Otherwise, if
 //       decay_t<decltype(false ? declval<D1>() : declval<D2>())>
-void test_bullet_three_two() {
+//       denotes a type, let C denote that type.
+void test_bullet_three_three() {
   {
     using T1 = int const*;
     using T2 = int*;
@@ -188,7 +194,16 @@
   }
 }
 
-// (3.4)
+#if TEST_STD_VER > 17
+// (4.3.4)
+//    -- Otherwise, if COND_RES(CREF(D1), CREF(D2)) denotes a type, let C denote
+//       the type decay_t<COND_RES(CREF(D1), CREF(D2))>.
+void test_bullet_three_four() {
+  static_assert(std::is_same_v<CommonType<std::reference_wrapper<int>, int>, int>);
+}
+#endif
+
+// (4.4)
 // -- If sizeof...(T) is greater than two, let T1, T2, and R, respectively,
 // denote the first, second, and (pack of) remaining types constituting T.
 // Let C denote the same type, if any, as common_type_t<T1, T2>. If there is
@@ -291,7 +306,10 @@
   test_bullet_one();
   test_bullet_two();
   test_bullet_three_one();
-  test_bullet_three_two();
+  test_bullet_three_three();
+# if TEST_STD_VER > 17
+  test_bullet_three_four();
+# endif
   test_bullet_four();
 #endif
 
Index: test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/meta/meta.trans/meta.trans.other/common_reference.pass.cpp
@@ -0,0 +1,226 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
+
+// type_traits
+
+// common_reference
+
+#include <type_traits>
+
+using std::common_reference;
+using std::common_reference_t;
+using std::is_same_v;
+using std::void_t;
+
+template <class, class = void>
+constexpr bool is_trait = false;
+template <class T>
+constexpr bool is_trait<T, void_t<typename T::type>> = true;
+
+// A slightly simplified variation of std::tuple
+template <class...> struct Tuple {};
+
+template <class, class, class> struct Tuple_helper {};
+template <class... Ts, class... Us>
+struct Tuple_helper<void_t<common_reference_t<Ts, Us>...>, Tuple<Ts...>, Tuple<Us...>>
+{
+    using type = Tuple<common_reference_t<Ts, Us>...>;
+};
+
+namespace std
+{
+    template <class... Ts, class... Us,
+        template <class> class TQual, template <class> class UQual>
+    struct basic_common_reference<::Tuple<Ts...>, ::Tuple<Us...>, TQual, UQual>
+        : ::Tuple_helper<void, Tuple<TQual<Ts>...>, Tuple<UQual<Us>...>>
+    {};
+}
+
+struct X2 {};
+struct Y2 {};
+struct Z2 {};
+
+namespace std
+{
+    template <>
+    struct common_type<X2, Y2>
+    {
+        using type = Z2;
+    };
+    template <>
+    struct common_type<Y2, X2>
+    {
+        using type = Z2;
+    };
+}
+
+// (6.1)
+//  -- If sizeof...(T) is zero, there shall be no member type.
+void test_bullet_one() {
+    static_assert(!is_trait<common_reference<>>);
+}
+
+// (6.2)
+//  -- Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+//     pack T. The member typedef type shall denote the same type as T0.
+void test_bullet_two() {
+    static_assert(is_same_v<common_reference_t<void>, void>);
+    static_assert(is_same_v<common_reference_t<int>, int>);
+    static_assert(is_same_v<common_reference_t<int&>, int&>);
+    static_assert(is_same_v<common_reference_t<int&&>, int&&>);
+    static_assert(is_same_v<common_reference_t<int const>, int const>);
+    static_assert(is_same_v<common_reference_t<int const&>, int const&>);
+    static_assert(is_same_v<common_reference_t<int const&&>, int const&&>);
+    static_assert(is_same_v<common_reference_t<int volatile[]>, int volatile[]>);
+    static_assert(is_same_v<common_reference_t<int volatile (&)[]>, int volatile (&)[]>);
+    static_assert(is_same_v<common_reference_t<int volatile (&&)[]>, int volatile (&&)[]>);
+    static_assert(is_same_v<common_reference_t<void(&)()>, void(&)()>);
+    static_assert(is_same_v<common_reference_t<void(&&)()>, void(&&)()>);
+}
+
+// (6.3)
+//  -- Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+//     the pack T. Then
+// (6.3.1)
+//    -- If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed,
+//       then the member typedef type denotes that type.
+void test_bullet_three_one() {
+    {
+        struct B {};
+        struct D : B {};
+        static_assert(is_same_v<common_reference_t<B&, D&>, B&>);
+        static_assert(is_same_v<common_reference_t<B const&, D&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B&, D const&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B&, D const&, D&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B&, D&, B&, D&>, B&>);
+
+        static_assert(is_same_v<common_reference_t<B&&, D&&>, B&&>);
+        static_assert(is_same_v<common_reference_t<B const&&, D&&>, B const&&>);
+        static_assert(is_same_v<common_reference_t<B&&, D const&&>, B const&&>);
+        static_assert(is_same_v<common_reference_t<B&, D&&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B&, D const&&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B const&, D&&>, B const&>);
+
+        static_assert(is_same_v<common_reference_t<B&&, D&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B&&, D const&>, B const&>);
+        static_assert(is_same_v<common_reference_t<B const&&, D&>, B const&>);
+    }
+
+    static_assert(is_same_v<
+        common_reference_t<int const volatile&&, int volatile&&>,
+        int const volatile&&>);
+    static_assert(is_same_v<
+        common_reference_t<int&&, int const&, int volatile&>,
+        int const volatile&>);
+
+    static_assert(is_same_v<
+        common_reference_t<int (&)[10], int (&&)[10]>,
+        int const (&)[10]>);
+    static_assert(is_same_v<
+        common_reference_t<int const (&)[10], int volatile (&)[10]>,
+        int const volatile (&)[10]>);
+}
+
+// (6.3.2)
+//    -- Otherwise, if basic_common_reference<remove_cvref_t<T1>,
+//       remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, then the
+//       member typedef type denotes that type.
+void test_bullet_three_two() {
+    static_assert(is_same_v<
+        common_reference_t<const Tuple<int, short>&, Tuple<int&, short volatile&>>,
+        Tuple<const int&, const volatile short&>>);
+    static_assert(is_same_v<
+        common_reference_t<volatile Tuple<int, short>&, const Tuple<int, short>&>,
+        const volatile Tuple<int, short>&>);
+}
+
+// (6.3.3)
+//    -- Otherwise, if COND_RES(T1, T2) is well-formed, then the member typedef
+//       type denotes that type.
+void test_bullet_three_three() {
+    static_assert(is_same_v<common_reference_t<void, void>, void>);
+    static_assert(is_same_v<common_reference_t<int, short>, int>);
+    static_assert(is_same_v<common_reference_t<int, short&>, int>);
+    static_assert(is_same_v<common_reference_t<int&, short&>, int>);
+    static_assert(is_same_v<common_reference_t<int&, short>, int>);
+
+    // tricky volatile reference case
+    static_assert(is_same_v<common_reference_t<int&&, int volatile&>, int>);
+    static_assert(is_same_v<common_reference_t<int volatile&, int&&>, int>);
+
+    static_assert(is_same_v<common_reference_t<int (&)[10], int (&)[11]>, int*>);
+
+    {
+        // https://github.com/ericniebler/stl2/issues/338
+        struct MyIntRef { MyIntRef(int&); };
+        static_assert(is_same_v<common_reference_t<int&, MyIntRef>, MyIntRef>);
+    }
+}
+
+// (6.3.4)
+//    -- Otherwise, if common_type_t<T1, T2> is well-formed, then the member
+//       typedef type denotes that type.
+void test_bullet_three_four() {
+    {
+        struct moveonly {
+            moveonly() = default;
+            moveonly(moveonly&&) = default;
+            moveonly& operator=(moveonly&&) = default;
+        };
+        struct moveonly2 : moveonly {};
+
+        static_assert(is_same_v<common_reference_t<moveonly  const&, moveonly >, moveonly>);
+        static_assert(is_same_v<common_reference_t<moveonly2 const&, moveonly >, moveonly>);
+        static_assert(is_same_v<common_reference_t<moveonly  const&, moveonly2>, moveonly>);
+    }
+
+    static_assert(is_same_v<common_reference_t<X2&, Y2 const&>, Z2>);
+}
+
+// (6.3.5)
+//    -- Otherwise, there shall be no member type.
+void test_bullet_three_five() {
+    static_assert(!is_trait<
+        common_reference<volatile Tuple<short>&, const Tuple<int, short>&>>);
+}
+
+// (6.4)
+//  -- Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest,
+//     respectively, denote the first, second, and (pack of) remaining types
+//     comprising T. Let C be the type common_reference_t<T1, T2>. Then:
+// (6.4.1)
+//    -- If there is such a type C, the member typedef type shall denote the
+//       same type, if any, as common_reference_t<C, Rest...>.
+void test_bullet_four_one() {
+    static_assert(is_same_v<common_reference_t<int, int, int>, int>);
+    static_assert(is_same_v<
+        common_reference_t<int&&, int const&, int volatile&>,
+        int const volatile&>);
+    static_assert(is_same_v<common_reference_t<int&&, int const&, float&>, float>);
+}
+
+// (6.4.2)
+//    -- Otherwise, there shall be no member type.
+void test_bullet_four_two() {
+    static_assert(!is_trait<common_reference<int, short, int, char*>>);
+}
+
+int main() {
+    test_bullet_one();
+    test_bullet_two();
+    test_bullet_three_one();
+    test_bullet_three_two();
+    test_bullet_three_three();
+    test_bullet_three_four();
+    test_bullet_three_five();
+    test_bullet_four_one();
+    test_bullet_four_two();
+}
Index: include/type_traits
===================================================================
--- include/type_traits
+++ include/type_traits
@@ -350,9 +350,9 @@
       template <class T> inline constexpr bool is_nothrow_move_assignable_v
         = is_nothrow_move_assignable<T>::value;                          // C++17
       template <class T, class U> inline constexpr bool is_nothrow_swappable_with_v
-        = is_nothrow_swappable_with<T, U>::value;                       // C++17
+        = is_nothrow_swappable_with<T, U>::value;                        // C++17
       template <class T> inline constexpr bool is_nothrow_swappable_v
-        = is_nothrow_swappable<T>::value;                               // C++17
+        = is_nothrow_swappable<T>::value;                                // C++17
       template <class T> inline constexpr bool is_nothrow_destructible_v
         = is_nothrow_destructible<T>::value;                             // C++17
       template <class T> inline constexpr bool has_virtual_destructor_v
@@ -395,6 +395,11 @@
       template<class B>
         inline constexpr bool negation_v = negation<B>::value;           // C++17
 
+      template <class T, class U, template <class> class TQual, template <class> class UQual>
+        struct basic_common_reference { };                                 // C++20
+      template <class... T> struct common_reference;                       // C++20
+      template <class... T>                                                // C++20
+        using common_reference_t = typename common_reference<T...>::type;  // C++20
 }
 
 */
@@ -414,6 +419,11 @@
 template <class>
 struct __void_t { typedef void type; };
 
+#if _LIBCPP_STD_VER > 14
+#define __cpp_lib_void_t 201411
+template <class...> using void_t = void;
+#endif // _LIBCPP_STD_VER > 14
+
 template <class _Tp>
 struct __identity { typedef _Tp type; };
 
@@ -2098,8 +2108,33 @@
 
 // bullet 3 - sizeof...(Tp) == 2
 
+#if _LIBCPP_STD_VER > 17
+// Let COND_RES(X, Y) be:
+template <class _Tp, class _Up>
+using __cond_res =
+    decltype(false ? _VSTD::declval<_Tp(&)()>()() : _VSTD::declval<_Up(&)()>()());
+
+template <class _Tp, class _Up, class = void>
+struct __common_type3 {};
+
+// sub-bullet 4 - "if COND_RES(CREF(D1), CREF(D2)) denotes a type..."
+template <class _Tp>
+using __cref = add_lvalue_reference_t<const _Tp>;
+
+template <class _Tp, class _Up>
+struct __common_type3<_Tp, _Up, void_t<__cond_res<__cref<_Tp>, __cref<_Up>>>>
+{
+    using type = decay_t<__cond_res<__cref<_Tp>, __cref<_Up>>>;
+};
+
+template <class _Tp, class _Up, class = void>
+struct __common_type2_imp : __common_type3<_Tp, _Up> {};
+#else  // ^^^ _LIBCPP_STD_VER > 17 / _LIBCPP_STD_VER <= 17 vvv
 template <class _Tp, class _Up, class = void>
 struct __common_type2_imp {};
+#endif // _LIBCPP_STD_VER > 17
+
+// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
 
 template <class _Tp, class _Up>
 struct __common_type2_imp<_Tp, _Up,
@@ -2112,6 +2147,8 @@
     )>::type type;
 };
 
+// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
+
 template <class _Tp, class _Up,
           class _DTp = typename decay<_Tp>::type,
           class _DUp = typename decay<_Up>::type>
@@ -2158,7 +2195,174 @@
 template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type;
 #endif
 
-#endif  // _LIBCPP_HAS_NO_VARIADICS
+#if _LIBCPP_STD_VER > 17
+
+template <class, class, template <class> class, template <class> class>
+struct _LIBCPP_TEMPLATE_VIS basic_common_reference
+{};
+
+// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM’s
+// top-level cv-qualifiers.
+template <class _Tp>
+struct __copy_cv_
+{
+    template <class _Up> using __fn = _Up;
+};
+template <class _Tp>
+struct __copy_cv_<const _Tp>
+{
+    template <class _Up> using __fn = add_const_t<_Up>;
+};
+template <class _Tp>
+struct __copy_cv_<volatile _Tp>
+{
+    template <class _Up> using __fn = add_volatile_t<_Up>;
+};
+template <class _Tp>
+struct __copy_cv_<const volatile _Tp>
+{
+    template <class _Up> using __fn = add_cv_t<_Up>;
+};
+template <class _From, class _To>
+using __copy_cv = typename __copy_cv_<_From>::template __fn<_To>;
+
+// Let XREF(A) denote a unary class [sic] template T such [...]
+// [Note: XREF(A) is __xref<A>::template __fn]
+template <class _Tp>
+struct __xref
+{
+    template <class _Up> using __fn = __copy_cv<_Tp, _Up>;
+};
+template <class _Tp>
+struct __xref<_Tp&>
+{
+    template <class _Up> using __fn = add_lvalue_reference_t<__copy_cv<_Tp, _Up>>;
+};
+template <class _Tp>
+struct __xref<_Tp&&>
+{
+    template <class _Up> using __fn = add_rvalue_reference_t<__copy_cv<_Tp, _Up>>;
+};
+
+template <class _Tp, class _Up,
+    class _Result = __cond_res<__copy_cv<_Tp, _Up>&, __copy_cv<_Up, _Tp>&>,
+    class = enable_if_t<is_lvalue_reference_v<_Result>>>
+using __ll_common_ref = _Result;
+
+template <class _Tp, class _Up>
+using __rr_common_ref = remove_reference_t<__ll_common_ref<_Tp, _Up>>&&;
+
+// Note C: For the common_reference trait applied to a parameter pack [...]
+
+// bullet 1 - sizeof...(T) == 0
+
+template <class...> struct _LIBCPP_TEMPLATE_VIS common_reference {};
+
+template <class... _Types>
+using common_reference_t = typename common_reference<_Types...>::type;
+
+// bullet 2 - sizeof...(T) == 1
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS common_reference<_Tp>
+{
+    using type = _Tp;
+};
+
+// bullet 3 - sizeof...(T) == 2
+
+// sub-bullet 4 & 5 - [...] if common_type_t<T1, T2> is well-formed [...]
+//                  - Otherwise, there shall be no member type.
+
+template <class _Tp, class _Up, class = void>
+struct __common_reference4
+    : common_type<_Tp, _Up>
+{};
+
+// sub-bullet 3 - [...] if COND_RES(T1, T2) is well-formed [...]
+
+template <class _Tp, class _Up>
+struct __common_reference4<_Tp, _Up, void_t<__cond_res<_Tp, _Up>>>
+{
+    using type = __cond_res<_Tp, _Up>;
+};
+
+// sub-bullet 2 - [...] if basic_common_reference<[...]>::type is well-formed [...]
+
+template <class _Tp, class _Up>
+using __basic_common_ref = typename basic_common_reference<
+    remove_cvref_t<_Tp>, remove_cvref_t<_Up>,
+    __xref<_Tp>::template __fn, __xref<_Up>::template __fn>::type;
+
+template <class _Tp, class _Up, class = void>
+struct __common_reference3
+    : __common_reference4<_Tp, _Up>
+{};
+
+template <class _Tp, class _Up>
+struct __common_reference3<_Tp, _Up, void_t<__basic_common_ref<_Tp, _Up>>>
+{
+    using type = __basic_common_ref<_Tp, _Up>;
+};
+
+// sub-bullet 1 - If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed [...]
+
+template <class _Tp, class _Up, class = void>
+struct __common_reference2
+    : __common_reference3<_Tp, _Up>
+{};
+
+template <class _Tp, class _Up>
+struct __common_reference2<_Tp&, _Up&, void_t<__ll_common_ref<_Tp, _Up>>>
+{
+    using type = __ll_common_ref<_Tp, _Up>;
+};
+
+template <class _Tp, class _Up>
+struct __common_reference2<_Tp&&, _Up&, enable_if_t<
+    is_convertible_v<_Tp&&, __ll_common_ref<const _Tp, _Up>>>>
+{
+    using type = __ll_common_ref<const _Tp, _Up>;
+};
+
+template <class _Tp, class _Up>
+struct __common_reference2<_Tp&, _Up&&, enable_if_t<
+    is_convertible_v<_Up&&, __ll_common_ref<const _Up, _Tp>>>>
+{
+    using type = __ll_common_ref<const _Up, _Tp>;
+};
+
+template <class _Tp, class _Up>
+struct __common_reference2<_Tp&&, _Up&&, enable_if_t<
+    is_convertible_v<_Tp&&, __rr_common_ref<_Tp, _Up>> &&
+    is_convertible_v<_Up&&, __rr_common_ref<_Tp, _Up>>>>
+{
+    using type = __rr_common_ref<_Tp, _Up>;
+};
+
+template <class _Tp, class _Up>
+struct _LIBCPP_TEMPLATE_VIS common_reference<_Tp, _Up>
+    : __common_reference2<_Tp, _Up>
+{};
+
+// bullet 4 - sizeof...(T) > 2
+
+template <class _Void, class _Tp, class _Up, class... _Types>
+struct __fold_common_reference
+{};
+template <class _Tp, class _Up, class... _Types>
+struct __fold_common_reference<void_t<common_reference_t<_Tp, _Up>>, _Tp, _Up, _Types...>
+    : common_reference<common_reference_t<_Tp, _Up>, _Types...>
+{};
+
+template <class _Tp, class _Up, class _Vp, class... _Rest>
+struct _LIBCPP_TEMPLATE_VIS common_reference<_Tp, _Up, _Vp, _Rest...>
+    : __fold_common_reference<void, _Tp, _Up, _Vp, _Rest...>
+{};
+
+#endif // _LIBCPP_STD_VER > 17
+
+#endif // _LIBCPP_HAS_NO_VARIADICS
 
 // is_assignable
 
@@ -4746,12 +4950,7 @@
 
 #endif  // _LIBCPP_CXX03_LANG
 
-#if _LIBCPP_STD_VER > 14
-
-#define __cpp_lib_void_t 201411
-template <class...> using void_t = void;
-
-# ifndef _LIBCPP_HAS_NO_VARIADICS
+#if _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_VARIADICS)
 template <class... _Args>
 struct conjunction : __and_<_Args...> {};
 template<class... _Args>
@@ -4769,8 +4968,7 @@
 template<class _Tp>
 _LIBCPP_INLINE_VAR constexpr bool negation_v
     = negation<_Tp>::value;
-# endif // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_STD_VER > 14
+#endif  // _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_VARIADICS)
 
 // These traits are used in __tree and __hash_table
 #ifndef _LIBCPP_CXX03_LANG
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to