github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/gc/export.go (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 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 10 "sort" 11 "unicode" 12 "unicode/utf8" 13 ) 14 15 var asmlist *NodeList 16 17 // Mark n's symbol as exported 18 func exportsym(n *Node) { 19 if n == nil || n.Sym == nil { 20 return 21 } 22 if n.Sym.Flags&(SymExport|SymPackage) != 0 { 23 if n.Sym.Flags&SymPackage != 0 { 24 Yyerror("export/package mismatch: %v", Sconv(n.Sym, 0)) 25 } 26 return 27 } 28 29 n.Sym.Flags |= SymExport 30 31 if Debug['E'] != 0 { 32 fmt.Printf("export symbol %v\n", Sconv(n.Sym, 0)) 33 } 34 exportlist = list(exportlist, n) 35 } 36 37 func exportname(s string) bool { 38 if s[0] < utf8.RuneSelf { 39 return 'A' <= s[0] && s[0] <= 'Z' 40 } 41 r, _ := utf8.DecodeRuneInString(s) 42 return unicode.IsUpper(r) 43 } 44 45 func initname(s string) bool { 46 return s == "init" 47 } 48 49 // exportedsym reports whether a symbol will be visible 50 // to files that import our package. 51 func exportedsym(sym *Sym) bool { 52 // Builtins are visible everywhere. 53 if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg { 54 return true 55 } 56 57 return sym.Pkg == localpkg && exportname(sym.Name) 58 } 59 60 func autoexport(n *Node, ctxt uint8) { 61 if n == nil || n.Sym == nil { 62 return 63 } 64 if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { 65 return 66 } 67 if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method 68 return 69 } 70 71 // -A is for cmd/gc/mkbuiltin script, so export everything 72 if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) { 73 exportsym(n) 74 } 75 if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 { 76 n.Sym.Flags |= SymAsm 77 asmlist = list(asmlist, n) 78 } 79 } 80 81 func dumppkg(p *Pkg) { 82 if p == nil || p == localpkg || p.Exported != 0 || p == builtinpkg { 83 return 84 } 85 p.Exported = 1 86 suffix := "" 87 if p.Direct == 0 { 88 suffix = " // indirect" 89 } 90 fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix) 91 } 92 93 // Look for anything we need for the inline body 94 func reexportdeplist(ll *NodeList) { 95 for ; ll != nil; ll = ll.Next { 96 reexportdep(ll.N) 97 } 98 } 99 100 func reexportdep(n *Node) { 101 if n == nil { 102 return 103 } 104 105 //print("reexportdep %+hN\n", n); 106 switch n.Op { 107 case ONAME: 108 switch n.Class &^ PHEAP { 109 // methods will be printed along with their type 110 // nodes for T.Method expressions 111 case PFUNC: 112 if n.Left != nil && n.Left.Op == OTYPE { 113 break 114 } 115 116 // nodes for method calls. 117 if n.Type == nil || n.Type.Thistuple > 0 { 118 break 119 } 120 fallthrough 121 122 // fallthrough 123 case PEXTERN: 124 if n.Sym != nil && !exportedsym(n.Sym) { 125 if Debug['E'] != 0 { 126 fmt.Printf("reexport name %v\n", Sconv(n.Sym, 0)) 127 } 128 exportlist = list(exportlist, n) 129 } 130 } 131 132 // Local variables in the bodies need their type. 133 case ODCL: 134 t := n.Left.Type 135 136 if t != Types[t.Etype] && t != idealbool && t != idealstring { 137 if Isptr[t.Etype] { 138 t = t.Type 139 } 140 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 141 if Debug['E'] != 0 { 142 fmt.Printf("reexport type %v from declaration\n", Sconv(t.Sym, 0)) 143 } 144 exportlist = list(exportlist, t.Sym.Def) 145 } 146 } 147 148 case OLITERAL: 149 t := n.Type 150 if t != Types[n.Type.Etype] && t != idealbool && t != idealstring { 151 if Isptr[t.Etype] { 152 t = t.Type 153 } 154 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 155 if Debug['E'] != 0 { 156 fmt.Printf("reexport literal type %v\n", Sconv(t.Sym, 0)) 157 } 158 exportlist = list(exportlist, t.Sym.Def) 159 } 160 } 161 fallthrough 162 163 // fallthrough 164 case OTYPE: 165 if n.Sym != nil && !exportedsym(n.Sym) { 166 if Debug['E'] != 0 { 167 fmt.Printf("reexport literal/type %v\n", Sconv(n.Sym, 0)) 168 } 169 exportlist = list(exportlist, n) 170 } 171 172 // for operations that need a type when rendered, put the type on the export list. 173 case OCONV, 174 OCONVIFACE, 175 OCONVNOP, 176 ORUNESTR, 177 OARRAYBYTESTR, 178 OARRAYRUNESTR, 179 OSTRARRAYBYTE, 180 OSTRARRAYRUNE, 181 ODOTTYPE, 182 ODOTTYPE2, 183 OSTRUCTLIT, 184 OARRAYLIT, 185 OPTRLIT, 186 OMAKEMAP, 187 OMAKESLICE, 188 OMAKECHAN: 189 t := n.Type 190 191 if t.Sym == nil && t.Type != nil { 192 t = t.Type 193 } 194 if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) { 195 if Debug['E'] != 0 { 196 fmt.Printf("reexport type for expression %v\n", Sconv(t.Sym, 0)) 197 } 198 exportlist = list(exportlist, t.Sym.Def) 199 } 200 } 201 202 reexportdep(n.Left) 203 reexportdep(n.Right) 204 reexportdeplist(n.List) 205 reexportdeplist(n.Rlist) 206 reexportdeplist(n.Ninit) 207 reexportdep(n.Ntest) 208 reexportdep(n.Nincr) 209 reexportdeplist(n.Nbody) 210 reexportdeplist(n.Nelse) 211 } 212 213 func dumpexportconst(s *Sym) { 214 n := s.Def 215 typecheck(&n, Erv) 216 if n == nil || n.Op != OLITERAL { 217 Fatal("dumpexportconst: oconst nil: %v", Sconv(s, 0)) 218 } 219 220 t := n.Type // may or may not be specified 221 dumpexporttype(t) 222 223 if t != nil && !isideal(t) { 224 fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(&n.Val, obj.FmtSharp)) 225 } else { 226 fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(&n.Val, obj.FmtSharp)) 227 } 228 } 229 230 func dumpexportvar(s *Sym) { 231 n := s.Def 232 typecheck(&n, Erv|Ecall) 233 if n == nil || n.Type == nil { 234 Yyerror("variable exported but not defined: %v", Sconv(s, 0)) 235 return 236 } 237 238 t := n.Type 239 dumpexporttype(t) 240 241 if t.Etype == TFUNC && n.Class == PFUNC { 242 if n.Func != nil && n.Func.Inl != nil { 243 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 244 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 245 if Debug['l'] < 2 { 246 typecheckinl(n) 247 } 248 249 // NOTE: The space after %#S here is necessary for ld's export data parser. 250 fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp)) 251 252 reexportdeplist(n.Func.Inl) 253 } else { 254 fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp)) 255 } 256 } else { 257 fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp)) 258 } 259 } 260 261 type methodbyname []*Type 262 263 func (x methodbyname) Len() int { 264 return len(x) 265 } 266 267 func (x methodbyname) Swap(i, j int) { 268 x[i], x[j] = x[j], x[i] 269 } 270 271 func (x methodbyname) Less(i, j int) bool { 272 a := x[i] 273 b := x[j] 274 return stringsCompare(a.Sym.Name, b.Sym.Name) < 0 275 } 276 277 func dumpexporttype(t *Type) { 278 if t == nil { 279 return 280 } 281 if t.Printed != 0 || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype { 282 return 283 } 284 t.Printed = 1 285 286 if t.Sym != nil && t.Etype != TFIELD { 287 dumppkg(t.Sym.Pkg) 288 } 289 290 dumpexporttype(t.Type) 291 dumpexporttype(t.Down) 292 293 if t.Sym == nil || t.Etype == TFIELD { 294 return 295 } 296 297 n := 0 298 for f := t.Method; f != nil; f = f.Down { 299 dumpexporttype(f) 300 n++ 301 } 302 303 m := make([]*Type, n) 304 i := 0 305 for f := t.Method; f != nil; f = f.Down { 306 m[i] = f 307 i++ 308 } 309 sort.Sort(methodbyname(m[:n])) 310 311 fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong)) 312 var f *Type 313 for i := 0; i < n; i++ { 314 f = m[i] 315 if f.Nointerface { 316 fmt.Fprintf(bout, "\t//go:nointerface\n") 317 } 318 if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl 319 320 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 321 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 322 if Debug['l'] < 2 { 323 typecheckinl(f.Type.Nname) 324 } 325 fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp)) 326 reexportdeplist(f.Type.Nname.Func.Inl) 327 } else { 328 fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp)) 329 } 330 } 331 } 332 333 func dumpsym(s *Sym) { 334 if s.Flags&SymExported != 0 { 335 return 336 } 337 s.Flags |= SymExported 338 339 if s.Def == nil { 340 Yyerror("unknown export symbol: %v", Sconv(s, 0)) 341 return 342 } 343 344 // print("dumpsym %O %+S\n", s->def->op, s); 345 dumppkg(s.Pkg) 346 347 switch s.Def.Op { 348 default: 349 Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), Sconv(s, 0)) 350 351 case OLITERAL: 352 dumpexportconst(s) 353 354 case OTYPE: 355 if s.Def.Type.Etype == TFORW { 356 Yyerror("export of incomplete type %v", Sconv(s, 0)) 357 } else { 358 dumpexporttype(s.Def.Type) 359 } 360 361 case ONAME: 362 dumpexportvar(s) 363 } 364 } 365 366 func dumpexport() { 367 lno := lineno 368 369 fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name) 370 if safemode != 0 { 371 fmt.Fprintf(bout, " safe") 372 } 373 fmt.Fprintf(bout, "\n") 374 375 for _, p := range pkgs { 376 if p.Direct != 0 { 377 dumppkg(p) 378 } 379 } 380 381 for l := exportlist; l != nil; l = l.Next { 382 lineno = l.N.Lineno 383 dumpsym(l.N.Sym) 384 } 385 386 fmt.Fprintf(bout, "\n$$\n") 387 lineno = lno 388 } 389 390 /* 391 * import 392 */ 393 394 /* 395 * return the sym for ss, which should match lexical 396 */ 397 func importsym(s *Sym, op int) *Sym { 398 if s.Def != nil && int(s.Def.Op) != op { 399 pkgstr := fmt.Sprintf("during import %q", importpkg.Path) 400 redeclare(s, pkgstr) 401 } 402 403 // mark the symbol so it is not reexported 404 if s.Def == nil { 405 if exportname(s.Name) || initname(s.Name) { 406 s.Flags |= SymExport 407 } else { 408 s.Flags |= SymPackage // package scope 409 } 410 } 411 412 return s 413 } 414 415 /* 416 * return the type pkg.name, forward declaring if needed 417 */ 418 func pkgtype(s *Sym) *Type { 419 importsym(s, OTYPE) 420 if s.Def == nil || s.Def.Op != OTYPE { 421 t := typ(TFORW) 422 t.Sym = s 423 s.Def = typenod(t) 424 } 425 426 if s.Def.Type == nil { 427 Yyerror("pkgtype %v", Sconv(s, 0)) 428 } 429 return s.Def.Type 430 } 431 432 var numImport = make(map[string]int) 433 434 func importimport(s *Sym, path string) { 435 // Informational: record package name 436 // associated with import path, for use in 437 // human-readable messages. 438 439 if isbadimport(path) { 440 errorexit() 441 } 442 p := mkpkg(path) 443 if p.Name == "" { 444 p.Name = s.Name 445 numImport[s.Name]++ 446 } else if p.Name != s.Name { 447 Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path) 448 } 449 450 if incannedimport == 0 && myimportpath != "" && path == myimportpath { 451 Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path) 452 errorexit() 453 } 454 } 455 456 func importconst(s *Sym, t *Type, n *Node) { 457 importsym(s, OLITERAL) 458 Convlit(&n, t) 459 460 if s.Def != nil { // TODO: check if already the same. 461 return 462 } 463 464 if n.Op != OLITERAL { 465 Yyerror("expression must be a constant") 466 return 467 } 468 469 if n.Sym != nil { 470 n1 := Nod(OXXX, nil, nil) 471 *n1 = *n 472 n = n1 473 } 474 475 n.Orig = newname(s) 476 n.Sym = s 477 declare(n, PEXTERN) 478 479 if Debug['E'] != 0 { 480 fmt.Printf("import const %v\n", Sconv(s, 0)) 481 } 482 } 483 484 func importvar(s *Sym, t *Type) { 485 importsym(s, ONAME) 486 if s.Def != nil && s.Def.Op == ONAME { 487 if Eqtype(t, s.Def.Type) { 488 return 489 } 490 Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(s, 0), Tconv(s.Def.Type, 0), s.Importdef.Path, Tconv(t, 0), importpkg.Path) 491 } 492 493 n := newname(s) 494 s.Importdef = importpkg 495 n.Type = t 496 declare(n, PEXTERN) 497 498 if Debug['E'] != 0 { 499 fmt.Printf("import var %v %v\n", Sconv(s, 0), Tconv(t, obj.FmtLong)) 500 } 501 } 502 503 func importtype(pt *Type, t *Type) { 504 // override declaration in unsafe.go for Pointer. 505 // there is no way in Go code to define unsafe.Pointer 506 // so we have to supply it. 507 if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" { 508 t = Types[TUNSAFEPTR] 509 } 510 511 if pt.Etype == TFORW { 512 n := pt.Nod 513 copytype(pt.Nod, t) 514 pt.Nod = n // unzero nod 515 pt.Sym.Importdef = importpkg 516 pt.Sym.Lastlineno = int32(parserline()) 517 declare(n, PEXTERN) 518 checkwidth(pt) 519 } else if !Eqtype(pt.Orig, t) { 520 Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(pt.Sym, 0), Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path) 521 } 522 523 if Debug['E'] != 0 { 524 fmt.Printf("import type %v %v\n", Tconv(pt, 0), Tconv(t, obj.FmtLong)) 525 } 526 } 527 528 func dumpasmhdr() { 529 var b *obj.Biobuf 530 531 b, err := obj.Bopenw(asmhdr) 532 if err != nil { 533 Fatal("%v", err) 534 } 535 fmt.Fprintf(b, "// generated by %cg -asmhdr from package %s\n\n", Thearch.Thechar, localpkg.Name) 536 var n *Node 537 var t *Type 538 for l := asmlist; l != nil; l = l.Next { 539 n = l.N 540 if isblanksym(n.Sym) { 541 continue 542 } 543 switch n.Op { 544 case OLITERAL: 545 fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, Vconv(&n.Val, obj.FmtSharp)) 546 547 case OTYPE: 548 t = n.Type 549 if t.Etype != TSTRUCT || t.Map != nil || t.Funarg != 0 { 550 break 551 } 552 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 553 for t = t.Type; t != nil; t = t.Down { 554 if !isblanksym(t.Sym) { 555 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width)) 556 } 557 } 558 } 559 } 560 561 obj.Bterm(b) 562 }