Bug 1221368 - Change MakeTuple to decay the types of its arguments (r=froydnj)

This commit is contained in:
Bill McCloskey 2015-11-02 16:50:06 -08:00
Родитель d90f4749ea
Коммит 47b5adaa34
5 изменённых файлов: 148 добавлений и 17 удалений

Просмотреть файл

@ -335,18 +335,6 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
namespace mozilla {
namespace detail {
template<typename T>
struct IsFunction
{
static const bool value = false;
};
template<typename R, typename... A>
struct IsFunction<R(A...)>
{
static const bool value = true;
};
template<typename T>
struct AssertionConditionType
{

Просмотреть файл

@ -417,9 +417,10 @@ auto Get(Tuple<Elements...>&& aTuple)
* auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char>
*/
template<typename... Elements>
Tuple<Elements...> MakeTuple(Elements&&... aElements)
inline Tuple<typename Decay<Elements>::Type...>
MakeTuple(Elements&&... aElements)
{
return Tuple<Elements...>(Forward<Elements>(aElements)...);
return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...);
}
/**
@ -436,7 +437,8 @@ Tuple<Elements...> MakeTuple(Elements&&... aElements)
* Tie(i, f, c) = FunctionThatReturnsATuple();
*/
template<typename... Elements>
Tuple<Elements&...> Tie(Elements&... aVariables)
inline Tuple<Elements&...>
Tie(Elements&... aVariables)
{
return Tuple<Elements&...>(aVariables...);
}

Просмотреть файл

@ -164,6 +164,40 @@ struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type>
namespace detail {
template<typename T>
struct IsFunPtr;
template<typename>
struct IsFunPtr
: public FalseType
{};
template<typename Result, typename... ArgTypes>
struct IsFunPtr<Result(*)(ArgTypes...)>
: public TrueType
{};
}; // namespace detail
/**
* IsFunction determines whether a type is a function type. Function pointers
* don't qualify here--only the type of an actual function symbol. We do not
* correctly handle varags function types because of a bug in MSVC.
*
* Given the function:
* void f(int) {}
*
* mozilla::IsFunction<void(int)> is true;
* mozilla::IsFunction<void(*)(int)> is false;
* mozilla::IsFunction<decltype(f)> is true.
*/
template<typename T>
struct IsFunction
: public detail::IsFunPtr<typename RemoveCV<T>::Type *>
{};
namespace detail {
template<typename T>
struct IsPointerHelper : FalseType {};
@ -1063,6 +1097,22 @@ struct RemovePointer
: detail::RemovePointerHelper<T, typename RemoveCV<T>::Type>
{};
/**
* Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants
* std::add_pointer to work differently for function types. We don't implement
* that behavior here.
*
* mozilla::AddPointer<int> is int*;
* mozilla::AddPointer<int*> is int**;
* mozilla::AddPointer<int&> is int*;
* mozilla::AddPointer<int* const> is int** const.
*/
template<typename T>
struct AddPointer
{
typedef typename RemoveReference<T>::Type* Type;
};
/* 20.9.7.6 Other transformations [meta.trans.other] */
/**
@ -1111,6 +1161,51 @@ struct Conditional<false, A, B>
typedef B Type;
};
namespace detail {
template<typename U,
bool IsArray = IsArray<U>::value,
bool IsFunction = IsFunction<U>::value>
struct DecaySelector;
template<typename U>
struct DecaySelector<U, false, false>
{
typedef typename RemoveCV<U>::Type Type;
};
template<typename U>
struct DecaySelector<U, true, false>
{
typedef typename RemoveExtent<U>::Type* Type;
};
template<typename U>
struct DecaySelector<U, false, true>
{
typedef typename AddPointer<U>::Type Type;
};
}; // namespace detail
/**
* Strips const/volatile off a type and decays it from an lvalue to an
* rvalue. So function types are converted to function pointers, arrays to
* pointers, and references are removed.
*
* mozilla::Decay<int>::Type is int
* mozilla::Decay<int&>::Type is int
* mozilla::Decay<int&&>::Type is int
* mozilla::Decay<const int&>::Type is int
* mozilla::Decay<int[2]>::Type is int*
* mozilla::Decay<int(int)>::Type is int(*)(int)
*/
template<typename T>
class Decay
: public detail::DecaySelector<typename RemoveReference<T>::Type>
{
};
} /* namespace mozilla */
#endif /* mozilla_TypeTraits_h */

Просмотреть файл

@ -236,7 +236,7 @@ TestGet()
CHECK(y == 42);
}
static bool
static void
TestMakeTuple()
{
auto tuple = MakeTuple(42, 0.5f, 'c');
@ -244,7 +244,13 @@ TestMakeTuple()
CHECK(Get<0>(tuple) == 42);
CHECK(Get<1>(tuple) == 0.5f);
CHECK(Get<2>(tuple) == 'c');
return true;
// Make sure we don't infer the type to be Tuple<int&>.
int x = 1;
auto tuple2 = MakeTuple(x);
CHECK_TYPE(tuple2, Tuple<int>);
x = 2;
CHECK(Get<0>(tuple2) == 1);
}
static bool

Просмотреть файл

@ -8,8 +8,11 @@
#include "mozilla/TypeTraits.h"
using mozilla::AddLvalueReference;
using mozilla::AddPointer;
using mozilla::AddRvalueReference;
using mozilla::Decay;
using mozilla::DeclVal;
using mozilla::IsFunction;
using mozilla::IsArray;
using mozilla::IsBaseOf;
using mozilla::IsClass;
@ -27,6 +30,13 @@ using mozilla::MakeUnsigned;
using mozilla::RemoveExtent;
using mozilla::RemovePointer;
static_assert(!IsFunction<int>::value,
"int is not a function type");
static_assert(IsFunction<void(int)>::value,
"void(int) is a function type");
static_assert(!IsFunction<void(*)(int)>::value,
"void(*)(int) is not a function type");
static_assert(!IsArray<bool>::value,
"bool not an array");
static_assert(IsArray<bool[]>::value,
@ -489,6 +499,36 @@ static_assert(IsSame<RemovePointer<bool TestRemovePointer::*>::Type,
bool TestRemovePointer::*>::value,
"removing pointer from bool S::* must return bool S::*");
static_assert(IsSame<AddPointer<int>::Type, int*>::value,
"adding pointer to int must return int*");
static_assert(IsSame<AddPointer<int*>::Type, int**>::value,
"adding pointer to int* must return int**");
static_assert(IsSame<AddPointer<int&>::Type, int*>::value,
"adding pointer to int& must return int*");
static_assert(IsSame<AddPointer<int* const>::Type, int* const*>::value,
"adding pointer to int* const must return int* const*");
static_assert(IsSame<AddPointer<int* volatile>::Type, int* volatile*>::value,
"adding pointer to int* volatile must return int* volatile*");
static_assert(IsSame<Decay<int>::Type, int>::value,
"decaying int must return int");
static_assert(IsSame<Decay<int*>::Type, int*>::value,
"decaying int* must return int*");
static_assert(IsSame<Decay<int* const>::Type, int*>::value,
"decaying int* const must return int*");
static_assert(IsSame<Decay<int* volatile>::Type, int*>::value,
"decaying int* volatile must return int*");
static_assert(IsSame<Decay<int&>::Type, int>::value,
"decaying int& must return int");
static_assert(IsSame<Decay<const int&>::Type, int>::value,
"decaying const int& must return int");
static_assert(IsSame<Decay<int&&>::Type, int>::value,
"decaying int&& must return int");
static_assert(IsSame<Decay<int[1]>::Type, int*>::value,
"decaying int[1] must return int*");
static_assert(IsSame<Decay<void(int)>::Type, void(*)(int)>::value,
"decaying void(int) must return void(*)(int)");
/*
* Android's broken [u]intptr_t inttype macros are broken because its PRI*PTR
* macros are defined as "ld", but sizeof(long) is 8 and sizeof(intptr_t)