diff -r 000000000000 -r 6474c204b198 mfbt/NullPtr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mfbt/NullPtr.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +/* + * Implements a workaround for compilers which do not support the C++11 nullptr + * constant. + */ + +#ifndef mozilla_NullPtr_h +#define mozilla_NullPtr_h + +#if defined(__clang__) +# if !__has_extension(cxx_nullptr) +# error "clang version natively supporting nullptr is required." +# endif +# define MOZ_HAVE_CXX11_NULLPTR +#elif defined(__GNUC__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L +# include "mozilla/Compiler.h" +# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) +# define MOZ_HAVE_CXX11_NULLPTR +# endif +# endif +#elif defined(_MSC_VER) + // The minimum supported MSVC (10, _MSC_VER 1600) supports nullptr. +# define MOZ_HAVE_CXX11_NULLPTR +#endif + +namespace mozilla { + +/** + * IsNullPointer::value is true iff T is the type of C++11's nullptr. If + * nullptr is emulated, IsNullPointer::value is false for all T. + * + * IsNullPointer is useful to give an argument the true decltype(nullptr) type. + * decltype(nullptr) doesn't work when nullptr is emulated. The simplest + * workaround is to use template overloading and SFINAE to expose an overload + * only if an argument's type is decltype(nullptr). Some examples (that assume + * namespace mozilla has been opened, for simplicity): + * + * // foo(T*), foo(stuff that converts to T*), and foo(decltype(nullptr)) + * // (only invoked if nullptr is true nullptr, otherwise foo(T*) is invoked) + * // but nothing else + * void foo(T*) { } + * template + * void foo(N, + * typename EnableIf::value, int>::Type dummy = 0) + * { } + * + * // foo(T*) *exactly* and foo(decltype(nullptr)), nothing else + * void foo(T*) { } + * template + * void foo(U, + * typename EnableIf::value, int>::Type dummy = 0) + * MOZ_DELETE; + * + * The exact details of how set up the SFINAE bits vary on a case-by-case basis. + * If you need help with this (and unless you've internalized way more sadmaking + * nullptr-emulation knowledge than you should have, you do), feel free to poke + * the person with blame on this comment with questions. :-) + * + * Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer + * (fixed in C++1y), so in the interests of easing a switch to , + * this trait lives elsewhere. + */ +template +struct IsNullPointer { static const bool value = false; }; + +} // namespace mozilla + +/** + * mozilla::NullptrT is a type that's sort of like decltype(nullptr). But it + * can't be identical, because emulated nullptr doesn't have a distinct type. + * Only with gcc 4.4/4.5, emulated nullptr is __null, and decltype(__null) is + * int or long. But passing __null to an int/long parameter triggers + * -Werror=conversion-null errors with gcc 4.5, or (depending on subsequent use + * inside the overloaded function) can trigger pointer-to-integer comparison + * compiler errors. So fairly often, actually, NullptrT is *not* what you want. + * + * Instead, often you should use template-based overloading in concert with + * SFINAE to add a nullptr overload -- see the comments by IsNullPointer. + * + * So when *should* you use NullptrT? Thus far, the only truly good use seems + * to be as an argument type for operator overloads (because C++ doesn't allow + * operator= to have more than one argument, operator== to have more than two, + * &c.). But even in such cases, it really only works if there are no other + * overloads of the operator that accept a pointer type. If you want both T* + * and nullptr_t overloads, you'll have to wait til we drop gcc 4.4/4.5 support. + * (Currently b2g is the only impediment to this.) + */ +#ifdef MOZ_HAVE_CXX11_NULLPTR + // decltype does the right thing for actual nullptr. + namespace mozilla { + typedef decltype(nullptr) NullptrT; + template<> + struct IsNullPointer { static const bool value = true; }; + } +# undef MOZ_HAVE_CXX11_NULLPTR +#elif MOZ_IS_GCC +# define nullptr __null + // void* sweeps up more than just nullptr, but compilers supporting true + // nullptr are the majority now, so they should detect mistakes. If you're + // feeling paranoid, check/assert that your NullptrT equals nullptr. + namespace mozilla { typedef void* NullptrT; } +#else +# error "No compiler support for nullptr or its emulation." +#endif + +#endif /* mozilla_NullPtr_h */