export.c 10 KB
Newer Older
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Russ Cox's avatar
Russ Cox committed
5 6
#include	<u.h>
#include	<libc.h>
7 8 9
#include	"go.h"
#include	"y.tab.h"

10
static void	dumpexporttype(Type *t);
11

12
// Mark n's symbol as exported
Ken Thompson's avatar
export  
Ken Thompson committed
13
void
Russ Cox's avatar
Russ Cox committed
14
exportsym(Node *n)
Ken Thompson's avatar
export  
Ken Thompson committed
15
{
Russ Cox's avatar
Russ Cox committed
16
	if(n == N || n->sym == S)
Ken Thompson's avatar
export  
Ken Thompson committed
17
		return;
Russ Cox's avatar
Russ Cox committed
18 19 20
	if(n->sym->flags & (SymExport|SymPackage)) {
		if(n->sym->flags & SymPackage)
			yyerror("export/package mismatch: %S", n->sym);
Ken Thompson's avatar
export  
Ken Thompson committed
21
		return;
22
	}
Russ Cox's avatar
Russ Cox committed
23
	n->sym->flags |= SymExport;
Ken Thompson's avatar
export  
Ken Thompson committed
24

Russ Cox's avatar
Russ Cox committed
25
	exportlist = list(exportlist, n);
Ken Thompson's avatar
export  
Ken Thompson committed
26 27
}

28
// Mark n's symbol as package-local
Russ Cox's avatar
Russ Cox committed
29
static void
Russ Cox's avatar
Russ Cox committed
30
packagesym(Node *n)
31
{
Russ Cox's avatar
Russ Cox committed
32
	if(n == N || n->sym == S)
33
		return;
Russ Cox's avatar
Russ Cox committed
34 35 36
	if(n->sym->flags & (SymExport|SymPackage)) {
		if(n->sym->flags & SymExport)
			yyerror("export/package mismatch: %S", n->sym);
37 38
		return;
	}
Russ Cox's avatar
Russ Cox committed
39
	n->sym->flags |= SymPackage;
40

Russ Cox's avatar
Russ Cox committed
41
	exportlist = list(exportlist, n);
42
}
Ken Thompson's avatar
Ken Thompson committed
43

Russ Cox's avatar
Russ Cox committed
44 45 46 47 48 49 50 51 52 53 54
int
exportname(char *s)
{
	Rune r;

	if((uchar)s[0] < Runeself)
		return 'A' <= s[0] && s[0] <= 'Z';
	chartorune(&r, s);
	return isupperrune(r);
}

55 56 57 58 59 60
static int
initname(char *s)
{
	return strcmp(s, "init") == 0;
}

Russ Cox's avatar
Russ Cox committed
61
void
Russ Cox's avatar
Russ Cox committed
62
autoexport(Node *n, int ctxt)
Russ Cox's avatar
Russ Cox committed
63
{
Russ Cox's avatar
Russ Cox committed
64
	if(n == N || n->sym == S)
Russ Cox's avatar
Russ Cox committed
65
		return;
Russ Cox's avatar
Russ Cox committed
66
	if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
Russ Cox's avatar
Russ Cox committed
67
		return;
Russ Cox's avatar
Russ Cox committed
68 69
	if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left)	// method
		return;
70
	if(exportname(n->sym->name) || initname(n->sym->name))
Russ Cox's avatar
Russ Cox committed
71 72 73
		exportsym(n);
	else
		packagesym(n);
Russ Cox's avatar
Russ Cox committed
74 75
}

Russ Cox's avatar
Russ Cox committed
76
static void
77 78
dumppkg(Pkg *p)
{
79 80
	char *suffix;

81
	if(p == nil || p == localpkg || p->exported || p == builtinpkg)
82 83
		return;
	p->exported = 1;
84 85 86 87
	suffix = "";
	if(!p->direct)
		suffix = " // indirect";
	Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
88 89
}

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
// Look for anything we need for the inline body
static void reexportdep(Node *n);
static void
reexportdeplist(NodeList *ll)
{
	for(; ll ;ll=ll->next)
		reexportdep(ll->n);
}

