]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/main.go
[dev.inline] cmd/compile: parse source files concurrently
[gostls13.git] / src / cmd / compile / internal / gc / main.go
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 //go:generate go run mkbuiltin.go
6
7 package gc
8
9 import (
10         "bufio"
11         "bytes"
12         "cmd/compile/internal/ssa"
13         "cmd/internal/obj"
14         "cmd/internal/src"
15         "cmd/internal/sys"
16         "flag"
17         "fmt"
18         "io"
19         "log"
20         "os"
21         "path"
22         "runtime"
23         "strconv"
24         "strings"
25 )
26
27 var imported_unsafe bool
28
29 var (
30         buildid string
31 )
32
33 var (
34         Debug_append  int
35         Debug_closure int
36         Debug_panic   int
37         Debug_slice   int
38         Debug_wb      int
39 )
40
41 // Debug arguments.
42 // These can be specified with the -d flag, as in "-d nil"
43 // to set the debug_checknil variable. In general the list passed
44 // to -d can be comma-separated.
45 var debugtab = []struct {
46         name string
47         val  *int
48 }{
49         {"append", &Debug_append},         // print information about append compilation
50         {"closure", &Debug_closure},       // print information about closure compilation
51         {"disablenil", &disable_checknil}, // disable nil checks
52         {"gcprog", &Debug_gcprog},         // print dump of GC programs
53         {"nil", &Debug_checknil},          // print information about nil checks
54         {"panic", &Debug_panic},           // do not hide any compiler panic
55         {"slice", &Debug_slice},           // print information about slice compilation
56         {"typeassert", &Debug_typeassert}, // print information about type assertion inlining
57         {"wb", &Debug_wb},                 // print information about write barriers
58         {"export", &Debug_export},         // print export data
59 }
60
61 func usage() {
62         fmt.Printf("usage: compile [options] file.go...\n")
63         obj.Flagprint(1)
64         Exit(2)
65 }
66
67 func hidePanic() {
68         if Debug_panic == 0 && nsavederrors+nerrors > 0 {
69                 // If we've already complained about things
70                 // in the program, don't bother complaining
71                 // about a panic too; let the user clean up
72                 // the code and try again.
73                 if err := recover(); err != nil {
74                         errorexit()
75                 }
76         }
77 }
78
79 func doversion() {
80         p := obj.Expstring()
81         if p == "X:none" {
82                 p = ""
83         }
84         sep := ""
85         if p != "" {
86                 sep = " "
87         }
88         fmt.Printf("compile version %s%s%s\n", obj.Version, sep, p)
89         os.Exit(0)
90 }
91
92 // supportsDynlink reports whether or not the code generator for the given
93 // architecture supports the -shared and -dynlink flags.
94 func supportsDynlink(arch *sys.Arch) bool {
95         return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
96 }
97
98 // timing data for compiler phases
99 var timings Timings
100 var benchfile string
101
102 // Main parses flags and Go source files specified in the command-line
103 // arguments, type-checks the parsed Go package, compiles functions to machine
104 // code, and finally writes the compiled package definition to disk.
105 func Main() {
106         timings.Start("fe", "init")
107
108         defer hidePanic()
109
110         Ctxt = obj.Linknew(Thearch.LinkArch)
111         Ctxt.DiagFunc = yyerror
112         Ctxt.Bso = bufio.NewWriter(os.Stdout)
113
114         localpkg = mkpkg("")
115         localpkg.Prefix = "\"\""
116
117         // pseudo-package, for scoping
118         builtinpkg = mkpkg("go.builtin")
119         builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
120
121         // pseudo-package, accessed by import "unsafe"
122         unsafepkg = mkpkg("unsafe")
123         unsafepkg.Name = "unsafe"
124
125         // real package, referred to by generated runtime calls
126         Runtimepkg = mkpkg("runtime")
127         Runtimepkg.Name = "runtime"
128
129         // pseudo-packages used in symbol tables
130         itabpkg = mkpkg("go.itab")
131         itabpkg.Name = "go.itab"
132         itabpkg.Prefix = "go.itab" // not go%2eitab
133
134         itablinkpkg = mkpkg("go.itablink")
135         itablinkpkg.Name = "go.itablink"
136         itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
137
138         trackpkg = mkpkg("go.track")
139         trackpkg.Name = "go.track"
140         trackpkg.Prefix = "go.track" // not go%2etrack
141
142         typepkg = mkpkg("type")
143         typepkg.Name = "type"
144
145         // pseudo-package used for map zero values
146         mappkg = mkpkg("go.map")
147         mappkg.Name = "go.map"
148         mappkg.Prefix = "go.map"
149
150         Nacl = obj.GOOS == "nacl"
151         if Nacl {
152                 flag_largemodel = true
153         }
154
155         flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
156         obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
157         obj.Flagcount("B", "disable bounds checking", &Debug['B'])
158         flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
159         obj.Flagcount("E", "debug symbol export", &Debug['E'])
160         obj.Flagfn1("I", "add `directory` to import search path", addidir)
161         obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
162         obj.Flagcount("N", "disable optimizations", &Debug['N'])
163         obj.Flagcount("S", "print assembly listing", &Debug['S'])
164         obj.Flagfn0("V", "print compiler version", doversion)
165         obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
166         flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
167         flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
168         flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
169         flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`")
170         obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
171         obj.Flagcount("f", "debug stack frames", &Debug['f'])
172         obj.Flagcount("h", "halt on error", &Debug['h'])
173         obj.Flagcount("i", "debug line number stack", &Debug['i'])
174         obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
175         flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
176         obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
177         obj.Flagcount("l", "disable inlining", &Debug['l'])
178         flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
179         obj.Flagcount("live", "debug liveness analysis", &debuglive)
180         obj.Flagcount("m", "print optimization decisions", &Debug['m'])
181         flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
182         flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
183         flag.StringVar(&outfile, "o", "", "write output to `file`")
184         flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
185         flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file")
186         obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
187         flag.BoolVar(&flag_race, "race", false, "enable race detector")
188         obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
189         flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
190         flag.BoolVar(&safemode, "u", false, "reject unsafe code")
191         obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
192         obj.Flagcount("w", "debug type checking", &Debug['w'])
193         flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
194         var flag_shared bool
195         var flag_dynlink bool
196         if supportsDynlink(Thearch.LinkArch.Arch) {
197                 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
198                 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
199         }
200         if Thearch.LinkArch.Family == sys.AMD64 {
201                 flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model")
202         }
203         flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
204         flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
205         flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
206         flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
207         flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
208         obj.Flagparse(usage)
209
210         Ctxt.Flag_shared = flag_dynlink || flag_shared
211         Ctxt.Flag_dynlink = flag_dynlink
212         Ctxt.Flag_optimize = Debug['N'] == 0
213
214         Ctxt.Debugasm = int32(Debug['S'])
215         Ctxt.Debugvlog = int32(Debug['v'])
216
217         if flag.NArg() < 1 {
218                 usage()
219         }
220
221         if outfile == "" {
222                 p := flag.Arg(0)
223                 if i := strings.LastIndex(p, "/"); i >= 0 {
224                         p = p[i+1:]
225                 }
226                 if runtime.GOOS == "windows" {
227                         if i := strings.LastIndex(p, `\`); i >= 0 {
228                                 p = p[i+1:]
229                         }
230                 }
231                 if i := strings.LastIndex(p, "."); i >= 0 {
232                         p = p[:i]
233                 }
234                 suffix := ".o"
235                 if writearchive {
236                         suffix = ".a"
237                 }
238                 outfile = p + suffix
239         }
240
241         startProfile()
242
243         if flag_race {
244                 racepkg = mkpkg("runtime/race")
245                 racepkg.Name = "race"
246         }
247         if flag_msan {
248                 msanpkg = mkpkg("runtime/msan")
249                 msanpkg.Name = "msan"
250         }
251         if flag_race && flag_msan {
252                 log.Fatal("cannot use both -race and -msan")
253         } else if flag_race || flag_msan {
254                 instrumenting = true
255         }
256
257         // parse -d argument
258         if debugstr != "" {
259         Split:
260                 for _, name := range strings.Split(debugstr, ",") {
261                         if name == "" {
262                                 continue
263                         }
264                         val := 1
265                         valstring := ""
266                         if i := strings.Index(name, "="); i >= 0 {
267                                 var err error
268                                 val, err = strconv.Atoi(name[i+1:])
269                                 if err != nil {
270                                         log.Fatalf("invalid debug value %v", name)
271                                 }
272                                 name = name[:i]
273                         } else if i := strings.Index(name, ":"); i >= 0 {
274                                 valstring = name[i+1:]
275                                 name = name[:i]
276                         }
277                         for _, t := range debugtab {
278                                 if t.name == name {
279                                         if t.val != nil {
280                                                 *t.val = val
281                                                 continue Split
282                                         }
283                                 }
284                         }
285                         // special case for ssa for now
286                         if strings.HasPrefix(name, "ssa/") {
287                                 // expect form ssa/phase/flag
288                                 // e.g. -d=ssa/generic_cse/time
289                                 // _ in phase name also matches space
290                                 phase := name[4:]
291                                 flag := "debug" // default flag is debug
292                                 if i := strings.Index(phase, "/"); i >= 0 {
293                                         flag = phase[i+1:]
294                                         phase = phase[:i]
295                                 }
296                                 err := ssa.PhaseOption(phase, flag, val, valstring)
297                                 if err != "" {
298                                         log.Fatalf(err)
299                                 }
300                                 continue Split
301                         }
302                         log.Fatalf("unknown debug key -d %s\n", name)
303                 }
304         }
305
306         // enable inlining.  for now:
307         //      default: inlining on.  (debug['l'] == 1)
308         //      -l: inlining off  (debug['l'] == 0)
309         //      -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
310         if Debug['l'] <= 1 {
311                 Debug['l'] = 1 - Debug['l']
312         }
313
314         Widthint = Thearch.LinkArch.IntSize
315         Widthptr = Thearch.LinkArch.PtrSize
316         Widthreg = Thearch.LinkArch.RegSize
317
318         initUniverse()
319
320         blockgen = 1
321         dclcontext = PEXTERN
322         nerrors = 0
323
324         timings.Start("fe", "loadsys")
325         loadsys()
326
327         timings.Start("fe", "parse")
328         lines := parseFiles(flag.Args())
329         timings.Stop()
330         timings.AddEvent(int64(lines), "lines")
331
332         testdclstack()
333         finishUniverse()
334
335         typecheckok = true
336         if Debug['f'] != 0 {
337                 frame(1)
338         }
339
340         // Process top-level declarations in phases.
341
342         // Phase 1: const, type, and names and types of funcs.
343         //   This will gather all the information about types
344         //   and methods but doesn't depend on any of it.
345         defercheckwidth()
346
347         // Don't use range--typecheck can add closures to xtop.
348         timings.Start("fe", "typecheck", "top1")
349         for i := 0; i < len(xtop); i++ {
350                 if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
351                         xtop[i] = typecheck(xtop[i], Etop)
352                 }
353         }
354
355         // Phase 2: Variable assignments.
356         //   To check interface assignments, depends on phase 1.
357
358         // Don't use range--typecheck can add closures to xtop.
359         timings.Start("fe", "typecheck", "top2")
360         for i := 0; i < len(xtop); i++ {
361                 if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
362                         xtop[i] = typecheck(xtop[i], Etop)
363                 }
364         }
365         resumecheckwidth()
366
367         // Phase 3: Type check function bodies.
368         // Don't use range--typecheck can add closures to xtop.
369         timings.Start("fe", "typecheck", "func")
370         var fcount int64
371         for i := 0; i < len(xtop); i++ {
372                 if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
373                         Curfn = xtop[i]
374                         decldepth = 1
375                         saveerrors()
376                         typecheckslice(Curfn.Nbody.Slice(), Etop)
377                         checkreturn(Curfn)
378                         if nerrors != 0 {
379                                 Curfn.Nbody.Set(nil) // type errors; do not compile
380                         }
381                         fcount++
382                 }
383         }
384         timings.AddEvent(fcount, "funcs")
385
386         // Phase 4: Decide how to capture closed variables.
387         // This needs to run before escape analysis,
388         // because variables captured by value do not escape.
389         timings.Start("fe", "capturevars")
390         for _, n := range xtop {
391                 if n.Op == ODCLFUNC && n.Func.Closure != nil {
392                         Curfn = n
393                         capturevars(n)
394                 }
395         }
396
397         Curfn = nil
398
399         if nsavederrors+nerrors != 0 {
400                 errorexit()
401         }
402
403         // Phase 5: Inlining
404         timings.Start("fe", "inlining")
405         if Debug['l'] > 1 {
406                 // Typecheck imported function bodies if debug['l'] > 1,
407                 // otherwise lazily when used or re-exported.
408                 for _, n := range importlist {
409                         if n.Func.Inl.Len() != 0 {
410                                 saveerrors()
411                                 typecheckinl(n)
412                         }
413                 }
414
415                 if nsavederrors+nerrors != 0 {
416                         errorexit()
417                 }
418         }
419
420         if Debug['l'] != 0 {
421                 // Find functions that can be inlined and clone them before walk expands them.
422                 visitBottomUp(xtop, func(list []*Node, recursive bool) {
423                         for _, n := range list {
424                                 if !recursive {
425                                         caninl(n)
426                                 } else {
427                                         if Debug['m'] > 1 {
428                                                 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
429                                         }
430                                 }
431                                 inlcalls(n)
432                         }
433                 })
434         }
435
436         // Phase 6: Escape analysis.
437         // Required for moving heap allocations onto stack,
438         // which in turn is required by the closure implementation,
439         // which stores the addresses of stack variables into the closure.
440         // If the closure does not escape, it needs to be on the stack
441         // or else the stack copier will not update it.
442         // Large values are also moved off stack in escape analysis;
443         // because large values may contain pointers, it must happen early.
444         timings.Start("fe", "escapes")
445         escapes(xtop)
446
447         // Phase 7: Transform closure bodies to properly reference captured variables.
448         // This needs to happen before walk, because closures must be transformed
449         // before walk reaches a call of a closure.
450         timings.Start("fe", "xclosures")
451         for _, n := range xtop {
452                 if n.Op == ODCLFUNC && n.Func.Closure != nil {
453                         Curfn = n
454                         transformclosure(n)
455                 }
456         }
457
458         Curfn = nil
459
460         // Phase 8: Compile top level functions.
461         // Don't use range--walk can add functions to xtop.
462         timings.Start("be", "compilefuncs")
463         fcount = 0
464         for i := 0; i < len(xtop); i++ {
465                 if xtop[i].Op == ODCLFUNC {
466                         funccompile(xtop[i])
467                         fcount++
468                 }
469         }
470         timings.AddEvent(fcount, "funcs")
471
472         if nsavederrors+nerrors == 0 {
473                 fninit(xtop)
474         }
475
476         if compiling_runtime {
477                 checknowritebarrierrec()
478         }
479
480         // Phase 9: Check external declarations.
481         timings.Start("be", "externaldcls")
482         for i, n := range externdcl {
483                 if n.Op == ONAME {
484                         externdcl[i] = typecheck(externdcl[i], Erv)
485                 }
486         }
487
488         if nerrors+nsavederrors != 0 {
489                 errorexit()
490         }
491
492         // Write object data to disk.
493         timings.Start("be", "dumpobj")
494         dumpobj()
495         if asmhdr != "" {
496                 dumpasmhdr()
497         }
498
499         if nerrors+nsavederrors != 0 {
500                 errorexit()
501         }
502
503         flusherrors()
504         timings.Stop()
505
506         if benchfile != "" {
507                 if err := writebench(benchfile); err != nil {
508                         log.Fatalf("cannot write benchmark data: %v", err)
509                 }
510         }
511 }
512
513 func writebench(filename string) error {
514         f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
515         if err != nil {
516                 return err
517         }
518
519         var buf bytes.Buffer
520         fmt.Fprintln(&buf, "commit:", obj.Version)
521         fmt.Fprintln(&buf, "goos:", runtime.GOOS)
522         fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
523         timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
524
525         n, err := f.Write(buf.Bytes())
526         if err != nil {
527                 return err
528         }
529         if n != buf.Len() {
530                 panic("bad writer")
531         }
532
533         return f.Close()
534 }
535
536 var importMap = map[string]string{}
537
538 func addImportMap(s string) {
539         if strings.Count(s, "=") != 1 {
540                 log.Fatal("-importmap argument must be of the form source=actual")
541         }
542         i := strings.Index(s, "=")
543         source, actual := s[:i], s[i+1:]
544         if source == "" || actual == "" {
545                 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
546         }
547         importMap[source] = actual
548 }
549
550 func saveerrors() {
551         nsavederrors += nerrors
552         nerrors = 0
553 }
554
555 func arsize(b *bufio.Reader, name string) int {
556         var buf [ArhdrSize]byte
557         if _, err := io.ReadFull(b, buf[:]); err != nil {
558                 return -1
559         }
560         aname := strings.Trim(string(buf[0:16]), " ")
561         if !strings.HasPrefix(aname, name) {
562                 return -1
563         }
564         asize := strings.Trim(string(buf[48:58]), " ")
565         i, _ := strconv.Atoi(asize)
566         return i
567 }
568
569 func skiptopkgdef(b *bufio.Reader) bool {
570         // archive header
571         p, err := b.ReadString('\n')
572         if err != nil {
573                 log.Fatalf("reading input: %v", err)
574         }
575         if p != "!<arch>\n" {
576                 return false
577         }
578
579         // package export block should be first
580         sz := arsize(b, "__.PKGDEF")
581         return sz > 0
582 }
583
584 var idirs []string
585
586 func addidir(dir string) {
587         if dir != "" {
588                 idirs = append(idirs, dir)
589         }
590 }
591
592 func isDriveLetter(b byte) bool {
593         return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
594 }
595
596 // is this path a local name?  begins with ./ or ../ or /
597 func islocalname(name string) bool {
598         return strings.HasPrefix(name, "/") ||
599                 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
600                 strings.HasPrefix(name, "./") || name == "." ||
601                 strings.HasPrefix(name, "../") || name == ".."
602 }
603
604 func findpkg(name string) (file string, ok bool) {
605         if islocalname(name) {
606                 if safemode || nolocalimports {
607                         return "", false
608                 }
609
610                 // try .a before .6.  important for building libraries:
611                 // if there is an array.6 in the array.a library,
612                 // want to find all of array.a, not just array.6.
613                 file = fmt.Sprintf("%s.a", name)
614                 if _, err := os.Stat(file); err == nil {
615                         return file, true
616                 }
617                 file = fmt.Sprintf("%s.o", name)
618                 if _, err := os.Stat(file); err == nil {
619                         return file, true
620                 }
621                 return "", false
622         }
623
624         // local imports should be canonicalized already.
625         // don't want to see "encoding/../encoding/base64"
626         // as different from "encoding/base64".
627         if q := path.Clean(name); q != name {
628                 yyerror("non-canonical import path %q (should be %q)", name, q)
629                 return "", false
630         }
631
632         for _, dir := range idirs {
633                 file = fmt.Sprintf("%s/%s.a", dir, name)
634                 if _, err := os.Stat(file); err == nil {
635                         return file, true
636                 }
637                 file = fmt.Sprintf("%s/%s.o", dir, name)
638                 if _, err := os.Stat(file); err == nil {
639                         return file, true
640                 }
641         }
642
643         if obj.GOROOT != "" {
644                 suffix := ""
645                 suffixsep := ""
646                 if flag_installsuffix != "" {
647                         suffixsep = "_"
648                         suffix = flag_installsuffix
649                 } else if flag_race {
650                         suffixsep = "_"
651                         suffix = "race"
652                 } else if flag_msan {
653                         suffixsep = "_"
654                         suffix = "msan"
655                 }
656
657                 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
658                 if _, err := os.Stat(file); err == nil {
659                         return file, true
660                 }
661                 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
662                 if _, err := os.Stat(file); err == nil {
663                         return file, true
664                 }
665         }
666
667         return "", false
668 }
669
670 // loadsys loads the definitions for the low-level runtime functions,
671 // so that the compiler can generate calls to them,
672 // but does not make them visible to user code.
673 func loadsys() {
674         block = 1
675         iota_ = -1000000
676
677         importpkg = Runtimepkg
678         typecheckok = true
679         defercheckwidth()
680
681         typs := runtimeTypes()
682         for _, d := range runtimeDecls {
683                 sym := Pkglookup(d.name, importpkg)
684                 typ := typs[d.typ]
685                 switch d.tag {
686                 case funcTag:
687                         importsym(sym, ONAME)
688                         n := newfuncname(sym)
689                         n.Type = typ
690                         declare(n, PFUNC)
691                 case varTag:
692                         importvar(sym, typ)
693                 default:
694                         Fatalf("unhandled declaration tag %v", d.tag)
695                 }
696         }
697
698         typecheckok = false
699         resumecheckwidth()
700         importpkg = nil
701 }
702
703 func importfile(f *Val, indent []byte) {
704         if importpkg != nil {
705                 Fatalf("importpkg not nil")
706         }
707
708         path_, ok := f.U.(string)
709         if !ok {
710                 yyerror("import statement not a string")
711                 return
712         }
713
714         if len(path_) == 0 {
715                 yyerror("import path is empty")
716                 return
717         }
718
719         if isbadimport(path_) {
720                 return
721         }
722
723         // The package name main is no longer reserved,
724         // but we reserve the import path "main" to identify
725         // the main package, just as we reserve the import
726         // path "math" to identify the standard math package.
727         if path_ == "main" {
728                 yyerror("cannot import \"main\"")
729                 errorexit()
730         }
731
732         if myimportpath != "" && path_ == myimportpath {
733                 yyerror("import %q while compiling that package (import cycle)", path_)
734                 errorexit()
735         }
736
737         if mapped, ok := importMap[path_]; ok {
738                 path_ = mapped
739         }
740
741         if path_ == "unsafe" {
742                 if safemode {
743                         yyerror("cannot import package unsafe")
744                         errorexit()
745                 }
746
747                 importpkg = unsafepkg
748                 imported_unsafe = true
749                 return
750         }
751
752         if islocalname(path_) {
753                 if path_[0] == '/' {
754                         yyerror("import path cannot be absolute path")
755                         return
756                 }
757
758                 prefix := Ctxt.Pathname
759                 if localimport != "" {
760                         prefix = localimport
761                 }
762                 path_ = path.Join(prefix, path_)
763
764                 if isbadimport(path_) {
765                         return
766                 }
767         }
768
769         file, found := findpkg(path_)
770         if !found {
771                 yyerror("can't find import: %q", path_)
772                 errorexit()
773         }
774
775         importpkg = mkpkg(path_)
776
777         if importpkg.Imported {
778                 return
779         }
780
781         importpkg.Imported = true
782
783         impf, err := os.Open(file)
784         if err != nil {
785                 yyerror("can't open import: %q: %v", path_, err)
786                 errorexit()
787         }
788         defer impf.Close()
789         imp := bufio.NewReader(impf)
790
791         const pkgSuffix = ".a"
792         if strings.HasSuffix(file, pkgSuffix) {
793                 if !skiptopkgdef(imp) {
794                         yyerror("import %s: not a package file", file)
795                         errorexit()
796                 }
797         }
798
799         // check object header
800         p, err := imp.ReadString('\n')
801         if err != nil {
802                 log.Fatalf("reading input: %v", err)
803         }
804         if len(p) > 0 {
805                 p = p[:len(p)-1]
806         }
807
808         if p != "empty archive" {
809                 if !strings.HasPrefix(p, "go object ") {
810                         yyerror("import %s: not a go object file: %s", file, p)
811                         errorexit()
812                 }
813
814                 q := fmt.Sprintf("%s %s %s %s", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
815                 if p[10:] != q {
816                         yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
817                         errorexit()
818                 }
819         }
820
821         // process header lines
822         safe := false
823         for {
824                 p, err = imp.ReadString('\n')
825                 if err != nil {
826                         log.Fatalf("reading input: %v", err)
827                 }
828                 if p == "\n" {
829                         break // header ends with blank line
830                 }
831                 if strings.HasPrefix(p, "safe") {
832                         safe = true
833                         break // ok to ignore rest
834                 }
835         }
836         if safemode && !safe {
837                 yyerror("cannot import unsafe package %q", importpkg.Path)
838         }
839
840         // assume files move (get installed) so don't record the full path
841         // (e.g., for file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a")
842         Ctxt.AddImport(file[len(file)-len(path_)-len(pkgSuffix):])
843
844         // In the importfile, if we find:
845         // $$\n  (textual format): not supported anymore
846         // $$B\n (binary format) : import directly, then feed the lexer a dummy statement
847
848         // look for $$
849         var c byte
850         for {
851                 c, err = imp.ReadByte()
852                 if err != nil {
853                         break
854                 }
855                 if c == '$' {
856                         c, err = imp.ReadByte()
857                         if c == '$' || err != nil {
858                                 break
859                         }
860                 }
861         }
862
863         // get character after $$
864         if err == nil {
865                 c, _ = imp.ReadByte()
866         }
867
868         switch c {
869         case '\n':
870                 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
871
872         case 'B':
873                 if Debug_export != 0 {
874                         fmt.Printf("importing %s (%s)\n", path_, file)
875                 }
876                 imp.ReadByte() // skip \n after $$B
877                 Import(imp)
878
879         default:
880                 yyerror("no import in %q", path_)
881                 errorexit()
882         }
883 }
884
885 func pkgnotused(lineno src.XPos, path string, name string) {
886         // If the package was imported with a name other than the final
887         // import path element, show it explicitly in the error message.
888         // Note that this handles both renamed imports and imports of
889         // packages containing unconventional package declarations.
890         // Note that this uses / always, even on Windows, because Go import
891         // paths always use forward slashes.
892         elem := path
893         if i := strings.LastIndex(elem, "/"); i >= 0 {
894                 elem = elem[i+1:]
895         }
896         if name == "" || elem == name {
897                 yyerrorl(lineno, "imported and not used: %q", path)
898         } else {
899                 yyerrorl(lineno, "imported and not used: %q as %s", path, name)
900         }
901 }
902
903 func mkpackage(pkgname string) {
904         if localpkg.Name == "" {
905                 if pkgname == "_" {
906                         yyerror("invalid package name _")
907                 }
908                 localpkg.Name = pkgname
909         } else {
910                 if pkgname != localpkg.Name {
911                         yyerror("package %s; expected %s", pkgname, localpkg.Name)
912                 }
913         }
914 }
915
916 func clearImports() {
917         for _, s := range localpkg.Syms {
918                 if s.Def == nil {
919                         continue
920                 }
921                 if s.Def.Op == OPACK {
922                         // throw away top-level package name leftover
923                         // from previous file.
924                         // leave s->block set to cause redeclaration
925                         // errors if a conflicting top-level name is
926                         // introduced by a different file.
927                         if !s.Def.Used && nsyntaxerrors == 0 {
928                                 pkgnotused(s.Def.Pos, s.Def.Name.Pkg.Path, s.Name)
929                         }
930                         s.Def = nil
931                         continue
932                 }
933
934                 if s.Def.Sym != s && s.Flags&SymAlias == 0 {
935                         // throw away top-level name left over
936                         // from previous import . "x"
937                         if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
938                                 pkgnotused(s.Def.Name.Pack.Pos, s.Def.Name.Pack.Name.Pkg.Path, "")
939                                 s.Def.Name.Pack.Used = true
940                         }
941
942                         s.Def = nil
943                         continue
944                 }
945         }
946 }