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