Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site utah-cs.UUCP Path: utzoo!linus!decvax!ittvax!dcdwest!sdcsvax!sdcrdcf!hplabs!utah-cs!donn From: donn@utah-cs.UUCP Newsgroups: net.lang.c,net.bugs.4bsd Subject: Re: C compiler bug etc. [More fixes] Message-ID: <3013@utah-cs.UUCP> Date: Tue, 28-Aug-84 23:20:49 EDT Article-I.D.: utah-cs.3013 Posted: Tue Aug 28 23:20:49 1984 Date-Received: Thu, 30-Aug-84 10:07:25 EDT References: <73@ur-valhalla.UUCP> <8164@umcp-cs.UUCP> <3009@utah-cs.UUCP> <74@ur-valhalla.UUCP> Organization: University of Utah CS Dept Lines: 180 It seems that the fix I supplied uncovers another bug in the compiler. Here is the result which Krzysztof Kozminski found -- a program that used to work: ------------------------------------------------------------------------ main() { int big_number = ((~((unsigned) 0)) >> 1); printf("this is a big number: %d\n",big_number); } ------------------------------------------------------------------------ ... is suddenly broken -- it prints -1 instead of 2147483647. What's going on is that the old compiler didn't evaluate the expression '((~((unsigned) 0)) >> 1)' into a constant; instead it generated the actual instructions to compute the result from the constants 0 and 1. The new version is 'smarter' -- it realizes that it can compute the expression ahead of time, but gets it wrong... The fix is to force the compiler to look for unsigned constants. The following changes in conval() in mip/trees.c will do the trick: ------------------------------------------------------------------------ *** /tmp/,RCSt1019513 Mon Aug 27 23:59:25 1984 --- trees.c Mon Aug 27 23:34:41 1984 *************** *** 571,577 p->tn.lval -= val; break; case MUL: ! p->tn.lval *= val; break; case DIV: if( val == 0 ) uerror( "division by 0" ); --- 571,578 ----- p->tn.lval -= val; break; case MUL: ! if ( u ) p->tn.lval = (unsigned) p->tn.lval * val; ! else p->tn.lval *= val; break; case DIV: if( val == 0 ) uerror( "division by 0" ); *************** *** 575,580 break; case DIV: if( val == 0 ) uerror( "division by 0" ); else p->tn.lval /= val; break; case MOD: --- 576,582 ----- break; case DIV: if( val == 0 ) uerror( "division by 0" ); + else if ( u ) p->tn.lval = (unsigned) p->tn.lval / val; else p->tn.lval /= val; break; case MOD: *************** *** 579,584 break; case MOD: if( val == 0 ) uerror( "division by 0" ); else p->tn.lval %= val; break; case AND: --- 581,587 ----- break; case MOD: if( val == 0 ) uerror( "division by 0" ); + else if ( u ) p->tn.lval = (unsigned) p->tn.lval % val; else p->tn.lval %= val; break; case AND: *************** *** 596,602 break; case RS: i = val; ! p->tn.lval = p->tn.lval >> i; break; case UNARY MINUS: --- 599,606 ----- break; case RS: i = val; ! if ( u ) p->tn.lval = (unsigned) p->tn.lval >> i; ! else p->tn.lval = p->tn.lval >> i; break; case UNARY MINUS: ------------------------------------------------------------------------ Tell me if I missed a case here... Poking around in the code some more, I noticed another bug. The following C code: ------------------------------------------------------------------------ float x = (int) 2.3 / 3.2; ------------------------------------------------------------------------ ... will elicit the following complaint from the compiler: ------------------------------------------------------------------------ x.c, line 1: compiler error: expression causes compiler loop: try simplifying ------------------------------------------------------------------------ This bug is again a matter of not simplifying constant expressions in initializers. The fix is in clocal() in pcc/local.c: ------------------------------------------------------------------------ *** /tmp/,RCSt1019533 Tue Aug 28 00:05:36 1984 --- local.c Mon Aug 27 23:32:42 1984 *************** *** 85,91 case SCONV: m = (p->in.type == FLOAT || p->in.type == DOUBLE ); ml = (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE ); ! if( m != ml ) break; /* now, look for conversions downwards */ --- 85,99 ----- case SCONV: m = (p->in.type == FLOAT || p->in.type == DOUBLE ); ml = (p->in.left->in.type == FLOAT || p->in.left->in.type == DOUBLE ); ! if ( ml && !m ) { ! /* float type to int type */ ! r = block( ICON, NULL, NULL, INT, 0, 0 ); ! r->tn.lval = (int) p->in.left->fpn.dval; ! r->tn.rval = NONAME; ! p->in.left->in.op = FREE; ! p->in.left = r; ! } ! else if ( ml != m ) break; /* now, look for conversions downwards */ ------------------------------------------------------------------------ This probably doesn't catch everything... I know of several other ways to give your compiler fits: ------------------------------------------------------------------------ int i = (int) &i / 2; ------------------------------------------------------------------------ A similar but less horrible program also makes the compiler croak: ------------------------------------------------------------------------ int i = 1; int j = 2; int k = &j - &i; ------------------------------------------------------------------------ More fun and games: ------------------------------------------------------------------------ struct { int a, b, c; } x; int i = &x.c - &x.i; ------------------------------------------------------------------------ In the same vein: ------------------------------------------------------------------------ char buf[50]; int i = &buf[40] - &buf[30]; ------------------------------------------------------------------------ Unfortunately I don't know what to do about these... Are they legal C? 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