[Top][All Lists]

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

doc for the 'verify' module

From: Bruno Haible
Subject: doc for the 'verify' module
Date: Tue, 2 May 2006 16:33:28 +0200
User-agent: KMail/1.5


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


============================= doc/verify.texi ==================================
@node Compile-time Assertions
@section Compile-time Assertions

@cindex assertion
@findex verify
@findex verify_true

The @samp{verify} module provides a header file @file{verify.h} that
defines two macros: @code{verify (@var{EXPRESSION})} and
@code{verify_true (@var{EXPRESSION})}.  Both verify that the @var{EXPRESSION}
is a constant expression and that it evaluates to non-zero.  If not, a
compile-time error results.

The difference between the two is that @code{verify (@var{EXPRESSION});}
is meant for use as a declaration; it can occur outside of functions.
Whereas @code{verify_true (@var{EXPRESSION})} is an expression that can
be casted to @code{void} or used in comma expressions.

The definition of these macros is involved; here comes an explanation of
the details.

The first step is @samp{(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 @samp{W} is wrapped in a type
@samp{struct verify_type__ @{ unsigned int dummy: W; @}}.
If @code{W} is negative, this yields a compile-time error.  No compiler can
deal with an bit field of negative size.

You might think that an array size check would have the same effect, that
is, that the type @samp{struct verify_type__ @{ unsigned int dummy[W]; @}}
would work as well.  Outside of functions, this is true, but inside a
function, some compilers (such as C++ compilers and GNU C) allow local
parameters and variables inside array size expressions.  With this type,
int function (int n)
  verify (n >= 0);
@end smallexample
would fail to give an error "non-constant expression".

For the @samp{verify} macro, the @samp{struct verify_type__} will need to
somehow be embedded into a declaration.  This declaration must declare an
entity (type or variable or function).  (If the declaration declares no
entity, some compilers will give a warning; this is undesirable.)  If
the declared entity uses the type directly, such as in
struct dummy @address@hidden;
typedef struct @address@hidden dummy;
extern struct @address@hidden *dummy;
extern void dummy (struct @address@hidden *);
extern struct @address@hidden *dummy (void);
@end smallexample
two uses of the @samp{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 verify_type__ @address@hidden * GL_CONCAT(dummy,__LINE__);
@end smallexample
But this has the problem that two invocations of @samp{verify}, from within
a macro, would collide - since the __LINE__ value would be the same for both

The solution to this problem is to use the @samp{sizeof} operator.  It
yields a number, getting rid of the identity of the type.  Declarations like
typedef int dummy [sizeof (struct @address@hidden)];
extern int dummy [sizeof (struct @address@hidden)];
extern void dummy (int [sizeof (struct @address@hidden)]);
extern int (*dummy (void)) [sizeof (struct @address@hidden)];
@end smallexample
can in theory be repeated.

The @samp{typedef} alternative is eliminated because a type cannot be
declared twice anyway.  So this constrains us to declare a variable or
extern int dummy [sizeof (struct @address@hidden)];
extern void dummy (int [sizeof (struct @address@hidden)]);
extern int (*dummy (void)) [sizeof (struct @address@hidden)];
@end smallexample

Use a named struct or an unnamed struct?  Which of the following alternatives
can be used?

extern int dummy [sizeof (struct @address@hidden)];
extern int dummy [sizeof (struct verify_type__ @address@hidden)];
extern void dummy (int [sizeof (struct @address@hidden)]);
extern void dummy (int [sizeof (struct verify_type__ @address@hidden)]);
extern int (*dummy (void)) [sizeof (struct @address@hidden)];
extern int (*dummy (void)) [sizeof (struct verify_type__ @address@hidden)];
@end smallexample

In C, we have the following constraints:
@itemize @bullet
In the second and sixth case, the struct type is exported to the outer scope;
two such declarations therefore collide.
In the third and fourth case, gcc gives a warning "structure defined inside
In the first case, when used inside a function, gcc gives a warning
"unused variable `dummy'".
@end itemize

The only remaining possibility is:
extern int (*dummy (void)) [sizeof (struct @address@hidden)];
@end smallexample

When using this possibility, we exploit the fact that while the struct has
only a scope limited to the declaration, gcc does not warn about it.
If gcc did introduce a warning in this case, a fix would be to define the
@code{verify} macro differently for gcc: instead of using a struct type,
use an array size, and use @code{__builtin_constant_p} to catch the case of
the local variables that are allowed in an array size expression:
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 90)
# define verify(R) \
    extern int (* verify_function__ (void)) \
               [__builtin_constant_p ((R)) ? ((R) ? 1 : -1) : -1]
@end smallexample

Whereas in C++, any struct definition inside @code{sizeof} is invalid; the
fix is to use a template type instead.
@end enumerate

reply via email to

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