static void
reexportdep(Node *n)
{
	Type *t;

	if(!n)
		return;

Luuk van Dijk's avatar
Luuk van Dijk committed
107
//	print("reexportdep %+hN\n", n);
108 109 110 111
	switch(n->op) {
	case ONAME:
		switch(n->class&~PHEAP) {
		case PFUNC:
Luuk van Dijk's avatar
Luuk van Dijk committed
112 113 114 115
			// methods will be printed along with their type
			if(!n->type || n->type->thistuple > 0)
				break;
			// fallthrough
116 117 118 119 120 121
		case PEXTERN:
			if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
				exportlist = list(exportlist, n);
		}
		break;

122 123 124 125 126 127 128 129 130 131 132
	case ODCL:
		// Local variables in the bodies need their type.
		t = n->left->type;
		if(t != types[t->etype] && t != idealbool && t != idealstring) {
			if(isptr[t->etype])
				t = t->type;
			if (t && t->sym && t->sym->def && t->sym->pkg != localpkg  && t->sym->pkg != builtinpkg) {
				exportlist = list(exportlist, t->sym->def);
			}
		}
		break;
Luuk van Dijk's avatar
Luuk van Dijk committed
133

134
	case OLITERAL:
Luuk van Dijk's avatar
Luuk van Dijk committed
135
		t = n->type;
Russ Cox's avatar
Russ Cox committed
136
		if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
Luuk van Dijk's avatar
Luuk van Dijk committed
137 138 139 140 141 142 143 144 145
			if(isptr[t->etype])
				t = t->type;
			if (t && t->sym && t->sym->def && t->sym->pkg != localpkg  && t->sym->pkg != builtinpkg) {
//				print("reexport literal type %+hN\n", t->sym->def);
				exportlist = list(exportlist, t->sym->def);
			}
		}
		// fallthrough
	case OTYPE:
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
		if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
			exportlist = list(exportlist, n);
		break;

	// for operations that need a type when rendered, put the type on the export list.
	case OCONV:
	case OCONVIFACE:
	case OCONVNOP:
	case ODOTTYPE:
	case OSTRUCTLIT:
	case OPTRLIT:
		t = n->type;
		if(!t->sym && t->type)
			t = t->type;
		if (t && t->sym && t->sym->def && t->sym->pkg != localpkg  && t->sym->pkg != builtinpkg) {
//			print("reexport convnop %+hN\n", t->sym->def);
			exportlist = list(exportlist, t->sym->def);
		}
		break;
	}

	reexportdep(n->left);
	reexportdep(n->right);
	reexportdeplist(n->list);
	reexportdeplist(n->rlist);
	reexportdeplist(n->ninit);
	reexportdep(n->ntest);
	reexportdep(n->nincr);
	reexportdeplist(n->nbody);
	reexportdeplist(n->nelse);
}


Russ Cox's avatar
Russ Cox committed
179
static void
180 181 182 183 184
dumpexportconst(Sym *s)
{
	Node *n;
	Type *t;

Russ Cox's avatar
Russ Cox committed
185
	n = s->def;
Russ Cox's avatar
Russ Cox committed
186
	typecheck(&n, Erv);
187
	if(n == N || n->op != OLITERAL)
Ken Thompson's avatar
Ken Thompson committed
188
		fatal("dumpexportconst: oconst nil: %S", s);
189 190

	t = n->type;	// may or may not be specified
Luuk van Dijk's avatar
Luuk van Dijk committed
191
	dumpexporttype(t);
192

Russ Cox's avatar
Russ Cox committed
193
	if(t != T && !isideal(t))
Luuk van Dijk's avatar
Luuk van Dijk committed
194 195 196
		Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
	else
		Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
197 198
}

