From 768e05f0bc477eccfa9bf263e905fdf60c52fbde Mon Sep 17 00:00:00 2001 From: Fredrik Roubert Date: Mon, 13 Jul 2015 15:49:25 +0200 Subject: [PATCH] When using C++11, use static_assert to implement COMPILE_ASSERT. This is a cherry-pick from the Chromium project, from where this implementation of basictypes.h once originated: https://chromium.googlesource.com/chromium/src/+/539fc83 --- cpp/src/phonenumbers/base/basictypes.h | 65 ++++++++++++++++++++++++-- tools/cpp/src/base/basictypes.h | 26 +++++++++-- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/cpp/src/phonenumbers/base/basictypes.h b/cpp/src/phonenumbers/base/basictypes.h index b54abb7be..ed32ae9ae 100644 --- a/cpp/src/phonenumbers/base/basictypes.h +++ b/cpp/src/phonenumbers/base/basictypes.h @@ -189,17 +189,72 @@ char (&ArraySizeHelper(const T (&array)[N]))[N]; // the expression is false, most compilers will issue a warning/error // containing the name of the variable. +#if __cplusplus >= 201103L + +// Under C++11, just use static_assert. +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +#else + template struct CompileAssert { }; -#if !defined(COMPILE_ASSERT) -#if __cplusplus >= 201103L -#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) +// Annotate a variable indicating it's ok if the variable is not used. +// (Typically used to silence a compiler warning when the assignment +// is important for some other reason.) +// Use like: +// int x ALLOW_UNUSED = ...; +#if defined(COMPILER_GCC) +#define ALLOW_UNUSED __attribute__((unused)) #else -#define COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] +#define ALLOW_UNUSED #endif + +#define COMPILE_ASSERT(expr, msg) \ + typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] ALLOW_UNUSED + +// Implementation details of COMPILE_ASSERT: +// +// - COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outer parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + #endif } // namespace phonenumbers diff --git a/tools/cpp/src/base/basictypes.h b/tools/cpp/src/base/basictypes.h index 3f5b336a0..9d7e12c75 100644 --- a/tools/cpp/src/base/basictypes.h +++ b/tools/cpp/src/base/basictypes.h @@ -230,15 +230,31 @@ inline To implicit_cast(From const &f) { // the expression is false, most compilers will issue a warning/error // containing the name of the variable. +#if __cplusplus >= 201103L + +// Under C++11, just use static_assert. +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +#else + template struct CompileAssert { }; -#if !defined(COMPILE_ASSERT) -#define COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] +// Annotate a variable indicating it's ok if the variable is not used. +// (Typically used to silence a compiler warning when the assignment +// is important for some other reason.) +// Use like: +// int x ALLOW_UNUSED = ...; +#if defined(COMPILER_GCC) +#define ALLOW_UNUSED __attribute__((unused)) +#else +#define ALLOW_UNUSED #endif +#define COMPILE_ASSERT(expr, msg) \ + typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] ALLOW_UNUSED + // Implementation details of COMPILE_ASSERT: // // - COMPILE_ASSERT works by defining an array type that has -1 @@ -261,7 +277,7 @@ struct CompileAssert { // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// - The outer parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert @@ -280,6 +296,8 @@ struct CompileAssert { // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. +#endif + // Used to explicitly mark the return value of a function as unused. If you are // really sure you don't want to do anything with the return value of a function // that has been marked WARN_UNUSED_RESULT, wrap it with this. Example: