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