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