bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: doc for the 'verify' module


From: Paul Eggert
Subject: Re: doc for the 'verify' module
Date: Tue, 02 May 2006 16:43:44 -0700
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)

Bruno Haible <address@hidden> writes:

> I propose to add the attached doc to the 'verify' module. It captures the
> interesting details of the verify macro. Objections?

Thanks.

Most of that documentation talks about internals to the 'verify'
module.  Wouldn't it be better to put the internals elsewhere, and
have the documentation talk only about behavior that users of 'verify'
care about?

For now, I installed this:

2006-05-02  Paul Eggert  <address@hidden>

        * doc/verify.texi: New file, partly based on a proposal by Bruno Haible.
        * lib/verify.h: Document the internals better.  Most of this change
        was written by Bruno Haible.

Index: lib/verify.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/verify.h,v
retrieving revision 1.7
diff -p -u -r1.7 verify.h
--- lib/verify.h        5 Oct 2005 06:50:03 -0000       1.7
+++ lib/verify.h        2 May 2006 23:36:48 -0000
@@ -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 <int w>
--- /dev/null   2005-09-24 22:00:15.000000000 -0700
+++ doc/verify.texi     2006-05-02 16:33:08.000000000 -0700
@@ -0,0 +1,82 @@
address@hidden GNU verify module documentation
+
address@hidden Copyright (C) 2006 Free Software Foundation, Inc.
+
address@hidden Permission is granted to copy, distribute and/or modify this 
document
address@hidden under the terms of the GNU Free Documentation License, Version 
1.2
address@hidden or any later version published by the Free Software Foundation;
address@hidden with no Invariant Sections, no Front-Cover Texts, and no 
Back-Cover
address@hidden Texts.  A copy of the license is included in the ``GNU Free
address@hidden Documentation License'' file as part of this distribution.
+
address@hidden Compile-time Assertions
address@hidden Compile-time Assertions
+
address@hidden assertion
address@hidden verify
address@hidden 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.
+
address@hidden (@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.
+
address@hidden 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
address@hidden (@var{EXPRESSION});} even when @var{EXPRESSION} is
+nonzero.
+
+Here are some example uses.
+
address@hidden
+#include <verify.h>
+
+#include <limits.h>
+#include <time.h>
+
+/* 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))
address@hidden example




reply via email to

[Prev in Thread] Current Thread [Next in Thread]