📄 lint.c
字号:
WERROR( MESSAGE( 21 ) ); if ( htmpname != NULL && p->in.right->tn.lval == 0 ) /* "unsigned comparison with 0?" */ WERROR( MESSAGE( 115 ) ); } break; case COMOP: down1 = EFF; case ANDAND: case OROR: case QUEST: down2 = down; /* go recursively left, then right */ np1 = lnp; lprt( p->in.left, down1, use1, 0 ); np2 = lnp; lprt( p->in.right, down2, use2, 0 ); lmerge( np1, np2, 0 ); return; case SCONV: case PCONV: case COLON: down1 = down2 = down; break; case CALL: case STCALL: case FORTCALL: acount = ctargs( p->in.right ); case UNARY CALL: case UNARY STCALL: case UNARY FORTCALL: if( p->in.left->in.op == ICON && (q = STP(p->in.left->tn.rval)) != NULL ){ /* used to be &name */ int lty; fsave( ftitle ); /* * if we're generating a library -C then * we don't want to output references to functions */ if( Cflag ) break; /* if a function used in an effects context is * cast to type void then consider its value * to have been disposed of properly * thus a call of type void in an effects * context is construed to be used in a value * context */ if (down == EFF) lty = (p->in.type == TVOID) ? LUV | LUE : LUE; else lty = LUV; outdef(q, lty, acount); if( acount ) lpta( p->in.right ); } break; case ICON: /* look for &name case */ if( (q = STP(p->tn.rval)) != NULL ) { q->sflags |= (SREF|SSET); } return; case NAME: if( (q = STP(p->tn.rval)) != NULL ) { if( (uses&VALUSED) && !(q->sflags&SSET) ){ if( q->sclass == AUTO || q->sclass == REGISTER ){ if( !ISARY(q->stype ) && !ISFTN(q->stype) && (q->stype != STRTY || stasg) && q->stype!=UNIONTY ){ /* "%s may be used before set" */ WERROR( MESSAGE( 1 ), q->sname ); q->sflags |= SSET; } } } if( uses & VALASGOP ) break; /* not a real use */ if( uses & VALSET ) q->sflags |= SSET; if( uses & VALUSED ) q->sflags |= SREF; if( uses & VALADDR ) q->sflags |= (SREF|SSET); if( p->tn.lval == 0 ){ lnp->lid = p->tn.rval; lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED); if( ++lnp >= &lnames[LNAMES] ) --lnp; } } return; } if (stasg && (p->in.left->in.type == STRTY)){ if (stasg == STASG_RIGHT) use1 = VALUSED; else if (stasg == STASG_LEFT) use1 = VALSET; } /* recurse, going down the right side first if we can */ switch( optype(p->in.op) ){ case BITYPE: np1 = lnp; lprt( p->in.right, down2, use2, (p->in.op == STASG) ? STASG_RIGHT : 0 ); case UTYPE: np2 = lnp; lprt( p->in.left, down1, use1, (p->in.op == STASG | stasg) ? STASG_LEFT : 0 ); } if( optype(p->in.op) == BITYPE ){ if( p->in.op == ASSIGN && p->in.left->in.op == NAME ) /* special case for a = .. a .. */ lmerge( np1, np2, 0 ); else lmerge( np1, np2, p->in.op != COLON ); /* look for assignments to fields, and complain */ if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p ); }}/* lmerge */lmerge( np1, np2, flag ) struct lnm *np1, *np2;{ /* np1 and np2 point to lists of lnm members, for the two sides * of a binary operator * flag is 1 if commutation is possible, 0 otherwise * lmerge returns a merged list, starting at np1, resetting lnp * it also complains, if appropriate, about side effects */ register struct lnm *npx, *npy; for( npx = np2; npx < lnp; ++npx ){ /* is it already there? */ for( npy = np1; npy < np2; ++npy ){ if( npx->lid == npy->lid ){ /* yes */ if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) ) ; /* do nothing */ else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) || (npx->flgs&npy->flgs&VALSET) ) { struct symtab *q; char *s; q = STP(npy->lid); s = (q == NULL ? "(null)" : q->sname); /* "evaluation order for ``%s'' undefined" */ if( flag ) WERROR( MESSAGE( 0 ), s ); } if( npy->flgs == 0 ) npx->flgs = 0; else npy->flgs |= npx->flgs; goto foundit; } } /* not there: update entry */ np2->lid = npx->lid; np2->flgs = npx->flgs; ++np2; foundit: ; } /* all finished: merged list is at np1 */ lnp = np2;}/* efcode - handle end of a function */efcode(){ /* code for the end of a function */ register struct symtab *cfp; cfp = STP(curftn); if (cfp == NULL) return; if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) ) outdef( cfp, LRV, DECTY ); if( !vflag ){ vflag = argflag; argflag = 0; } if( retstat == RETVAL+NRETVAL ) /* "function %s has return(e); and return;" */ WERROR( MESSAGE( 43 ), cfp->sname); /* * See if main() falls off its end or has just a return; */ if (!strcmp(cfp->sname, "main") && (reached || (retstat & NRETVAL))) /* "main() returns random value to invocation environment" */ WERROR(MESSAGE(127));}/* aocode - called when automatic p is removed from stab */aocode(p) struct symtab *p;{ register struct symtab *cfs; cfs = STP(curftn); if (cfs == NULL) return; if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){ if( p->sclass == PARAM || p->sclass == REGISTER && p->slevel == 1 ) { /* "argument %s unused in function %s" */ if( vflag ) WERROR( MESSAGE( 13 ), p->sname, cfs->sname ); } else /* "%s unused in function %s" */ if( p->sclass != TYPEDEF ) WERROR( MESSAGE( 6 ), p->sname, cfs->sname ); } if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET && !ISARY(p->stype) && !ISFTN(p->stype) ) /* "%s set but not used in function %s" */ WERROR( MESSAGE( 3 ), p->sname, cfs->sname ); if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ) if( !zflag && dimtab[p->sizoff+1] < 0 ){ if (p->stype == ENUMTY) /* "enum %s never defined" */ WERROR( MESSAGE( 104 ), p->sname ); else /* "struct/union %s never defined" */ WERROR( MESSAGE( 102 ), p->sname ); }}/* defname - define the current location as the name p->sname */defnam( p ) register struct symtab *p;{ if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return; if( !ISFTN( p->stype ) ) outdef( p, p->sclass==STATIC? LDS : (libflag?LIB:LDI), USUAL );}#endif /* ifndef CXREF *//* zecode - n integer words of zeros */zecode( n ){ OFFSZ temp; temp = n; inoff += temp*SZINT;}/*ARGSUSED*/mklval( p ) NODE *p; { /* can we make this operand into a legal lvalue, if it isn't one already? One version of pcc does so if it is a cast on the left hand side of an assignment. Since that is highly nonportable, we won't bother. */ return 0; }/* andable - can the NAME node p accept & ? */andable( p ) NODE *p;{ register struct symtab *s; if( p->in.op != NAME ) cerror( "andable error" ); if( p->tn.rval < 0 ) return(1); /* labels are andable */ if( (s = STP(p->tn.rval)) == NULL ) return(0); if( s->sclass == AUTO || s->sclass == PARAM ) return(0); /* "cannot take address of %s" */ if( s->sclass == REGISTER ) UERROR( MESSAGE( 18 ), s->sname ); return(1);}/* clocal - do local checking on tree * (pcc uses this routine to do local tree rewriting) */NODE *clocal(p) NODE *p;{ register o; register TWORD t, tl; int s; switch( o = p->in.op ){ case SCONV: case PCONV: if( p->in.left->in.type==ENUMTY ) p->in.left = pconvert( p->in.left ); /* assume conversion takes place; type is inherited */ t = p->in.type; tl = p->in.left->in.type;#ifndef CXREF/* for the future: put aflag in a place where NAME is available; that is, check * assignment and arithmetic operators for leftchild NAME and rightchild SCONV * so that when message is printed it is possible to name the offending lval * note that the lval may be a temporary (NONAME) */ if( aflag && ( tl == LONG || tl == ULONG ) && t!=LONG && t!=ULONG && t!=TVOID && t!=FLOAT && t!=DOUBLE ) /* "conversion from long may lose accuracy" */ WERROR( MESSAGE( 26 ) ); if( aflag && pflag && tl != LONG && tl != ULONG && tl != FLOAT && tl != DOUBLE && ( t == LONG || t == ULONG ) && p->in.left->in.op != ICON ) /* conversion to long may sign-extend incorrectly */ WERROR( MESSAGE( 27 ) ); if( ISPTR(tl) && ISPTR(t) ){ tl = DECREF(tl); t = DECREF(t); switch( ISFTN(t) + ISFTN(tl) ){ case 0: /* neither is a function pointer */ if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ) { /* "possible pointer alignment problem" */ if( hflag || pflag || (target == sparcAL)) WERROR( MESSAGE( 91 ) ); } break; case 1: /* "questionable conversion of function pointer" */ WERROR( MESSAGE( 95 ) ); case 2: ; } }#endif if (o == SCONV) { /* * Must do integer <-> floating conversions here, so * that if e.g. a floating-point expression cast to * "int" is being used as an array dimension, we check * it properly. */ if( p->in.left->in.op == ICON ) { if( p->in.type == FLOAT || p->in.type == DOUBLE ) { if (ISUNSIGNED(tl)) { p->in.left->fpn.dval = (unsigned)p->in.left->tn.lval; } else { p->in.left->fpn.dval = p->in.left->tn.lval; } p->in.left->in.op = FCON; } } else if( p->in.left->in.op == FCON ) { if( p->in.type != FLOAT && p->in.type != DOUBLE ) { p->in.left->in.op = ICON; p->in.left->tn.lval = (CONSZ)p->in.left->fpn.dval; p->in.left->tn.rval = NONAME; p->in.left->tn.name = (char*)0; } } } p->in.left->in.type = p->in.type; p->in.left->fn.cdim = p->fn.cdim; p->in.left->fn.csiz = p->fn.csiz; p->in.op = FREE; return( p->in.left ); case PVCONV: case PMCONV: if( p->in.right->in.op != ICON ) cerror( "bad conversion"); p->in.op = FREE; return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) ); case RS: case LS: case ASG RS: case ASG LS: if( p->in.right->in.op != ICON ) break; s = p->in.right->tn.lval; if( s < 0 ) /* "negative shift" */ WERROR( MESSAGE( 136 ) ); else if( s >= dimtab[ p->fn.csiz ] ) /* "shift greater than size of object" */ WERROR( MESSAGE( 137 ) ); break; } return(p);}/* offcon - make structure offset node */NODE *offcon( off, t, d, s ) OFFSZ off; TWORD t;{ register NODE *p; p = bcon(0); p->tn.lval = off/SZCHAR; return(p);}/* noinit - return storage class for such as "int a;" */noinit(){ return( pflag ? EXTDEF : EXTERN );}/* cinit - initialize p into size sz */cinit( p, sz ) NODE *p;{ inoff += sz; if( p->in.op == INIT ){ if( p->in.left->in.op == ICON ) return; if( p->in.left->in.op == FCON ) return; if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return; } /* "illegal initialization" */ UERROR( MESSAGE( 61 ) );}#ifndef CXREF/* exname - make a name look like an external name * if checking for portability or if running on gcos or ibm, * truncate name to six characters */char *exname( p ) char *p;{ static char aa[8]; register int i;#if !( ibm | gcos ) if( !pflag ) return(p);#endif for( i=0; i<6; ++i ){ if( isupper(*p ) ) aa[i] = tolower( *p ); else aa[i] = *p; if( *p ) ++p; } aa[6] = '\0'; return( aa );}/* strip - strip full name to get basename */char *strip(s) register char *s;{ static char x[BUFSIZ+1]; register char *p; register char c; /* * Trim off leading quote, if any. */ if (*s == '"') s++; /* * Trim off leading "./"; "cpp" tends to insert it before include * file names. */ if (strncmp(s, "./", 2) == 0) s += 2; /* * Copy until the end of the string or until a trailing quote. */ p = x; while( (c = *s++) != '\0' && c != '"' ){ if ( p > &x[BUFSIZ] ) { /* 5 feb 80: simulate a call to cerror( ) */ fprintf(stderr, "%s: compiler error: filename too long\n", x); exit(1); /* cannot call cerror( ) * because cerror( ) calls where( ) and where( ) calls * strip( ) and this is strip */ } *p++ = c; } *p = '\0'; return( x );}/* fsave - save file name on intermediate file */fsave( s ) char *s; { static union rec fsname; static char buf[BUFSIZ+1]; s = strip( s ); if( strcmp( s, buf ) ){ /* new one */ strcpy( buf, s ); fsname.f.decflag = LFN; fsname.f.mno = getpid(); fwrite( (char *)&fsname, sizeof(fsname), 1, stdout ); fwrite( buf, strlen( buf ) + 1, 1, stdout ); }}#endif /* ifndef CXREF *//* where - print the location of an error * if the filename is a C file (the source file) then just print the lineno * the filename is taken care of in a title * if the file is a header file ( unlikely but possible) * then the filename is printed with the line number of the error * where is called by cerror, uerror and werror * (it is not called by luerror or lwerror) */where( f ) char f;{ extern fprintf( );#ifndef CXREF extern enum boolean iscfile( ); extern char *strip( ); char *filename; extern char *htmpname;#endif if( f == 'u' && nerrors > 1 ) --nerrors; /* don't get "too many errors" */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -