[net.bugs] C Compiler bug

ravi@flairvax.UUCP (06/15/83)

   A very simple program 


	#include <stdio.h>
	
	main ()
	{

          char *c[],*d[];

	  *c = "i am a string";
	  *d = "so what";

	  printf("%s\n",*c);
	  printf("%s\n",*d);

	}


   on 4.1bsd  produced

        
	so what
	so what


   whereas the C compiler on the TOPS-20 and other variations of the above
   program on 4.1 bsd produced the correct result.

   I am curious to find out WHY?.



   ravi
   Fairchild Research,
   Palo Alto,CA.

olson@fortune.UUCP (06/24/83)

#R:flairvax:-13100:fortune:1800003:000:67
fortune!olson    Jun 23 20:36:00 1983

See the recent (last 3 days articles on this subject in net.lang.c

rbutterworth@watmath.UUCP (Ray Butterworth) (07/25/86)

> >    i = i/2.5;
> vs.
> >    i /= 2.5;

So, does anyone have a fix for this bug?
I'll trade for a fix for a problem with void functions and the ?: operator.

void f3(which)
{
    extern void f1(),f2();
    which?f1():f2();
}
cc(1) gives an "incompatible types" error.


In /usr/src/lib/mip/trees.c add the line indicated by "->>".
This lets the above code lint and compile ok (and I don't think it causes
any new problems).

...
opact( p )  NODE *p; {
...
    switch( optype(o=p->in.op) ){
...
        case COLON:
            if( mt12 & MENU ) return( NCVT+PUN+PTMATCH );
            else if( mt12 & MDBI ) return( TYMATCH );
...
            else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
->>         else if ( (!mt1) && (!mt2) ) return TYPL;
            break;

        case ASSIGN:

ark@alice.UucP (Andrew Koenig) (07/26/86)

> So, does anyone have a fix for this bug?
> I'll trade for a fix for a problem with void functions and the ?: operator.
> 
> void f3(which)
> {
>     extern void f1(),f2();
>     which?f1():f2();
> }
> cc(1) gives an "incompatible types" error.

As it should.  The only thing you're allowed to do with void values
is throw them away.

greg@utcsri.UUCP (Gregory Smith) (07/27/86)

In article <5858@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes:
>> So, does anyone have a fix for this bug?
>> I'll trade for a fix for a problem with void functions and the ?: operator.
>> 
>> void f3(which)
>> {
>>     extern void f1(),f2();
>>     which?f1():f2();
>> }
>> cc(1) gives an "incompatible types" error.
>
>As it should.  The only thing you're allowed to do with void values
>is throw them away.

But it is being thrown away. In e1?e2:e3, the contexts of e2 and e3 are
inherited from the context of the ?: operator itself. In this case,
that is in a 'for effect' or void context, so f1() and f2() should be
treated as 'thrown away' too.


-- 
"You'll need more than a Tylenol if you don't tell me where my father is!"
						- The Ice Pirates
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

donn@utah-cs.UUCP (Donn Seeley) (07/27/86)

The 'i /= f' bug is fixed in 4.3 BSD.  Someone (Hugh Redelmeier) stated
earlier that this bug was fixed in System V but some implementations
caused side effects in the left hand side to be duplicated.  This was
one of the problems that made the fix quite difficult for 4.3; the
solution was fairly ugly but it works.  Essentially what happens is
that the compiler front end notices the special situation and avoids
'type balancing'; special code table entries enable the code generator
to spot these trees and do the right thing.  (This approach is properly
termed 'hacking'.)  I wasn't able to test this bug on our local System V
boxen -- neither of them (SGI Iris, rev 3.4; HP-UX 5.0) have any form
of the '/=' fix...

The 4.3 compiler no longer generates an 'incompatible types' message
for void expressions in the ':' part of a '?' expression -- it prints
'value of void expression used'!

Will wonders never Cse,

Donn Seeley    University of Utah CS Dept    donn@utah-cs.arpa
40 46' 6"N 111 50' 34"W    (801) 581-5668    decvax!utah-cs!donn

rbutterworth@watmath.UUCP (Ray Butterworth) (07/28/86)

> > void f3(which)
> > {
> >     extern void f1(),f2();
> >     which?f1():f2();
> > }
> > cc(1) gives an "incompatible types" error.
> 
> As it should.  The only thing you're allowed to do with void values
> is throw them away.

If I'm not throwing them away, what is it you think I'm doing with them?

Also, the proposed ANSI draft explicitly states that the second and third
operands of ?: may each have (void) type, so I'm not trying anything
unusual here.

jcz@sas.UUCP (Carl Zeigler) (07/29/86)

  In article <5858@alice.uUCp>, ark@alice.UucP (Andrew Koenig) writes:
  > > So, does anyone have a fix for this bug?
  > > I'll trade for a fix for a problem with void functions and the ?: operator
  > > 
  > > void f3(which)
  > > {
  > >     extern void f1(),f2();
  > >     which?f1():f2();
  > > }
  > > cc(1) gives an "incompatible types" error.
  > 
  > As it should.  The only thing you're allowed to do with void values
  > is throw them away.


Scan again, Andrew, the (void) values are being thrown away.

-- 
John Carl Zeigler         "Just once I'd like to meet an alien menace
SAS Institute Inc.            that wasn't impervious to bullets !"
Cary, NC  27511
(919) 467-8000			...!mcnc!rti-sel!sas!jcz

ark@alice.UucP (Andrew Koenig) (07/29/86)

> If I'm not throwing them away, what is it you think I'm doing with them?

> Also, the proposed ANSI draft explicitly states that the second and third
> operands of ?: may each have (void) type, so I'm not trying anything
> unusual here.

I think you're using them to form another value.  It is irrelevant
that you're then throwing that value away.  Suppose f() is void
and you say:

	f()+1;

Now you're adding 1 to a void and throwing the result away.  Should that
be permitted?

More seriously, I can actually see both sides of the argument.  But the
construction ...?f():g()  where f() and g() are void is close enough
to the edge that I wouldn't want to use it in any context where I might
ultimately want to run it on a lot of compilers.  Why not just say

	if (...) f(); else g();

??

jsdy@hadron.UUCP (Joseph S. D. Yao) (07/31/86)

In article <461@watmath.UUCP> rbutterworth@watmath.UUCP (Ray Butterworth) writes:
>> > void f3(which)
>> > {
>> >     extern void f1(),f2();
>> >     which?f1():f2();
>> > }
>> > cc(1) gives an "incompatible types" error.
>> As it should.  The only thing you're allowed to do with void values
>> is throw them away.
>If I'm not throwing them away, what is it you think I'm doing with them?
>Also, the proposed ANSI draft explicitly states that the second and third
>operands of ?: may each have (void) type, so I'm not trying anything
>unusual here.

My 1984 version of X3J11 (has it been that long?) agrees with K&R
that each of the operands must have a value.  This makes intuitive
sense.  The meaning of X ? Y : Z is: an expression whose value is
the value of Y, if the value of X is non-zero; otherwise, the value
of Z.  By this, all three must evaluate to some value.

Do you have a more recent edition of X3J11 that  r e a l l y  lets
voids in there?  Ugh!  (What date?)  Besides which, all C compilers
until just recently (Lattice, Microsoft) had been written to K&R
and v7-s3-s5, not to the ANSI standard.
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)

whp@cbnap.UUCP (W. H. Pollock x4575 3S235) (07/31/86)

In article <134@sas.UUCP> jcz@sas.UUCP (Carl Zeigler) writes:
>
>  > > void f3(which)
>  > > {
>  > >     extern void f1(),f2();
>  > >     which?f1():f2();
>  > > }
>  > > cc(1) gives an "incompatible types" error.
>  > 
>  > As it should.  The only thing you're allowed to do with void values
>  > is throw them away.
>
>Scan again, Andrew, the (void) values are being thrown away.

The void values are not thrown away!  Remember that (A?B:C) is an
expression *returning a value*.  C is giving the error because it can't
determine the type of the return value.  This is clearer in the following:

	void f3(which)
	{
	    int f1();
	    void f2();
	    int foo;
	    ...
	    foo = which?f1():f2();
	    ...
	}

which results in the same error message, for the same reason.  Another
example:

	f4()
	{
	    ...
	    return ((void) expression);
	}

Note it doesn't mater what use is made of the return value (in the original
example it is thrown on the floor, which is what probably confused some
people).

aka@cbrma.UUCP (Andy Kashyap) (07/31/86)

In article <134@sas.UUCP> jcz@sas.UUCP (Carl Zeigler) writes:
>  In article <5858@alice.uUCp>, ark@alice.UucP (Andrew Koenig) writes:
>  > > So, does anyone have a fix for this bug?
>  > >
>  > > void f3(which)
>  > > {
>  > >     extern void f1(),f2();
>  > >     which?f1():f2();
>  > > }
>  > > cc(1) gives an "incompatible types" error.
>  > 
>  > As it should.  The only thing you're allowed to do with void values
>  > is throw them away.
>
>Scan again, Andrew, the (void) values are being thrown away.
>

No they are NOT; the value from the '?:' operator is being thrown away.
The '?:' operator expects a non-void value so it can decide 'which' and
pass the result to a higher level of expression (in this case there happens
to be none). The complaint of "incompatible types" is the result of the
'?:' operator expecting a non-void type as arguments and the arguments
providing a void type.
Wasn't that obvious from the diagnostics??? ;-)

To re-phrase, the '?:' doesn't look at its operands (parameters or arguments)
as function calls -- they might as well be 'f1()+5' or so -- but as
expressions. Therefore it '*RETURNS THE VALUE* of one of its operands
depending on the third'.

A semantic point of view:

A function call is an expression and can, therefore, be used anywhere an
expression can be used. When you declare a function (void), you state that
you intend to use that function as a statement instead, that you do not 
intend to use it in any operations. It can now only be used where a statement
can. Keep in mind that an expression is a statement, but NOT vice-versa.

If you look up the reference section of K&R, somewhere it says something
like this (I don't have my K&R with me):
	...
	expression -> expression ? expression : expression
	...
Thus you can not use a statement (ie (void) f1()) where an expression is
expected.

The BUG: there ain't none.
The FIX: use 'if' instead.

- andy kashyap
-- 

+---------------------------------------------------------------------------+
: Jim, what's the value of Pi?                         : Andy Kashyap       :
: About 3.14159. Why do you ask, Doctor?               : AT&T Bell Labs     :
: Actually, Captain, the exact value is 3.1415926535...: Columbus OH        :
: Kirk & McCoy: Shut Up, Spock!!!                      : ..!cbosgd!cbrma!aka:
+---------------------------------------------------------------------------+

dbw@ariel.UUCP (DAVE B. WOOD) (08/01/86)

> construction ...?f():g()  where f() and g() are void...

Don't forget side effects.

mikes@apple.UUCP (Mike Shannon) (08/05/86)

Just to be sure we're all on the same wavelength about void expressions
with the ?: operator:
	Consider the case where you're writing a really complex #define macro,
and you decide that you'd like some sort of IF statement in it,
(take a look at getchar()).  Can't you see a case where you might want to
call a void function, and then set the value of the #define macro to be
a side effect of the function?  Sort of like
#define foo(c) buffer_empty?fill_buff(),first_char_in_buf:first_char_in_buf
	I mean, it seems to me that the 'pro' argument is that you get flow of
control in #define's. Although when you way that 'void things cannot participate
in expressions', a rational person would say that conditional expressions are
expressions and so you can't have a void thing in that kind of expression.
-- 
			Michael Shannon {apple!mikes}

ark@alice.UucP (Andrew Koenig) (08/06/86)

>	Consider the case where you're writing a really complex #define macro,
>and you decide that you'd like some sort of IF statement in it,
>(take a look at getchar()).  Can't you see a case where you might want to
>call a void function, and then set the value of the #define macro to be
>a side effect of the function?  Sort of like
>#define foo(c) buffer_empty?fill_buff(),first_char_in_buf:first_char_in_buf

No problem using a void as the LHS of a comma operator, just as
there's no problem using a void before a semicolon.

Of course, you'd better parenthesize:

	#define foo(c) (empty?(fill(),first):first)

Moreover, fill() probably returns a value you don't want to ignore,
so maybe you should write it to return either the value of first or
an error code.  You can then write

	(empty?fill():first)

which avoids the void issue altogether.

apc@cblpe.UUCP (Alan Curtis) (08/20/86)

In article <134@sas.UUCP> jcz@sas.UUCP (Carl Zeigler) writes:
>
>  In article <5858@alice.uUCp>, ark@alice.UucP (Andrew Koenig) writes:
>  > > So, does anyone have a fix for this bug?
>  > > 
>  > > void f3(which)
>  > > {
>  > >     extern void f1(),f2();
>  > >     which?f1():f2();
>  > > }
>  > > cc(1) gives an "incompatible types" error.
>  > 
>  > As it should.  The only thing you're allowed to do with void values
>  > is throw them away.
>
>
>Scan again, Andrew, the (void) values are being thrown away.
>
No, the value of the statement is being thrown away, not the value
of the void(s).

Would you let me say:
	.
	.
	.
	f1() + f2();
	.
	.

Since I am throwing both away?
Alan Curtis

guy@sun.uucp (Guy Harris) (08/21/86)

> No, the value of the statement is being thrown away, not the value
> of the void(s).

True, but one can imagine the ":" half-operator selecting between one of the
two "void" values.  One then throws away the value returned by the "?"/":"
operator.

> 
> Would you let me say:
> 	.
> 	.
> 	.
> 	f1() + f2();
> 	.
> 	.
> 
> Since I am throwing both away?

No, you're not.  You're adding them and then throwing the *sum* away.
"void" "value"s can't be added.  If you consider "void" to be a sort-of
type, the set of whose values is a singleton set, then you can consider

	boolean_expression ? void_value_1 : void_value_2

to select one of the two "void" values and yield it as a result, so the ":"
half-operator, unlike the "+" operator, can act on two "void" values.
(Regardless of the value of the <boolean_expression>, the value yielded by
the expression will be the same, since <void_value_1> == <void_value_2> ==
any other void value you can think of.)

Think of it this way: "void" values require 0 bits to represent them, since
the set of all such values has only one element.  As such, "sizeof(void)"
should be 0.  As such, if you say

	void x;

"x" takes up no memory.  Given that, declaring objects of type "void" isn't
very useful.  An attempt to do so is probably an error, so it is rejected.

Also, if objects of type "void" were implemented, most implementations would
run the risk of giving it the same address as the next datum declared.  So
taking the address of a "void" is kind of useless, and so "void *" isn't
useful as a true "pointer to void", so it can be overloaded.

Also, since all "void" values are the same, an attempt to compare them is
probably an error, so "==", etc. aren't defined over the set of "void"
values either.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)