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