Russ Cox's avatar
Russ Cox committed
199
static void
200 201 202 203 204
dumpexportvar(Sym *s)
{
	Node *n;
	Type *t;

Russ Cox's avatar
Russ Cox committed
205
	n = s->def;
Luuk van Dijk's avatar
Luuk van Dijk committed
206
	typecheck(&n, Erv|Ecall);
Ken Thompson's avatar
Ken Thompson committed
207
	if(n == N || n->type == T) {
Ken Thompson's avatar
Ken Thompson committed
208
		yyerror("variable exported but not defined: %S", s);
Ken Thompson's avatar
Ken Thompson committed
209 210
		return;
	}
211 212

	t = n->type;
Luuk van Dijk's avatar
Luuk van Dijk committed
213
	dumpexporttype(t);
214

215 216
	if(t->etype == TFUNC && n->class == PFUNC) {
		if (n->inl) {
Luuk van Dijk's avatar
Luuk van Dijk committed
217 218 219 220
			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
			if(debug['l'] < 2)
				typecheckinl(n);
221 222 223 224 225
			Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
			reexportdeplist(n->inl);
		} else
			Bprint(bout, "\tfunc %#S%#hT\n", s, t);
	} else
Luuk van Dijk's avatar
Luuk van Dijk committed
226
		Bprint(bout, "\tvar %#S %#T\n", s, t);
Russ Cox's avatar
Russ Cox committed
227 228
}

Russ Cox's avatar
Russ Cox committed
229 230 231 232 233 234 235 236 237 238
static int
methcmp(const void *va, const void *vb)
{
	Type *a, *b;
	
	a = *(Type**)va;
	b = *(Type**)vb;
	return strcmp(a->sym->name, b->sym->name);
}

Russ Cox's avatar
Russ Cox committed
239
static void
Luuk van Dijk's avatar
Luuk van Dijk committed
240
dumpexporttype(Type *t)
Russ Cox's avatar
Russ Cox committed
241
{
Luuk van Dijk's avatar
Luuk van Dijk committed
242
	Type *f;
Russ Cox's avatar
Russ Cox committed
243 244
	Type **m;
	int i, n;
245

Luuk van Dijk's avatar
Luuk van Dijk committed
246 247
	if(t == T)
		return;
Russ Cox's avatar
Russ Cox committed
248
	if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
Luuk van Dijk's avatar
Luuk van Dijk committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
		return;
	t->printed = 1;

	if(t->sym != S && t->etype != TFIELD)
		dumppkg(t->sym->pkg);

	dumpexporttype(t->type);
	dumpexporttype(t->down);

	if (t->sym == S || t->etype == TFIELD)
		return;

	n = 0;
	for(f=t->method; f!=T; f=f->down) {	
		dumpexporttype(f);
		n++;
	}

	m = mal(n*sizeof m[0]);
	i = 0;
	for(f=t->method; f!=T; f=f->down)
		m[i++] = f;
	qsort(m, n, sizeof m[0], methcmp);

	Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
	for(i=0; i<n; i++) {
		f = m[i];
276
		if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
Luuk van Dijk's avatar
Luuk van Dijk committed
277 278 279 280
			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
			if(debug['l'] < 2)
				typecheckinl(f->type->nname);
281 282 283 284
			Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
			reexportdeplist(f->type->nname->inl);
		} else
			Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type);
Luuk van Dijk's avatar
Luuk van Dijk committed
285 286 287 288 289 290
	}
}

