Bug 712129 - Implement MOZ_STATIC_ASSERT and MOZ_STATIC_ASSERT_IF. r=luke

This commit is contained in:
Jeff Walden 2011-12-19 16:58:30 -05:00
Родитель 677b43a2b8
Коммит a158abd5b6
5 изменённых файлов: 114 добавлений и 50 удалений

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

@ -89,33 +89,8 @@ JS_BEGIN_EXTERN_C
# define JS_THREADSAFE_ASSERT(expr) ((void) 0) # define JS_THREADSAFE_ASSERT(expr) ((void) 0)
#endif #endif
/* #define JS_STATIC_ASSERT(cond) MOZ_STATIC_ASSERT(cond, "JS_STATIC_ASSERT")
* JS_STATIC_ASSERT #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
*
* A compile-time assert. "cond" must be a constant expression. The macro can
* be used only in places where an "extern" declaration is allowed.
*/
#ifdef __SUNPRO_CC
/*
* Sun Studio C++ compiler has a bug
* "sizeof expression not accepted as size of array parameter"
* It happens when js_static_assert() function is declared inside functions.
* The bug number is 6688515. It is not public yet.
* Therefore, for Sun Studio, declare js_static_assert as an array instead.
*/
# define JS_STATIC_ASSERT(cond) extern char js_static_assert[(cond) ? 1 : -1]
#else
# ifdef __COUNTER__
# define JS_STATIC_ASSERT_GLUE1(x,y) x##y
# define JS_STATIC_ASSERT_GLUE(x,y) JS_STATIC_ASSERT_GLUE1(x,y)
# define JS_STATIC_ASSERT(cond) \
typedef int JS_STATIC_ASSERT_GLUE(js_static_assert, __COUNTER__)[(cond) ? 1 : -1]
# else
# define JS_STATIC_ASSERT(cond) extern void js_static_assert(int arg[(cond) ? 1 : -1])
# endif
#endif
#define JS_STATIC_ASSERT_IF(cond, expr) JS_STATIC_ASSERT(!(cond) || (expr))
/* /*
* Abort the process in a non-graceful manner. This will cause a core file, * Abort the process in a non-graceful manner. This will cause a core file,

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

@ -43,6 +43,87 @@
#include "mozilla/Types.h" #include "mozilla/Types.h"
/*
* MOZ_STATIC_ASSERT may be used to assert a condition *at compile time*. This
* can be useful when you make certain assumptions about what must hold for
* optimal, or even correct, behavior. For example, you might assert that the
* size of a struct is a multiple of the target architecture's word size:
*
* struct S { ... };
* MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
* "S should be a multiple of word size for efficiency");
*
* This macro can be used in any location where both an extern declaration and a
* typedef could be used.
*
* Be aware of the gcc 4.2 concerns noted further down when writing patches that
* use this macro, particularly if a patch only bounces on OS X.
*/
#ifdef __cplusplus
# if defined(__clang__)
# ifndef __has_extension
# define __has_extension __has_feature /* compatibility, for older versions of clang */
# endif
# if __has_extension(cxx_static_assert)
# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), reason)
# endif
# elif defined(__GNUC__)
# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), #cond)
# endif
# elif defined(_MSC_VER)
# if _MSC_VER >= 1600 /* MSVC 10 */
# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), #cond)
# endif
# elif defined(__HP_aCC)
# if __HP_aCC >= 62500 && defined(_HP_CXX0x_SOURCE)
# define MOZ_STATIC_ASSERT(cond, reason) static_assert((cond), #cond)
# endif
# endif
#endif
#ifndef MOZ_STATIC_ASSERT
# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y
# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y)
# if defined(__SUNPRO_CC)
/*
* The Sun Studio C++ compiler is buggy when declaring, inside a function,
* another extern'd function with an array argument whose length contains a
* sizeof, triggering the error message "sizeof expression not accepted as
* size of array parameter". This bug (6688515, not public yet) would hit
* defining moz_static_assert as a function, so we always define an extern
* array for Sun Studio.
*
* We include the line number in the symbol name in a best-effort attempt
* to avoid conflicts (see below).
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1]
# elif defined(__COUNTER__)
/*
* If there was no preferred alternative, use a compiler-agnostic version.
*
* Note that the non-__COUNTER__ version has a bug in C++: it can't be used
* in both |extern "C"| and normal C++ in the same translation unit. (Alas
* |extern "C"| isn't allowed in a function.) The only affected compiler
* we really care about is gcc 4.2. For that compiler and others like it,
* we include the line number in the function name to do the best we can to
* avoid conflicts. These should be rare: a conflict would require use of
* MOZ_STATIC_ASSERT on the same line in separate files in the same
* translation unit, *and* the uses would have to be in code with
* different linkage, *and* the first observed use must be in C++-linkage
* code.
*/
# define MOZ_STATIC_ASSERT(cond, reason) \
typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1]
# else
# define MOZ_STATIC_ASSERT(cond, reason) \
extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1])
# endif
#endif
#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
/* /*
* XXX: we're cheating here in order to avoid creating object files * XXX: we're cheating here in order to avoid creating object files
* for mfbt /just/ to provide a function like FatalError() to be used * for mfbt /just/ to provide a function like FatalError() to be used

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

@ -36,6 +36,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Assertions.h"
#include "nsAtomTable.h" #include "nsAtomTable.h"
#include "nsStaticAtom.h" #include "nsStaticAtom.h"
#include "nsString.h" #include "nsString.h"
@ -406,16 +408,17 @@ GetAtomHashEntry(const PRUnichar* aString, PRUint32 aLength)
class CheckStaticAtomSizes class CheckStaticAtomSizes
{ {
CheckStaticAtomSizes() { CheckStaticAtomSizes() {
PR_STATIC_ASSERT((sizeof(nsFakeStringBuffer<1>().mRefCnt) == MOZ_STATIC_ASSERT((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
sizeof(nsStringBuffer().mRefCount)) && sizeof(nsStringBuffer().mRefCount)) &&
(sizeof(nsFakeStringBuffer<1>().mSize) == (sizeof(nsFakeStringBuffer<1>().mSize) ==
sizeof(nsStringBuffer().mStorageSize)) && sizeof(nsStringBuffer().mStorageSize)) &&
(offsetof(nsFakeStringBuffer<1>, mRefCnt) == (offsetof(nsFakeStringBuffer<1>, mRefCnt) ==
offsetof(nsStringBuffer, mRefCount)) && offsetof(nsStringBuffer, mRefCount)) &&
(offsetof(nsFakeStringBuffer<1>, mSize) == (offsetof(nsFakeStringBuffer<1>, mSize) ==
offsetof(nsStringBuffer, mStorageSize)) && offsetof(nsStringBuffer, mStorageSize)) &&
(offsetof(nsFakeStringBuffer<1>, mStringData) == (offsetof(nsFakeStringBuffer<1>, mStringData) ==
sizeof(nsStringBuffer))); sizeof(nsStringBuffer)),
"mocked-up strings' representations should be compatible");
} }
}; };

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

@ -64,12 +64,12 @@ const nsTArrayHeader* nsTArray_base<Alloc>::GetAutoArrayBufferUnsafe(size_t elem
// If we're on a 32-bit system and elemAlign is 8, we need to adjust our // If we're on a 32-bit system and elemAlign is 8, we need to adjust our
// pointer to take into account the extra alignment in the auto array. // pointer to take into account the extra alignment in the auto array.
// Check that the auto array is padded as we expect. MOZ_STATIC_ASSERT(sizeof(void*) != 4 ||
PR_STATIC_ASSERT(sizeof(void*) != 4 || (MOZ_ALIGNOF(mozilla::AlignedElem<8>) == 8 &&
(MOZ_ALIGNOF(mozilla::AlignedElem<8>) == 8 && sizeof(nsAutoTArray<mozilla::AlignedElem<8>, 1>) ==
sizeof(nsAutoTArray<mozilla::AlignedElem<8>, 1>) == sizeof(void*) + sizeof(nsTArrayHeader) +
sizeof(void*) + sizeof(nsTArrayHeader) + 4 + sizeof(mozilla::AlignedElem<8>)),
4 + sizeof(mozilla::AlignedElem<8>))); "auto array padding wasn't what we expected");
// We don't support alignments greater than 8 bytes. // We don't support alignments greater than 8 bytes.
NS_ABORT_IF_FALSE(elemAlign <= 4 || elemAlign == 8, "unsupported alignment."); NS_ABORT_IF_FALSE(elemAlign <= 4 || elemAlign == 8, "unsupported alignment.");
@ -115,7 +115,8 @@ bool nsTArray_base<Alloc>::UsesAutoArrayBuffer() const {
// owned by this nsAutoTArray. We statically assert that elem_type's // owned by this nsAutoTArray. We statically assert that elem_type's
// alignment is 8 bytes or less in nsAutoArrayBase. // alignment is 8 bytes or less in nsAutoArrayBase.
PR_STATIC_ASSERT(sizeof(nsTArrayHeader) > 4); MOZ_STATIC_ASSERT(sizeof(nsTArrayHeader) > 4,
"see comment above");
#ifdef DEBUG #ifdef DEBUG
PRPtrdiff diff = reinterpret_cast<const char*>(GetAutoArrayBuffer(8)) - PRPtrdiff diff = reinterpret_cast<const char*>(GetAutoArrayBuffer(8)) -

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

@ -39,6 +39,9 @@
#ifndef nsTArray_h__ #ifndef nsTArray_h__
#define nsTArray_h__ #define nsTArray_h__
#include "mozilla/Assertions.h"
#include "mozilla/Util.h"
#include <string.h> #include <string.h>
#include "prtypes.h" #include "prtypes.h"
@ -47,7 +50,6 @@
#include "nsQuickSort.h" #include "nsQuickSort.h"
#include "nsDebug.h" #include "nsDebug.h"
#include "nsTraceRefcnt.h" #include "nsTraceRefcnt.h"
#include "mozilla/Util.h"
#include NEW_H #include NEW_H
// //
@ -1316,9 +1318,9 @@ private:
friend class nsTArray_base; friend class nsTArray_base;
void Init() { void Init() {
// We can't handle alignments greater than 8; see MOZ_STATIC_ASSERT(MOZ_ALIGNOF(elem_type) <= 8,
// nsTArray_base::UsesAutoArrayBuffer(). "can't handle alignments greater than 8, "
PR_STATIC_ASSERT(MOZ_ALIGNOF(elem_type) <= 8); "see nsTArray_base::UsesAutoArrayBuffer()");
*base_type::PtrToHdr() = reinterpret_cast<Header*>(&mAutoBuf); *base_type::PtrToHdr() = reinterpret_cast<Header*>(&mAutoBuf);
base_type::Hdr()->mLength = 0; base_type::Hdr()->mLength = 0;
@ -1367,8 +1369,10 @@ public:
// 64-bit system, where the compiler inserts 4 bytes of padding at the end of // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
// the auto array to make its size a multiple of alignof(void*) == 8 bytes. // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
PR_STATIC_ASSERT(sizeof(nsAutoTArray<PRUint32, 2>) == MOZ_STATIC_ASSERT(sizeof(nsAutoTArray<PRUint32, 2>) ==
sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(PRUint32) * 2); sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(PRUint32) * 2,
"nsAutoTArray shouldn't contain any extra padding, "
"see the comment");
template<class E, PRUint32 N> template<class E, PRUint32 N>
class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N> class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>