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