diff mbox

[10/10] bug.h: Add gcc 4.2+ versions of BUILD_BUG_ON_* macros

Message ID 1348874411-28288-11-git-send-email-daniel.santos@pobox.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Daniel Santos Sept. 28, 2012, 11:20 p.m. UTC
BUILD_BUG_ON42(arg)
BUILD_BUG_ON_CONST42(arg)

Prior to gcc 4.2, the optimizer was unable to determine that many
constant values stored in structs were indeed compile-time constants and
optimize them out.  Sometimes, it will find an intergral value to be a
compile-time constant, but fail to perform a bit-wise AND at
compile-time.  These two macros provide a mechanism to perform these
build-time checks, but not break on older compilers where we already
know they can't be checked at compile time.

For specific details, consult the doc comments for BUILD_BUG_ON_CONST.
These macros are used in the generic rbtree code.

Signed-off-by: Daniel Santos <daniel.santos@pobox.com>
---
 include/linux/bug.h |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

Comments

Michel Lespinasse Oct. 2, 2012, 12:55 a.m. UTC | #1
On Fri, Sep 28, 2012 at 4:20 PM, Daniel Santos <daniel.santos@pobox.com> wrote:
> BUILD_BUG_ON42(arg)
> BUILD_BUG_ON_CONST42(arg)
>
> Prior to gcc 4.2, the optimizer was unable to determine that many
> constant values stored in structs were indeed compile-time constants and
> optimize them out.  Sometimes, it will find an intergral value to be a
> compile-time constant, but fail to perform a bit-wise AND at
> compile-time.  These two macros provide a mechanism to perform these
> build-time checks, but not break on older compilers where we already
> know they can't be checked at compile time.
>
> For specific details, consult the doc comments for BUILD_BUG_ON_CONST.
> These macros are used in the generic rbtree code.

I think the names are quite confusing. BUILD_BUG_ON_NON_CONST42 sounds
like it's checking if 42 is a constant.

The name probably shouldn't mention what compiler versions support
this check, but instead it should hint as to when you should use this
instead of BUILD_BUG_ON_CONST ? Maybe BUILD_BUG_ON_CONST_DEREF or
something (I'm pretty bad with names too :)
Daniel Santos Oct. 2, 2012, 4:04 p.m. UTC | #2
On 10/01/2012 07:55 PM, Michel Lespinasse wrote:
> On Fri, Sep 28, 2012 at 4:20 PM, Daniel Santos <daniel.santos@pobox.com> wrote:
>> BUILD_BUG_ON42(arg)
>> BUILD_BUG_ON_CONST42(arg)
>>
>> Prior to gcc 4.2, the optimizer was unable to determine that many
>> constant values stored in structs were indeed compile-time constants and
>> optimize them out.  Sometimes, it will find an intergral value to be a
>> compile-time constant, but fail to perform a bit-wise AND at
>> compile-time.  These two macros provide a mechanism to perform these
>> build-time checks, but not break on older compilers where we already
>> know they can't be checked at compile time.
>>
>> For specific details, consult the doc comments for BUILD_BUG_ON_CONST.
>> These macros are used in the generic rbtree code.
>
> I think the names are quite confusing. BUILD_BUG_ON_NON_CONST42 sounds
> like it's checking if 42 is a constant.
>
> The name probably shouldn't mention what compiler versions support
> this check, but instead it should hint as to when you should use this
> instead of BUILD_BUG_ON_CONST ? Maybe BUILD_BUG_ON_CONST_DEREF or
> something (I'm pretty bad with names too :)
I completely agree about the naming, but I'm also stumped. I choose
version 4.2 after writing a test program & group of scripts and sifting
through the results of 220k tests of __builtin_constant_p()!  In gcc
4.2, there are still some tests that will fail, but I went with 4.2 as
the "good version" mostly because:

a. the broken tests didn't affect my generic red-black tree
implementation, and
b. broken cases in 4.2 were the slim minority.

For instance calling __builtin_constant_p() on a dereferenced pointer in
4.2 always fails, while dereferencing a global static array (of
primitives) returns 1 in pretty much every case that it should
(excepting global non-static const, which also fails in 4.7 and perhaps
the compiler figures that somewhere else, const can be cast away and the
data modified anyway?).

Maybe it would be better in the long term to create multiple macros for
testing various constructs.  Verbosity does really start to increase
here, but I suppose we can work out some type of nomenclature to control
that while still being clear about what the macro does (not that I have
any ideas at the moment).

BUILD_BUG_ON_NON_CONST_PTR_DEREF     - gcc 4.4
BUILD_BUG_ON_NON_CONST_ARRAY_DEREF   - gcc 4.2
BUILD_BUG_ON_NON_CONST_STRUCT_MEMBER - gcc 4.2 (unless it's a pointer or
you use -O1)
etc.

To make it any more clear, I suppose I will have to clean up my test
results and share them again (an 82k spreadsheet uncompressed).  Let me
know if you want to see it.  So it's really for a sort of
full-disclosure that I use the suffix "42" and not something more
specific to what it should test.

Alternately, we can just call it something like
BUILD_BUG_ON_NON_CONST_MODERN and bump the version up gcc 4.4, which is
just as functional as 4.7.

Daniel





--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/bug.h b/include/linux/bug.h
index e30f600..d14c23c 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -2,6 +2,7 @@ 
 #define _LINUX_BUG_H
 
 #include <asm/bug.h>
+#include <linux/compiler.h>
 
 enum bug_trap_type {
 	BUG_TRAP_TYPE_NONE = 0,
@@ -129,6 +130,41 @@  struct pt_regs;
 #define BUILD_BUG_ON_NON_CONST(exp)
 #endif
 
+
+#if GCC_VERSION >= 40200
+/**
+ * BUILD_BUG_ON_NON_CONST42 - break compile if expression cannot be determined
+ *                            to be a compile-time constant (disabled prior to
+ *                            gcc 4.2)
+ * @exp: value to test for compile-time constness
+ *
+ * Use this macro instead of BUILD_BUG_ON_NON_CONST when testing struct
+ * members or dereferenced arrays and pointers.  Note that the version checks
+ * for this macro are not perfect.  BUILD_BUG_ON_NON_CONST42 expands to nothing
+ * prior to gcc-4.2, after which it is the same as BUILD_BUG_ON_NON_CONST.
+ * However, there are still many checks that will break with this macro (see
+ * the Gory Details section of BUILD_BUG_ON_NON_CONST for more info).
+ *
+ * See also BUILD_BUG_ON_NON_CONST()
+ */
+# define BUILD_BUG_ON_NON_CONST42(exp) BUILD_BUG_ON_NON_CONST(exp)
+
+/**
+ * BUILD_BUG_ON42 - break compile if expression cannot be determined
+ *                   (disabled prior to gcc 4.2)
+ *
+ * This gcc-version check is necessary due to breakages in testing struct
+ * members prior to gcc 4.2.
+ *
+ * See also BUILD_BUG_ON()
+ */
+# define BUILD_BUG_ON42(arg) BUILD_BUG_ON(arg)
+#else
+# define BUILD_BUG_ON_NON_CONST42(exp)
+# define BUILD_BUG_ON42(arg)
+#endif /* GCC_VERSION >= 40200 */
+
+
 #endif	/* __CHECKER__ */
 
 #ifdef CONFIG_GENERIC_BUG