github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/cc/dpchk.c (about) 1 // Inferno utils/cc/dpchk.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 #include <u.h> 32 #include "cc.h" 33 #include "y.tab.h" 34 35 enum 36 { 37 Fnone = 0, 38 Fl, 39 Fvl, 40 Fignor, 41 Fstar, 42 Fadj, 43 44 Fverb = 10, 45 }; 46 47 typedef struct Tprot Tprot; 48 struct Tprot 49 { 50 Type* type; 51 Bits flag; 52 Tprot* link; 53 }; 54 55 typedef struct Tname Tname; 56 struct Tname 57 { 58 char* name; 59 int param; 60 int count; 61 Tname* link; 62 Tprot* prot; 63 }; 64 65 static Type* indchar; 66 static uchar flagbits[512]; 67 static char* lastfmt; 68 static int lastadj; 69 static int lastverb; 70 static int nstar; 71 static Tprot* tprot; 72 static Tname* tname; 73 74 void 75 argflag(int c, int v) 76 { 77 78 switch(v) { 79 case Fignor: 80 case Fstar: 81 case Fl: 82 case Fvl: 83 flagbits[c] = v; 84 break; 85 case Fverb: 86 flagbits[c] = lastverb; 87 /*print("flag-v %c %d\n", c, lastadj);*/ 88 lastverb++; 89 break; 90 case Fadj: 91 flagbits[c] = lastadj; 92 /*print("flag-l %c %d\n", c, lastadj);*/ 93 lastadj++; 94 break; 95 } 96 } 97 98 Bits 99 getflag(char *s) 100 { 101 Bits flag; 102 int f; 103 Fmt fmt; 104 Rune c; 105 106 flag = zbits; 107 nstar = 0; 108 fmtstrinit(&fmt); 109 for(;;) { 110 s += chartorune(&c, s); 111 if(c == 0 || c >= nelem(flagbits)) 112 break; 113 fmtrune(&fmt, c); 114 f = flagbits[c]; 115 switch(f) { 116 case Fnone: 117 argflag(c, Fverb); 118 f = flagbits[c]; 119 break; 120 case Fstar: 121 nstar++; 122 case Fignor: 123 continue; 124 case Fl: 125 if(bset(flag, Fl)) 126 flag = bor(flag, blsh(Fvl)); 127 } 128 flag = bor(flag, blsh(f)); 129 if(f >= Fverb) 130 break; 131 } 132 free(lastfmt); 133 lastfmt = fmtstrflush(&fmt); 134 return flag; 135 } 136 137 static void 138 newprot(Sym *m, Type *t, char *s, Tprot **prot) 139 { 140 Bits flag; 141 Tprot *l; 142 143 if(t == T) { 144 warn(Z, "%s: newprot: type not defined", m->name); 145 return; 146 } 147 flag = getflag(s); 148 for(l=*prot; l; l=l->link) 149 if(beq(flag, l->flag) && sametype(t, l->type)) 150 return; 151 l = alloc(sizeof(*l)); 152 l->type = t; 153 l->flag = flag; 154 l->link = *prot; 155 *prot = l; 156 } 157 158 static Tname* 159 newname(char *s, int p, int count) 160 { 161 Tname *l; 162 163 for(l=tname; l; l=l->link) 164 if(strcmp(l->name, s) == 0) { 165 if(p >= 0 && l->param != p) 166 yyerror("vargck %s already defined\n", s); 167 return l; 168 } 169 if(p < 0) 170 return nil; 171 172 l = alloc(sizeof(*l)); 173 l->name = s; 174 l->param = p; 175 l->link = tname; 176 l->count = count; 177 tname = l; 178 return l; 179 } 180 181 void 182 arginit(void) 183 { 184 int i; 185 186 /* debug['F'] = 1;*/ 187 /* debug['w'] = 1;*/ 188 189 lastadj = Fadj; 190 lastverb = Fverb; 191 indchar = typ(TIND, types[TCHAR]); 192 193 memset(flagbits, Fnone, sizeof(flagbits)); 194 195 for(i='0'; i<='9'; i++) 196 argflag(i, Fignor); 197 argflag('.', Fignor); 198 argflag('#', Fignor); 199 argflag('u', Fignor); 200 argflag('h', Fignor); 201 argflag('+', Fignor); 202 argflag('-', Fignor); 203 204 argflag('*', Fstar); 205 argflag('l', Fl); 206 207 argflag('o', Fverb); 208 flagbits['x'] = flagbits['o']; 209 flagbits['X'] = flagbits['o']; 210 } 211 212 static char* 213 getquoted(void) 214 { 215 int c; 216 Rune r; 217 Fmt fmt; 218 219 c = getnsc(); 220 if(c != '"') 221 return nil; 222 fmtstrinit(&fmt); 223 for(;;) { 224 r = getr(); 225 if(r == '\n') { 226 free(fmtstrflush(&fmt)); 227 return nil; 228 } 229 if(r == '"') 230 break; 231 fmtrune(&fmt, r); 232 } 233 free(lastfmt); 234 lastfmt = fmtstrflush(&fmt); 235 return strdup(lastfmt); 236 } 237 238 void 239 pragvararg(void) 240 { 241 Sym *s; 242 int n, c; 243 char *t; 244 Type *ty; 245 Tname *l; 246 247 if(!debug['F']) 248 goto out; 249 s = getsym(); 250 if(s && strcmp(s->name, "argpos") == 0) 251 goto ckpos; 252 if(s && strcmp(s->name, "type") == 0) 253 goto cktype; 254 if(s && strcmp(s->name, "flag") == 0) 255 goto ckflag; 256 if(s && strcmp(s->name, "countpos") == 0) 257 goto ckcount; 258 yyerror("syntax in #pragma varargck"); 259 goto out; 260 261 ckpos: 262 /*#pragma varargck argpos warn 2*/ 263 s = getsym(); 264 if(s == S) 265 goto bad; 266 n = getnsn(); 267 if(n < 0) 268 goto bad; 269 newname(s->name, n, 0); 270 goto out; 271 272 ckcount: 273 /*#pragma varargck countpos name 2*/ 274 s = getsym(); 275 if(s == S) 276 goto bad; 277 n = getnsn(); 278 if(n < 0) 279 goto bad; 280 newname(s->name, 0, n); 281 goto out; 282 283 ckflag: 284 /*#pragma varargck flag 'c'*/ 285 c = getnsc(); 286 if(c != '\'') 287 goto bad; 288 c = getr(); 289 if(c == '\\') 290 c = getr(); 291 else if(c == '\'') 292 goto bad; 293 if(c == '\n') 294 goto bad; 295 if(getc() != '\'') 296 goto bad; 297 argflag(c, Fignor); 298 goto out; 299 300 cktype: 301 c = getnsc(); 302 unget(c); 303 if(c != '"') { 304 /*#pragma varargck type name int*/ 305 s = getsym(); 306 if(s == S) 307 goto bad; 308 l = newname(s->name, -1, -1); 309 s = getsym(); 310 if(s == S) 311 goto bad; 312 ty = s->type; 313 while((c = getnsc()) == '*') 314 ty = typ(TIND, ty); 315 unget(c); 316 newprot(s, ty, "a", &l->prot); 317 goto out; 318 } 319 320 /*#pragma varargck type O int*/ 321 t = getquoted(); 322 if(t == nil) 323 goto bad; 324 s = getsym(); 325 if(s == S) 326 goto bad; 327 ty = s->type; 328 while((c = getnsc()) == '*') 329 ty = typ(TIND, ty); 330 unget(c); 331 newprot(s, ty, t, &tprot); 332 goto out; 333 334 bad: 335 yyerror("syntax in #pragma varargck"); 336 337 out: 338 while(getnsc() != '\n') 339 ; 340 } 341 342 Node* 343 nextarg(Node *n, Node **a) 344 { 345 if(n == Z) { 346 *a = Z; 347 return Z; 348 } 349 if(n->op == OLIST) { 350 *a = n->left; 351 return n->right; 352 } 353 *a = n; 354 return Z; 355 } 356 357 void 358 checkargs(Node *nn, char *s, int pos) 359 { 360 Node *a, *n; 361 Bits flag; 362 Tprot *l; 363 364 if(!debug['F']) 365 return; 366 n = nn; 367 for(;;) { 368 s = strchr(s, '%'); 369 if(s == 0) { 370 nextarg(n, &a); 371 if(a != Z) 372 warn(nn, "more arguments than format %T", 373 a->type); 374 return; 375 } 376 s++; 377 flag = getflag(s); 378 while(nstar > 0) { 379 n = nextarg(n, &a); 380 pos++; 381 nstar--; 382 if(a == Z) { 383 warn(nn, "more format than arguments %s", 384 lastfmt); 385 return; 386 } 387 if(a->type == T) 388 continue; 389 if(!sametype(types[TINT], a->type) && 390 !sametype(types[TUINT], a->type)) 391 warn(nn, "format mismatch '*' in %s %T, arg %d", 392 lastfmt, a->type, pos); 393 } 394 for(l=tprot; l; l=l->link) 395 if(sametype(types[TVOID], l->type)) { 396 if(beq(flag, l->flag)) { 397 s++; 398 goto loop; 399 } 400 } 401 402 n = nextarg(n, &a); 403 pos++; 404 if(a == Z) { 405 warn(nn, "more format than arguments %s", 406 lastfmt); 407 return; 408 } 409 if(a->type == 0) 410 continue; 411 for(l=tprot; l; l=l->link) 412 if(sametype(a->type, l->type)) { 413 /*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ 414 if(beq(flag, l->flag)) 415 goto loop; 416 } 417 warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos); 418 loop:; 419 } 420 } 421 422 void 423 dpcheck(Node *n) 424 { 425 char *s; 426 Node *a, *b; 427 Tname *l; 428 Tprot *tl; 429 int i, j; 430 431 if(n == Z) 432 return; 433 b = n->left; 434 if(b == Z || b->op != ONAME) 435 return; 436 s = b->sym->name; 437 for(l=tname; l; l=l->link) 438 if(strcmp(s, l->name) == 0) 439 break; 440 if(l == 0) 441 return; 442 443 if(l->count > 0) { 444 // fetch count, then check remaining length 445 i = l->count; 446 a = nil; 447 b = n->right; 448 while(i > 0) { 449 b = nextarg(b, &a); 450 i--; 451 } 452 if(a == Z) { 453 diag(n, "can't find count arg"); 454 return; 455 } 456 if(a->op != OCONST || !typechl[a->type->etype]) { 457 diag(n, "count is invalid constant"); 458 return; 459 } 460 j = a->vconst; 461 i = 0; 462 while(b != Z) { 463 b = nextarg(b, &a); 464 i++; 465 } 466 if(i != j) 467 diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j); 468 } 469 470 if(l->prot != nil) { 471 // check that all arguments after param or count 472 // are listed in type list. 473 i = l->count; 474 if(i == 0) 475 i = l->param; 476 if(i == 0) 477 return; 478 a = nil; 479 b = n->right; 480 while(i > 0) { 481 b = nextarg(b, &a); 482 i--; 483 } 484 if(a == Z) { 485 diag(n, "can't find count/param arg"); 486 return; 487 } 488 while(b != Z) { 489 b = nextarg(b, &a); 490 for(tl=l->prot; tl; tl=tl->link) 491 if(sametype(a->type, tl->type)) 492 break; 493 if(tl == nil) 494 diag(a, "invalid type %T in call to %s", a->type, s); 495 } 496 } 497 498 if(l->param <= 0) 499 return; 500 i = l->param; 501 a = nil; 502 b = n->right; 503 while(i > 0) { 504 b = nextarg(b, &a); 505 i--; 506 } 507 if(a == Z) { 508 diag(n, "can't find format arg"); 509 return; 510 } 511 if(!sametype(indchar, a->type)) { 512 diag(n, "format arg type %T", a->type); 513 return; 514 } 515 if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { 516 /* warn(n, "format arg not constant string");*/ 517 return; 518 } 519 s = a->left->cstring; 520 checkargs(b, s, l->param); 521 } 522 523 void 524 pragpack(void) 525 { 526 Sym *s; 527 528 packflg = 0; 529 s = getsym(); 530 if(s) { 531 packflg = atoi(s->name+1); 532 if(strcmp(s->name, "on") == 0 || 533 strcmp(s->name, "yes") == 0) 534 packflg = 1; 535 } 536 while(getnsc() != '\n') 537 ; 538 if(debug['f']) 539 if(packflg) 540 print("%4d: pack %d\n", lineno, packflg); 541 else 542 print("%4d: pack off\n", lineno); 543 } 544 545 void 546 pragfpround(void) 547 { 548 Sym *s; 549 550 fproundflg = 0; 551 s = getsym(); 552 if(s) { 553 fproundflg = atoi(s->name+1); 554 if(strcmp(s->name, "on") == 0 || 555 strcmp(s->name, "yes") == 0) 556 fproundflg = 1; 557 } 558 while(getnsc() != '\n') 559 ; 560 if(debug['f']) 561 if(fproundflg) 562 print("%4d: fproundflg %d\n", lineno, fproundflg); 563 else 564 print("%4d: fproundflg off\n", lineno); 565 } 566 567 void 568 pragtextflag(void) 569 { 570 Sym *s; 571 572 s = getsym(); 573 if(s == S) { 574 textflag = getnsn(); 575 } else { 576 if(s->macro) { 577 macexpand(s, symb); 578 } 579 if(symb[0] < '0' || symb[0] > '9') 580 yyerror("pragma textflag not an integer"); 581 textflag = atoi(symb); 582 } 583 while(getnsc() != '\n') 584 ; 585 if(debug['f']) 586 print("%4d: textflag %d\n", lineno, textflag); 587 } 588 589 void 590 pragdataflag(void) 591 { 592 Sym *s; 593 594 s = getsym(); 595 if(s == S) { 596 dataflag = getnsn(); 597 } else { 598 if(s->macro) { 599 macexpand(s, symb); 600 } 601 if(symb[0] < '0' || symb[0] > '9') 602 yyerror("pragma dataflag not an integer"); 603 dataflag = atoi(symb); 604 } 605 while(getnsc() != '\n') 606 ; 607 if(debug['f']) 608 print("%4d: dataflag %d\n", lineno, dataflag); 609 } 610 611 void 612 pragincomplete(void) 613 { 614 Sym *s; 615 Type *t; 616 int istag, w, et; 617 618 istag = 0; 619 s = getsym(); 620 if(s == nil) 621 goto out; 622 et = 0; 623 w = s->lexical; 624 if(w == LSTRUCT) 625 et = TSTRUCT; 626 else if(w == LUNION) 627 et = TUNION; 628 if(et != 0){ 629 s = getsym(); 630 if(s == nil){ 631 yyerror("missing struct/union tag in pragma incomplete"); 632 goto out; 633 } 634 if(s->lexical != LNAME && s->lexical != LTYPE){ 635 yyerror("invalid struct/union tag: %s", s->name); 636 goto out; 637 } 638 dotag(s, et, 0); 639 istag = 1; 640 }else if(strcmp(s->name, "_off_") == 0){ 641 debug['T'] = 0; 642 goto out; 643 }else if(strcmp(s->name, "_on_") == 0){ 644 debug['T'] = 1; 645 goto out; 646 } 647 t = s->type; 648 if(istag) 649 t = s->suetag; 650 if(t == T) 651 yyerror("unknown type %s in pragma incomplete", s->name); 652 else if(!typesu[t->etype]) 653 yyerror("not struct/union type in pragma incomplete: %s", s->name); 654 else 655 t->garb |= GINCOMPLETE; 656 out: 657 while(getnsc() != '\n') 658 ; 659 if(debug['f']) 660 print("%s incomplete\n", s->name); 661 } 662 663 Sym* 664 getimpsym(void) 665 { 666 int c; 667 char *cp; 668 669 c = getnsc(); 670 if(isspace(c) || c == '"') { 671 unget(c); 672 return S; 673 } 674 for(cp = symb;;) { 675 if(cp <= symb+NSYMB-4) 676 *cp++ = c; 677 c = getc(); 678 if(c > 0 && !isspace(c) && c != '"') 679 continue; 680 unget(c); 681 break; 682 } 683 *cp = 0; 684 if(cp > symb+NSYMB-4) 685 yyerror("symbol too large: %s", symb); 686 return lookup(); 687 } 688 689 static int 690 more(void) 691 { 692 int c; 693 694 do 695 c = getnsc(); 696 while(c == ' ' || c == '\t'); 697 unget(c); 698 return c != '\n'; 699 } 700 701 void 702 pragcgo(char *verb) 703 { 704 Sym *local, *remote; 705 char *p; 706 707 if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) { 708 p = getquoted(); 709 if(p == nil) 710 goto err1; 711 fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p); 712 goto out; 713 714 err1: 715 yyerror("usage: #pragma cgo_dynamic_linker \"path\""); 716 goto out; 717 } 718 719 if(strcmp(verb, "dynexport") == 0) 720 verb = "cgo_export_dynamic"; 721 if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) { 722 local = getimpsym(); 723 if(local == nil) 724 goto err2; 725 if(!more()) { 726 fmtprint(&pragcgobuf, "%s %q\n", verb, local->name); 727 goto out; 728 } 729 remote = getimpsym(); 730 if(remote == nil) 731 goto err2; 732 fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name); 733 goto out; 734 735 err2: 736 yyerror("usage: #pragma %s local [remote]", verb); 737 goto out; 738 } 739 740 if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) { 741 local = getimpsym(); 742 if(local == nil) 743 goto err3; 744 if(!more()) { 745 fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local->name); 746 goto out; 747 } 748 remote = getimpsym(); 749 if(remote == nil) 750 goto err3; 751 if(!more()) { 752 fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local->name, remote->name); 753 goto out; 754 } 755 p = getquoted(); 756 if(p == nil) 757 goto err3; 758 fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local->name, remote->name, p); 759 goto out; 760 761 err3: 762 yyerror("usage: #pragma cgo_import_dynamic local [remote [\"library\"]]"); 763 goto out; 764 } 765 766 if(strcmp(verb, "cgo_import_static") == 0) { 767 local = getimpsym(); 768 if(local == nil) 769 goto err4; 770 fmtprint(&pragcgobuf, "cgo_import_static %q\n", local->name); 771 goto out; 772 773 err4: 774 yyerror("usage: #pragma cgo_import_static local [remote]"); 775 goto out; 776 } 777 778 if(strcmp(verb, "cgo_ldflag") == 0) { 779 p = getquoted(); 780 if(p == nil) 781 goto err5; 782 fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p); 783 goto out; 784 785 err5: 786 yyerror("usage: #pragma cgo_ldflag \"arg\""); 787 goto out; 788 } 789 790 out: 791 while(getnsc() != '\n') 792 ; 793 }