From a10a240530cb9398d49070e7e0f5f0afc1eb03ed Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 19 Jun 2012 13:55:23 -0700 Subject: [PATCH] Bug 766347 - Implement mozilla::IsConvertible to detect when a value of one type will convert to a value of another type. r=luke --HG-- extra : rebase_source : d25c1b84dfc928a0bc4dcfb43e31b6035882849e --- mfbt/TypeTraits.h | 42 +++++++++++++++++++++++++- mfbt/tests/Makefile.in | 1 + mfbt/tests/TestTypeTraits.cpp | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 mfbt/tests/TestTypeTraits.cpp diff --git a/mfbt/TypeTraits.h b/mfbt/TypeTraits.h index 178ecdf26fc3..8f04e7a4aca5 100644 --- a/mfbt/TypeTraits.h +++ b/mfbt/TypeTraits.h @@ -27,8 +27,48 @@ class IsBaseOf private: static char test(Base* b); static int test(...); + public: - static const bool value = (sizeof(test(static_cast(0))) == sizeof(char)); + static const bool value = + sizeof(test(static_cast(0))) == sizeof(char); +}; + +/* + * IsConvertible determines whether a value of type From will implicitly convert + * to a value of type To. For example: + * + * struct A {}; + * struct B : public A {}; + * struct C {}; + * + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false. + * + * For obscure reasons, you can't use IsConvertible when the types being tested + * are related through private inheritance, and you'll get a compile error if + * you try. Just don't do it! + */ +template +struct IsConvertible +{ + private: + static From create(); + + template + static char test(To to); + + template + static int test(...); + + public: + static const bool value = + sizeof(test(create())) == sizeof(char); }; /* diff --git a/mfbt/tests/Makefile.in b/mfbt/tests/Makefile.in index 31f87b5b60ae..eb6221925909 100644 --- a/mfbt/tests/Makefile.in +++ b/mfbt/tests/Makefile.in @@ -13,6 +13,7 @@ STL_FLAGS = CPP_UNIT_TESTS = \ TestCheckedInt.cpp \ + TestTypeTraits.cpp \ $(NULL) # in order to prevent rules.mk from trying to link to libraries that are diff --git a/mfbt/tests/TestTypeTraits.cpp b/mfbt/tests/TestTypeTraits.cpp new file mode 100644 index 000000000000..269d38429eb6 --- /dev/null +++ b/mfbt/tests/TestTypeTraits.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" + +using mozilla::IsConvertible; + +class A { }; +class B : public A { }; +class C : private A { }; +class D { }; + +static void +TestIsConvertible() +{ + // Pointer type convertibility + MOZ_ASSERT((IsConvertible::value), + "A* should convert to A*"); + MOZ_ASSERT((IsConvertible::value), + "B* should convert to A*"); + MOZ_ASSERT((!IsConvertible::value), + "A* shouldn't convert to B*"); + MOZ_ASSERT((!IsConvertible::value), + "A* shouldn't convert to C*"); + MOZ_ASSERT((!IsConvertible::value), + "A* shouldn't convert to unrelated D*"); + MOZ_ASSERT((!IsConvertible::value), + "D* shouldn't convert to unrelated A*"); + + // Instance type convertibility + MOZ_ASSERT((IsConvertible::value), + "A is A"); + MOZ_ASSERT((IsConvertible::value), + "B converts to A"); + MOZ_ASSERT((!IsConvertible::value), + "D and A are unrelated"); + MOZ_ASSERT((!IsConvertible::value), + "A and D are unrelated"); + + // These cases seem to require C++11 support to properly implement them, so + // for now just disable them. + //MOZ_ASSERT((!IsConvertible::value), + // "C* shouldn't convert to A* (private inheritance)"); + //MOZ_ASSERT((!IsConvertible::value), + // "C doesn't convert to A (private inheritance)"); +} + +int +main() +{ + TestIsConvertible(); +}