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 = 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.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 != 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 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 = list(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 = list(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 = list(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 = list(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 = list(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 Fatal("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 type methodbyname []*Type 257 258 func (x methodbyname) Len() int { 259 return len(x) 260 } 261 262 func (x methodbyname) Swap(i, j int) { 263 x[i], x[j] = x[j], x[i] 264 } 265 266 func (x methodbyname) Less(i, j int) bool { 267 a := x[i] 268 b := x[j] 269 return stringsCompare(a.Sym.Name, b.Sym.Name) < 0 270 } 271 272 func dumpexporttype(t *Type) { 273 if t == nil { 274 return 275 } 276 if t.Printed != 0 || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype { 277 return 278 } 279 t.Printed = 1 280 281 if t.Sym != nil && t.Etype != TFIELD { 282 dumppkg(t.Sym.Pkg) 283 } 284 285 dumpexporttype(t.Type) 286 dumpexporttype(t.Down) 287 288 if t.Sym == nil || t.Etype == TFIELD { 289 return 290 } 291 292 n := 0 293 for f := t.Method; f != nil; f = f.Down { 294 dumpexporttype(f) 295 n++ 296 } 297 298 m := make([]*Type, n) 299 i := 0 300 for f := t.Method; f != nil; f = f.Down { 301 m[i] = f 302 i++ 303 } 304 sort.Sort(methodbyname(m[:n])) 305 306 fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong)) 307 var f *Type 308 for i := 0; i < n; i++ { 309 f = m[i] 310 if f.Nointerface { 311 fmt.Fprintf(bout, "\t//go:nointerface\n") 312 } 313 if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl 314 315 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 316 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 317 if Debug['l'] < 2 { 318 typecheckinl(f.Type.Nname) 319 } 320 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)) 321 reexportdeplist(f.Type.Nname.Func.Inl) 322 } else { 323 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)) 324 } 325 } 326 } 327 328 func dumpsym(s *Sym) { 329 if s.Flags&SymExported != 0 { 330 return 331 } 332 s.Flags |= SymExported 333 334 if s.Def == nil { 335 Yyerror("unknown export symbol: %v", s) 336 return 337 } 338 339 // print("dumpsym %O %+S\n", s->def->op, s); 340 dumppkg(s.Pkg) 341 342 switch s.Def.Op { 343 default: 344 Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), s) 345 346 case OLITERAL: 347 dumpexportconst(s) 348 349 case OTYPE: 350 if s.Def.Type.Etype == TFORW { 351 Yyerror("export of incomplete type %v", s) 352 } else { 353 dumpexporttype(s.Def.Type) 354 } 355 356 case ONAME: 357 dumpexportvar(s) 358 } 359 } 360 361 func dumpexport() { 362 lno := lineno 363 364 if buildid != "" { 365 fmt.Fprintf(bout, "build id %q\n", buildid) 366 } 367 fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name) 368 if safemode != 0 { 369 fmt.Fprintf(bout, " safe") 370 } 371 fmt.Fprintf(bout, "\n") 372 373 for _, p := range pkgs { 374 if p.Direct != 0 { 375 dumppkg(p) 376 } 377 } 378 379 for l := exportlist; l != nil; l = l.Next { 380 lineno = l.N.Lineno 381 dumpsym(l.N.Sym) 382 } 383 384 fmt.Fprintf(bout, "\n$$\n") 385 lineno = lno 386 } 387 388 /* 389 * import 390 */ 391 392 /* 393 * return the sym for ss, which should match lexical 394 */ 395 func importsym(s *Sym, op int) *Sym { 396 if s.Def != nil && int(s.Def.Op) != op { 397 pkgstr := fmt.Sprintf("during import %q", importpkg.Path) 398 redeclare(s, pkgstr) 399 } 400 401 // mark the symbol so it is not reexported 402 if s.Def == nil { 403 if exportname(s.Name) || initname(s.Name) { 404 s.Flags |= SymExport 405 } else { 406 s.Flags |= SymPackage // package scope 407 } 408 } 409 410 return s 411 } 412 413 /* 414 * return the type pkg.name, forward declaring if needed 415 */ 416 func pkgtype(s *Sym) *Type { 417 importsym(s, OTYPE) 418 if s.Def == nil || s.Def.Op != OTYPE { 419 t := typ(TFORW) 420 t.Sym = s 421 s.Def = typenod(t) 422 s.Def.Name = new(Name) 423 } 424 425 if s.Def.Type == nil { 426 Yyerror("pkgtype %v", s) 427 } 428 return s.Def.Type 429 } 430 431 var numImport = make(map[string]int) 432 433 func importimport(s *Sym, path string) { 434 // Informational: record package name 435 // associated with import path, for use in 436 // human-readable messages. 437 438 if isbadimport(path) { 439 errorexit() 440 } 441 p := mkpkg(path) 442 if p.Name == "" { 443 p.Name = s.Name 444 numImport[s.Name]++ 445 } else if p.Name != s.Name { 446 Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path) 447 } 448 449 if incannedimport == 0 && myimportpath != "" && path == myimportpath { 450 Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path) 451 errorexit() 452 } 453 } 454 455 func importconst(s *Sym, t *Type, n *Node) { 456 importsym(s, OLITERAL) 457 Convlit(&n, t) 458 459 if s.Def != nil { // TODO: check if already the same. 460 return 461 } 462 463 if n.Op != OLITERAL { 464 Yyerror("expression must be a constant") 465 return 466 } 467 468 if n.Sym != nil { 469 n1 := Nod(OXXX, nil, nil) 470 *n1 = *n 471 n = n1 472 } 473 474 n.Orig = newname(s) 475 n.Sym = s 476 declare(n, PEXTERN) 477 478 if Debug['E'] != 0 { 479 fmt.Printf("import const %v\n", s) 480 } 481 } 482 483 func importvar(s *Sym, t *Type) { 484 importsym(s, ONAME) 485 if s.Def != nil && s.Def.Op == ONAME { 486 if Eqtype(t, s.Def.Type) { 487 return 488 } 489 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) 490 } 491 492 n := newname(s) 493 s.Importdef = importpkg 494 n.Type = t 495 declare(n, PEXTERN) 496 497 if Debug['E'] != 0 { 498 fmt.Printf("import var %v %v\n", s, Tconv(t, obj.FmtLong)) 499 } 500 } 501 502 func importtype(pt *Type, t *Type) { 503 // override declaration in unsafe.go for Pointer. 504 // there is no way in Go code to define unsafe.Pointer 505 // so we have to supply it. 506 if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" { 507 t = Types[TUNSAFEPTR] 508 } 509 510 if pt.Etype == TFORW { 511 n := pt.Nod 512 copytype(pt.Nod, t) 513 pt.Nod = n // unzero nod 514 pt.Sym.Importdef = importpkg 515 pt.Sym.Lastlineno = int32(parserline()) 516 declare(n, PEXTERN) 517 checkwidth(pt) 518 } else if !Eqtype(pt.Orig, t) { 519 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) 520 } 521 522 if Debug['E'] != 0 { 523 fmt.Printf("import type %v %v\n", pt, Tconv(t, obj.FmtLong)) 524 } 525 } 526 527 func dumpasmhdr() { 528 var b *obj.Biobuf 529 530 b, err := obj.Bopenw(asmhdr) 531 if err != nil { 532 Fatal("%v", err) 533 } 534 fmt.Fprintf(b, "// generated by %cg -asmhdr from package %s\n\n", Thearch.Thechar, localpkg.Name) 535 var n *Node 536 var t *Type 537 for l := asmlist; l != nil; l = l.Next { 538 n = l.N 539 if isblanksym(n.Sym) { 540 continue 541 } 542 switch n.Op { 543 case OLITERAL: 544 fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, Vconv(n.Val(), obj.FmtSharp)) 545 546 case OTYPE: 547 t = n.Type 548 if t.Etype != TSTRUCT || t.Map != nil || t.Funarg != 0 { 549 break 550 } 551 fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) 552 for t = t.Type; t != nil; t = t.Down { 553 if !isblanksym(t.Sym) { 554 fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width)) 555 } 556 } 557 } 558 } 559 560 obj.Bterm(b) 561 } 562