From 5e11f44bd58d2a210655ee26ecd9ac0135d9c645 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 2 May 2006 23:39:59 +0000 Subject: [PATCH] * doc/verify.texi: New file. * lib/verify.h: Document the internals better. --- doc/ChangeLog | 4 +++ doc/verify.texi | 82 +++++++++++++++++++++++++++++++++++++++++++ lib/ChangeLog | 5 +++ lib/verify.h | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 doc/verify.texi diff --git a/doc/ChangeLog b/doc/ChangeLog index 33bd45a51..612211753 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2006-05-02 Paul Eggert + + * verify.texi: New file, partly based on a proposal by Bruno Haible. + 2006-04-29 Bruno Haible * gcd.texi: New file. diff --git a/doc/verify.texi b/doc/verify.texi new file mode 100644 index 000000000..218bdb972 --- /dev/null +++ b/doc/verify.texi @@ -0,0 +1,82 @@ +@c GNU verify module documentation + +@c Copyright (C) 2006 Free Software Foundation, Inc. + +@c Permission is granted to copy, distribute and/or modify this document +@c under the terms of the GNU Free Documentation License, Version 1.2 +@c or any later version published by the Free Software Foundation; +@c with no Invariant Sections, no Front-Cover Texts, and no Back-Cover +@c Texts. A copy of the license is included in the ``GNU Free +@c Documentation License'' file as part of this distribution. + +@node Compile-time Assertions +@section Compile-time Assertions + +@cindex assertion +@findex verify +@findex verify_true + +The @samp{verify} module supports compile-time tests, as opposed to +the standard @file{assert.h} header which supports only runtime tests. +Since the tests occur at compile-time, they are more reliable, and +they require no runtime overhead. + +This module provides a header file @file{verify.h} that defines two +macros: @code{verify (@var{EXPRESSION})} and @code{verify_true +(@var{EXPRESSION})}. Both accept an integer constant expression +argument and verify that it is nonzero. If not, a compile-time error +results. + +@code{verify (@var{EXPRESSION});} is a declaration; it can occur +outside of functions. In contrast, @code{verify_true +(@var{EXPRESSION})} is an integer constant expression that always +evaluates to 1; it can be used in macros that expand to +expressions. + +@var{EXPRESSION} should be an integer constant expression in the sense +of the C standard. Its leaf operands should be integer, enumeration, +or character constants; or @code{sizeof} expressions that return +constants; or floating constants that are the immediate operands of +casts. Outside a @code{sizeof} subexpression, @var{EXPRESSION} should +not contain any assignments, function calls, comma operators, casts to +non-integer types, or subexpressions whose values are outside the +representable ranges for their types. If @var{EXPRESSION} is not an +integer constant expression, then a compiler might reject a usage like +@samp{verify (@var{EXPRESSION});} even when @var{EXPRESSION} is +nonzero. + +Here are some example uses. + +@example +#include + +#include +#include + +/* Verify that time_t is an integer type. */ +verify ((time_t) 1.5 == 1); + +/* Verify that time_t is at least as wide as int. */ +verify (INT_MIN == (time_t) INT_MIN); +verify (INT_MAX == (time_t) INT_MAX); + +/* Verify that time_t is signed. */ +verify ((time_t) -1 < 0); + +/* Verify that time_t uses two's complement representation. */ +verify (~ (time_t) -1 == 0); + +/* Return the maximum value of the integer type T, + verifying that T is an unsigned integer type. */ +#define MAX_UNSIGNED_VAL_WITH_COMMA(t) \ + (verify_true (0 < (T) -1), (T) -1) + +/* Same as MAX_UNSIGNED_VAL_WITH_COMMA, + but expand to an integer constant expression, + which cannot contain a comma operator. + The cast to (T) is outside the conditional expression + so that the result is of type T + even when T is narrower than unsigned int. */ +#define MAX_UNSIGNED_VAL(t) ((T) \ + ((T) (verify_true (0 < (T) -1) ? -1 : 0)) +@end example diff --git a/lib/ChangeLog b/lib/ChangeLog index 54882c074..153879d7a 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,8 @@ +2006-05-02 Paul Eggert + + * verify.h: Document the internals better. Most of this change + was written by Bruno Haible. + 2006-04-29 Bruno Haible * gcd.c: Use WORD_T and GCD instead of unsigned long and gcd. diff --git a/lib/verify.h b/lib/verify.h index 328980fa3..d603b1737 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -1,6 +1,6 @@ /* Compile-time assert-like macros. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,25 +16,111 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* Written by Paul Eggert and Jim Meyering. */ +/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */ #ifndef VERIFY_H # define VERIFY_H 1 -/* Each of these macros verifies that its argument R is a nonzero - constant expression. To be portable, R's type must be integer (or - boolean). Unlike assert, there is no run-time overhead. +/* Each of these macros verifies that its argument R is nonzero. To + be portable, R should be an integer constant expression. Unlike + assert (R), there is no run-time overhead. There are two macros, since no single macro can be used in all - contexts in C. verify_true (R) is for scalar contexts, where it - may be cast to void if need be. verify (R) is for declaration + contexts in C. verify_true (R) is for scalar contexts, including + integer constant expression contexts. verify (R) is for declaration contexts, e.g., the top level. - The symbols verify_error_if_negative_size__ and verify_function__ - are private to this header. */ + Symbols ending in "__" are private to this header. + + The code below uses several ideas. + + * The first step is ((R) ? 1 : -1). Given an expression R, of + integral or boolean or floating-point type, this yields an + expression of integral type, whose value is later verified to be + constant and nonnegative. + + * Next this expression W is wrapped in a type + struct verify_type__ { unsigned int verify_error_if_negative_size__: W; }. + If W is negative, this yields a compile-time error. No compiler can + deal with a bit-field of negative size. + + One might think that an array size check would have the same + effect, that is, that the type struct { unsigned int dummy[W]; } + would work as well. However, inside a function, some compilers + (such as C++ compilers and GNU C) allow local parameters and + variables inside array size expressions. With these compilers, + an array size check would not properly diagnose this misuse of + the verify macro: + + void function (int n) { verify (n < 0); } + + * For the verify macro, the struct verify_type__ will need to + somehow be embedded into a declaration. To be portable, this + declaration must declare an object, a constant, a function, or a + typedef name. If the declared entity uses the type directly, + such as in + + struct dummy {...}; + typedef struct {...} dummy; + extern struct {...} *dummy; + extern void dummy (struct {...} *); + extern struct {...} *dummy (void); + + two uses of the verify macro would yield colliding declarations + if the entity names are not disambiguated. A workaround is to + attach the current line number to the entity name: + + #define GL_CONCAT0(x, y) x##y + #define GL_CONCAT(x, y) GL_CONCAT0 (x, y) + extern struct {...} * GL_CONCAT(dummy,__LINE__); + + But this has the problem that two invocations of verify from + within the same macro would collide, since the __LINE__ value + would be the same for both invocations. + + A solution is to use the sizeof operator. It yields a number, + getting rid of the identity of the type. Declarations like + + extern int dummy [sizeof (struct {...})]; + extern void dummy (int [sizeof (struct {...})]); + extern int (*dummy (void)) [sizeof (struct {...})]; + + can be repeated. + + * Should the implementation use a named struct or an unnamed struct? + Which of the following alternatives can be used? + + extern int dummy [sizeof (struct {...})]; + extern int dummy [sizeof (struct verify_type__ {...})]; + extern void dummy (int [sizeof (struct {...})]); + extern void dummy (int [sizeof (struct verify_type__ {...})]); + extern int (*dummy (void)) [sizeof (struct {...})]; + extern int (*dummy (void)) [sizeof (struct verify_type__ {...})]; + + In the second and sixth case, the struct type is exported to the + outer scope; two such declarations therefore collide. GCC warns + about the first, third, and fourth cases. So the only remaining + possibility is the fifth case: + + extern int (*dummy (void)) [sizeof (struct {...})]; + + * This implementation exploits the fact that GCC does not warn about + the last declaration mentioned above. If a future version of GCC + introduces a warning for this, the problem could be worked around + by using code specialized to GCC, e.g.,: + + #if 4 <= __GNUC__ + # define verify(R) \ + extern int (* verify_function__ (void)) \ + [__builtin_constant_p (R) && (R) ? 1 : -1] + #endif + + * In C++, any struct definition inside sizeof is invalid. + Use a template type to work around the problem. */ + /* Verify requirement R at compile-time, as an integer constant expression. - Return true. */ + Return 1. */ # ifdef __cplusplus template -- 2.11.0