static void
dumpsym(Sym *s)
{
Russ Cox's avatar
Russ Cox committed
291
	if(s->flags & SymExported)
292
		return;
Russ Cox's avatar
Russ Cox committed
293
	s->flags |= SymExported;
294

Russ Cox's avatar
Russ Cox committed
295
	if(s->def == N) {
Russ Cox's avatar
Russ Cox committed
296
		yyerror("unknown export symbol: %S", s);
Russ Cox's avatar
Russ Cox committed
297 298
		return;
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
299
//	print("dumpsym %O %+S\n", s->def->op, s);
300 301
	dumppkg(s->pkg);

Russ Cox's avatar
Russ Cox committed
302 303 304
	switch(s->def->op) {
	default:
		yyerror("unexpected export symbol: %O %S", s->def->op, s);
305
		break;
306

Russ Cox's avatar
Russ Cox committed
307 308
	case OLITERAL:
		dumpexportconst(s);
309
		break;
310

Russ Cox's avatar
Russ Cox committed
311
	case OTYPE:
Luuk van Dijk's avatar
Luuk van Dijk committed
312 313 314 315
		if(s->def->type->etype == TFORW)
			yyerror("export of incomplete type %S", s);
		else
			dumpexporttype(s->def->type);
316
		break;
317

Russ Cox's avatar
Russ Cox committed
318 319
	case ONAME:
		dumpexportvar(s);
320 321 322 323 324 325 326
		break;
	}
}

void
dumpexport(void)
{
Russ Cox's avatar
Russ Cox committed
327
	NodeList *l;
328 329
	int32 i, lno;
	Pkg *p;
330

Ken Thompson's avatar
Ken Thompson committed
331
	lno = lineno;
332

Luuk van Dijk's avatar
Luuk van Dijk committed
333
	Bprint(bout, "\n$$  // exports\n    package %s", localpkg->name);
334 335 336
	if(safemode)
		Bprint(bout, " safe");
	Bprint(bout, "\n");
Ken Thompson's avatar
Ken Thompson committed
337

338 339 340 341 342
	for(i=0; i<nelem(phash); i++)
		for(p=phash[i]; p; p=p->link)
			if(p->direct)
				dumppkg(p);

Russ Cox's avatar
Russ Cox committed
343 344 345
	for(l=exportlist; l; l=l->next) {
		lineno = l->n->lineno;
		dumpsym(l->n->sym);
346 347
	}

Luuk van Dijk's avatar
Luuk van Dijk committed
348
	Bprint(bout, "\n$$  // local types\n\n$$\n");   // 6l expects this. (see ld/go.c)
349

Ken Thompson's avatar
Ken Thompson committed
350
	lineno = lno;
351 352 353
}

/*
Russ Cox's avatar
Russ Cox committed
354
 * import
355
 */
Ken Thompson's avatar
Ken Thompson committed
356

Russ Cox's avatar
Russ Cox committed
357 358 359
/*
 * return the sym for ss, which should match lexical
 */
Ken Thompson's avatar
Ken Thompson committed
360
Sym*
Russ Cox's avatar
Russ Cox committed
361
importsym(Sym *s, int op)
Ken Thompson's avatar
Ken Thompson committed
362
{
363 364 365 366 367 368
	char *pkgstr;

	if(s->def != N && s->def->op != op) {
		pkgstr = smprint("during import \"%Z\"", importpkg->path);
		redeclare(s, pkgstr);
	}
369 370 371

	// mark the symbol so it is not reexported
	if(s->def == N) {
372
		if(exportname(s->name) || initname(s->name))
Russ Cox's avatar
Russ Cox committed
373
			s->flags |= SymExport;
374
		else
Russ Cox's avatar
Russ Cox committed
375
			s->flags |= SymPackage;	// package scope
376
	}
Ken Thompson's avatar
Ken Thompson committed
377 378 379
	return s;
}

380
/*
Russ Cox's avatar
Russ Cox committed
381
 * return the type pkg.name, forward declaring if needed
382
 */
Russ Cox's avatar
Russ Cox committed
383
Type*
Russ Cox's avatar
Russ Cox committed
384
pkgtype(Sym *s)
385
{
Russ Cox's avatar
Russ Cox committed
386
	Type *t;
387

Russ Cox's avatar
Russ Cox committed
388 389
	importsym(s, OTYPE);
	if(s->def == N || s->def->op != OTYPE) {
Russ Cox's avatar
Russ Cox committed
390 391
		t = typ(TFORW);
		t->sym = s;
Russ Cox's avatar
Russ Cox committed
392
		s->def = typenod(t);
393
	}
Russ Cox's avatar
Russ Cox committed
394
	if(s->def->type == T)
Luuk van Dijk's avatar
Luuk van Dijk committed
395
		yyerror("pkgtype %S", s);
Russ Cox's avatar
Russ Cox committed
396
	return s->def->type;
397 398
}

399 400
void
importimport(Sym *s, Strlit *z)
401
{
402 403 404 405 406
	// Informational: record package name
	// associated with import path, for use in
	// human-readable messages.
	Pkg *p;

407 408
	if(isbadimport(z))
		errorexit();
409 410 411 412 413 414 415 416 417 418 419
	p = mkpkg(z);
	if(p->name == nil) {
		p->name = s->name;
		pkglookup(s->name, nil)->npkg++;
	} else if(strcmp(p->name, s->name) != 0)
		yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
	
	if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
		yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
		errorexit();
	}
420 421
}

