diff options
Diffstat (limited to 'src/cmd/gc/subr.c')
-rw-r--r-- | src/cmd/gc/subr.c | 3851 |
1 files changed, 0 insertions, 3851 deletions
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c deleted file mode 100644 index 40b0c4fd1..000000000 --- a/src/cmd/gc/subr.c +++ /dev/null @@ -1,3851 +0,0 @@ -// 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 "md5.h" -#include "y.tab.h" -#include "opnames.h" -#include "yerr.h" - -static void dodump(Node*, int); - -typedef struct Error Error; -struct Error -{ - int lineno; - int seq; - char *msg; -}; -static Error *err; -static int nerr; -static int merr; - -void -errorexit(void) -{ - flusherrors(); - if(outfile) - remove(outfile); - exit(1); -} - -extern int yychar; -int -parserline(void) -{ - if(yychar != 0 && yychar != -2) // parser has one symbol lookahead - return prevlineno; - return lineno; -} - -static void -adderr(int line, char *fmt, va_list arg) -{ - Fmt f; - Error *p; - - erroring++; - fmtstrinit(&f); - fmtprint(&f, "%L: ", line); - fmtvprint(&f, fmt, arg); - fmtprint(&f, "\n"); - erroring--; - - if(nerr >= merr) { - if(merr == 0) - merr = 16; - else - merr *= 2; - p = realloc(err, merr*sizeof err[0]); - if(p == nil) { - merr = nerr; - flusherrors(); - print("out of memory\n"); - errorexit(); - } - err = p; - } - err[nerr].seq = nerr; - err[nerr].lineno = line; - err[nerr].msg = fmtstrflush(&f); - nerr++; -} - -static int -errcmp(const void *va, const void *vb) -{ - Error *a, *b; - - a = (Error*)va; - b = (Error*)vb; - if(a->lineno != b->lineno) - return a->lineno - b->lineno; - if(a->seq != b->seq) - return a->seq - b->seq; - return strcmp(a->msg, b->msg); -} - -void -flusherrors(void) -{ - int i; - - if(nerr == 0) - return; - qsort(err, nerr, sizeof err[0], errcmp); - for(i=0; i<nerr; i++) - if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0) - print("%s", err[i].msg); - nerr = 0; -} - -static void -hcrash(void) -{ - if(debug['h']) { - flusherrors(); - if(outfile) - unlink(outfile); - *(volatile int*)0 = 0; - } -} - -void -yyerrorl(int line, char *fmt, ...) -{ - va_list arg; - - va_start(arg, fmt); - adderr(line, fmt, arg); - va_end(arg); - - hcrash(); - nerrors++; - if(nerrors >= 10 && !debug['e']) { - flusherrors(); - print("%L: too many errors\n", line); - errorexit(); - } -} - -extern int yystate, yychar; - -void -yyerror(char *fmt, ...) -{ - int i; - static int lastsyntax; - va_list arg; - char buf[512], *p; - - if(strncmp(fmt, "syntax error", 12) == 0) { - nsyntaxerrors++; - - if(debug['x']) - print("yyerror: yystate=%d yychar=%d\n", yystate, yychar); - - // only one syntax error per line - if(lastsyntax == lexlineno) - return; - lastsyntax = lexlineno; - - if(strstr(fmt, "{ or {")) { - // The grammar has { and LBRACE but both show up as {. - // Rewrite syntax error referring to "{ or {" to say just "{". - strecpy(buf, buf+sizeof buf, fmt); - p = strstr(buf, "{ or {"); - if(p) - memmove(p+1, p+6, strlen(p+6)+1); - fmt = buf; - } - - // look for parse state-specific errors in list (see go.errors). - for(i=0; i<nelem(yymsg); i++) { - if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) { - yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg); - return; - } - } - - // plain "syntax error" gets "near foo" added - if(strcmp(fmt, "syntax error") == 0) { - yyerrorl(lexlineno, "syntax error near %s", lexbuf); - return; - } - - // if bison says "syntax error, more info"; print "syntax error: more info". - if(fmt[12] == ',') { - yyerrorl(lexlineno, "syntax error:%s", fmt+13); - return; - } - - yyerrorl(lexlineno, "%s", fmt); - return; - } - - va_start(arg, fmt); - adderr(parserline(), fmt, arg); - va_end(arg); - - hcrash(); - nerrors++; - if(nerrors >= 10 && !debug['e']) { - flusherrors(); - print("%L: too many errors\n", parserline()); - errorexit(); - } -} - -void -warn(char *fmt, ...) -{ - va_list arg; - - va_start(arg, fmt); - adderr(parserline(), fmt, arg); - va_end(arg); - - hcrash(); -} - -void -fatal(char *fmt, ...) -{ - va_list arg; - - flusherrors(); - - print("%L: internal compiler error: ", lineno); - va_start(arg, fmt); - vfprint(1, fmt, arg); - va_end(arg); - print("\n"); - - // If this is a released compiler version, ask for a bug report. - if(strncmp(getgoversion(), "release", 7) == 0) { - print("\n"); - print("Please file a bug report including a short program that triggers the error.\n"); - print("http://code.google.com/p/go/issues/entry?template=compilerbug\n"); - } - hcrash(); - errorexit(); -} - -void -linehist(char *file, int32 off, int relative) -{ - Hist *h; - char *cp; - - if(debug['i']) { - if(file != nil) { - if(off < 0) - print("pragma %s", file); - else - if(off > 0) - print("line %s", file); - else - print("import %s", file); - } else - print("end of import"); - print(" at line %L\n", lexlineno); - } - - if(off < 0 && file[0] != '/' && !relative) { - cp = mal(strlen(file) + strlen(pathname) + 2); - sprint(cp, "%s/%s", pathname, file); - file = cp; - } - - h = mal(sizeof(Hist)); - h->name = file; - h->line = lexlineno; - h->offset = off; - h->link = H; - if(ehist == H) { - hist = h; - ehist = h; - return; - } - ehist->link = h; - ehist = h; -} - -int32 -setlineno(Node *n) -{ - int32 lno; - - lno = lineno; - if(n != N) - switch(n->op) { - case ONAME: - case OTYPE: - case OPACK: - case OLITERAL: - break; - default: - lineno = n->lineno; - if(lineno == 0) { - if(debug['K']) - warn("setlineno: line 0"); - lineno = lno; - } - } - return lno; -} - -uint32 -stringhash(char *p) -{ - int32 h; - int c; - - h = 0; - for(;;) { - c = *p++; - if(c == 0) - break; - h = h*PRIME1 + c; - } - - if(h < 0) { - h = -h; - if(h < 0) - h = 0; - } - return h; -} - -Sym* -lookup(char *name) -{ - return pkglookup(name, localpkg); -} - -Sym* -pkglookup(char *name, Pkg *pkg) -{ - Sym *s; - uint32 h; - int c; - - h = stringhash(name) % NHASH; - c = name[0]; - for(s = hash[h]; s != S; s = s->link) { - if(s->name[0] != c || s->pkg != pkg) - continue; - if(strcmp(s->name, name) == 0) - return s; - } - - s = mal(sizeof(*s)); - s->name = mal(strlen(name)+1); - strcpy(s->name, name); - - s->pkg = pkg; - - s->link = hash[h]; - hash[h] = s; - s->lexical = LNAME; - - return s; -} - -Sym* -restrictlookup(char *name, Pkg *pkg) -{ - if(!exportname(name) && pkg != localpkg) - yyerror("cannot refer to unexported name %s.%s", pkg->name, name); - return pkglookup(name, pkg); -} - - -// find all the exported symbols in package opkg -// and make them available in the current package -void -importdot(Pkg *opkg, Node *pack) -{ - Sym *s, *s1; - uint32 h; - int n; - - n = 0; - for(h=0; h<NHASH; h++) { - for(s = hash[h]; s != S; s = s->link) { - if(s->pkg != opkg) - continue; - if(s->def == N) - continue; - if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot - continue; - s1 = lookup(s->name); - if(s1->def != N) { - redeclare(s1, "during import"); - continue; - } - s1->def = s->def; - s1->block = s->block; - s1->def->pack = pack; - n++; - } - } - if(n == 0) { - // can't possibly be used - there were no symbols - yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path); - } -} - -static void -gethunk(void) -{ - char *h; - int32 nh; - - nh = NHUNK; - if(thunk >= 10L*NHUNK) - nh = 10L*NHUNK; - h = (char*)malloc(nh); - if(h == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; -} - -void* -mal(int32 n) -{ - void *p; - - if(n >= NHUNK) { - p = malloc(n); - if(p == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - memset(p, 0, n); - return p; - } - - while((uintptr)hunk & MAXALIGN) { - hunk++; - nhunk--; - } - if(nhunk < n) - gethunk(); - - p = hunk; - nhunk -= n; - hunk += n; - memset(p, 0, n); - return p; -} - -void* -remal(void *p, int32 on, int32 n) -{ - void *q; - - q = (uchar*)p + on; - if(q != hunk || nhunk < n) { - if(on+n >= NHUNK) { - q = mal(on+n); - memmove(q, p, on); - return q; - } - if(nhunk < on+n) - gethunk(); - memmove(hunk, p, on); - p = hunk; - hunk += on; - nhunk -= on; - } - hunk += n; - nhunk -= n; - return p; -} - -Node* -nod(int op, Node *nleft, Node *nright) -{ - Node *n; - - n = mal(sizeof(*n)); - n->op = op; - n->left = nleft; - n->right = nright; - n->lineno = parserline(); - n->xoffset = BADWIDTH; - n->orig = n; - return n; -} - -int -algtype(Type *t) -{ - int a; - - if(issimple[t->etype] || isptr[t->etype] || - t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) { - if(t->width == widthptr) - a = AMEMWORD; - else - a = AMEM; // just bytes (int, ptr, etc) - } else if(t->etype == TSTRING) - a = ASTRING; // string - else if(isnilinter(t)) - a = ANILINTER; // nil interface - else if(t->etype == TINTER) - a = AINTER; // interface - else - a = ANOEQ; // just bytes, but no hash/eq - return a; -} - -Type* -maptype(Type *key, Type *val) -{ - Type *t; - - - if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) { - if(key->etype == TFORW) { - // map[key] used during definition of key. - // postpone check until key is fully defined. - // if there are multiple uses of map[key] - // before key is fully defined, the error - // will only be printed for the first one. - // good enough. - if(key->maplineno == 0) - key->maplineno = lineno; - } else - yyerror("invalid map key type %T", key); - } - t = typ(TMAP); - t->down = key; - t->type = val; - return t; -} - -Type* -typ(int et) -{ - Type *t; - - t = mal(sizeof(*t)); - t->etype = et; - t->width = BADWIDTH; - t->lineno = lineno; - t->orig = t; - return t; -} - -static int -methcmp(const void *va, const void *vb) -{ - Type *a, *b; - int i; - - a = *(Type**)va; - b = *(Type**)vb; - i = strcmp(a->sym->name, b->sym->name); - if(i != 0) - return i; - if(!exportname(a->sym->name)) { - i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s); - if(i != 0) - return i; - } - return 0; -} - -Type* -sortinter(Type *t) -{ - Type *f; - int i; - Type **a; - - if(t->type == nil || t->type->down == nil) - return t; - - i=0; - for(f=t->type; f; f=f->down) - i++; - a = mal(i*sizeof f); - i = 0; - for(f=t->type; f; f=f->down) - a[i++] = f; - qsort(a, i, sizeof a[0], methcmp); - while(i-- > 0) { - a[i]->down = f; - f = a[i]; - } - t->type = f; - return t; -} - -Node* -nodintconst(int64 v) -{ - Node *c; - - c = nod(OLITERAL, N, N); - c->addable = 1; - c->val.u.xval = mal(sizeof(*c->val.u.xval)); - mpmovecfix(c->val.u.xval, v); - c->val.ctype = CTINT; - c->type = types[TIDEAL]; - ullmancalc(c); - return c; -} - -Node* -nodfltconst(Mpflt* v) -{ - Node *c; - - c = nod(OLITERAL, N, N); - c->addable = 1; - c->val.u.fval = mal(sizeof(*c->val.u.fval)); - mpmovefltflt(c->val.u.fval, v); - c->val.ctype = CTFLT; - c->type = types[TIDEAL]; - ullmancalc(c); - return c; -} - -void -nodconst(Node *n, Type *t, int64 v) -{ - memset(n, 0, sizeof(*n)); - n->op = OLITERAL; - n->addable = 1; - ullmancalc(n); - n->val.u.xval = mal(sizeof(*n->val.u.xval)); - mpmovecfix(n->val.u.xval, v); - n->val.ctype = CTINT; - n->type = t; - - if(isfloat[t->etype]) - fatal("nodconst: bad type %T", t); -} - -Node* -nodnil(void) -{ - Node *c; - - c = nodintconst(0); - c->val.ctype = CTNIL; - c->type = types[TNIL]; - return c; -} - -Node* -nodbool(int b) -{ - Node *c; - - c = nodintconst(0); - c->val.ctype = CTBOOL; - c->val.u.bval = b; - c->type = idealbool; - return c; -} - -Type* -aindex(Node *b, Type *t) -{ - Type *r; - int bound; - - bound = -1; // open bound - typecheck(&b, Erv); - if(b != nil) { - switch(consttype(b)) { - default: - yyerror("array bound must be an integer expression"); - break; - case CTINT: - bound = mpgetfix(b->val.u.xval); - if(bound < 0) - yyerror("array bound must be non negative"); - break; - } - } - - // fixed array - r = typ(TARRAY); - r->type = t; - r->bound = bound; - return r; -} - -static void -indent(int dep) -{ - int i; - - for(i=0; i<dep; i++) - print(". "); -} - -static void -dodumplist(NodeList *l, int dep) -{ - for(; l; l=l->next) - dodump(l->n, dep); -} - -static void -dodump(Node *n, int dep) -{ - if(n == N) - return; - - indent(dep); - if(dep > 10) { - print("...\n"); - return; - } - - if(n->ninit != nil) { - print("%O-init\n", n->op); - dodumplist(n->ninit, dep+1); - indent(dep); - } - - switch(n->op) { - default: - print("%N\n", n); - dodump(n->left, dep+1); - dodump(n->right, dep+1); - break; - - case OTYPE: - print("%O %S type=%T\n", n->op, n->sym, n->type); - if(n->type == T && n->ntype) { - indent(dep); - print("%O-ntype\n", n->op); - dodump(n->ntype, dep+1); - } - break; - - case OIF: - print("%O%J\n", n->op, n); - dodump(n->ntest, dep+1); - if(n->nbody != nil) { - indent(dep); - print("%O-then\n", n->op); - dodumplist(n->nbody, dep+1); - } - if(n->nelse != nil) { - indent(dep); - print("%O-else\n", n->op); - dodumplist(n->nelse, dep+1); - } - break; - - case OSELECT: - print("%O%J\n", n->op, n); - dodumplist(n->nbody, dep+1); - break; - - case OSWITCH: - case OFOR: - print("%O%J\n", n->op, n); - dodump(n->ntest, dep+1); - - if(n->nbody != nil) { - indent(dep); - print("%O-body\n", n->op); - dodumplist(n->nbody, dep+1); - } - - if(n->nincr != N) { - indent(dep); - print("%O-incr\n", n->op); - dodump(n->nincr, dep+1); - } - break; - - case OCASE: - // the right side points to label of the body - if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME) - print("%O%J GOTO %N\n", n->op, n, n->right->left); - else - print("%O%J\n", n->op, n); - dodump(n->left, dep+1); - break; - - case OXCASE: - print("%N\n", n); - dodump(n->left, dep+1); - dodump(n->right, dep+1); - indent(dep); - print("%O-nbody\n", n->op); - dodumplist(n->nbody, dep+1); - break; - } - - if(0 && n->ntype != nil) { - indent(dep); - print("%O-ntype\n", n->op); - dodump(n->ntype, dep+1); - } - if(n->list != nil) { - indent(dep); - print("%O-list\n", n->op); - dodumplist(n->list, dep+1); - } - if(n->rlist != nil) { - indent(dep); - print("%O-rlist\n", n->op); - dodumplist(n->rlist, dep+1); - } - if(n->op != OIF && n->nbody != nil) { - indent(dep); - print("%O-nbody\n", n->op); - dodumplist(n->nbody, dep+1); - } -} - -void -dumplist(char *s, NodeList *l) -{ - print("%s\n", s); - dodumplist(l, 1); -} - -void -dump(char *s, Node *n) -{ - print("%s [%p]\n", s, n); - dodump(n, 1); -} - -static char* -goopnames[] = -{ - [OADDR] = "&", - [OADD] = "+", - [OANDAND] = "&&", - [OANDNOT] = "&^", - [OAND] = "&", - [OAPPEND] = "append", - [OAS] = "=", - [OAS2] = "=", - [OBREAK] = "break", - [OCALL] = "function call", - [OCAP] = "cap", - [OCASE] = "case", - [OCLOSE] = "close", - [OCOMPLEX] = "complex", - [OCOM] = "^", - [OCONTINUE] = "continue", - [OCOPY] = "copy", - [ODEC] = "--", - [ODEFER] = "defer", - [ODIV] = "/", - [OEQ] = "==", - [OFALL] = "fallthrough", - [OFOR] = "for", - [OGE] = ">=", - [OGOTO] = "goto", - [OGT] = ">", - [OIF] = "if", - [OIMAG] = "imag", - [OINC] = "++", - [OIND] = "*", - [OLEN] = "len", - [OLE] = "<=", - [OLSH] = "<<", - [OLT] = "<", - [OMAKE] = "make", - [OMINUS] = "-", - [OMOD] = "%", - [OMUL] = "*", - [ONEW] = "new", - [ONE] = "!=", - [ONOT] = "!", - [OOROR] = "||", - [OOR] = "|", - [OPANIC] = "panic", - [OPLUS] = "+", - [OPRINTN] = "println", - [OPRINT] = "print", - [ORANGE] = "range", - [OREAL] = "real", - [ORECV] = "<-", - [ORETURN] = "return", - [ORSH] = ">>", - [OSELECT] = "select", - [OSEND] = "<-", - [OSUB] = "-", - [OSWITCH] = "switch", - [OXOR] = "^", -}; - -int -Oconv(Fmt *fp) -{ - int o; - - o = va_arg(fp->args, int); - if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) - return fmtstrcpy(fp, goopnames[o]); - if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) - return fmtprint(fp, "O-%d", o); - return fmtstrcpy(fp, opnames[o]); -} - -int -Lconv(Fmt *fp) -{ - struct - { - Hist* incl; /* start of this include file */ - int32 idel; /* delta line number to apply to include */ - Hist* line; /* start of this #line directive */ - int32 ldel; /* delta line number to apply to #line */ - } a[HISTSZ]; - int32 lno, d; - int i, n; - Hist *h; - - lno = va_arg(fp->args, int32); - - n = 0; - for(h=hist; h!=H; h=h->link) { - if(h->offset < 0) - continue; - if(lno < h->line) - break; - if(h->name) { - if(h->offset > 0) { - // #line directive - if(n > 0 && n < HISTSZ) { - a[n-1].line = h; - a[n-1].ldel = h->line - h->offset + 1; - } - } else { - // beginning of file - if(n < HISTSZ) { - a[n].incl = h; - a[n].idel = h->line; - a[n].line = 0; - } - n++; - } - continue; - } - n--; - if(n > 0 && n < HISTSZ) { - d = h->line - a[n].incl->line; - a[n-1].ldel += d; - a[n-1].idel += d; - } - } - - if(n > HISTSZ) - n = HISTSZ; - - for(i=n-1; i>=0; i--) { - if(i != n-1) { - if(fp->flags & ~(FmtWidth|FmtPrec)) - break; - fmtprint(fp, " "); - } - if(debug['L']) - fmtprint(fp, "%s/", pathname); - if(a[i].line) - fmtprint(fp, "%s:%d[%s:%d]", - a[i].line->name, lno-a[i].ldel+1, - a[i].incl->name, lno-a[i].idel+1); - else - fmtprint(fp, "%s:%d", - a[i].incl->name, lno-a[i].idel+1); - lno = a[i].incl->line - 1; // now print out start of this file - } - if(n == 0) - fmtprint(fp, "<epoch>"); - - return 0; -} - -/* -s%,%,\n%g -s%\n+%\n%g -s%^[ ]*T%%g -s%,.*%%g -s%.+% [T&] = "&",%g -s%^ ........*\]%&~%g -s%~ %%g -*/ - -static char* -etnames[] = -{ - [TINT] = "INT", - [TUINT] = "UINT", - [TINT8] = "INT8", - [TUINT8] = "UINT8", - [TINT16] = "INT16", - [TUINT16] = "UINT16", - [TINT32] = "INT32", - [TUINT32] = "UINT32", - [TINT64] = "INT64", - [TUINT64] = "UINT64", - [TUINTPTR] = "UINTPTR", - [TFLOAT32] = "FLOAT32", - [TFLOAT64] = "FLOAT64", - [TCOMPLEX64] = "COMPLEX64", - [TCOMPLEX128] = "COMPLEX128", - [TBOOL] = "BOOL", - [TPTR32] = "PTR32", - [TPTR64] = "PTR64", - [TFUNC] = "FUNC", - [TARRAY] = "ARRAY", - [TSTRUCT] = "STRUCT", - [TCHAN] = "CHAN", - [TMAP] = "MAP", - [TINTER] = "INTER", - [TFORW] = "FORW", - [TFIELD] = "FIELD", - [TSTRING] = "STRING", - [TANY] = "ANY", -}; - -int -Econv(Fmt *fp) -{ - int et; - - et = va_arg(fp->args, int); - if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) - return fmtprint(fp, "E-%d", et); - return fmtstrcpy(fp, etnames[et]); -} - -static const char* classnames[] = { - "Pxxx", - "PEXTERN", - "PAUTO", - "PPARAM", - "PPARAMOUT", - "PPARAMREF", - "PFUNC", -}; - -int -Jconv(Fmt *fp) -{ - Node *n; - char *s; - - n = va_arg(fp->args, Node*); - if(n->ullman != 0) - fmtprint(fp, " u(%d)", n->ullman); - - if(n->addable != 0) - fmtprint(fp, " a(%d)", n->addable); - - if(n->vargen != 0) - fmtprint(fp, " g(%d)", n->vargen); - - if(n->lineno != 0) - fmtprint(fp, " l(%d)", n->lineno); - - if(n->xoffset != BADWIDTH) - fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta); - - if(n->class != 0) { - s = ""; - if (n->class & PHEAP) s = ",heap"; - if ((n->class & ~PHEAP) < nelem(classnames)) - fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s); - else - fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s); - } - - if(n->colas != 0) - fmtprint(fp, " colas(%d)", n->colas); - - if(n->funcdepth != 0) - fmtprint(fp, " f(%d)", n->funcdepth); - - if(n->typecheck != 0) - fmtprint(fp, " tc(%d)", n->typecheck); - - if(n->dodata != 0) - fmtprint(fp, " dd(%d)", n->dodata); - - if(n->isddd != 0) - fmtprint(fp, " isddd(%d)", n->isddd); - - if(n->implicit != 0) - fmtprint(fp, " implicit(%d)", n->implicit); - - if(n->pun != 0) - fmtprint(fp, " pun(%d)", n->pun); - - if(n->used != 0) - fmtprint(fp, " used(%d)", n->used); - return 0; -} - -int -Sconv(Fmt *fp) -{ - Sym *s; - - s = va_arg(fp->args, Sym*); - if(s == S) { - fmtstrcpy(fp, "<S>"); - return 0; - } - - if(fp->flags & FmtShort) - goto shrt; - - if(exporting || (fp->flags & FmtSharp)) { - if(packagequotes) - fmtprint(fp, "\"%Z\"", s->pkg->path); - else - fmtprint(fp, "%s", s->pkg->prefix); - fmtprint(fp, ".%s", s->name); - return 0; - } - - if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) { - // This one is for the user. If the package name - // was used by multiple packages, give the full - // import path to disambiguate. - if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) { - fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); - return 0; - } - fmtprint(fp, "%s.%s", s->pkg->name, s->name); - return 0; - } - -shrt: - fmtstrcpy(fp, s->name); - return 0; -} - -static char* -basicnames[] = -{ - [TINT] = "int", - [TUINT] = "uint", - [TINT8] = "int8", - [TUINT8] = "uint8", - [TINT16] = "int16", - [TUINT16] = "uint16", - [TINT32] = "int32", - [TUINT32] = "uint32", - [TINT64] = "int64", - [TUINT64] = "uint64", - [TUINTPTR] = "uintptr", - [TFLOAT32] = "float32", - [TFLOAT64] = "float64", - [TCOMPLEX64] = "complex64", - [TCOMPLEX128] = "complex128", - [TBOOL] = "bool", - [TANY] = "any", - [TSTRING] = "string", - [TNIL] = "nil", - [TIDEAL] = "ideal", - [TBLANK] = "blank", -}; - -int -Tpretty(Fmt *fp, Type *t) -{ - Type *t1; - Sym *s; - - if(0 && debug['r']) { - debug['r'] = 0; - fmtprint(fp, "%T (orig=%T)", t, t->orig); - debug['r'] = 1; - return 0; - } - - if(t->etype != TFIELD - && t->sym != S - && !(fp->flags&FmtLong)) { - s = t->sym; - if(t == types[t->etype] && t->etype != TUNSAFEPTR) - return fmtprint(fp, "%s", s->name); - if(exporting) { - if(fp->flags & FmtShort) - fmtprint(fp, "%hS", s); - else - fmtprint(fp, "%S", s); - if(s->pkg != localpkg) - return 0; - if(t->vargen) - fmtprint(fp, "ยท%d", t->vargen); - return 0; - } - return fmtprint(fp, "%S", s); - } - - if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) { - if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL) - fmtprint(fp, "ideal "); - return fmtprint(fp, "%s", basicnames[t->etype]); - } - - switch(t->etype) { - case TPTR32: - case TPTR64: - if(fp->flags&FmtShort) // pass flag thru for methodsym - return fmtprint(fp, "*%hT", t->type); - return fmtprint(fp, "*%T", t->type); - - case TCHAN: - switch(t->chan) { - case Crecv: - return fmtprint(fp, "<-chan %T", t->type); - case Csend: - return fmtprint(fp, "chan<- %T", t->type); - } - if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv) - return fmtprint(fp, "chan (%T)", t->type); - return fmtprint(fp, "chan %T", t->type); - - case TMAP: - return fmtprint(fp, "map[%T] %T", t->down, t->type); - - case TFUNC: - // t->type is method struct - // t->type->down is result struct - // t->type->down->down is arg struct - if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) { - fmtprint(fp, "method("); - for(t1=getthisx(t)->type; t1; t1=t1->down) { - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - } - - if(!(fp->flags&FmtByte)) - fmtprint(fp, "func"); - fmtprint(fp, "("); - for(t1=getinargx(t)->type; t1; t1=t1->down) { - if(noargnames && t1->etype == TFIELD) { - if(t1->isddd) - fmtprint(fp, "...%T", t1->type->type); - else - fmtprint(fp, "%T", t1->type); - } else - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - switch(t->outtuple) { - case 0: - break; - case 1: - t1 = getoutargx(t)->type; - if(t1 == T) { - // failure to typecheck earlier; don't know the type - fmtprint(fp, " ?unknown-type?"); - break; - } - if(t1->etype == TFIELD) - t1 = t1->type; - fmtprint(fp, " %T", t1); - break; - default: - t1 = getoutargx(t)->type; - fmtprint(fp, " ("); - for(; t1; t1=t1->down) { - if(noargnames && t1->etype == TFIELD) - fmtprint(fp, "%T", t1->type); - else - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - break; - } - return 0; - - case TARRAY: - if(t->bound >= 0) - return fmtprint(fp, "[%d]%T", (int)t->bound, t->type); - if(t->bound == -100) - return fmtprint(fp, "[...]%T", t->type); - return fmtprint(fp, "[]%T", t->type); - - case TINTER: - fmtprint(fp, "interface {"); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, " "); - if(exportname(t1->sym->name)) - fmtprint(fp, "%hS", t1->sym); - else - fmtprint(fp, "%S", t1->sym); - fmtprint(fp, "%hhT", t1->type); - if(t1->down) - fmtprint(fp, ";"); - } - return fmtprint(fp, " }"); - - case TSTRUCT: - if(t->funarg) { - fmtprint(fp, "("); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - return fmtprint(fp, ")"); - } - fmtprint(fp, "struct {"); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, " %T", t1); - if(t1->down) - fmtprint(fp, ";"); - } - return fmtprint(fp, " }"); - - case TFIELD: - if(t->sym == S || t->embedded) { - if(exporting) - fmtprint(fp, "? "); - } else - fmtprint(fp, "%hS ", t->sym); - if(t->isddd) - fmtprint(fp, "...%T", t->type->type); - else - fmtprint(fp, "%T", t->type); - if(t->note) { - fmtprint(fp, " "); - if(exporting) - fmtprint(fp, ":"); - fmtprint(fp, "\"%Z\"", t->note); - } - return 0; - - case TFORW: - if(exporting) - yyerror("undefined type %S", t->sym); - if(t->sym) - return fmtprint(fp, "undefined %S", t->sym); - return fmtprint(fp, "undefined"); - - case TUNSAFEPTR: - if(exporting) - return fmtprint(fp, "\"unsafe\".Pointer"); - return fmtprint(fp, "unsafe.Pointer"); - } - - // Don't know how to handle - fall back to detailed prints. - return -1; -} - -int -Tconv(Fmt *fp) -{ - Type *t, *t1; - int r, et, sharp, minus; - - sharp = (fp->flags & FmtSharp); - minus = (fp->flags & FmtLeft); - fp->flags &= ~(FmtSharp|FmtLeft); - - t = va_arg(fp->args, Type*); - if(t == T) - return fmtstrcpy(fp, "<T>"); - - t->trecur++; - if(t->trecur > 5) { - fmtprint(fp, "..."); - goto out; - } - - if(!debug['t']) { - if(sharp) - exporting++; - if(minus) - noargnames++; - r = Tpretty(fp, t); - if(sharp) - exporting--; - if(minus) - noargnames--; - if(r >= 0) { - t->trecur--; - return 0; - } - } - - if(sharp || exporting) - fatal("missing %E case during export", t->etype); - - et = t->etype; - fmtprint(fp, "%E ", et); - if(t->sym != S) - fmtprint(fp, "<%S>", t->sym); - - switch(et) { - default: - if(t->type != T) - fmtprint(fp, " %T", t->type); - break; - - case TFIELD: - fmtprint(fp, "%T", t->type); - break; - - case TFUNC: - if(fp->flags & FmtLong) - fmtprint(fp, "%d%d%d(%lT,%lT)%lT", - t->thistuple, t->intuple, t->outtuple, - t->type, t->type->down->down, t->type->down); - else - fmtprint(fp, "%d%d%d(%T,%T)%T", - t->thistuple, t->intuple, t->outtuple, - t->type, t->type->down->down, t->type->down); - break; - - case TINTER: - fmtprint(fp, "{"); - if(fp->flags & FmtLong) - for(t1=t->type; t1!=T; t1=t1->down) - fmtprint(fp, "%lT;", t1); - fmtprint(fp, "}"); - break; - - case TSTRUCT: - fmtprint(fp, "{"); - if(fp->flags & FmtLong) - for(t1=t->type; t1!=T; t1=t1->down) - fmtprint(fp, "%lT;", t1); - fmtprint(fp, "}"); - break; - - case TMAP: - fmtprint(fp, "[%T]%T", t->down, t->type); - break; - - case TARRAY: - if(t->bound >= 0) - fmtprint(fp, "[%d]%T", t->bound, t->type); - else - fmtprint(fp, "[]%T", t->type); - break; - - case TPTR32: - case TPTR64: - fmtprint(fp, "%T", t->type); - break; - } - -out: - t->trecur--; - return 0; -} - -int -Nconv(Fmt *fp) -{ - char buf1[500]; - Node *n; - - n = va_arg(fp->args, Node*); - if(n == N) { - fmtprint(fp, "<N>"); - goto out; - } - - if(fp->flags & FmtSign) { - if(n->type == T) - fmtprint(fp, "%#N", n); - else if(n->type->etype == TNIL) - fmtprint(fp, "nil"); - else - fmtprint(fp, "%#N (type %T)", n, n->type); - goto out; - } - - if(fp->flags & FmtSharp) { - if(n->orig != N) - n = n->orig; - exprfmt(fp, n, 0); - goto out; - } - - switch(n->op) { - default: - fmtprint(fp, "%O%J", n->op, n); - break; - - case ONAME: - case ONONAME: - if(n->sym == S) { - fmtprint(fp, "%O%J", n->op, n); - break; - } - fmtprint(fp, "%O-%S G%d%J", n->op, - n->sym, n->vargen, n); - goto ptyp; - - case OREGISTER: - fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n); - break; - - case OLITERAL: - switch(n->val.ctype) { - default: - snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype); - break; - case CTINT: - snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval); - break; - case CTFLT: - snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval)); - break; - case CTCPLX: - snprint(buf1, sizeof(buf1), "(F%g+F%gi)", - mpgetflt(&n->val.u.cval->real), - mpgetflt(&n->val.u.cval->imag)); - break; - case CTSTR: - snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval); - break; - case CTBOOL: - snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval); - break; - case CTNIL: - snprint(buf1, sizeof(buf1), "N"); - break; - } - fmtprint(fp, "%O-%s%J", n->op, buf1, n); - break; - - case OASOP: - fmtprint(fp, "%O-%O%J", n->op, n->etype, n); - break; - - case OTYPE: - fmtprint(fp, "%O %T", n->op, n->type); - break; - } - if(n->sym != S) - fmtprint(fp, " %S G%d", n->sym, n->vargen); - -ptyp: - if(n->type != T) - fmtprint(fp, " %T", n->type); - -out: - return 0; -} - -Node* -treecopy(Node *n) -{ - Node *m; - - if(n == N) - return N; - - switch(n->op) { - default: - m = nod(OXXX, N, N); - *m = *n; - m->left = treecopy(n->left); - m->right = treecopy(n->right); - m->list = listtreecopy(n->list); - if(m->defn) - abort(); - break; - - case ONONAME: - if(n->sym == lookup("iota")) { - // Not sure yet whether this is the real iota, - // but make a copy of the Node* just in case, - // so that all the copies of this const definition - // don't have the same iota value. - m = nod(OXXX, N, N); - *m = *n; - m->iota = iota; - break; - } - // fall through - case ONAME: - case OLITERAL: - case OTYPE: - m = n; - break; - } - return m; -} - -int -Zconv(Fmt *fp) -{ - Rune r; - Strlit *sp; - char *s, *se; - int n; - - sp = va_arg(fp->args, Strlit*); - if(sp == nil) - return fmtstrcpy(fp, "<nil>"); - - s = sp->s; - se = s + sp->len; - while(s < se) { - n = chartorune(&r, s); - s += n; - switch(r) { - case Runeerror: - if(n == 1) { - fmtprint(fp, "\\x%02x", (uchar)*(s-1)); - break; - } - // fall through - default: - if(r < ' ') { - fmtprint(fp, "\\x%02x", r); - break; - } - fmtrune(fp, r); - break; - case '\t': - fmtstrcpy(fp, "\\t"); - break; - case '\n': - fmtstrcpy(fp, "\\n"); - break; - case '\"': - case '\\': - fmtrune(fp, '\\'); - fmtrune(fp, r); - break; - } - } - return 0; -} - -int -isnil(Node *n) -{ - if(n == N) - return 0; - if(n->op != OLITERAL) - return 0; - if(n->val.ctype != CTNIL) - return 0; - return 1; -} - -int -isptrto(Type *t, int et) -{ - if(t == T) - return 0; - if(!isptr[t->etype]) - return 0; - t = t->type; - if(t == T) - return 0; - if(t->etype != et) - return 0; - return 1; -} - -int -istype(Type *t, int et) -{ - return t != T && t->etype == et; -} - -int -isfixedarray(Type *t) -{ - return t != T && t->etype == TARRAY && t->bound >= 0; -} - -int -isslice(Type *t) -{ - return t != T && t->etype == TARRAY && t->bound < 0; -} - -int -isblank(Node *n) -{ - char *p; - - if(n == N || n->sym == S) - return 0; - p = n->sym->name; - if(p == nil) - return 0; - return p[0] == '_' && p[1] == '\0'; -} - -int -isselect(Node *n) -{ - Sym *s; - - if(n == N) - return 0; - n = n->left; - s = pkglookup("selectsend", runtimepkg); - if(s == n->sym) - return 1; - s = pkglookup("selectrecv", runtimepkg); - if(s == n->sym) - return 1; - s = pkglookup("selectrecv2", runtimepkg); - if(s == n->sym) - return 1; - s = pkglookup("selectdefault", runtimepkg); - if(s == n->sym) - return 1; - return 0; -} - -int -isinter(Type *t) -{ - return t != T && t->etype == TINTER; -} - -int -isnilinter(Type *t) -{ - if(!isinter(t)) - return 0; - if(t->type != T) - return 0; - return 1; -} - -int -isideal(Type *t) -{ - if(t == T) - return 0; - if(t == idealstring || t == idealbool) - return 1; - switch(t->etype) { - case TNIL: - case TIDEAL: - return 1; - } - return 0; -} - -/* - * given receiver of type t (t == r or t == *r) - * return type to hang methods off (r). - */ -Type* -methtype(Type *t) -{ - if(t == T) - return T; - - // strip away pointer if it's there - if(isptr[t->etype]) { - if(t->sym != S) - return T; - t = t->type; - if(t == T) - return T; - } - - // need a type name - if(t->sym == S) - return T; - - // check types - if(!issimple[t->etype]) - switch(t->etype) { - default: - return T; - case TSTRUCT: - case TARRAY: - case TMAP: - case TCHAN: - case TSTRING: - case TFUNC: - break; - } - - return t; -} - -int -cplxsubtype(int et) -{ - switch(et) { - case TCOMPLEX64: - return TFLOAT32; - case TCOMPLEX128: - return TFLOAT64; - } - fatal("cplxsubtype: %E\n", et); - return 0; -} - -static int -eqnote(Strlit *a, Strlit *b) -{ - if(a == b) - return 1; - if(a == nil || b == nil) - return 0; - if(a->len != b->len) - return 0; - return memcmp(a->s, b->s, a->len) == 0; -} - -// Return 1 if t1 and t2 are identical, following the spec rules. -// -// Any cyclic type must go through a named type, and if one is -// named, it is only identical to the other if they are the same -// pointer (t1 == t2), so there's no chance of chasing cycles -// ad infinitum, so no need for a depth counter. -int -eqtype(Type *t1, Type *t2) -{ - if(t1 == t2) - return 1; - if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym) - return 0; - - switch(t1->etype) { - case TINTER: - case TSTRUCT: - for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { - if(t1->etype != TFIELD || t2->etype != TFIELD) - fatal("struct/interface missing field: %T %T", t1, t2); - if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note)) - return 0; - } - return t1 == T && t2 == T; - - case TFUNC: - // Loop over structs: receiver, in, out. - for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { - Type *ta, *tb; - - if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) - fatal("func missing struct: %T %T", t1, t2); - - // Loop over fields in structs, ignoring argument names. - for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) { - if(ta->etype != TFIELD || tb->etype != TFIELD) - fatal("func struct missing field: %T %T", ta, tb); - if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type)) - return 0; - } - if(ta != T || tb != T) - return 0; - } - return t1 == T && t2 == T; - - case TARRAY: - if(t1->bound != t2->bound) - return 0; - break; - - case TCHAN: - if(t1->chan != t2->chan) - return 0; - break; - } - - return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type); -} - -// Are t1 and t2 equal struct types when field names are ignored? -// For deciding whether the result struct from g can be copied -// directly when compiling f(g()). -int -eqtypenoname(Type *t1, Type *t2) -{ - if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT) - return 0; - - t1 = t1->type; - t2 = t2->type; - for(;;) { - if(!eqtype(t1, t2)) - return 0; - if(t1 == T) - return 1; - t1 = t1->down; - t2 = t2->down; - } -} - -// Is type src assignment compatible to type dst? -// If so, return op code to use in conversion. -// If not, return 0. -// -// It is the caller's responsibility to call exportassignok -// to check for assignments to other packages' unexported fields, -int -assignop(Type *src, Type *dst, char **why) -{ - Type *missing, *have; - int ptr; - - if(why != nil) - *why = ""; - - if(safemode && src != T && src->etype == TUNSAFEPTR) { - yyerror("cannot use unsafe.Pointer"); - errorexit(); - } - - if(src == dst) - return OCONVNOP; - if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T) - return 0; - - // 1. src type is identical to dst. - if(eqtype(src, dst)) - return OCONVNOP; - - // 2. src and dst have identical underlying types - // and either src or dst is not a named type or - // both are interface types. - if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER)) - return OCONVNOP; - - // 3. dst is an interface type and src implements dst. - if(dst->etype == TINTER && src->etype != TNIL) { - if(implements(src, dst, &missing, &have, &ptr)) - return OCONVIFACE; - if(why != nil) { - if(isptrto(src, TINTER)) - *why = smprint(":\n\t%T is pointer to interface, not interface", src); - else if(have && have->sym == missing->sym) - *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else if(ptr) - *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)", - src, dst, missing->sym); - else if(have) - *why = smprint(":\n\t%T does not implement %T (missing %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else - *why = smprint(":\n\t%T does not implement %T (missing %S method)", - src, dst, missing->sym); - } - return 0; - } - if(isptrto(dst, TINTER)) { - if(why != nil) - *why = smprint(":\n\t%T is pointer to interface, not interface", dst); - return 0; - } - if(src->etype == TINTER && dst->etype != TBLANK) { - if(why != nil) - *why = ": need type assertion"; - return 0; - } - - // 4. src is a bidirectional channel value, dst is a channel type, - // src and dst have identical element types, and - // either src or dst is not a named type. - if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN) - if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S)) - return OCONVNOP; - - // 5. src is the predeclared identifier nil and dst is a nillable type. - if(src->etype == TNIL) { - switch(dst->etype) { - case TARRAY: - if(dst->bound != -100) // not slice - break; - case TPTR32: - case TPTR64: - case TFUNC: - case TMAP: - case TCHAN: - case TINTER: - return OCONVNOP; - } - } - - // 6. rule about untyped constants - already converted by defaultlit. - - // 7. Any typed value can be assigned to the blank identifier. - if(dst->etype == TBLANK) - return OCONVNOP; - - return 0; -} - -// Can we convert a value of type src to a value of type dst? -// If so, return op code to use in conversion (maybe OCONVNOP). -// If not, return 0. -int -convertop(Type *src, Type *dst, char **why) -{ - int op; - - if(why != nil) - *why = ""; - - if(src == dst) - return OCONVNOP; - if(src == T || dst == T) - return 0; - - // 1. src can be assigned to dst. - if((op = assignop(src, dst, why)) != 0) - return op; - - // The rules for interfaces are no different in conversions - // than assignments. If interfaces are involved, stop now - // with the good message from assignop. - // Otherwise clear the error. - if(src->etype == TINTER || dst->etype == TINTER) - return 0; - if(why != nil) - *why = ""; - - // 2. src and dst have identical underlying types. - if(eqtype(src->orig, dst->orig)) - return OCONVNOP; - - // 3. src and dst are unnamed pointer types - // and their base types have identical underlying types. - if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S) - if(eqtype(src->type->orig, dst->type->orig)) - return OCONVNOP; - - // 4. src and dst are both integer or floating point types. - if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) { - if(simtype[src->etype] == simtype[dst->etype]) - return OCONVNOP; - return OCONV; - } - - // 5. src and dst are both complex types. - if(iscomplex[src->etype] && iscomplex[dst->etype]) { - if(simtype[src->etype] == simtype[dst->etype]) - return OCONVNOP; - return OCONV; - } - - // 6. src is an integer or has type []byte or []int - // and dst is a string type. - if(isint[src->etype] && dst->etype == TSTRING) - return ORUNESTR; - - if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) { - switch(src->type->etype) { - case TUINT8: - return OARRAYBYTESTR; - case TINT: - return OARRAYRUNESTR; - } - } - - // 7. src is a string and dst is []byte or []int. - // String to slice. - if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) { - switch(dst->type->etype) { - case TUINT8: - return OSTRARRAYBYTE; - case TINT: - return OSTRARRAYRUNE; - } - } - - // 8. src is a pointer or uintptr and dst is unsafe.Pointer. - if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR) - return OCONVNOP; - - // 9. src is unsafe.Pointer and dst is a pointer or uintptr. - if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR)) - return OCONVNOP; - - return 0; -} - -// Convert node n for assignment to type t. -Node* -assignconv(Node *n, Type *t, char *context) -{ - int op; - Node *r, *old; - char *why; - - if(n == N || n->type == T) - return n; - - old = n; - old->diag++; // silence errors about n; we'll issue one below - defaultlit(&n, t); - old->diag--; - if(t->etype == TBLANK) - return n; - - exportassignok(n->type, context); - if(eqtype(n->type, t)) - return n; - - op = assignop(n->type, t, &why); - if(op == 0) { - yyerror("cannot use %+N as type %T in %s%s", n, t, context, why); - op = OCONV; - } - - r = nod(op, n, N); - r->type = t; - r->typecheck = 1; - r->implicit = 1; - return r; -} - -static int -subtype(Type **stp, Type *t, int d) -{ - Type *st; - -loop: - st = *stp; - if(st == T) - return 0; - - d++; - if(d >= 10) - return 0; - - switch(st->etype) { - default: - return 0; - - case TPTR32: - case TPTR64: - case TCHAN: - case TARRAY: - stp = &st->type; - goto loop; - - case TANY: - if(!st->copyany) - return 0; - *stp = t; - break; - - case TMAP: - if(subtype(&st->down, t, d)) - break; - stp = &st->type; - goto loop; - - case TFUNC: - for(;;) { - if(subtype(&st->type, t, d)) - break; - if(subtype(&st->type->down->down, t, d)) - break; - if(subtype(&st->type->down, t, d)) - break; - return 0; - } - break; - - case TSTRUCT: - for(st=st->type; st!=T; st=st->down) - if(subtype(&st->type, t, d)) - return 1; - return 0; - } - return 1; -} - -/* - * Is this a 64-bit type? - */ -int -is64(Type *t) -{ - if(t == T) - return 0; - switch(simtype[t->etype]) { - case TINT64: - case TUINT64: - case TPTR64: - return 1; - } - return 0; -} - -/* - * Is a conversion between t1 and t2 a no-op? - */ -int -noconv(Type *t1, Type *t2) -{ - int e1, e2; - - e1 = simtype[t1->etype]; - e2 = simtype[t2->etype]; - - switch(e1) { - case TINT8: - case TUINT8: - return e2 == TINT8 || e2 == TUINT8; - - case TINT16: - case TUINT16: - return e2 == TINT16 || e2 == TUINT16; - - case TINT32: - case TUINT32: - case TPTR32: - return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32; - - case TINT64: - case TUINT64: - case TPTR64: - return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64; - - case TFLOAT32: - return e2 == TFLOAT32; - - case TFLOAT64: - return e2 == TFLOAT64; - } - return 0; -} - -void -argtype(Node *on, Type *t) -{ - dowidth(t); - if(!subtype(&on->type, t, 0)) - fatal("argtype: failed %N %T\n", on, t); -} - -Type* -shallow(Type *t) -{ - Type *nt; - - if(t == T) - return T; - nt = typ(0); - *nt = *t; - if(t->orig == t) - nt->orig = nt; - return nt; -} - -static Type* -deep(Type *t) -{ - Type *nt, *xt; - - if(t == T) - return T; - - switch(t->etype) { - default: - nt = t; // share from here down - break; - - case TANY: - nt = shallow(t); - nt->copyany = 1; - break; - - case TPTR32: - case TPTR64: - case TCHAN: - case TARRAY: - nt = shallow(t); - nt->type = deep(t->type); - break; - - case TMAP: - nt = shallow(t); - nt->down = deep(t->down); - nt->type = deep(t->type); - break; - - case TFUNC: - nt = shallow(t); - nt->type = deep(t->type); - nt->type->down = deep(t->type->down); - nt->type->down->down = deep(t->type->down->down); - break; - - case TSTRUCT: - nt = shallow(t); - nt->type = shallow(t->type); - xt = nt->type; - - for(t=t->type; t!=T; t=t->down) { - xt->type = deep(t->type); - xt->down = shallow(t->down); - xt = xt->down; - } - break; - } - return nt; -} - -Node* -syslook(char *name, int copy) -{ - Sym *s; - Node *n; - - s = pkglookup(name, runtimepkg); - if(s == S || s->def == N) - fatal("syslook: can't find runtime.%s", name); - - if(!copy) - return s->def; - - n = nod(0, N, N); - *n = *s->def; - n->type = deep(s->def->type); - - return n; -} - -/* - * compute a hash value for type t. - * if t is a method type, ignore the receiver - * so that the hash can be used in interface checks. - * %-T (which calls Tpretty, above) already contains - * all the necessary logic to generate a representation - * of the type that completely describes it. - * using smprint here avoids duplicating that code. - * using md5 here is overkill, but i got tired of - * accidental collisions making the runtime think - * two types are equal when they really aren't. - */ -uint32 -typehash(Type *t) -{ - char *p; - MD5 d; - - longsymnames = 1; - if(t->thistuple) { - // hide method receiver from Tpretty - t->thistuple = 0; - p = smprint("%-T", t); - t->thistuple = 1; - }else - p = smprint("%-T", t); - longsymnames = 0; - md5reset(&d); - md5write(&d, (uchar*)p, strlen(p)); - free(p); - return md5sum(&d); -} - -Type* -ptrto(Type *t) -{ - Type *t1; - - if(tptr == 0) - fatal("ptrto: nil"); - t1 = typ(tptr); - t1->type = t; - t1->width = widthptr; - t1->align = widthptr; - return t1; -} - -void -frame(int context) -{ - char *p; - NodeList *l; - Node *n; - int flag; - - p = "stack"; - l = nil; - if(curfn) - l = curfn->dcl; - if(context) { - p = "external"; - l = externdcl; - } - - flag = 1; - for(; l; l=l->next) { - n = l->n; - switch(n->op) { - case ONAME: - if(flag) - print("--- %s frame ---\n", p); - print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type); - flag = 0; - break; - - case OTYPE: - if(flag) - print("--- %s frame ---\n", p); - print("%O %T\n", n->op, n->type); - flag = 0; - break; - } - } -} - -/* - * calculate sethi/ullman number - * roughly how many registers needed to - * compile a node. used to compile the - * hardest side first to minimize registers. - */ -void -ullmancalc(Node *n) -{ - int ul, ur; - - if(n == N) - return; - - switch(n->op) { - case OREGISTER: - case OLITERAL: - case ONAME: - ul = 1; - if(n->class == PPARAMREF || (n->class & PHEAP)) - ul++; - goto out; - case OCALL: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - ul = UINF; - goto out; - } - ul = 1; - if(n->left != N) - ul = n->left->ullman; - ur = 1; - if(n->right != N) - ur = n->right->ullman; - if(ul == ur) - ul += 1; - if(ur > ul) - ul = ur; - -out: - n->ullman = ul; -} - -void -badtype(int o, Type *tl, Type *tr) -{ - Fmt fmt; - char *s; - - fmtstrinit(&fmt); - if(tl != T) - fmtprint(&fmt, "\n %T", tl); - if(tr != T) - fmtprint(&fmt, "\n %T", tr); - - // common mistake: *struct and *interface. - if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) { - if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER) - fmtprint(&fmt, "\n (*struct vs *interface)"); - else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT) - fmtprint(&fmt, "\n (*interface vs *struct)"); - } - s = fmtstrflush(&fmt); - yyerror("illegal types for operand: %O%s", o, s); -} - -/* - * iterator to walk a structure declaration - */ -Type* -structfirst(Iter *s, Type **nn) -{ - Type *n, *t; - - n = *nn; - if(n == T) - goto bad; - - switch(n->etype) { - default: - goto bad; - - case TSTRUCT: - case TINTER: - case TFUNC: - break; - } - - t = n->type; - if(t == T) - goto rnil; - - if(t->etype != TFIELD) - fatal("structfirst: not field %T", t); - - s->t = t; - return t; - -bad: - fatal("structfirst: not struct %T", n); - -rnil: - return T; -} - -Type* -structnext(Iter *s) -{ - Type *n, *t; - - n = s->t; - t = n->down; - if(t == T) - goto rnil; - - if(t->etype != TFIELD) - goto bad; - - s->t = t; - return t; - -bad: - fatal("structnext: not struct %T", n); - -rnil: - return T; -} - -/* - * iterator to this and inargs in a function - */ -Type* -funcfirst(Iter *s, Type *t) -{ - Type *fp; - - if(t == T) - goto bad; - - if(t->etype != TFUNC) - goto bad; - - s->tfunc = t; - s->done = 0; - fp = structfirst(s, getthis(t)); - if(fp == T) { - s->done = 1; - fp = structfirst(s, getinarg(t)); - } - return fp; - -bad: - fatal("funcfirst: not func %T", t); - return T; -} - -Type* -funcnext(Iter *s) -{ - Type *fp; - - fp = structnext(s); - if(fp == T && !s->done) { - s->done = 1; - fp = structfirst(s, getinarg(s->tfunc)); - } - return fp; -} - -Type** -getthis(Type *t) -{ - if(t->etype != TFUNC) - fatal("getthis: not a func %T", t); - return &t->type; -} - -Type** -getoutarg(Type *t) -{ - if(t->etype != TFUNC) - fatal("getoutarg: not a func %T", t); - return &t->type->down; -} - -Type** -getinarg(Type *t) -{ - if(t->etype != TFUNC) - fatal("getinarg: not a func %T", t); - return &t->type->down->down; -} - -Type* -getthisx(Type *t) -{ - return *getthis(t); -} - -Type* -getoutargx(Type *t) -{ - return *getoutarg(t); -} - -Type* -getinargx(Type *t) -{ - return *getinarg(t); -} - -/* - * return !(op) - * eg == <=> != - */ -int -brcom(int a) -{ - switch(a) { - case OEQ: return ONE; - case ONE: return OEQ; - case OLT: return OGE; - case OGT: return OLE; - case OLE: return OGT; - case OGE: return OLT; - } - fatal("brcom: no com for %A\n", a); - return a; -} - -/* - * return reverse(op) - * eg a op b <=> b r(op) a - */ -int -brrev(int a) -{ - switch(a) { - case OEQ: return OEQ; - case ONE: return ONE; - case OLT: return OGT; - case OGT: return OLT; - case OLE: return OGE; - case OGE: return OLE; - } - fatal("brcom: no rev for %A\n", a); - return a; -} - -/* - * return side effect-free n, appending side effects to init. - * result is assignable if n is. - */ -Node* -safeexpr(Node *n, NodeList **init) -{ - Node *l; - Node *r; - Node *a; - - if(n == N) - return N; - - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - - case ODOT: - l = safeexpr(n->left, init); - if(l == n->left) - return n; - r = nod(OXXX, N, N); - *r = *n; - r->left = l; - typecheck(&r, Erv); - walkexpr(&r, init); - return r; - - case ODOTPTR: - case OIND: - l = safeexpr(n->left, init); - if(l == n->left) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->left = l; - walkexpr(&a, init); - return a; - - case OINDEX: - case OINDEXMAP: - l = safeexpr(n->left, init); - r = safeexpr(n->right, init); - if(l == n->left && r == n->right) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->left = l; - a->right = r; - walkexpr(&a, init); - return a; - } - - // make a copy; must not be used as an lvalue - if(islvalue(n)) - fatal("missing lvalue case in safeexpr: %N", n); - return cheapexpr(n, init); -} - -/* - * return side-effect free and cheap n, appending side effects to init. - * result may not be assignable. - */ -Node* -cheapexpr(Node *n, NodeList **init) -{ - Node *a, *l; - - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - } - - l = nod(OXXX, N, N); - tempname(l, n->type); - a = nod(OAS, l, n); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - return l; -} - -void -setmaxarg(Type *t) -{ - int32 w; - - dowidth(t); - w = t->argwid; - if(t->argwid >= MAXWIDTH) - fatal("bad argwid %T", t); - if(w > maxarg) - maxarg = w; -} - -/* unicode-aware case-insensitive strcmp */ - -static int -cistrcmp(char *p, char *q) -{ - Rune rp, rq; - - while(*p || *q) { - if(*p == 0) - return +1; - if(*q == 0) - return -1; - p += chartorune(&rp, p); - q += chartorune(&rq, q); - rp = tolowerrune(rp); - rq = tolowerrune(rq); - if(rp < rq) - return -1; - if(rp > rq) - return +1; - } - return 0; -} - -/* - * code to resolve elided DOTs - * in embedded types - */ - -// search depth 0 -- -// return count of fields+methods -// found with a given name -static int -lookdot0(Sym *s, Type *t, Type **save, int ignorecase) -{ - Type *f, *u; - int c; - - u = t; - if(isptr[u->etype]) - u = u->type; - - c = 0; - if(u->etype == TSTRUCT || u->etype == TINTER) { - for(f=u->type; f!=T; f=f->down) - if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) { - if(save) - *save = f; - c++; - } - } - u = methtype(t); - if(u != T) { - for(f=u->method; f!=T; f=f->down) - if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) { - if(save) - *save = f; - c++; - } - } - return c; -} - -// search depth d -- -// return count of fields+methods -// found at search depth. -// answer is in dotlist array and -// count of number of ways is returned. -int -adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase) -{ - Type *f, *u; - int c, a; - - if(t->trecur) - return 0; - t->trecur = 1; - - if(d == 0) { - c = lookdot0(s, t, save, ignorecase); - goto out; - } - - c = 0; - u = t; - if(isptr[u->etype]) - u = u->type; - if(u->etype != TSTRUCT && u->etype != TINTER) - goto out; - - d--; - for(f=u->type; f!=T; f=f->down) { - if(!f->embedded) - continue; - if(f->sym == S) - continue; - a = adddot1(s, f->type, d, save, ignorecase); - if(a != 0 && c == 0) - dotlist[d].field = f; - c += a; - } - -out: - t->trecur = 0; - return c; -} - -// in T.field -// find missing fields that -// will give shortest unique addressing. -// modify the tree with missing type names. -Node* -adddot(Node *n) -{ - Type *t; - Sym *s; - int c, d; - - typecheck(&n->left, Etype|Erv); - t = n->left->type; - if(t == T) - goto ret; - - if(n->left->op == OTYPE) - goto ret; - - if(n->right->op != ONAME) - goto ret; - s = n->right->sym; - if(s == S) - goto ret; - - for(d=0; d<nelem(dotlist); d++) { - c = adddot1(s, t, d, nil, 0); - if(c > 0) - goto out; - } - goto ret; - -out: - if(c > 1) - yyerror("ambiguous DOT reference %T.%S", t, s); - - // rebuild elided dots - for(c=d-1; c>=0; c--) - n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym)); -ret: - return n; -} - - -/* - * code to help generate trampoline - * functions for methods on embedded - * subtypes. - * these are approx the same as - * the corresponding adddot routines - * except that they expect to be called - * with unique tasks and they return - * the actual methods. - */ - -typedef struct Symlink Symlink; -struct Symlink -{ - Type* field; - uchar good; - uchar followptr; - Symlink* link; -}; -static Symlink* slist; - -static void -expand0(Type *t, int followptr) -{ - Type *f, *u; - Symlink *sl; - - u = t; - if(isptr[u->etype]) { - followptr = 1; - u = u->type; - } - - if(u->etype == TINTER) { - for(f=u->type; f!=T; f=f->down) { - if(!exportname(f->sym->name) && f->sym->pkg != localpkg) - continue; - if(f->sym->flags & SymUniq) - continue; - f->sym->flags |= SymUniq; - sl = mal(sizeof(*sl)); - sl->field = f; - sl->link = slist; - sl->followptr = followptr; - slist = sl; - } - return; - } - - u = methtype(t); - if(u != T) { - for(f=u->method; f!=T; f=f->down) { - if(!exportname(f->sym->name) && f->sym->pkg != localpkg) - continue; - if(f->sym->flags & SymUniq) - continue; - f->sym->flags |= SymUniq; - sl = mal(sizeof(*sl)); - sl->field = f; - sl->link = slist; - sl->followptr = followptr; - slist = sl; - } - } -} - -static void -expand1(Type *t, int d, int followptr) -{ - Type *f, *u; - - if(t->trecur) - return; - if(d == 0) - return; - t->trecur = 1; - - if(d != nelem(dotlist)-1) - expand0(t, followptr); - - u = t; - if(isptr[u->etype]) { - followptr = 1; - u = u->type; - } - if(u->etype != TSTRUCT && u->etype != TINTER) - goto out; - - for(f=u->type; f!=T; f=f->down) { - if(!f->embedded) - continue; - if(f->sym == S) - continue; - expand1(f->type, d-1, followptr); - } - -out: - t->trecur = 0; -} - -void -expandmeth(Sym *s, Type *t) -{ - Symlink *sl; - Type *f; - int c, d; - - if(s == S) - return; - if(t == T || t->xmethod != nil) - return; - - // mark top-level method symbols - // so that expand1 doesn't consider them. - for(f=t->method; f != nil; f=f->down) - f->sym->flags |= SymUniq; - - // generate all reachable methods - slist = nil; - expand1(t, nelem(dotlist)-1, 0); - - // check each method to be uniquely reachable - for(sl=slist; sl!=nil; sl=sl->link) { - sl->field->sym->flags &= ~SymUniq; - for(d=0; d<nelem(dotlist); d++) { - c = adddot1(sl->field->sym, t, d, &f, 0); - if(c == 0) - continue; - if(c == 1) { - sl->good = 1; - sl->field = f; - } - break; - } - } - - for(f=t->method; f != nil; f=f->down) - f->sym->flags &= ~SymUniq; - - t->xmethod = t->method; - for(sl=slist; sl!=nil; sl=sl->link) { - if(sl->good) { - // add it to the base type method list - f = typ(TFIELD); - *f = *sl->field; - f->embedded = 1; // needs a trampoline - if(sl->followptr) - f->embedded = 2; - f->down = t->xmethod; - t->xmethod = f; - } - } -} - -/* - * Given funarg struct list, return list of ODCLFIELD Node fn args. - */ -static NodeList* -structargs(Type **tl, int mustname) -{ - Iter savet; - Node *a, *n; - NodeList *args; - Type *t; - char buf[100]; - int gen; - - args = nil; - gen = 0; - for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { - n = N; - if(t->sym) - n = newname(t->sym); - else if(mustname) { - // have to give it a name so we can refer to it in trampoline - snprint(buf, sizeof buf, ".anon%d", gen++); - n = newname(lookup(buf)); - } - a = nod(ODCLFIELD, n, typenod(t->type)); - a->isddd = t->isddd; - if(n != N) - n->isddd = t->isddd; - args = list(args, a); - } - return args; -} - -/* - * Generate a wrapper function to convert from - * a receiver of type T to a receiver of type U. - * That is, - * - * func (t T) M() { - * ... - * } - * - * already exists; this function generates - * - * func (u U) M() { - * u.M() - * } - * - * where the types T and U are such that u.M() is valid - * and calls the T.M method. - * The resulting function is for use in method tables. - * - * rcvr - U - * method - M func (t T)(), a TFIELD type struct - * newnam - the eventual mangled name of this function - */ -void -genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) -{ - Node *this, *fn, *call, *n, *t, *pad; - NodeList *l, *args, *in, *out; - Type *tpad; - int isddd; - Val v; - - if(debug['r']) - print("genwrapper rcvrtype=%T method=%T newnam=%S\n", - rcvr, method, newnam); - - lineno = 1; // less confusing than end of input - - dclcontext = PEXTERN; - markdcl(); - - this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr)); - this->left->ntype = this->right; - in = structargs(getinarg(method->type), 1); - out = structargs(getoutarg(method->type), 0); - - fn = nod(ODCLFUNC, N, N); - fn->nname = newname(newnam); - t = nod(OTFUNC, N, N); - l = list1(this); - if(iface && rcvr->width < types[tptr]->width) { - // Building method for interface table and receiver - // is smaller than the single pointer-sized word - // that the interface call will pass in. - // Add a dummy padding argument after the - // receiver to make up the difference. - tpad = typ(TARRAY); - tpad->type = types[TUINT8]; - tpad->bound = types[tptr]->width - rcvr->width; - pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad)); - l = list(l, pad); - } - t->list = concat(l, in); - t->rlist = out; - fn->nname->ntype = t; - funchdr(fn); - - // arg list - args = nil; - isddd = 0; - for(l=in; l; l=l->next) { - args = list(args, l->n->left); - isddd = l->n->left->isddd; - } - - // generate nil pointer check for better error - if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) { - // generating wrapper from *T to T. - n = nod(OIF, N, N); - n->ntest = nod(OEQ, this->left, nodnil()); - // these strings are already in the reflect tables, - // so no space cost to use them here. - l = nil; - v.ctype = CTSTR; - v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name - l = list(l, nodlit(v)); - v.u.sval = strlit(rcvr->type->sym->name); // type name - l = list(l, nodlit(v)); - v.u.sval = strlit(method->sym->name); - l = list(l, nodlit(v)); // method name - call = nod(OCALL, syslook("panicwrap", 0), N); - call->list = l; - n->nbody = list1(call); - fn->nbody = list(fn->nbody, n); - } - - // generate call - call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N); - call->list = args; - call->isddd = isddd; - if(method->type->outtuple > 0) { - n = nod(ORETURN, N, N); - n->list = list1(call); - call = n; - } - fn->nbody = list(fn->nbody, call); - - if(0 && debug['r']) - dumplist("genwrapper body", fn->nbody); - - funcbody(fn); - curfn = fn; - typecheck(&fn, Etop); - typechecklist(fn->nbody, Etop); - curfn = nil; - funccompile(fn, 0); -} - -static Type* -ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase) -{ - int i, c, d; - Type *m; - - *followptr = 0; - - if(t == T) - return T; - - for(d=0; d<nelem(dotlist); d++) { - c = adddot1(s, t, d, &m, ignorecase); - if(c > 1) { - yyerror("%T.%S is ambiguous", t, s); - return T; - } - if(c == 1) { - for(i=0; i<d; i++) { - if(isptr[dotlist[i].field->type->etype]) { - *followptr = 1; - break; - } - } - if(m->type->etype != TFUNC || m->type->thistuple == 0) { - yyerror("%T.%S is a field, not a method", t, s); - return T; - } - return m; - } - } - return T; -} - -int -implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) -{ - Type *t0, *im, *tm, *rcvr, *imtype; - int followptr; - - t0 = t; - if(t == T) - return 0; - - // if this is too slow, - // could sort these first - // and then do one loop. - - if(t->etype == TINTER) { - for(im=iface->type; im; im=im->down) { - for(tm=t->type; tm; tm=tm->down) { - if(tm->sym == im->sym) { - if(eqtype(tm->type, im->type)) - goto found; - *m = im; - *samename = tm; - *ptr = 0; - return 0; - } - } - *m = im; - *samename = nil; - *ptr = 0; - return 0; - found:; - } - return 1; - } - - t = methtype(t); - if(t != T) - expandmeth(t->sym, t); - for(im=iface->type; im; im=im->down) { - imtype = methodfunc(im->type, 0); - tm = ifacelookdot(im->sym, t, &followptr, 0); - if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) { - if(tm == T) - tm = ifacelookdot(im->sym, t, &followptr, 1); - *m = im; - *samename = tm; - *ptr = 0; - return 0; - } - // if pointer receiver in method, - // the method does not exist for value types. - rcvr = getthisx(tm->type)->type->type; - if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) { - if(0 && debug['r']) - yyerror("interface pointer mismatch"); - - *m = im; - *samename = nil; - *ptr = 1; - return 0; - } - } - return 1; -} - -/* - * even simpler simtype; get rid of ptr, bool. - * assuming that the front end has rejected - * all the invalid conversions (like ptr -> bool) - */ -int -simsimtype(Type *t) -{ - int et; - - if(t == 0) - return 0; - - et = simtype[t->etype]; - switch(et) { - case TPTR32: - et = TUINT32; - break; - case TPTR64: - et = TUINT64; - break; - case TBOOL: - et = TUINT8; - break; - } - return et; -} - -NodeList* -concat(NodeList *a, NodeList *b) -{ - if(a == nil) - return b; - if(b == nil) - return a; - - a->end->next = b; - a->end = b->end; - b->end = nil; - return a; -} - -NodeList* -list1(Node *n) -{ - NodeList *l; - - if(n == nil) - return nil; - if(n->op == OBLOCK && n->ninit == nil) - return n->list; - l = mal(sizeof *l); - l->n = n; - l->end = l; - return l; -} - -NodeList* -list(NodeList *l, Node *n) -{ - return concat(l, list1(n)); -} - -void -listsort(NodeList** l, int(*f)(Node*, Node*)) -{ - NodeList *l1, *l2, *le; - - if(*l == nil || (*l)->next == nil) - return; - - l1 = *l; - l2 = *l; - for(;;) { - l2 = l2->next; - if(l2 == nil) - break; - l2 = l2->next; - if(l2 == nil) - break; - l1 = l1->next; - } - - l2 = l1->next; - l1->next = nil; - l2->end = (*l)->end; - (*l)->end = l1; - - l1 = *l; - listsort(&l1, f); - listsort(&l2, f); - - if ((*f)(l1->n, l2->n) < 0) { - *l = l1; - } else { - *l = l2; - l2 = l1; - l1 = *l; - } - - // now l1 == *l; and l1 < l2 - - while ((l1 != nil) && (l2 != nil)) { - while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0) - l1 = l1->next; - - // l1 is last one from l1 that is < l2 - le = l1->next; // le is the rest of l1, first one that is >= l2 - if (le != nil) - le->end = (*l)->end; - - (*l)->end = l1; // cut *l at l1 - *l = concat(*l, l2); // glue l2 to *l's tail - - l1 = l2; // l1 is the first element of *l that is < the new l2 - l2 = le; // ... because l2 now is the old tail of l1 - } - - *l = concat(*l, l2); // any remainder -} - -NodeList* -listtreecopy(NodeList *l) -{ - NodeList *out; - - out = nil; - for(; l; l=l->next) - out = list(out, treecopy(l->n)); - return out; -} - -Node* -liststmt(NodeList *l) -{ - Node *n; - - n = nod(OBLOCK, N, N); - n->list = l; - if(l) - n->lineno = l->n->lineno; - return n; -} - -/* - * return nelem of list - */ -int -count(NodeList *l) -{ - int n; - - n = 0; - for(; l; l=l->next) - n++; - return n; -} - -/* - * return nelem of list - */ -int -structcount(Type *t) -{ - int v; - Iter s; - - v = 0; - for(t = structfirst(&s, &t); t != T; t = structnext(&s)) - v++; - return v; -} - -/* - * return power of 2 of the constant - * operand. -1 if it is not a power of 2. - * 1000+ if it is a -(power of 2) - */ -int -powtwo(Node *n) -{ - uvlong v, b; - int i; - - if(n == N || n->op != OLITERAL || n->type == T) - goto no; - if(!isint[n->type->etype]) - goto no; - - v = mpgetfix(n->val.u.xval); - b = 1ULL; - for(i=0; i<64; i++) { - if(b == v) - return i; - b = b<<1; - } - - if(!issigned[n->type->etype]) - goto no; - - v = -v; - b = 1ULL; - for(i=0; i<64; i++) { - if(b == v) - return i+1000; - b = b<<1; - } - -no: - return -1; -} - -/* - * return the unsigned type for - * a signed integer type. - * returns T if input is not a - * signed integer type. - */ -Type* -tounsigned(Type *t) -{ - - // this is types[et+1], but not sure - // that this relation is immutable - switch(t->etype) { - default: - print("tounsigned: unknown type %T\n", t); - t = T; - break; - case TINT: - t = types[TUINT]; - break; - case TINT8: - t = types[TUINT8]; - break; - case TINT16: - t = types[TUINT16]; - break; - case TINT32: - t = types[TUINT32]; - break; - case TINT64: - t = types[TUINT64]; - break; - } - return t; -} - -/* - * magic number for signed division - * see hacker's delight chapter 10 - */ -void -smagic(Magic *m) -{ - int p; - uint64 ad, anc, delta, q1, r1, q2, r2, t; - uint64 mask, two31; - - m->bad = 0; - switch(m->w) { - default: - m->bad = 1; - return; - case 8: - mask = 0xffLL; - break; - case 16: - mask = 0xffffLL; - break; - case 32: - mask = 0xffffffffLL; - break; - case 64: - mask = 0xffffffffffffffffLL; - break; - } - two31 = mask ^ (mask>>1); - - p = m->w-1; - ad = m->sd; - if(m->sd < 0) - ad = -m->sd; - - // bad denominators - if(ad == 0 || ad == 1 || ad == two31) { - m->bad = 1; - return; - } - - t = two31; - ad &= mask; - - anc = t - 1 - t%ad; - anc &= mask; - - q1 = two31/anc; - r1 = two31 - q1*anc; - q1 &= mask; - r1 &= mask; - - q2 = two31/ad; - r2 = two31 - q2*ad; - q2 &= mask; - r2 &= mask; - - for(;;) { - p++; - q1 <<= 1; - r1 <<= 1; - q1 &= mask; - r1 &= mask; - if(r1 >= anc) { - q1++; - r1 -= anc; - q1 &= mask; - r1 &= mask; - } - - q2 <<= 1; - r2 <<= 1; - q2 &= mask; - r2 &= mask; - if(r2 >= ad) { - q2++; - r2 -= ad; - q2 &= mask; - r2 &= mask; - } - - delta = ad - r2; - delta &= mask; - if(q1 < delta || (q1 == delta && r1 == 0)) { - continue; - } - break; - } - - m->sm = q2+1; - if(m->sm & two31) - m->sm |= ~mask; - m->s = p-m->w; -} - -/* - * magic number for unsigned division - * see hacker's delight chapter 10 - */ -void -umagic(Magic *m) -{ - int p; - uint64 nc, delta, q1, r1, q2, r2; - uint64 mask, two31; - - m->bad = 0; - m->ua = 0; - - switch(m->w) { - default: - m->bad = 1; - return; - case 8: - mask = 0xffLL; - break; - case 16: - mask = 0xffffLL; - break; - case 32: - mask = 0xffffffffLL; - break; - case 64: - mask = 0xffffffffffffffffLL; - break; - } - two31 = mask ^ (mask>>1); - - m->ud &= mask; - if(m->ud == 0 || m->ud == two31) { - m->bad = 1; - return; - } - nc = mask - (-m->ud&mask)%m->ud; - p = m->w-1; - - q1 = two31/nc; - r1 = two31 - q1*nc; - q1 &= mask; - r1 &= mask; - - q2 = (two31-1) / m->ud; - r2 = (two31-1) - q2*m->ud; - q2 &= mask; - r2 &= mask; - - for(;;) { - p++; - if(r1 >= nc-r1) { - q1 <<= 1; - q1++; - r1 <<= 1; - r1 -= nc; - } else { - q1 <<= 1; - r1 <<= 1; - } - q1 &= mask; - r1 &= mask; - if(r2+1 >= m->ud-r2) { - if(q2 >= two31-1) { - m->ua = 1; - } - q2 <<= 1; - q2++; - r2 <<= 1; - r2++; - r2 -= m->ud; - } else { - if(q2 >= two31) { - m->ua = 1; - } - q2 <<= 1; - r2 <<= 1; - r2++; - } - q2 &= mask; - r2 &= mask; - - delta = m->ud - 1 - r2; - delta &= mask; - - if(p < m->w+m->w) - if(q1 < delta || (q1 == delta && r1 == 0)) { - continue; - } - break; - } - m->um = q2+1; - m->s = p-m->w; -} - -Sym* -ngotype(Node *n) -{ - if(n->sym != S && n->realtype != T) - if(strncmp(n->sym->name, "autotmp_", 8) != 0) - if(strncmp(n->sym->name, "statictmp_", 8) != 0) - return typename(n->realtype)->left->sym; - - return S; -} - -/* - * Convert raw string to the prefix that will be used in the symbol table. - * Invalid bytes turn into %xx. Right now the only bytes that need - * escaping are %, ., and ", but we escape all control characters too. - */ -static char* -pathtoprefix(char *s) -{ - static char hex[] = "0123456789abcdef"; - char *p, *r, *w; - int n; - - // check for chars that need escaping - n = 0; - for(r=s; *r; r++) - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') - n++; - - // quick exit - if(n == 0) - return s; - - // escape - p = mal((r-s)+1+2*n); - for(r=s, w=p; *r; r++) { - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') { - *w++ = '%'; - *w++ = hex[(*r>>4)&0xF]; - *w++ = hex[*r&0xF]; - } else - *w++ = *r; - } - *w = '\0'; - return p; -} - -Pkg* -mkpkg(Strlit *path) -{ - Pkg *p; - int h; - - if(strlen(path->s) != path->len) { - yyerror("import path contains NUL byte"); - errorexit(); - } - - h = stringhash(path->s) & (nelem(phash)-1); - for(p=phash[h]; p; p=p->link) - if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0) - return p; - - p = mal(sizeof *p); - p->path = path; - p->prefix = pathtoprefix(path->s); - p->link = phash[h]; - phash[h] = p; - return p; -} - -Strlit* -strlit(char *s) -{ - Strlit *t; - - t = mal(sizeof *t + strlen(s)); - strcpy(t->s, s); - t->len = strlen(s); - return t; -} |