[comp.lang.c] Function pointer casts in ANSI C

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) (11/29/90)

ANSI C guarantees that a pointer to a function can be cast to another
function pointer type and back, and retain its value. However, if it
is used ``at a wrong type'', the results are undefined.

My question is: Can a conforming compiler generate a warning for casts
(and arguments) that will ``go wrong'' but not for those that work?
I'm thinking of something like this:

	void myqsort(void **, int (*)(void *, void *));

	typedef struct { ... } data;

	int foo(data * a, data * b) { ... }

	int main() {
	    data *sort[NSORT];

	    ...
	    myqsort(sort, foo);
	    ...
	}

This will work as expected if and only if exactly the same calling
sequence is generated for the following two calls to foo:

	    void *a, *b;

	    foo(a, b);
	    ( (void (*)(void *, void *))foo )(a, b);

If it works, the compiler should warn about a non-portable cast; if it
doesn't work, the warning should say 'cast between pointers to
functions with incompatible calling sequences' or something. And the
former might be easier to turn off than the latter.

The questions are: Do any compilers implement this test? Would it be
difficult to do so in, e.g., gcc? And is it legal for a conforming
ANSI C compiler to diagnose only ``bad'' casts?

--
Lars Mathiesen, DIKU, U of Copenhagen, Denmark      [uunet!]mcsun!diku!thorinn
Institute of Datalogy -- we're scientists, not engineers.      thorinn@diku.dk

gwyn@smoke.brl.mil (Doug Gwyn) (11/30/90)

In article <1990Nov29.110114.21565@diku.dk> thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>My question is: Can a conforming compiler generate a warning for casts
>(and arguments) that will ``go wrong'' but not for those that work?

A conforming implementation must produce at least one diagnostic for each
translation unit that violates a syntax rule or constraint.  Diagnostics
may be produced under other circumstances, but are not required.

In your example, the syntax is presumably correct, so that leaves only the
question of whether a constraint is violated.  The relevant constraint
appears to be in 3.3.2.2 (Function Calls): each argument must be
assignment-compatible with the corresponding parameter.  This leads us to
3.3.16.1 (Simple Assignment), where the constraints require pointers to
compatible types (apart from the qualifiers).  That leads to 3.1.2.6
(Compatible Type and Composite Type), which immediately leads to 3.5.4
(Declarators), more specifically 3.5.4.3 (Function Declarators (Including
Prototypes)), where inder Semantics we finally find out what is really
required: return value and parameters must have compatible types.  So,
the final constraint to be checked is whether void* and data* are
compatible types.  This leads us around to 3.5.4.1, which requires that
void and data be compatible types.  The search ends here, because there
is nothing in the standard that says that void is compatible with a
structure type.

Thus a constraint IS violated, and a diagnostic IS required.  The
compiler could go ahead and translate the source into object code that
might actually work; there is no requirement that a conforming
implementation reject programs that generate diagnostics.

manning@nntp-server.caltech.edu (Evan Marshall Manning) (11/30/90)

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>My question is: Can a conforming compiler generate a warning for casts
>(and arguments) that will ``go wrong'' but not for those that work?

gwyn@smoke.brl.mil (Doug Gwyn) writes:

>A conforming implementation must produce at least one diagnostic for each
>translation unit that violates a syntax rule or constraint.  Diagnostics
>may be produced under other circumstances, but are not required.

My favorite lint (from Gimpel) would call those that work "non-portable",
and issue a more serious warning/error message for those that not will
work.

***************************************************************************
Your eyes are weary from staring at the CRT for so | Evan M. Manning
long.  You feel sleepy.  Notice how restful it is  |      is
to watch the cursor blink.  Close your eyes.  The  |manning@gap.cco.caltech.edu
opinions stated above are yours.  You cannot       | manning@mars.jpl.nasa.gov
imagine why you ever felt otherwise.               | gleeper@tybalt.caltech.edu

thorinn@rimfaxe.diku.dk (Lars Henrik Mathiesen) (12/04/90)

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>My question is: Can a conforming compiler generate a warning for casts
>(and arguments) that will ``go wrong'' but not for those that work?

gwyn@smoke.brl.mil (Doug Gwyn) writes:
>A conforming implementation must produce at least one diagnostic for each
>translation unit that violates a syntax rule or constraint.  Diagnostics
>may be produced under other circumstances, but are not required.

Doug's analysis applies to the "(and arguments)" in the question. For
casts, 3.3.4 (Cast operators) Semantics tells us that behaviour is
undefined because the function types are incompatible, but no
diagnostic is required.

manning@nntp-server.caltech.edu (Evan Marshall Manning) writes:
>My favorite lint (from Gimpel) would call those that work "non-portable",
>and issue a more serious warning/error message for those that not will
>work.

Is this lint architecture- and compiler-specific (or configurable)
since it knows what works? Or does it just guess based on two's
complement, byte addressable, 32-bit int and pointer machines?

--
Lars Mathiesen, DIKU, U of Copenhagen, Denmark      [uunet!]mcsun!diku!thorinn
Institute of Datalogy -- we're scientists, not engineers.      thorinn@diku.dk

manning@nntp-server.caltech.edu (Evan Marshall Manning) (12/05/90)

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>My question is: Can a conforming compiler generate a warning for casts
>(and arguments) that will ``go wrong'' but not for those that work?

I wrote:
>My favorite lint (from Gimpel) would call those that work "non-portable",
>and issue a more serious warning/error message for those that not will
>work.

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) writes:
>Is this lint architecture- and compiler-specific (or configurable)
>since it knows what works? Or does it just guess based on two's
>complement, byte addressable, 32-bit int and pointer machines?

The Gimpel product I use is for PCs only, so it knows everything about
the processor architecture.  Various flags tell it sizeof int, data pointers,
and function pointers.  They're pretty good about providing flags for
everything reasonable so I'd bet there are one or two extra flags on
their more generic product.

***************************************************************************
Your eyes are weary from staring at the CRT for so | Evan M. Manning
long.  You feel sleepy.  Notice how restful it is  |      is
to watch the cursor blink.  Close your eyes.  The  |manning@gap.cco.caltech.edu
opinions stated above are yours.  You cannot       | manning@mars.jpl.nasa.gov
imagine why you ever felt otherwise.               | gleeper@tybalt.caltech.edu