422
void
Russ Cox's avatar
Russ Cox committed
423
importconst(Sym *s, Type *t, Node *n)
424
{
Russ Cox's avatar
Russ Cox committed
425 426
	Node *n1;

Russ Cox's avatar
Russ Cox committed
427
	importsym(s, OLITERAL);
428
	convlit(&n, t);
429 430

	if(s->def != N)	 // TODO: check if already the same.
Russ Cox's avatar
Russ Cox committed
431
		return;
432

Russ Cox's avatar
Russ Cox committed
433 434 435 436
	if(n->op != OLITERAL) {
		yyerror("expression must be a constant");
		return;
	}
437

Russ Cox's avatar
Russ Cox committed
438 439 440 441 442
	if(n->sym != S) {
		n1 = nod(OXXX, N, N);
		*n1 = *n;
		n = n1;
	}
443
	n->orig = newname(s);
Russ Cox's avatar
Russ Cox committed
444 445
	n->sym = s;
	declare(n, PEXTERN);
446

447
	if(debug['E'])
Russ Cox's avatar
Russ Cox committed
448
		print("import const %S\n", s);
449 450 451
}

void
452
importvar(Sym *s, Type *t)
453
{
Russ Cox's avatar
Russ Cox committed
454 455
	Node *n;

Russ Cox's avatar
Russ Cox committed
456 457
	importsym(s, ONAME);
	if(s->def != N && s->def->op == ONAME) {
Russ Cox's avatar
Russ Cox committed
458
		if(eqtype(t, s->def->type))
Russ Cox's avatar
Russ Cox committed
459
			return;
Luuk van Dijk's avatar
Luuk van Dijk committed
460
		yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", s, s->def->type, t);
Russ Cox's avatar
Russ Cox committed
461
	}
Russ Cox's avatar
Russ Cox committed
462 463
	n = newname(s);
	n->type = t;
464
	declare(n, PEXTERN);
465

466
	if(debug['E'])
Russ Cox's avatar
Russ Cox committed
467
		print("import var %S %lT\n", s, t);
468 469 470
}

void
Russ Cox's avatar
Russ Cox committed
471
importtype(Type *pt, Type *t)
472
{
473 474
	Node *n;

475 476 477 478 479 480 481
	// override declaration in unsafe.go for Pointer.
	// there is no way in Go code to define unsafe.Pointer
	// so we have to supply it.
	if(incannedimport &&
	   strcmp(importpkg->name, "unsafe") == 0 &&
	   strcmp(pt->nod->sym->name, "Pointer") == 0) {
		t = types[TUNSAFEPTR];
482
	}
483

484 485 486 487 488 489 490
	if(pt->etype == TFORW) {
		n = pt->nod;
		copytype(pt->nod, t);
		pt->nod = n;		// unzero nod
		pt->sym->lastlineno = parserline();
		declare(n, PEXTERN);
		checkwidth(pt);
491
	} else if(!eqtype(pt->orig, t))
492
		yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
493

494
	if(debug['E'])
Russ Cox's avatar
Russ Cox committed
495
		print("import type %T %lT\n", pt, t);
496
}