Bug 1221680 - Avoid hard errors when testing convertibility using the IsConvertible type trait. r=froydnj
authorBotond Ballo <botond@mozilla.com>
Fri, 06 Nov 2015 17:47:36 -0500
changeset 273031 43ca206bb8127d4de6ae1fa5e4af4b0f8ef9d14c
parent 273030 bb2ece1c131b9faf7d560ac10c4d8daa6f6a09b0
child 273032 40a37cb11607a03baa857eb41095956923676e5c
push id29693
push usercbook@mozilla.com
push dateWed, 18 Nov 2015 13:50:33 +0000
treeherdermozilla-central@1d6155d7e6c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1221680
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1221680 - Avoid hard errors when testing convertibility using the IsConvertible type trait. r=froydnj
mfbt/TypeTraits.h
mfbt/tests/TestTypeTraits.cpp
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -19,16 +19,28 @@
 
 #include <wchar.h>
 
 namespace mozilla {
 
 /* Forward declarations. */
 
 template<typename> struct RemoveCV;
+template<typename> struct AddRvalueReference;
+
+/* 20.2.4 Function template declval [declval] */
+
+/**
+ * DeclVal simplifies the definition of expressions which occur as unevaluated
+ * operands. It converts T to a reference type, making it possible to use in
+ * decltype expressions even if T does not have a default constructor, e.g.:
+ * decltype(DeclVal<TWithNoDefaultConstructor>().foo())
+ */
+template<typename T>
+typename AddRvalueReference<T>::Type DeclVal();
 
 /* 20.9.3 Helper classes [meta.help] */
 
 /**
  * Helper class used as a base for various type traits, exposed publicly
  * because <type_traits> exposes it as well.
  */
 template<typename T, T Value>
@@ -627,31 +639,35 @@ struct BaseOfTester<Type, const Type> : 
  */
 template<class Base, class Derived>
 struct IsBaseOf
   : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
 {};
 
 namespace detail {
 
+// This belongs inside ConvertibleTester, but it's pulled out to
+// work around a bug in the compiler used for hazard builds.
+template <typename To>
+static void ConvertibleTestHelper(To);
+
 template<typename From, typename To>
 struct ConvertibleTester
 {
 private:
-  static From create();
-
-  template<typename From1, typename To1>
-  static char test(To to);
+  template<typename From1, typename To1,
+           typename = decltype(ConvertibleTestHelper<To1>(DeclVal<From>()))>
+  static char test(int);
 
   template<typename From1, typename To1>
   static int test(...);
 
 public:
   static const bool value =
-    sizeof(test<From, To>(create())) == sizeof(char);
+    sizeof(test<From, To>(0)) == sizeof(char);
 };
 
 } // namespace detail
 
 /**
  * IsConvertible determines whether a value of type From will implicitly convert
  * to a value of type To.  For example:
  *
@@ -859,27 +875,16 @@ struct AddRvalueReferenceHelper<T, TIsNo
  * mozilla::AddRvalueReference<void>::Type is void;
  * mozilla::AddRvalueReference<struct S&>::Type is struct S&.
  */
 template<typename T>
 struct AddRvalueReference
   : detail::AddRvalueReferenceHelper<T>
 {};
 
-/* 20.2.4 Function template declval [declval] */
-
-/**
- * DeclVal simplifies the definition of expressions which occur as unevaluated
- * operands. It converts T to a reference type, making it possible to use in
- * decltype expressions even if T does not have a default constructor, e.g.:
- * decltype(DeclVal<TWithNoDefaultConstructor>().foo())
- */
-template<typename T>
-typename AddRvalueReference<T>::Type DeclVal();
-
 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
 
 template<bool B, typename T = void>
 struct EnableIf;
 
 namespace detail {
 
 template<bool MakeConst, typename T>
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -332,16 +332,20 @@ TestIsBaseOf()
   static_assert((!IsBaseOf<A, D>::value),
                 "A is not a base of D");
   static_assert((!IsBaseOf<D, A>::value),
                 "D is not a base of A");
   static_assert((IsBaseOf<B, B>::value),
                 "B is the same as B (and therefore, a base of B)");
 }
 
+class ExplicitCopyConstructor {
+  explicit ExplicitCopyConstructor(const ExplicitCopyConstructor&) = default;
+};
+
 static void
 TestIsConvertible()
 {
   // Pointer type convertibility
   static_assert((IsConvertible<A*, A*>::value),
                 "A* should convert to A*");
   static_assert((IsConvertible<B*, A*>::value),
                 "B* should convert to A*");
@@ -363,16 +367,20 @@ TestIsConvertible()
                 "D and A are unrelated");
   static_assert((!IsConvertible<A, D>::value),
                 "A and D are unrelated");
 
   static_assert(IsConvertible<void, void>::value, "void is void");
   static_assert(!IsConvertible<A, void>::value, "A shouldn't convert to void");
   static_assert(!IsConvertible<void, B>::value, "void shouldn't convert to B");
 
+  static_assert(!IsConvertible<const ExplicitCopyConstructor&,
+                               ExplicitCopyConstructor>::value,
+                "IsConvertible should test for implicit convertibility");
+
   // These cases seem to require C++11 support to properly implement them, so
   // for now just disable them.
   //static_assert((!IsConvertible<C*, A*>::value),
   //           "C* shouldn't convert to A* (private inheritance)");
   //static_assert((!IsConvertible<C, A>::value),
   //           "C doesn't convert to A (private inheritance)");
 }