[net.lang.c] 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.

kris@ur-valhalla.UUCP (Krzysztof Kozminski) (08/24/84)

Apparenly, cc compiler does not tolerate shifting unsigned values in
initialization of global variables. Trying to compile the subroutine on
the left produces the diagnostics:

    line 1: compiler error: expression causes compiler loop: try simplifying

These are source files:
	       bad.c                               good.c
 +-------------------------------------+---------------------------------------+
 | int one = (((unsigned) 2) >> 1);    |    int ONE()                          |
 | int ONE()                           |    {                                  |
 | {                                   |    int one = (((unsigned) 2) >> 1);   |
 | return one;                         |    return one;                        |
 | }                                   |    }                                  |
 +-------------------------------------+---------------------------------------+

However, after moving the declaration inside the subroutine as in the
subroutine on the right, everything works OK.

Unless I missed something, The Book does not forbid what I tried to do
(actually, I tried to initialize something to a largest positive
signed integer, i.e., complemented, unsigned zero shifted right by 1. After
I got a similar error message, a couple of experiments determined a minimum
expression causing the error).

Lint also complains about the initialization:
   bad.c(1): illegal initialization

Same thing happens when initializing static variables local to a procedure.
Does anybody have an explanation/fix for this error message ?
We run 4.1c BSD in case this matters (but the same thing occurs in 4.2).
-- 
	Krzysztof Kozminski
	{seismo,allegra,decvax}!rochester!ur-valhalla!kris

guy@rlgvax.UUCP (Guy Harris) (08/25/84)

> Apparenly, cc compiler does not tolerate shifting unsigned values in
> initialization of global variables. Trying to compile the subroutine on
> the left produces the diagnostics:
> 
>     line 1: compiler error: expression causes compiler loop: try simplifying
> 
>  | int one = (((unsigned) 2) >> 1);    |    int ONE()                          |

I believe you are correct, and it is a compiler bug.  I remember running
into similar bugs in our 68K C compiler; casts are not always dealt with
correctly in expressions evaluated at compile time.  Unfortunately, I
don't have a fix at hand.  (Some routine which, in effect, evaluates
casts at compile time is either not being called or isn't recognizing the
cast as something it should clean up.)

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

chris@umcp-cs.UUCP (08/25/84)

It's obviously a compiler bug.  More interesting is the code that
comes out of the (4.2BSD) compiler:

	% /lib/ccom
	int one = (unsigned) 2 >> 1;
[compiler output]
		.data
		.align	2
		.globl	_one
	_one:
		movl	$1,r0
		movl	r0,-4(fp)
		movl	-4(fp),r0
		movl	r0,-8(fp)
		movl	-8(fp),r0
		.
		.
		.

It only happens with the typecasts; ``int one = 2 >> 1;'' works.
``int one = (char) 2 >> 1;'' generates a similar endless stream, but
it begins differently:

		.data
		.align	2
		.globl	_one
	_one:
		movl	$2,r0
		movl	r0,-4(fp)
		mnegl	$1,r0
		movl	r0,-8(fp)
		movl	-8(fp),r0
		movl	r0,-12(fp)
		.
		.
		.

Obviously what's happening is this: during expression tree
optimization, the compiler is trying to compute the value at RUNtime.
However, as there are no free registers, it keeps sticking values into
r0, finding out it can't get another free register, pushing r0 for
safekeeping, getting the next number into r0, finding out it doesn't
have a free register for the ``ashl'' operation, . . . .  Things work
if the operation is done inside {}s because there are some registers
free.

The bug is probably simply that the compiler is missing optimizations
for expressions involving types other than `int' (and `long') for the
">>" and "<<" operators when both LHS and RHS are integer constants.
(Both << and >> generate the endless stream of junk).

(I wonder why the register allocation code doesn't scream loudly when
asked for registers while code generation is off?)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

donn@utah-cs.UUCP (08/25/84)

To recap:  The following program blows up the 4.2 (== System III?)
C compiler:

------------------------------------------------------------------------
int one = (unsigned) 2 >> 1;
------------------------------------------------------------------------

The precise message you get is:

