github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/cmd/compile/internal/gc/export.go (about)

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