mirror of
https://github.com/golang/go
synced 2024-10-03 17:21:21 -06:00
e6f3aa6c36
This change records more metadata about what influenced the creation of the object file. Specifically, if a package imports, say, "fmt" but does not need to describe any fmt types in its own export data, that package's object file did not mention the dependency on "fmt" before. Now it does. Listing the import is purely informational. It has no effect on which files are opened or consulted when importing a package. Import lines are marked indirect when they are needed to explain the API but were not imported directly. For example http imports crypto/tls and exports a struct with a field of type tls.ConnectionState, which contains an x509.Certificate. Since http does not import x509 but needs to explain the x509.Certificate type in its export data, the import of x509 is marked as indirect. These import lines were always present; marking them with the indirect comment makes clear which were imported directly and which are incidental. R=ken2 CC=golang-dev https://golang.org/cl/4295048
429 lines
7.2 KiB
C
429 lines
7.2 KiB
C
// 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.
|
|
|
|
#include "go.h"
|
|
#include "y.tab.h"
|
|
|
|
static void dumpsym(Sym*);
|
|
static void dumpexporttype(Sym*);
|
|
static void dumpexportvar(Sym*);
|
|
static void dumpexportconst(Sym*);
|
|
|
|
void
|
|
exportsym(Node *n)
|
|
{
|
|
if(n == N || n->sym == S)
|
|
return;
|
|
if(n->sym->flags & (SymExport|SymPackage)) {
|
|
if(n->sym->flags & SymPackage)
|
|
yyerror("export/package mismatch: %S", n->sym);
|
|
return;
|
|
}
|
|
n->sym->flags |= SymExport;
|
|
|
|
exportlist = list(exportlist, n);
|
|
}
|
|
|
|
static void
|
|
packagesym(Node *n)
|
|
{
|
|
if(n == N || n->sym == S)
|
|
return;
|
|
if(n->sym->flags & (SymExport|SymPackage)) {
|
|
if(n->sym->flags & SymExport)
|
|
yyerror("export/package mismatch: %S", n->sym);
|
|
return;
|
|
}
|
|
n->sym->flags |= SymPackage;
|
|
|
|
exportlist = list(exportlist, n);
|
|
}
|
|
|
|
int
|
|
exportname(char *s)
|
|
{
|
|
Rune r;
|
|
|
|
if((uchar)s[0] < Runeself)
|
|
return 'A' <= s[0] && s[0] <= 'Z';
|
|
chartorune(&r, s);
|
|
return isupperrune(r);
|
|
}
|
|
|
|
static int
|
|
initname(char *s)
|
|
{
|
|
return strcmp(s, "init") == 0;
|
|
}
|
|
|
|
void
|
|
autoexport(Node *n, int ctxt)
|
|
{
|
|
if(n == N || n->sym == S)
|
|
return;
|
|
if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
|
|
return;
|
|
if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
|
|
return;
|
|
if(exportname(n->sym->name) || initname(n->sym->name))
|
|
exportsym(n);
|
|
else
|
|
packagesym(n);
|
|
}
|
|
|
|
static void
|
|
dumppkg(Pkg *p)
|
|
{
|
|
char *suffix;
|
|
|
|
if(p == nil || p == localpkg || p->exported)
|
|
return;
|
|
p->exported = 1;
|
|
suffix = "";
|
|
if(!p->direct)
|
|
suffix = " // indirect";
|
|
Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
|
|
}
|
|
|
|
static void
|
|
dumpprereq(Type *t)
|
|
{
|
|
if(t == T)
|
|
return;
|
|
|
|
if(t->printed || t == types[t->etype])
|
|
return;
|
|
t->printed = 1;
|
|
|
|
if(t->sym != S) {
|
|
dumppkg(t->sym->pkg);
|
|
if(t->etype != TFIELD)
|
|
dumpsym(t->sym);
|
|
}
|
|
dumpprereq(t->type);
|
|
dumpprereq(t->down);
|
|
}
|
|
|
|
static void
|
|
dumpexportconst(Sym *s)
|
|
{
|
|
Node *n;
|
|
Type *t;
|
|
|
|
n = s->def;
|
|
typecheck(&n, Erv);
|
|
if(n == N || n->op != OLITERAL)
|
|
fatal("dumpexportconst: oconst nil: %S", s);
|
|
|
|
t = n->type; // may or may not be specified
|
|
if(t != T)
|
|
dumpprereq(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;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dumpexportvar(Sym *s)
|
|
{
|
|
Node *n;
|
|
Type *t;
|
|
|
|
n = s->def;
|
|
typecheck(&n, Erv);
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
dumpsym(Sym *s)
|
|
{
|
|
Type *f, *t;
|
|
Type **m;
|
|
int i, n;
|
|
|
|
if(s->flags & SymExported)
|
|
return;
|
|
s->flags |= SymExported;
|
|
|
|
if(s->def == N) {
|
|
yyerror("unknown export symbol: %S", s);
|
|
return;
|
|
}
|
|
|
|
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);
|
|
}
|
|
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)
|
|
{
|
|
NodeList *l;
|
|
int32 i, lno;
|
|
Pkg *p;
|
|
|
|
lno = lineno;
|
|
|
|
packagequotes = 1;
|
|
Bprint(bout, "\n$$ // exports\n");
|
|
|
|
Bprint(bout, " package %s", localpkg->name);
|
|
if(safemode)
|
|
Bprint(bout, " safe");
|
|
Bprint(bout, "\n");
|
|
|
|
for(i=0; i<nelem(phash); i++)
|
|
for(p=phash[i]; p; p=p->link)
|
|
if(p->direct)
|
|
dumppkg(p);
|
|
|
|
for(l=exportlist; l; l=l->next) {
|
|
lineno = l->n->lineno;
|
|
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;
|
|
|
|
lineno = lno;
|
|
}
|
|
|
|
/*
|
|
* import
|
|
*/
|
|
|
|
/*
|
|
* return the sym for ss, which should match lexical
|
|
*/
|
|
Sym*
|
|
importsym(Sym *s, int op)
|
|
{
|
|
if(s->def != N && s->def->op != op)
|
|
redeclare(s, "during import");
|
|
|
|
// mark the symbol so it is not reexported
|
|
if(s->def == N) {
|
|
if(exportname(s->name) || initname(s->name))
|
|
s->flags |= SymExport;
|
|
else
|
|
s->flags |= SymPackage; // package scope
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/*
|
|
* return the type pkg.name, forward declaring if needed
|
|
*/
|
|
Type*
|
|
pkgtype(Sym *s)
|
|
{
|
|
Type *t;
|
|
|
|
importsym(s, OTYPE);
|
|
if(s->def == N || s->def->op != OTYPE) {
|
|
t = typ(TFORW);
|
|
t->sym = s;
|
|
s->def = typenod(t);
|
|
}
|
|
if(s->def->type == T)
|
|
yyerror("pkgtype %lS", s);
|
|
return s->def->type;
|
|
}
|
|
|
|
static int
|
|
mypackage(Sym *s)
|
|
{
|
|
// we import all definitions for runtime.
|
|
// lowercase ones can only be used by the compiler.
|
|
return s->pkg == localpkg || s->pkg == runtimepkg;
|
|
}
|
|
|
|
void
|
|
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.
|
|
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->sym = s;
|
|
declare(n, PEXTERN);
|
|
|
|
if(debug['E'])
|
|
print("import const %S\n", s);
|
|
}
|
|
|
|
void
|
|
importvar(Sym *s, Type *t, int ctxt)
|
|
{
|
|
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);
|
|
}
|
|
n = newname(s);
|
|
n->type = t;
|
|
declare(n, ctxt);
|
|
|
|
if(debug['E'])
|
|
print("import var %S %lT\n", s, t);
|
|
}
|
|
|
|
void
|
|
importtype(Type *pt, Type *t)
|
|
{
|
|
if(pt != T && t != T)
|
|
typedcl2(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);
|
|
}
|
|
|