------------------------------------------------------------------------
"one.c", line 1: compiler error: expression causes compiler loop: try simplifying
------------------------------------------------------------------------

Chris Torek's observation is close to the mark (if not on it), but
perhaps it's not as clear as it could be.  The problem is that the
initializer is not being reduced to a constant before the code
generator receives it.  If the code generator gets an expression, it
goes ahead and generates the instructions needed to compute it;
apparently it doesn't mind if it ends up generating instructions into
data space, nor does it seem to care if any of the startup code for
processing text has been run.  The code generator can handle constant
initializers (with a fake opcode of INIT) and that's it.

More directly, what's happening is that when certain casts are
transmuted into conversions, the compiler neglects to canonicalize the
resulting trees.  (Some casts get a second chance -- try substituting
'+' for '<<' in the example and see what happens.) It's a fairly simple
matter to ensure that makety(), the routine which does the
transmutations, always canonicalizes the trees it returns.  Here are
the changes to /usr/src/lib/mip/trees.c:

------------------------------------------------------------------------
*** /tmp/,RCSt1008238	Sat Aug 25 06:30:16 1984
--- trees.c	Sat Aug 25 04:37:26 1984
***************
*** 1061,1067
  
  	if( t & TMASK ){
  		/* non-simple type */
! 		return( block( PCONV, p, NIL, t, d, s ) );
  		}
  
  	if( p->in.op == ICON ){

--- 1061,1067 -----
  
  	if( t & TMASK ){
  		/* non-simple type */
! 		return( clocal( block( PCONV, p, NIL, t, d, s ) ) );
  		}
  
  	if( p->in.op == ICON ){
***************
*** 1079,1085
  			}
  		}
  
! 	return( block( SCONV, p, NIL, t, d, s ) );
  
  	}
  

--- 1079,1085 -----
  			}
  		}
  
! 	return( clocal( block( SCONV, p, NIL, t, d, s ) ) );
  
  	}
  
------------------------------------------------------------------------

I'm not sure that the first change is strictly necessary, but better
safe than sorry.  At any rate the sample program now compiles
correctly.  I don't think these changes have any nasty side effects --
I recompiled the compiler with the changes installed and it produced
exactly the same binary as the old compiler did, for what it's worth.

If the System V C compiler fixes this, I don't want to hear about it,

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

chris@umcp-cs.UUCP (Chris Torek) (08/26/84)

As long as we have people fixing bugs, how about someone patching up the
pcc/ code that converts RS into LS and negates the shift?  It fixes up
constants but it doesn't remove double negations.  Example:

	foo () { register int i,j,k; k = i >> -j; }

produces (prettified)

	.align	1
	.globl	_foo
_foo:	.word	0xe000
	mnegl	r10,r0
	mnegl	r0,r0
	ashl	r0,r11,r0
	movl	r0,r9
	ret

