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