summaryrefslogtreecommitdiff
path: root/src/cmd/gc/export.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
committerOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
commit505c19580e0f43fe5224431459cacb7c21edd93d (patch)
tree79e2634c253d60afc0cc0b2f510dc7dcbb48497b /src/cmd/gc/export.c
parent1336a7c91e596c423a49d1194ea42d98bca0d958 (diff)
downloadgolang-505c19580e0f43fe5224431459cacb7c21edd93d.tar.gz
Imported Upstream version 1upstream/1
Diffstat (limited to 'src/cmd/gc/export.c')
-rw-r--r--src/cmd/gc/export.c345
1 files changed, 198 insertions, 147 deletions
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 014f0c5f0..bbed8ae36 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "y.tab.h"
-static void dumpsym(Sym*);
-static void dumpexporttype(Sym*);
-static void dumpexportvar(Sym*);
-static void dumpexportconst(Sym*);
+static void dumpexporttype(Type *t);
+// Mark n's symbol as exported
void
exportsym(Node *n)
{
@@ -25,6 +25,7 @@ exportsym(Node *n)
exportlist = list(exportlist, n);
}
+// Mark n's symbol as package-local
static void
packagesym(Node *n)
{
@@ -77,7 +78,7 @@ dumppkg(Pkg *p)
{
char *suffix;
- if(p == nil || p == localpkg || p->exported)
+ if(p == nil || p == localpkg || p->exported || p == builtinpkg)
return;
p->exported = 1;
suffix = "";
@@ -86,25 +87,84 @@ dumppkg(Pkg *p)
Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
}
+// Look for anything we need for the inline body
+static void reexportdep(Node *n);
static void
-dumpprereq(Type *t)
+reexportdeplist(NodeList *ll)
{
- if(t == T)
- return;
+ for(; ll ;ll=ll->next)
+ reexportdep(ll->n);
+}
+
+static void
+reexportdep(Node *n)
+{
+ Type *t;
- if(t->printed || t == types[t->etype])
+ if(!n)
return;
- t->printed = 1;
- if(t->sym != S) {
- dumppkg(t->sym->pkg);
- if(t->etype != TFIELD)
- dumpsym(t->sym);
+// print("reexportdep %+hN\n", n);
+ switch(n->op) {
+ case ONAME:
+ switch(n->class&~PHEAP) {
+ case PFUNC:
+ // methods will be printed along with their type
+ if(!n->type || n->type->thistuple > 0)
+ break;
+ // fallthrough
+ case PEXTERN:
+ if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
+ exportlist = list(exportlist, n);
+ }
+ break;
+
+
+ case OLITERAL:
+ t = n->type;
+ if(t != types[n->type->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) {
+// print("reexport literal type %+hN\n", t->sym->def);
+ exportlist = list(exportlist, t->sym->def);
+ }
+ }
+ // fallthrough
+ case OTYPE:
+ 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;
}
- dumpprereq(t->type);
- dumpprereq(t->down);
+
+ 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);
}
+
static void
dumpexportconst(Sym *s)
{
@@ -117,37 +177,12 @@ dumpexportconst(Sym *s)
fatal("dumpexportconst: oconst nil: %S", s);
t = n->type; // may or may not be specified
- if(t != T)
- dumpprereq(t);
+ dumpexporttype(t);
- Bprint(bout, "\t");
- Bprint(bout, "const %#S", s);
if(t != T && !isideal(t))
- Bprint(bout, " %#T", t);
- Bprint(bout, " = ");
-
- switch(n->val.ctype) {
- default:
- fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
- case CTINT:
- Bprint(bout, "%B\n", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- Bprint(bout, "true\n");
- else
- Bprint(bout, "false\n");
- break;
- case CTFLT:
- Bprint(bout, "%F\n", n->val.u.fval);
- break;
- case CTCPLX:
- Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
- break;
- case CTSTR:
- Bprint(bout, "\"%Z\"\n", n->val.u.sval);
- break;
- }
+ Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
+ else
+ Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
}
static void
@@ -157,38 +192,27 @@ dumpexportvar(Sym *s)
Type *t;
n = s->def;
- typecheck(&n, Erv);
+ typecheck(&n, Erv|Ecall);
if(n == N || n->type == T) {
yyerror("variable exported but not defined: %S", s);
return;
}
t = n->type;
- dumpprereq(t);
-
- Bprint(bout, "\t");
- if(t->etype == TFUNC && n->class == PFUNC)
- Bprint(bout, "func %#S %#hhT", s, t);
- else
- Bprint(bout, "var %#S %#T", s, t);
- Bprint(bout, "\n");
-}
-
-static void
-dumpexporttype(Sym *s)
-{
- Type *t;
-
- t = s->def->type;
- dumpprereq(t);
- Bprint(bout, "\t");
- switch (t->etype) {
- case TFORW:
- yyerror("export of incomplete type %T", t);
- return;
- }
- if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
- fatal("Bprint failed for %T", t);
+ dumpexporttype(t);
+
+ if(t->etype == TFUNC && n->class == PFUNC) {
+ if (n->inl) {
+ // 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);
+ Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
+ reexportdeplist(n->inl);
+ } else
+ Bprint(bout, "\tfunc %#S%#hT\n", s, t);
+ } else
+ Bprint(bout, "\tvar %#S %#T\n", s, t);
}
static int
@@ -202,12 +226,57 @@ methcmp(const void *va, const void *vb)
}
static void
-dumpsym(Sym *s)
+dumpexporttype(Type *t)
{
- Type *f, *t;
+ Type *f;
Type **m;
int i, n;
+ if(t == T)
+ return;
+ if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
+ 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];
+ if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
+ // 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);
+ 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);
+ }
+}
+
+static void
+dumpsym(Sym *s)
+{
if(s->flags & SymExported)
return;
s->flags |= SymExported;
@@ -216,56 +285,31 @@ dumpsym(Sym *s)
yyerror("unknown export symbol: %S", s);
return;
}
-
+// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg(s->pkg);
switch(s->def->op) {
default:
yyerror("unexpected export symbol: %O %S", s->def->op, s);
break;
+
case OLITERAL:
dumpexportconst(s);
break;
+
case OTYPE:
- t = s->def->type;
- n = 0;
- for(f=t->method; f!=T; f=f->down) {
- dumpprereq(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);
-
- dumpexporttype(s);
- for(i=0; i<n; i++) {
- f = m[i];
- Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
- f->type->type->type, f->sym, f->type);
- }
+ if(s->def->type->etype == TFORW)
+ yyerror("export of incomplete type %S", s);
+ else
+ dumpexporttype(s->def->type);
break;
+
case ONAME:
dumpexportvar(s);
break;
}
}
-static void
-dumptype(Type *t)
-{
- // no need to re-dump type if already exported
- if(t->printed)
- return;
-
- // no need to dump type if it's not ours (was imported)
- if(t->sym != S && t->sym->def == typenod(t) && !t->local)
- return;
-
- Bprint(bout, "type %#T %l#T\n", t, t);
-}
-
void
dumpexport(void)
{
@@ -275,10 +319,7 @@ dumpexport(void)
lno = lineno;
- packagequotes = 1;
- Bprint(bout, "\n$$ // exports\n");
-
- Bprint(bout, " package %s", localpkg->name);
+ Bprint(bout, "\n$$ // exports\n package %s", localpkg->name);
if(safemode)
Bprint(bout, " safe");
Bprint(bout, "\n");
@@ -293,15 +334,7 @@ dumpexport(void)
dumpsym(l->n->sym);
}
- Bprint(bout, "\n$$ // local types\n");
-
- for(l=typelist; l; l=l->next) {
- lineno = l->n->lineno;
- dumptype(l->n->type);
- }
-
- Bprint(bout, "\n$$\n");
- packagequotes = 0;
+ Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c)
lineno = lno;
}
@@ -344,16 +377,29 @@ pkgtype(Sym *s)
s->def = typenod(t);
}
if(s->def->type == T)
- yyerror("pkgtype %lS", s);
+ yyerror("pkgtype %S", s);
return s->def->type;
}
-static int
-mypackage(Sym *s)
+void
+importimport(Sym *s, Strlit *z)
{
- // we import all definitions for runtime.
- // lowercase ones can only be used by the compiler.
- return s->pkg == localpkg || s->pkg == runtimepkg;
+ // Informational: record package name
+ // associated with import path, for use in
+ // human-readable messages.
+ Pkg *p;
+
+ 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();
+ }
}
void
@@ -361,24 +407,23 @@ importconst(Sym *s, Type *t, Node *n)
{
Node *n1;
- if(!exportname(s->name) && !mypackage(s))
- return;
importsym(s, OLITERAL);
convlit(&n, t);
- if(s->def != N) {
- // TODO: check if already the same.
+
+ if(s->def != N) // TODO: check if already the same.
return;
- }
if(n->op != OLITERAL) {
yyerror("expression must be a constant");
return;
}
+
if(n->sym != S) {
n1 = nod(OXXX, N, N);
*n1 = *n;
n = n1;
}
+ n->orig = newname(s);
n->sym = s;
declare(n, PEXTERN);
@@ -387,23 +432,19 @@ importconst(Sym *s, Type *t, Node *n)
}
void
-importvar(Sym *s, Type *t, int ctxt)
+importvar(Sym *s, Type *t)
{
Node *n;
- if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
- return;
-
importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) {
if(eqtype(t, s->def->type))
return;
- yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
- s, s->def->type, t);
+ yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", s, s->def->type, t);
}
n = newname(s);
n->type = t;
- declare(n, ctxt);
+ declare(n, PEXTERN);
if(debug['E'])
print("import var %S %lT\n", s, t);
@@ -412,17 +453,27 @@ importvar(Sym *s, Type *t, int ctxt)
void
importtype(Type *pt, Type *t)
{
- if(pt != T && t != T)
- typedcl2(pt, t);
+ Node *n;
+
+ // 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];
+ }
+
+ 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);
+ } else if(!eqtype(pt->orig, t))
+ yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
if(debug['E'])
print("import type %T %lT\n", pt, t);
}
-
-void
-importmethod(Sym *s, Type *t)
-{
- checkwidth(t);
- addmethod(s, t, 0);
-}
-