What's the idea of the double mnegl?  I got disgusted enough with this
(and other similar but tougher-to-optimize) stuff in the output stage of
my Versatec TeX filter that I stuck in asm()s (under #ifdef vax though).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

root@ur-valhalla.UUCP (08/27/84)

Well, I've installed Donn Seeley's fix for the C compiler screwing up on
initializing shifted, unsigned variables, and found out a nasty side effect:
The (unsigned) cast is IGNORED!  This is my program:

	main()                          
	{       int big_number = ((~((unsigned) 0)) >> 1);
		printf("this is a big number: %d\n",big_number);
	}                               

Before installing the fix the program produced this output:

	this is a big number: 2147483647

(To remind the original problem: should big_number be declared as static or
as a global variable, C compiler would blow up and go into a loop).
After installing the fix, I got the following output:

	this is a big number: -1

Sigh.... 
-- 
Krzysztof Kozminski (truly sorry for not being able to fix the problem myself)
{seismo,allegra,decvax}!rochester!ur-valhalla!kris

mlr0@bunny.UUCP (Martin Resnick) (07/19/86)

Please try this code on your flavor of C compiler and see if you get the
correct results:
 
main()
{
   int i;
 
   i = 8;
   i = i/2.5;
   printf("i= %d\n", i);

   i = 8;
   i /= 2.5;
   printf("i= %d\n", i);
   exit(0);
}
 
The correct answer is 3 in both cases, not 4.

LINNDR%VUENGVAX.BITNET@WISCVM.ARPA (07/21/86)

I tried the i=i/2.5 vs. i/=2.5 program on two different compilers.
The VMS/EUNICE compiler (essentially the BSD4.2 cc) gives 3 & 4; the
VAX C (from DEC for VMS) gives 3 & 3.

David Linn
LINNDR@VUENGVAX.BITNET

3GTLJHW%CALSTATE.BITNET@WISCVM.ARPA (Joerg Hallbauer) (07/21/86)

   I tryed your program on our PR1ME under both PRIMOS and PRIMIX and the
result for both was the same:

i=3
i=3


--Joerg

mp@allegra.UUCP (Mark Plotnick) (07/21/86)

The i /= f and i *= f bugs occur in the 4.3bsd-beta and 4.2bsd
compilers (I don't know about pre-4.2).  The bug is that the
computation is done in integer rather than floating point.  The 4.3bsd
and System V VAX compilers do the right thing.

We first noticed this bug on a 4.3bsd-beta system, when we saw
"i *= 0.7" compile into "clrl _i".  Incorrect code, but it's sure fast!

	Mark Plotnick
	allegra!mp

jrw@hropus.UUCP (Jim Webb) (07/22/86)

> Please try this code on your flavor of C compiler and see if you get the
> correct results:
	.
	.
	.
> The correct answer is 3 in both cases, not 4.

I got 3 in both cases on my vax running System V Release 2.
-- 
Jim Webb           "Out of phase--get help"         ihnp4!houxm!hropus!jrw

st94wb@sdcc12.UUCP (wade blomgren) (07/22/86)

I tried the '/=' bug test on the following:

Pyramid 90x running 4.2/5.0 Unix (cc) - both answers == 3 (passed)

SUN 2 running Unix 4.2 release 1.4 (cc) - answers == 3,4  (failed)

Hmmmm...
   

Wade Blomgren
UCSD Academic Computing Svcs
....!sdcsvax!sdcc12!st94wb
....!sdcsvax!net1!wade

rlr@stcvax.UUCP (Roger Rose) (07/22/86)

I tried the program for V7 and 4.1 BSD compilers.  On both compilers
   {int i; i=8; i = i/2.5;} gives i=3.
   {int i; i=8; i/=2.5;} gives i=4.
-- 

Roger Rose
   UUCP:    {hao ihnp4 decvax}!stcvax!rlr
   USnail:  Storage Technology Corp. - MD 3T / Louisville, Co.  80028
   phone:   (303) 673-6873

brunner@sdsioa.UUCP (Rob Brunner X2830) (07/24/86)

> Pyramid 90x running 4.2/5.0 Unix (cc) - both answers == 3 (passed)
> SUN 2 running Unix 4.2 release 1.4 (cc) - answers == 3,4  (failed)

I ran the test on a Vax 11/750 running 4.2bsd cc and got 3,4
	... at least the bug isn't consistent across machines 8-).
-- 
Rob Brunner                              email:
Scripps Institution of Oceanography      brunner@sdsioa.UUCP
Mail Code A-010, UC San Diego            sdsioa!brunner@sdcsvax
San Diego, CA 92093                      {backbone}!sdcsvax!sdsioa!brunner
Phone: (619) 534-2040 (work)             (619) 452-7656 (home)

stevesu@copper.UUCP (Steve Summit) (07/24/86)

In article <501@bunny.UUCP>, mlr0@bunny.UUCP (Martin Resnick) writes:
> Please try this code on your flavor of C compiler...
(followed by code demonstrating essentially
>    i = i/2.5;
vs.
>    i /= 2.5;

The answer is absolutely unequivocal on this point.  A compiler
that does not treat i=i/float and i/=float identically is broken,
although many compilers are so broken.  This question was
discussed to death on the net a year or so ago.  The discussion
came to a screeching halt, quite unlike most net discussions,
when the following article appeared from one dmr@research:

> From: dmr@research.UUCP
> Newsgroups: net.lang.c
> Subject: bug in type conversion
> Date: Wed, 4-Jan-84 21:32:17 PST
>
> Mike O'Brien points out that in the C compilers he has available, the
> expression
> 	i *= d;
> where  i  is int and  d  is double is evaluated in fixed point, and
> wonders why.  The answer: it is a compiler bug.  I fixed it in
> (a post V7 version) of the 11 compiler, and it is fixed in the current
> System V compiler (by "current" I mean the one I tried;
> I don't know what is being shipped at this instant.)
>
> The manual is reasonably clear and unambiguous on the point, but
> it's not surprising that people for search for definition problems when
> the compilers are unanimously wrong.
>
> 	Dennis Ritchie

What the manual says is (K&R page 191):

	"The behavior of an expression of the form E1 op= E2 may
	be inferred by taking it as equivalent to E1 = E1 op (E2);
	however, E1 is evaluated only once."

The single evaluation of E1 is the only difference between the
two forms; any type casting, including truncation, should be done
exactly as if E1 = E1 op (E2) had been performed.

                                         Steve Summit
                                         tektronix!copper!stevesu

hugh@hcrvx1.UUCP (Hugh Redelmeier) (07/24/86)

In article <6224@allegra.UUCP> mp@allegra.UUCP (Mark Plotnick) writes:
>The i /= f and i *= f bugs occur in the 4.3bsd-beta and 4.2bsd
>compilers...  The 4.3bsd and System V VAX compilers do the right thing.

Well, not so fast.  Many System V compilers (I don't know about
4.3BSD -- we haven't gotten it yet!) have a bug in the fix to this
bug!  Try "*p++ /= f;" where p is "int *": the ++ gets done twice.
In fact, any side-effect on the left-hand-side would be done twice.
Allen McIntosh of HCR has fixed this (with some effort) as part of our
optimizer project (we produce a portable optimizer that fits into PCC
and f77).

Hugh Redelmeier (416) 922-1937
{utzoo, ihnp4, decvax}!hcr!hugh

jdptxt@adiron.UUCP (The Mad Hacker) (07/24/86)

The bug that is being discussed to death was in 4.1BSD as well.
Somebody else ran into this problem a few months after I started
programming professionally, and I gave him the solution to try
i = i * 0.5 instead of i *= 0.5.  I was told to never trust
mixed-mode Fortran arithmetic and the Pascal that I worked with
in college did not support float to integer conversions so I have
stayed away from these 'op=' in mixed-mode.  I always use them when
possible otherwise.


duke!adiron!jdp

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:

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

>> Please try this code on your flavor of C compiler...
>(followed by code demonstrating essentially
>>    i = i/2.5;
>vs.
>>    i /= 2.5;
>
>The answer is absolutely unequivocal on this point.  A compiler
>that does not treat i=i/float and i/=float identically is broken,
>although many compilers are so broken.  This question was
>discussed to death on the net a year or so ago...

Well, I am definitely adding "(int) op= (float) and related things
to my list of Things Not To Do If I Want To Make Life Easier.
This can be considered "defensive programming".

-- 
"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

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.

ado@elsie.UUCP (Arthur David Olson) (07/27/86)

For those with source code, here's an addition to "lint" to generate warnings
about
	float /= int
and
	int /= float
constructs.  This is an addition to the 4.1BSD version of "lint/lint.c",
in particular to the function "clocal"; your mileage will vary.
As always, the trade secret status of the code involved precludes a clearer
posting.  The addition is conditioned on "OLDVERSION".

	...
	NODE *
	clocal(p) NODE *p; {
	...
		switch( o = p->in.op ){
	#ifndef OLDVERSION
		case ASG MUL:
			if (pflag && p->in.right->in.op == SCONV)
				werror( "mixed-mode *= may surprise you");
			break;
		case ASG DIV:
			if (pflag && p->in.right->in.op == SCONV)
				werror( "mixed-mode /= may surprise you");
			break;
	#endif /* !OLDVERSION */
	...
--
Lint is an Oscar Madison trademark.
--
	UUCP: ..decvax!seismo!elsie!ado   ARPA: elsie!ado@seismo.ARPA
	DEC, VAX, Elsie & Ado are Digital, Borden & Ampex trademarks.

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)