[m-dev.] for review: MR_TypeInfo cleanup, part 1
Fergus Henderson
fjh at cs.mu.OZ.AU
Fri Mar 24 19:36:05 AEDT 2000
On 24-Mar-2000, Zoltan Somogyi <zs at cs.mu.OZ.AU> wrote:
> On 24-Mar-2000, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> > Hmm... here you just return the number directly, but
> > the MR_TYPECTOR_DESC_IS_HIGHER_ORDER() macro calls
> > MR_TYPECTOR_DESC_UNSIGNED(), which assumes that its argument
> > will be a pointer to a struct containing the number as its first field.
> >
> > So `MR_TYPECTOR_DESC_IS_HIGHER_ORDER(MR_TYPECTOR_DESC_MAKE_PRED(0))'
> > would lead to a seg fault. That sure looks to me like a bug.
>
> No, this is not a bug. MR_TYPECTOR_DESC_UNSIGNED() *does not* assume that
> its argument will be a pointer to a struct containing the number as its
> first field; it assumes that its argument is a value of type MR_TypeCtorDesc
> (i.e. a pointer) which it then simply casts to Unsigned. The
> MR_TYPECTOR_DESC_UNSIGNED macro does not do any dereferencing;
> it returns the *address* of the dummy field, not its contents.
Ah, I see now. You're absolutely correct.
This scheme is a quite nifty trick for getting type safety when using macros.
> I will document this scheme better before I commit.
That would be great, thanks.
It's a pity that for portability reasons we can't use more
straight-forward techniques to get type safety, such as using
inline functions, or perhaps using GNU C's `({ ... })' extension.
One small drawback with this technique is that it depends for its correctness
on the named field (e.g. `arity' or `type_ctor_desc_dummy_field') being the
*first* field in the type. Another minor drawback is that it only guarantees
that the type is a type with the given field name, not that it is the correct
type.
An alternative technique which avoids these drawbacks would be to use
the following macro:
/*
** MR_CHECK_EXPR_TYPE(expr, type):
** This macro checks that the given expression has a type
** which is compatible with (assignable to) the specified type,
** forcing a compile error if it does not.
** It does not evaluate the expression.
** Note that the specified type must be a complete type,
** i.e. it must not be a pointer to a struct which has
** not been defined.
**
** The implementation of this macro looks like it dereferences
** a null pointer, but because that code is inside sizeof(), it will
** not get executed; the compiler will instead just check that it is
** type-correct.
*/
#define MR_CHECK_EXPR_TYPE(expr, type) \
((void) sizeof(*(type *)NULL = (expr)))
With this macro, you can define macros like MR_TYPECTOR_DESC_UNSIGNED()
in a fairly straight-forward manner:
#define MR_TYPECTOR_DESC_UNSIGNED(typector_desc) \
( MR_CHECK_EXPR_TYPE(typector_desc, MR_TypeCtorDesc), \
(Unsigned) (typector_desc) )
But this is a relatively minor improvement; if you want to commit the
code as is, I'm happy to do the above change myself, as a separate change.
Cheers,
Fergus.
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list