Research V7 development
[unix-history] / usr / src / cmd / lint / lint.c
CommitLineData
d4674c91
SJ
1# include "mfile1"
2
3# include "lmanifest"
4
5# include <ctype.h>
6
7# define VAL 0
8# define EFF 1
9
10/* these are appropriate for the -p flag */
11int SZCHAR = 8;
12int SZINT = 16;
13int SZFLOAT = 32;
14int SZDOUBLE = 64;
15int SZLONG = 32;
16int SZSHORT = 16;
17int SZPOINT = 16;
18int ALCHAR = 8;
19int ALINT = 16;
20int ALFLOAT = 32;
21int ALDOUBLE = 64;
22int ALLONG = 32;
23int ALSHORT = 16;
24int ALPOINT = 16;
25int ALSTRUCT = 16;
26
27int vflag = 1; /* tell about unused argments */
28int xflag = 0; /* tell about unused externals */
29int argflag = 0; /* used to turn off complaints about arguments */
30int libflag = 0; /* used to generate library descriptions */
31int vaflag = -1; /* used to signal functions with a variable number of args */
32int aflag = 0; /* used th check precision of assignments */
33
34char *flabel = "xxx";
35
36# define LNAMES 100
37
38struct lnm {
39 short lid, flgs;
40 } lnames[LNAMES], *lnp;
41
42contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
43
44 *pl = *pr = VAL;
45 switch( p->op ){
46
47 case ANDAND:
48 case OROR:
49 case QUEST:
50 *pr = down;
51 break;
52
53 case SCONV:
54 case PCONV:
55 case COLON:
56 *pr = *pl = down;
57 break;
58
59 case COMOP:
60 *pl = EFF;
61 *pr = down;
62
63 case FORCE:
64 case INIT:
65 case UNARY CALL:
66 case STCALL:
67 case UNARY STCALL:
68 case CALL:
69 case UNARY FORTCALL:
70 case FORTCALL:
71 case CBRANCH:
72 break;
73
74 default:
75 if( asgop(p->op) ) break;
76 if( p->op == UNARY MUL && ( p->type == STRTY || p->type == UNIONTY) ) {
77 break; /* the compiler does this... */
78 }
79 if( down == EFF && hflag ) werror( "null effect" );
80
81 }
82 }
83
84ecode( p ) NODE *p; {
85 /* compile code for p */
86
87 fwalk( p, contx, EFF );
88 lnp = lnames;
89 lprt( p, EFF, 0 );
90 }
91
92ejobcode( flag ){
93 /* called after processing each job */
94 /* flag is nonzero if errors were detected */
95 register k;
96 register struct symtab *p;
97
98 for( p=stab; p< &stab[SYMTSZ]; ++p ){
99
100 if( p->stype != TNULL ) {
101
102 if( p->stype == STRTY || p->stype == UNIONTY ){
103 if( dimtab[p->sizoff+1] < 0 ){ /* never defined */
104 if( hflag ) werror( "struct/union %.7s never defined", p->sname );
105 }
106 }
107
108 switch( p->sclass ){
109
110 case STATIC:
111 if( p->suse > 0 ){
112 k = lineno;
113 lineno = p->suse;
114 uerror( "static variable %s unused",
115 p->sname );
116 lineno = k;
117 break;
118 }
119
120 case EXTERN:
121 case USTATIC:
122 /* with the xflag, worry about externs not used */
123 /* the filename may be wrong here... */
124 if( xflag && p->suse >= 0 && !libflag ){
125 printf( "%.7s\t%03d\t%o\t%d\t", p->sname, LDX, p->stype, 0 );
126 /* we don't really know the file number; we know only the line
127 number, so we put only that out */
128 printf( "\"???\"\t%d\t%s\n", p->suse, flabel );
129 }
130
131 case EXTDEF:
132 if( p->suse < 0 ){ /* used */
133 printf( "%.7s\t%03d\t%o\t%d\t", exname(p->sname), LUM, p->stype, 0 );
134 fident( -p->suse );
135 }
136 break;
137 }
138
139 }
140
141 }
142 exit( 0 );
143 }
144
145fident( line ){ /* like ident, but lineno = line */
146 register temp;
147 temp = lineno;
148 lineno = line;
149 ident();
150 lineno = temp;
151 }
152
153ident(){ /* write out file and line identification */
154 printf( "%s\t%d\t%s\n", ftitle, lineno, flabel );
155 }
156
157bfcode( a, n ) int a[]; {
158 /* code for the beginning of a function; a is an array of
159 indices in stab for the arguments; n is the number */
160 /* this must also set retlab */
161 register i;
162 register struct symtab *cfp;
163 register unsigned t;
164
165 retlab = 1;
166 cfp = &stab[curftn];
167
168 /* if variable number of arguments, only print the ones which will be checked */
169 if( vaflag > 0 ){
170 if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
171 else n = vaflag;
172 }
173 printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp->sname), libflag?LIB:LDI,
174 cfp->stype, vaflag>=0?-n:n );
175 vaflag = -1;
176
177 for( i=0; i<n; ++i ) {
178 switch( t = stab[a[i]].stype ){
179
180 case ULONG:
181 break;
182
183 case CHAR:
184 case SHORT:
185 t = INT;
186 break;
187
188 case UCHAR:
189 case USHORT:
190 case UNSIGNED:
191 t = UNSIGNED;
192 break;
193
194 }
195
196 printf( "%o\t", t );
197 }
198 ident();
199 }
200
201ctargs( p ) NODE *p; {
202 /* count arguments; p points to at least one */
203 /* the arguemnts are a tower of commasto the left */
204 register c;
205 c = 1; /* count the rhs */
206 while( p->op == CM ){
207 ++c;
208 p = p->left;
209 }
210 return( c );
211 }
212
213lpta( p ) NODE *p; {
214 TWORD t;
215
216 if( p->op == CM ){
217 lpta( p->left );
218 p = p->right;
219 }
220 switch( t = p->type ){
221
222 case CHAR:
223 case SHORT:
224 t = INT;
225 case LONG:
226 case ULONG:
227 case INT:
228 case UNSIGNED:
229 break;
230
231 case UCHAR:
232 case USHORT:
233 t = UNSIGNED;
234 break;
235
236 case FLOAT:
237 printf( "%o\t", DOUBLE );
238 return;
239
240 default:
241 printf( "%o\t", p->type );
242 return;
243 }
244
245 if( p->op == ICON ) printf( "%o<1\t", t );
246 else printf( "%o\t", t );
247 }
248
249# define VALSET 1
250# define VALUSED 2
251# define VALASGOP 4
252# define VALADDR 8
253
254lprt( p, down, uses ) register NODE *p; {
255 register struct symtab *q;
256 register id;
257 register acount;
258 register down1, down2;
259 register use1, use2;
260 register struct lnm *np1, *np2;
261
262 /* first, set variables which are set... */
263
264 use1 = use2 = VALUSED;
265 if( p->op == ASSIGN ) use1 = VALSET;
266 else if( p->op == UNARY AND ) use1 = VALADDR;
267 else if( asgop( p->op ) ){ /* =ops */
268 use1 = VALUSED|VALSET;
269 if( down == EFF ) use1 |= VALASGOP;
270 }
271
272
273 /* print the lines for lint */
274
275 down2 = down1 = VAL;
276 acount = 0;
277
278 switch( p->op ){
279
280 case EQ:
281 case NE:
282 case GT:
283 case GE:
284 case LT:
285 case LE:
286 if( p->left->type == CHAR && p->right->op==ICON && p->right->lval < 0 ){
287 werror( "nonportable character comparison" );
288 }
289 if( (p->op==EQ || p->op==NE ) && ISUNSIGNED(p->left->type) && p->right->op == ICON ){
290 if( p->right->lval < 0 && p->right->rval == NONAME && !ISUNSIGNED(p->right->type) ){
291 werror( "comparison of unsigned with negative constant" );
292 }
293 }
294 break;
295
296 case UGE:
297 case ULT:
298 if( p->right->op == ICON && p->right->lval == 0 && p->right->rval == NONAME ){
299 werror( "unsigned comparison with 0?" );
300 break;
301 }
302 case UGT:
303 case ULE:
304 if( p->right->op == ICON && p->right->lval <= 0 && !ISUNSIGNED(p->right->type) && p->right->rval == NONAME ){
305 werror( "degenerate unsigned comparison" );
306 }
307 break;
308
309 case COMOP:
310 down1 = EFF;
311
312 case ANDAND:
313 case OROR:
314 case QUEST:
315 down2 = down;
316 /* go recursively left, then right */
317 np1 = lnp;
318 lprt( p->left, down1, use1 );
319 np2 = lnp;
320 lprt( p->right, down2, use2 );
321 lmerge( np1, np2, 0 );
322 return;
323
324 case SCONV:
325 case PCONV:
326 case COLON:
327 down1 = down2 = down;
328 break;
329
330 case CALL:
331 case STCALL:
332 case FORTCALL:
333 acount = ctargs( p->right );
334 case UNARY CALL:
335 case UNARY STCALL:
336 case UNARY FORTCALL:
337 if( p->left->op == ICON && (id=p->left->rval) != NONAME ){ /* used to be &name */
338 printf( "%.7s\t%03d\t%o\t%d\t",
339 exname(stab[id].sname),
340 down==EFF ? LUE : LUV,
341 DECREF(p->left->type), acount );
342 if( acount ) lpta( p->right );
343 ident();
344 }
345 break;
346
347 case ICON:
348 /* look for &name case */
349 if( (id = p->rval) >= 0 && id != NONAME ){
350 q = &stab[id];
351 q->sflags |= (SREF|SSET);
352 }
353 return;
354
355 case NAME:
356 if( (id = p->rval) >= 0 && id != NONAME ){
357 q = &stab[id];
358 if( (uses&VALUSED) && !(q->sflags&SSET) ){
359 if( q->sclass == AUTO || q->sclass == REGISTER ){
360 if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY ){
361 werror( "%.7s may be used before set", q->sname );
362 q->sflags |= SSET;
363 }
364 }
365 }
366 if( uses & VALASGOP ) break; /* not a real use */
367 if( uses & VALSET ) q->sflags |= SSET;
368 if( uses & VALUSED ) q->sflags |= SREF;
369 if( uses & VALADDR ) q->sflags |= (SREF|SSET);
370 if( p->lval == 0 ){
371 lnp->lid = id;
372 lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
373 if( ++lnp >= &lnames[LNAMES] ) --lnp;
374 }
375 }
376 return;
377
378 }
379
380 /* recurse, going down the right side first if we can */
381
382 switch( optype(p->op) ){
383
384 case BITYPE:
385 np1 = lnp;
386 lprt( p->right, down2, use2 );
387 case UTYPE:
388 np2 = lnp;
389 lprt( p->left, down1, use1 );
390 }
391
392 if( optype(p->op) == BITYPE ){
393 if( p->op == ASSIGN && p->left->op == NAME ){ /* special case for a = .. a .. */
394 lmerge( np1, np2, 0 );
395 }
396 else lmerge( np1, np2, p->op != COLON );
397 /* look for assignments to fields, and complain */
398 if( p->op == ASSIGN && p->left->op == FLD && p->right->op == ICON ) fldcon( p );
399 }
400
401 }
402
403lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
404 /* np1 and np2 point to lists of lnm members, for the two sides
405 * of a binary operator
406 * flag is 1 if commutation is possible, 0 otherwise
407 * lmerge returns a merged list, starting at np1, resetting lnp
408 * it also complains, if appropriate, about side effects
409 */
410
411 register struct lnm *npx, *npy;
412
413 for( npx = np2; npx < lnp; ++npx ){
414
415 /* is it already there? */
416 for( npy = np1; npy < np2; ++npy ){
417 if( npx->lid == npy->lid ){ /* yes */
418 if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
419 ; /* do nothing */
420 else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
421 (npx->flgs&npy->flgs&VALSET) ){
422 if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
423 }
424 if( npy->flgs == 0 ) npx->flgs = 0;
425 else npy->flgs |= npx->flgs;
426 goto foundit;
427 }
428 }
429
430 /* not there: update entry */
431 np2->lid = npx->lid;
432 np2->flgs = npx->flgs;
433 ++np2;
434
435 foundit: ;
436 }
437
438 /* all finished: merged list is at np1 */
439 lnp = np2;
440 }
441
442efcode(){
443 /* code for the end of a function */
444 register struct symtab *cfp;
445
446 cfp = &stab[curftn];
447 if( retstat & RETVAL ){
448 printf( "%.7s\t%03d\t%o\t%d\t", exname(cfp->sname),
449 LRV, DECREF( cfp->stype), 0 );
450 ident();
451 }
452 if( !vflag ){
453 vflag = argflag;
454 argflag = 0;
455 }
456 if( retstat == RETVAL+NRETVAL )
457 werror( "function %.8s has return(e); and return;", cfp->sname);
458 }
459
460aocode(p) struct symtab *p; {
461 /* called when automatic p removed from stab */
462 register struct symtab *cfs;
463 cfs = &stab[curftn];
464 if(p->suse>0 && !(p->sflags&SMOS) ){
465 if( p->sclass == PARAM ){
466 if( vflag ) werror( "argument %.7s unused in function %.7s",
467 p->sname,
468 cfs->sname );
469 }
470 else {
471 if( p->sclass != TYPEDEF ) werror( "%.7s unused in function %.7s",
472 p->sname, cfs->sname );
473 }
474 }
475
476 if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
477 !ISARY(p->stype) && !ISFTN(p->stype) ){
478
479 werror( "%.7s set but not used in function %.7s", p->sname, cfs->sname );
480 }
481
482 if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
483 if( dimtab[p->sizoff+1] < 0 ) werror( "structure %.7s never defined", p->sname );
484 }
485
486 }
487
488defnam( p ) register struct symtab *p; {
489 /* define the current location as the name p->sname */
490
491 if( p->sclass == STATIC && p->slevel>1 ) return;
492
493 if( !ISFTN( p->stype ) ){
494 printf( "%.7s\t%03d\t%o\t%d\t",
495 exname(p->sname), libflag?LIB:LDI, p->stype, 0 );
496 ident();
497 }
498 }
499
500zecode( n ){
501 /* n integer words of zeros */
502 OFFSZ temp;
503 temp = n;
504 inoff += temp*SZINT;
505 ;
506 }
507
508andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */
509 register r;
510
511 if( p->op != NAME ) cerror( "andable error" );
512
513 if( (r = p->rval) < 0 ) return(1); /* labels are andable */
514
515 if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
516 return(1);
517 }
518
519NODE *
520clocal(p) NODE *p; {
521
522 /* this is called to do local transformations on
523 an expression tree preparitory to its being
524 written out in intermediate code.
525 */
526
527 /* the major essential job is rewriting the
528 automatic variables and arguments in terms of
529 REG and OREG nodes */
530 /* conversion ops which are not necessary are also clobbered here */
531 /* in addition, any special features (such as rewriting
532 exclusive or) are easily handled here as well */
533
534 register o;
535 register unsigned t, tl;
536
537 switch( o = p->op ){
538
539 case SCONV:
540 case PCONV:
541 if( p->left->type==ENUMTY ){
542 p->left = pconvert( p->left );
543 }
544 /* assume conversion takes place; type is inherited */
545 t = p->type;
546 tl = p->left->type;
547 if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG) ){
548 werror( "long assignment may lose accuracy" );
549 }
550 if( ISPTR(tl) && ISPTR(t) ){
551 tl = DECREF(tl);
552 t = DECREF(t);
553 switch( ISFTN(t) + ISFTN(tl) ){
554
555 case 0: /* neither is a function pointer */
556 if( talign(t,p->csiz) > talign(tl,p->left->csiz) ){
557 if( hflag||pflag ) werror( "possible pointer alignment problem" );
558 }
559 break;
560
561 case 1:
562 werror( "questionable conversion of function pointer" );
563
564 case 2:
565 ;
566 }
567 }
568 p->left->type = p->type;
569 p->left->cdim = p->cdim;
570 p->left->csiz = p->csiz;
571 p->op = FREE;
572 return( p->left );
573
574 case PVCONV:
575 case PMCONV:
576 if( p->right->op != ICON ) cerror( "bad conversion");
577 p->op = FREE;
578 return( buildtree( o==PMCONV?MUL:DIV, p->left, p->right ) );
579
580 }
581
582 return(p);
583 }
584
585NODE *
586offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */
587 register NODE *p;
588 p = bcon(0);
589 p->lval = off/SZCHAR;
590 return(p);
591 }
592
593noinit(){
594 /* storage class for such as "int a;" */
595 return( pflag ? EXTDEF : EXTERN );
596 }
597
598
599cinit( p, sz ) NODE *p; { /* initialize p into size sz */
600 inoff += sz;
601 if( p->op == INIT ){
602 if( p->left->op == ICON ) return;
603 if( p->left->op == NAME && p->left->type == MOE ) return;
604 }
605 uerror( "illegal initialization" );
606 }
607
608char *
609exname( p ) char *p; {
610 /* make a name look like an external name in the local machine */
611 static char aa[8];
612 register int i;
613
614 if( !pflag ) return(p);
615 for( i=0; i<6; ++i ){
616 if( isupper(*p ) ) aa[i] = tolower( *p );
617 else aa[i] = *p;
618 if( *p ) ++p;
619 }
620 aa[6] = '\0';
621 return( aa );
622 }
623
624where(f){ /* print true location of error */
625 if( f == 'u' && nerrors>1 ) --nerrors; /* don't get "too many errors" */
626 fprintf( stderr, "%s, line %d: ", ftitle, lineno );
627 }
628
629 /* a number of dummy routines, unneeded by lint */
630
631branch(n){;}
632defalign(n){;}
633deflab(n){;}
634bycode(t,i){;}
635cisreg(t){return(1);} /* everyting is a register variable! */
636
637fldty(p) struct symtab *p; {
638 ; /* all types are OK here... */
639 }
640
641fldal(t) unsigned t; { /* field alignment... */
642 if( t == ENUMTY ) return( ALCHAR ); /* this should be thought through better... */
643 if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
644 if( pflag ) uerror( "nonportable field type" );
645 }
646 else uerror( "illegal field type" );
647 return(ALINT);
648 }
649
650main( argc, argv ) char *argv[]; {
651 char *p;
652
653 /* handle options */
654
655 for( p=argv[1]; *p; ++p ){
656
657 switch( *p ){
658
659 case '-':
660 continue;
661
662 case 'L': /* produced by driver program */
663 flabel = p;
664 goto break2;
665
666 case '\0':
667 break;
668
669 case 'b':
670 brkflag = 1;
671 continue;
672
673 case 'p':
674 pflag = 1;
675 continue;
676
677 case 'c':
678 cflag = 1;
679 continue;
680
681 case 's':
682 /* for the moment, -s triggers -h */
683
684 case 'h':
685 hflag = 1;
686 continue;
687
688 case 'v':
689 vflag = 0;
690 continue;
691
692 case 'x':
693 xflag = 1;
694 continue;
695
696 case 'a':
697 aflag = 1;
698 case 'u': /* done in second pass */
699 case 'n': /* done in shell script */
700 continue;
701
702 case 't':
703 werror( "option %c now default: see `man 6 lint'", *p );
704 continue;
705
706 default:
707 uerror( "illegal option: %c", *p );
708 continue;
709
710 }
711 }
712
713 break2:
714 if( !pflag ){ /* set sizes to sizes of target machine */
715# ifdef gcos
716 SZCHAR = ALCHAR = 9;
717# else
718 SZCHAR = ALCHAR = 8;
719# endif
720 SZINT = ALINT = sizeof(int)*SZCHAR;
721 SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
722 SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
723 SZLONG = ALLONG = sizeof(long)*SZCHAR;
724 SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
725 SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
726 ALSTRUCT = ALINT;
727 /* now, fix some things up for various machines (I wish we had "alignof") */
728
729# ifdef pdp11
730 ALLONG = ALDOUBLE = ALFLOAT = ALINT;
731#endif
732# ifdef ibm
733 ALSTRUCT = ALCHAR;
734#endif
735 }
736
737 return( mainp1( argc, argv ) );
738 }
739
740ctype( type ) unsigned type; { /* are there any funny types? */
741 return( type );
742 }
743
744commdec( i ){
745 /* put out a common declaration */
746 register struct symtab *p;
747 p = &stab[i];
748 printf( "%.7s\t%03d\t%o\t%d\t", exname(p->sname), libflag?LIB:LDC, p->stype, 0 );
749 ident();
750 }
751
752isitfloat ( s ) char *s; {
753 /* s is a character string;
754 if floating point is implemented, set dcon to the value of s */
755 /* lint version
756 */
757 dcon = atof( s );
758 return( FCON );
759 }
760
761fldcon( p ) register NODE *p; {
762 /* p is an assignment of a constant to a field */
763 /* check to see if the assignment is going to overflow, or otherwise cause trouble */
764 register s;
765 CONSZ v;
766
767 if( !hflag & !pflag ) return;
768
769 s = UPKFSZ(p->left->rval);
770 v = p->right->lval;
771
772 switch( p->left->type ){
773
774 case CHAR:
775 case INT:
776 case SHORT:
777 case LONG:
778 case ENUMTY:
779 if( v>=0 && (v>>(s-1))==0 ) return;
780 werror( "precision lost in assignment to (possibly sign-extended) field" );
781 default:
782 return;
783
784 case UNSIGNED:
785 case UCHAR:
786 case USHORT:
787 case ULONG:
788 if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
789
790 return;
791 }
792
793 }