github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/cmd/gc/export.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include <u.h> 6 #include <libc.h> 7 #include "go.h" 8 #include "y.tab.h" 9 10 static void dumpexporttype(Type *t); 11 12 // Mark n's symbol as exported 13 void 14 exportsym(Node *n) 15 { 16 if(n == N || n->sym == S) 17 return; 18 if(n->sym->flags & (SymExport|SymPackage)) { 19 if(n->sym->flags & SymPackage) 20 yyerror("export/package mismatch: %S", n->sym); 21 return; 22 } 23 n->sym->flags |= SymExport; 24 25 if(debug['E']) 26 print("export symbol %S\n", n->sym); 27 exportlist = list(exportlist, n); 28 } 29 30 int 31 exportname(char *s) 32 { 33 Rune r; 34 35 if((uchar)s[0] < Runeself) 36 return 'A' <= s[0] && s[0] <= 'Z'; 37 chartorune(&r, s); 38 return isupperrune(r); 39 } 40 41 static int 42 initname(char *s) 43 { 44 return strcmp(s, "init") == 0; 45 } 46 47 // exportedsym reports whether a symbol will be visible 48 // to files that import our package. 49 static int 50 exportedsym(Sym *sym) 51 { 52 // Builtins are visible everywhere. 53 if(sym->pkg == builtinpkg || sym->origpkg == builtinpkg) 54 return 1; 55 56 return sym->pkg == localpkg && exportname(sym->name); 57 } 58 59 void 60 autoexport(Node *n, int ctxt) 61 { 62 if(n == N || n->sym == S) 63 return; 64 if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN) 65 return; 66 if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method 67 return; 68 // -A is for cmd/gc/mkbuiltin script, so export everything 69 if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name)) 70 exportsym(n); 71 } 72 73 static void 74 dumppkg(Pkg *p) 75 { 76 char *suffix; 77 78 if(p == nil || p == localpkg || p->exported || p == builtinpkg) 79 return; 80 p->exported = 1; 81 suffix = ""; 82 if(!p->direct) 83 suffix = " // indirect"; 84 Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix); 85 } 86 87 // Look for anything we need for the inline body 88 static void reexportdep(Node *n); 89 static void 90 reexportdeplist(NodeList *ll) 91 { 92 for(; ll ;ll=ll->next) 93 reexportdep(ll->n); 94 } 95 96 static void 97 reexportdep(Node *n) 98 { 99 Type *t; 100 101 if(!n) 102 return; 103 104 //print("reexportdep %+hN\n", n); 105 switch(n->op) { 106 case ONAME: 107 switch(n->class&~PHEAP) { 108 case PFUNC: 109 // methods will be printed along with their type 110 // nodes for T.Method expressions 111 if(n->left && n->left->op == OTYPE) 112 break; 113 // nodes for method calls. 114 if(!n->type || n->type->thistuple > 0) 115 break; 116 // fallthrough 117 case PEXTERN: 118 if(n->sym && !exportedsym(n->sym)) { 119 if(debug['E']) 120 print("reexport name %S\n", n->sym); 121 exportlist = list(exportlist, n); 122 } 123 } 124 break; 125 126 case ODCL: 127 // Local variables in the bodies need their type. 128 t = n->left->type; 129 if(t != types[t->etype] && t != idealbool && t != idealstring) { 130 if(isptr[t->etype]) 131 t = t->type; 132 if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { 133 if(debug['E']) 134 print("reexport type %S from declaration\n", t->sym); 135 exportlist = list(exportlist, t->sym->def); 136 } 137 } 138 break; 139 140 case OLITERAL: 141 t = n->type; 142 if(t != types[n->type->etype] && t != idealbool && t != idealstring) { 143 if(isptr[t->etype]) 144 t = t->type; 145 if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { 146 if(debug['E']) 147 print("reexport literal type %S\n", t->sym); 148 exportlist = list(exportlist, t->sym->def); 149 } 150 } 151 // fallthrough 152 case OTYPE: 153 if(n->sym && !exportedsym(n->sym)) { 154 if(debug['E']) 155 print("reexport literal/type %S\n", n->sym); 156 exportlist = list(exportlist, n); 157 } 158 break; 159 160 // for operations that need a type when rendered, put the type on the export list. 161 case OCONV: 162 case OCONVIFACE: 163 case OCONVNOP: 164 case ORUNESTR: 165 case OARRAYBYTESTR: 166 case OARRAYRUNESTR: 167 case OSTRARRAYBYTE: 168 case OSTRARRAYRUNE: 169 case ODOTTYPE: 170 case ODOTTYPE2: 171 case OSTRUCTLIT: 172 case OARRAYLIT: 173 case OPTRLIT: 174 case OMAKEMAP: 175 case OMAKESLICE: 176 case OMAKECHAN: 177 t = n->type; 178 if(!t->sym && t->type) 179 t = t->type; 180 if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { 181 if(debug['E']) 182 print("reexport type for expression %S\n", t->sym); 183 exportlist = list(exportlist, t->sym->def); 184 } 185 break; 186 } 187 188 reexportdep(n->left); 189 reexportdep(n->right); 190 reexportdeplist(n->list); 191 reexportdeplist(n->rlist); 192 reexportdeplist(n->ninit); 193 reexportdep(n->ntest); 194 reexportdep(n->nincr); 195 reexportdeplist(n->nbody); 196 reexportdeplist(n->nelse); 197 } 198 199 200 static void 201 dumpexportconst(Sym *s) 202 { 203 Node *n; 204 Type *t; 205 206 n = s->def; 207 typecheck(&n, Erv); 208 if(n == N || n->op != OLITERAL) 209 fatal("dumpexportconst: oconst nil: %S", s); 210 211 t = n->type; // may or may not be specified 212 dumpexporttype(t); 213 214 if(t != T && !isideal(t)) 215 Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val); 216 else 217 Bprint(bout, "\tconst %#S = %#V\n", s, &n->val); 218 } 219 220 static void 221 dumpexportvar(Sym *s) 222 { 223 Node *n; 224 Type *t; 225 226 n = s->def; 227 typecheck(&n, Erv|Ecall); 228 if(n == N || n->type == T) { 229 yyerror("variable exported but not defined: %S", s); 230 return; 231 } 232 233 t = n->type; 234 dumpexporttype(t); 235 236 if(t->etype == TFUNC && n->class == PFUNC) { 237 if (n->inl) { 238 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 239 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 240 if(debug['l'] < 2) 241 typecheckinl(n); 242 // NOTE: The space after %#S here is necessary for ld's export data parser. 243 Bprint(bout, "\tfunc %#S %#hT { %#H }\n", s, t, n->inl); 244 reexportdeplist(n->inl); 245 } else 246 Bprint(bout, "\tfunc %#S %#hT\n", s, t); 247 } else 248 Bprint(bout, "\tvar %#S %#T\n", s, t); 249 } 250 251 static int 252 methcmp(const void *va, const void *vb) 253 { 254 Type *a, *b; 255 256 a = *(Type**)va; 257 b = *(Type**)vb; 258 return strcmp(a->sym->name, b->sym->name); 259 } 260 261 static void 262 dumpexporttype(Type *t) 263 { 264 Type *f; 265 Type **m; 266 int i, n; 267 268 if(t == T) 269 return; 270 if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype) 271 return; 272 t->printed = 1; 273 274 if(t->sym != S && t->etype != TFIELD) 275 dumppkg(t->sym->pkg); 276 277 dumpexporttype(t->type); 278 dumpexporttype(t->down); 279 280 if (t->sym == S || t->etype == TFIELD) 281 return; 282 283 n = 0; 284 for(f=t->method; f!=T; f=f->down) { 285 dumpexporttype(f); 286 n++; 287 } 288 289 m = mal(n*sizeof m[0]); 290 i = 0; 291 for(f=t->method; f!=T; f=f->down) 292 m[i++] = f; 293 qsort(m, n, sizeof m[0], methcmp); 294 295 Bprint(bout, "\ttype %#S %#lT\n", t->sym, t); 296 for(i=0; i<n; i++) { 297 f = m[i]; 298 if(f->nointerface) 299 Bprint(bout, "\t//go:nointerface\n"); 300 if (f->type->nname && f->type->nname->inl) { // nname was set by caninl 301 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 302 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 303 if(debug['l'] < 2) 304 typecheckinl(f->type->nname); 305 Bprint(bout, "\tfunc (%#T) %#hhS %#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl); 306 reexportdeplist(f->type->nname->inl); 307 } else 308 Bprint(bout, "\tfunc (%#T) %#hhS %#hT\n", getthisx(f->type)->type, f->sym, f->type); 309 } 310 } 311 312 static void 313 dumpsym(Sym *s) 314 { 315 if(s->flags & SymExported) 316 return; 317 s->flags |= SymExported; 318 319 if(s->def == N) { 320 yyerror("unknown export symbol: %S", s); 321 return; 322 } 323 // print("dumpsym %O %+S\n", s->def->op, s); 324 dumppkg(s->pkg); 325 326 switch(s->def->op) { 327 default: 328 yyerror("unexpected export symbol: %O %S", s->def->op, s); 329 break; 330 331 case OLITERAL: 332 dumpexportconst(s); 333 break; 334 335 case OTYPE: 336 if(s->def->type->etype == TFORW) 337 yyerror("export of incomplete type %S", s); 338 else 339 dumpexporttype(s->def->type); 340 break; 341 342 case ONAME: 343 dumpexportvar(s); 344 break; 345 } 346 } 347 348 void 349 dumpexport(void) 350 { 351 NodeList *l; 352 int32 i, lno; 353 Pkg *p; 354 355 lno = lineno; 356 357 Bprint(bout, "\n$$\npackage %s", localpkg->name); 358 if(safemode) 359 Bprint(bout, " safe"); 360 Bprint(bout, "\n"); 361 362 for(i=0; i<nelem(phash); i++) 363 for(p=phash[i]; p; p=p->link) 364 if(p->direct) 365 dumppkg(p); 366 367 for(l=exportlist; l; l=l->next) { 368 lineno = l->n->lineno; 369 dumpsym(l->n->sym); 370 } 371 372 Bprint(bout, "\n$$\n"); 373 lineno = lno; 374 } 375 376 /* 377 * import 378 */ 379 380 /* 381 * return the sym for ss, which should match lexical 382 */ 383 Sym* 384 importsym(Sym *s, int op) 385 { 386 char *pkgstr; 387 388 if(s->def != N && s->def->op != op) { 389 pkgstr = smprint("during import \"%Z\"", importpkg->path); 390 redeclare(s, pkgstr); 391 } 392 393 // mark the symbol so it is not reexported 394 if(s->def == N) { 395 if(exportname(s->name) || initname(s->name)) 396 s->flags |= SymExport; 397 else 398 s->flags |= SymPackage; // package scope 399 } 400 return s; 401 } 402 403 /* 404 * return the type pkg.name, forward declaring if needed 405 */ 406 Type* 407 pkgtype(Sym *s) 408 { 409 Type *t; 410 411 importsym(s, OTYPE); 412 if(s->def == N || s->def->op != OTYPE) { 413 t = typ(TFORW); 414 t->sym = s; 415 s->def = typenod(t); 416 } 417 if(s->def->type == T) 418 yyerror("pkgtype %S", s); 419 return s->def->type; 420 } 421 422 void 423 importimport(Sym *s, Strlit *z) 424 { 425 // Informational: record package name 426 // associated with import path, for use in 427 // human-readable messages. 428 Pkg *p; 429 430 if(isbadimport(z)) 431 errorexit(); 432 p = mkpkg(z); 433 if(p->name == nil) { 434 p->name = s->name; 435 pkglookup(s->name, nil)->npkg++; 436 } else if(strcmp(p->name, s->name) != 0) 437 yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path); 438 439 if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) { 440 yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z); 441 errorexit(); 442 } 443 } 444 445 void 446 importconst(Sym *s, Type *t, Node *n) 447 { 448 Node *n1; 449 450 importsym(s, OLITERAL); 451 convlit(&n, t); 452 453 if(s->def != N) // TODO: check if already the same. 454 return; 455 456 if(n->op != OLITERAL) { 457 yyerror("expression must be a constant"); 458 return; 459 } 460 461 if(n->sym != S) { 462 n1 = nod(OXXX, N, N); 463 *n1 = *n; 464 n = n1; 465 } 466 n->orig = newname(s); 467 n->sym = s; 468 declare(n, PEXTERN); 469 470 if(debug['E']) 471 print("import const %S\n", s); 472 } 473 474 void 475 importvar(Sym *s, Type *t) 476 { 477 Node *n; 478 479 importsym(s, ONAME); 480 if(s->def != N && s->def->op == ONAME) { 481 if(eqtype(t, s->def->type)) 482 return; 483 yyerror("inconsistent definition for var %S during import\n\t%T (in \"%Z\")\n\t%T (in \"%Z\")", s, s->def->type, s->importdef->path, t, importpkg->path); 484 } 485 n = newname(s); 486 s->importdef = importpkg; 487 n->type = t; 488 declare(n, PEXTERN); 489 490 if(debug['E']) 491 print("import var %S %lT\n", s, t); 492 } 493 494 void 495 importtype(Type *pt, Type *t) 496 { 497 Node *n; 498 499 // override declaration in unsafe.go for Pointer. 500 // there is no way in Go code to define unsafe.Pointer 501 // so we have to supply it. 502 if(incannedimport && 503 strcmp(importpkg->name, "unsafe") == 0 && 504 strcmp(pt->nod->sym->name, "Pointer") == 0) { 505 t = types[TUNSAFEPTR]; 506 } 507 508 if(pt->etype == TFORW) { 509 n = pt->nod; 510 copytype(pt->nod, t); 511 pt->nod = n; // unzero nod 512 pt->sym->importdef = importpkg; 513 pt->sym->lastlineno = parserline(); 514 declare(n, PEXTERN); 515 checkwidth(pt); 516 } else if(!eqtype(pt->orig, t)) 517 yyerror("inconsistent definition for type %S during import\n\t%lT (in \"%Z\")\n\t%lT (in \"%Z\")", pt->sym, pt, pt->sym->importdef->path, t, importpkg->path); 518 519 if(debug['E']) 520 print("import type %T %lT\n", pt, t); 521 }