github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/export.go (about)

     1  // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/export.go
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package gc
     8  
     9  import (
    10  	"rsc.io/tmp/bootstrap/internal/obj"
    11  	"fmt"
    12  	"sort"
    13  	"unicode"
    14  	"unicode/utf8"
    15  )
    16  
    17  var asmlist *NodeList
    18  
    19  // Mark n's symbol as exported
    20  func exportsym(n *Node) {
    21  	if n == nil || n.Sym == nil {
    22  		return
    23  	}
    24  	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
    25  		if n.Sym.Flags&SymPackage != 0 {
    26  			Yyerror("export/package mismatch: %v", n.Sym)
    27  		}
    28  		return
    29  	}
    30  
    31  	n.Sym.Flags |= SymExport
    32  
    33  	if Debug['E'] != 0 {
    34  		fmt.Printf("export symbol %v\n", n.Sym)
    35  	}
    36  	exportlist = list(exportlist, n)
    37  }
    38  
    39  func exportname(s string) bool {
    40  	if s[0] < utf8.RuneSelf {
    41  		return 'A' <= s[0] && s[0] <= 'Z'
    42  	}
    43  	r, _ := utf8.DecodeRuneInString(s)
    44  	return unicode.IsUpper(r)
    45  }
    46  
    47  func initname(s string) bool {
    48  	return s == "init"
    49  }
    50  
    51  // exportedsym reports whether a symbol will be visible
    52  // to files that import our package.
    53  func exportedsym(sym *Sym) bool {
    54  	// Builtins are visible everywhere.
    55  	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
    56  		return true
    57  	}
    58  
    59  	return sym.Pkg == localpkg && exportname(sym.Name)
    60  }
    61  
    62  func autoexport(n *Node, ctxt uint8) {
    63  	if n == nil || n.Sym == nil {
    64  		return
    65  	}
    66  	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
    67  		return
    68  	}
    69  	if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method
    70  		return
    71  	}
    72  
    73  	// -A is for cmd/gc/mkbuiltin script, so export everything
    74  	if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) {
    75  		exportsym(n)
    76  	}
    77  	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
    78  		n.Sym.Flags |= SymAsm
    79  		asmlist = list(asmlist, n)
    80  	}
    81  }
    82  
    83  func dumppkg(p *Pkg) {
    84  	if p == nil || p == localpkg || p.Exported != 0 || p == builtinpkg {
    85  		return
    86  	}
    87  	p.Exported = 1
    88  	suffix := ""
    89  	if p.Direct == 0 {
    90  		suffix = " // indirect"
    91  	}
    92  	fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
    93  }
    94  
    95  // Look for anything we need for the inline body
    96  func reexportdeplist(ll *NodeList) {
    97  	for ; ll != nil; ll = ll.Next {
    98  		reexportdep(ll.N)
    99  	}
   100  }
   101  
   102  func reexportdep(n *Node) {
   103  	if n == nil {
   104  		return
   105  	}
   106  
   107  	//print("reexportdep %+hN\n", n);
   108  	switch n.Op {
   109  	case ONAME:
   110  		switch n.Class &^ PHEAP {
   111  		// methods will be printed along with their type
   112  		// nodes for T.Method expressions
   113  		case PFUNC:
   114  			if n.Left != nil && n.Left.Op == OTYPE {
   115  				break
   116  			}
   117  
   118  			// nodes for method calls.
   119  			if n.Type == nil || n.Type.Thistuple > 0 {
   120  				break
   121  			}
   122  			fallthrough
   123  
   124  		case PEXTERN:
   125  			if n.Sym != nil && !exportedsym(n.Sym) {
   126  				if Debug['E'] != 0 {
   127  					fmt.Printf("reexport name %v\n", n.Sym)
   128  				}
   129  				exportlist = list(exportlist, n)
   130  			}
   131  		}
   132  
   133  		// Local variables in the bodies need their type.
   134  	case ODCL:
   135  		t := n.Left.Type
   136  
   137  		if t != Types[t.Etype] && t != idealbool && t != idealstring {
   138  			if Isptr[t.Etype] {
   139  				t = t.Type
   140  			}
   141  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   142  				if Debug['E'] != 0 {
   143  					fmt.Printf("reexport type %v from declaration\n", t.Sym)
   144  				}
   145  				exportlist = list(exportlist, t.Sym.Def)
   146  			}
   147  		}
   148  
   149  	case OLITERAL:
   150  		t := n.Type
   151  		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
   152  			if Isptr[t.Etype] {
   153  				t = t.Type
   154  			}
   155  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   156  				if Debug['E'] != 0 {
   157  					fmt.Printf("reexport literal type %v\n", t.Sym)
   158  				}
   159  				exportlist = list(exportlist, t.Sym.Def)
   160  			}
   161  		}
   162  		fallthrough
   163  
   164  	case OTYPE:
   165  		if n.Sym != nil && !exportedsym(n.Sym) {
   166  			if Debug['E'] != 0 {
   167  				fmt.Printf("reexport literal/type %v\n", n.Sym)
   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", t.Sym)
   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", s)
   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", s)
   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", s)
   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), s)
   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", s)
   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", s)
   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", s)
   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)", s, s.Def.Type, s.Importdef.Path, t, 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", s, 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)", pt.Sym, 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", pt, 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  }