shithub: mc

Download patch

ref: 6b45f935bd240eb066fe4edd49b8cd0853bc5dd9
parent: efd6df04602a973f146e93797ffd057ae277f175
author: Ori Bernstein <[email protected]>
date: Tue Oct 7 15:22:17 EDT 2014

Add support for storing file ids.

--- a/6/isel.c
+++ b/6/isel.c
@@ -1111,10 +1111,10 @@
 static size_t getintlit(Node *n, char *failmsg)
 {
     if (exprop(n) != Olit)
-        fatal(n->line, "%s", failmsg);
+        fatal(n, "%s", failmsg);
     n = n->expr.args[0];
     if (n->lit.littype != Lint)
-        fatal(n->line, "%s", failmsg);
+        fatal(n, "%s", failmsg);
     return n->lit.intval;
 }
 
@@ -1132,7 +1132,7 @@
      * pulled out, and we should have vars with their pseudo-decls in their
      * place */
     if (exprop(base) != Ovar || !base->expr.isconst)
-        fatal(base->line, "slice base is not a constant value");
+        fatal(base, "slice base is not a constant value");
     loval = getintlit(lo, "lower bound in slice is not constant literal");
     hival = getintlit(hi, "upper bound in slice is not constant literal");
     sz = tysize(tybase(exprtype(base))->sub[0]);
@@ -1225,6 +1225,8 @@
 void genasm(FILE *fd, Func *fn, Htab *globls, Htab *strtab)
 {
     Isel is = {0,};
+    Node *n;
+    Bb *bb;
     size_t i, j;
     char buf[128];
 
@@ -1247,10 +1249,12 @@
         is.curbb = is.bb[j];
         if (!is.bb[j])
             continue;
-        for (i = 0; i < fn->cfg->bb[j]->nnl; i++) {
+        bb = fn->cfg->bb[j];
+        for (i = 0; i < bb->nnl; i++) {
             /* put in a comment that says where this line comes from */
+            n = bb->nl[i];
             snprintf(buf, sizeof buf, "\n\t# bb = %ld, bbidx = %ld, %s:%d",
-                     j, i, file->file.name, fn->cfg->bb[j]->nl[i]->line);
+                     j, i, file->file.files[n->fid], n->line);
             g(&is, Ilbl, locstrlbl(buf), NULL);
             isel(&is, fn->cfg->bb[j]->nl[i]);
         }
--- a/6/simp.c
+++ b/6/simp.c
@@ -1029,7 +1029,7 @@
                 /* ptr -> slice conversion is disallowed */
                 case Tyslice:
                     if (t->type == Typtr)
-                        fatal(val->line, "Bad cast from %s to %s",
+                        fatal(val, "Bad cast from %s to %s",
                               tystr(exprtype(val)), tystr(to));
                     r = slicebase(s, val, NULL);
                     break;
@@ -1047,13 +1047,13 @@
                     break;
                 case Tyflt32: case Tyflt64:
                     if (tybase(to)->type == Typtr)
-                        fatal(val->line, "Bad cast from %s to %s",
+                        fatal(val, "Bad cast from %s to %s",
                               tystr(exprtype(val)), tystr(to));
                     r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL);
                     r->expr.type = to;
                     break;
                 default:
-                    fatal(val->line, "Bad cast from %s to %s",
+                    fatal(val, "Bad cast from %s to %s",
                           tystr(exprtype(val)), tystr(to));
             }
             break;
@@ -1072,7 +1072,7 @@
                     r->expr.type = to;
                     break;
                 default:
-                    fatal(val->line, "Bad cast from %s to %s",
+                    fatal(val, "Bad cast from %s to %s",
                           tystr(exprtype(val)), tystr(to));
                     break;
             }
@@ -1079,7 +1079,7 @@
             break;
         /* no other destination types are handled as things stand */
         default:
-            fatal(val->line, "Bad cast from %s to %s",
+            fatal(val, "Bad cast from %s to %s",
                   tystr(exprtype(val)), tystr(to));
     }
     return r;
@@ -1338,7 +1338,7 @@
 
 static Node *comparecomplex(Simp *s, Node *n, Op op)
 {
-    fatal(n->line, "Complex comparisons not yet supported\n");
+    fatal(n, "Complex comparisons not yet supported\n");
     return NULL;
 }
 
@@ -1369,7 +1369,7 @@
     } else if (fields) {
         r = comparecomplex(s, n, exprop(n));
     } else {
-        fatal(n->line, "unsupported comparison on values");
+        fatal(n, "unsupported comparison on values");
     }
     return r;
 }
@@ -1573,12 +1573,12 @@
             break;
         case Obreak:
             if (s->nloopexit == 0)
-                fatal(n->line, "trying to break when not in loop");
+                fatal(n, "trying to break when not in loop");
             jmp(s, s->loopexit[s->nloopexit - 1]);
             break;
         case Ocontinue:
             if (s->nloopstep == 0)
-                fatal(n->line, "trying to continue when not in loop");
+                fatal(n, "trying to continue when not in loop");
             jmp(s, s->loopstep[s->nloopstep - 1]);
             break;
         case Oeq: case One:
--- a/opt/df.c
+++ b/opt/df.c
@@ -46,7 +46,7 @@
             checkpredret(cfg, pred);
         } else if (exprop(pred->nl[pred->nnl - 1]) != Oret) {
             dumpcfg(cfg, stdout);
-            fatal(pred->nl[pred->nnl-1]->line, "Reaches end of function without return\n");
+            fatal(pred->nl[pred->nnl-1], "Reaches end of function without return\n");
         }
     }
 }
--- a/parse/dump.c
+++ b/parse/dump.c
@@ -113,7 +113,7 @@
     findentf(fd, depth, "%s.%zd@%i", nodestr(n->type), n->nid, n->line);
     switch(n->type) {
         case Nfile:
-            fprintf(fd, "(name = %s)\n", n->file.name);
+            fprintf(fd, "(name = %s)\n", n->file.files[0]);
             findentf(fd, depth + 1, "Globls:\n");
             outstab(n->file.globls, fd, depth + 2);
             findentf(fd, depth + 1, "Exports:\n");
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -277,7 +277,7 @@
 
 package : Tpkg optident Tasn pkgbody Tendblk {
                 if (file->file.exports->name)
-                    fatal($1->line, "Package already declared\n");
+                    lfatal($1->line, 0, "Package already declared\n");
                 if ($2) {
                     updatens(file->file.exports, $2->str);
                     updatens(file->file.globls, $2->str);
@@ -322,7 +322,7 @@
                     if (!strcmp($1.str[i], "pkglocal"))
                         $$.type->ispkglocal = 1;
                     else
-                        fatal($$.line, "invalid type attribute '%s'", $1.str[i]);
+                        lfatal($$.line, 0, "invalid type attribute '%s'", $1.str[i]);
                 }
             }
         ;
@@ -896,7 +896,7 @@
             return;
         }
     }
-    fatal(t->line, "Constraint %s does not exist", str);
+    lfatal(t->line, t->file, "Constraint %s does not exist", str);
 }
 
 static Node *mkpseudodecl(Type *t)
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -128,9 +128,9 @@
     t2 = tystr(b);
     c = ctxstr(st, ctx);
     if (msg)
-        fatal(ctx->line, "Type \"%s\" incompatible with \"%s\" near %s: %s", t1, t2, c, msg);
+        fatal(ctx, "Type \"%s\" incompatible with \"%s\" near %s: %s", t1, t2, c, msg);
     else
-        fatal(ctx->line, "Type \"%s\" incompatible with \"%s\" near %s", t1, t2, c);
+        fatal(ctx, "Type \"%s\" incompatible with \"%s\" near %s", t1, t2, c);
     free(t1);
     free(t2);
     free(c);
@@ -301,7 +301,7 @@
     else
         t->traits = bsdup(base->traits);
     if (tyinfinite(st, t, NULL))
-        fatal(t->line, "Type %s includes itself", tystr(t));
+        lfatal(t->line, t->file, "Type %s includes itself", tystr(t));
     st->ingeneric--;
 }
 
@@ -320,9 +320,9 @@
                 ns = getns_str(ns, t->name->name.ns);
             }
             if (!ns)
-                fatal(t->name->line, "Could not resolve namespace \"%s\"", t->name->name.ns);
+                fatal(t->name, "Could not resolve namespace \"%s\"", t->name->name.ns);
             if (!(lu = gettype(ns, t->name)))
-                fatal(t->name->line, "Could not resolve type %s", namestr(t->name));
+                fatal(t->name, "Could not resolve type %s", namestr(t->name));
             tytab[t->tid] = lu;
         }
 
@@ -439,14 +439,14 @@
     if (args[0]->name.ns)
         ns = getns_str(ns, args[0]->name.ns);
     if (!ns)
-        fatal(n->line, "No namespace %s\n", args[0]->name.ns);
+        fatal(n, "No namespace %s\n", args[0]->name.ns);
     uc = getucon(ns, args[0]);
     if (!uc)
-        fatal(n->line, "no union constructor `%s", ctxstr(st, args[0]));
+        fatal(n, "no union constructor `%s", ctxstr(st, args[0]));
     if (!uc->etype && n->expr.nargs > 1)
-        fatal(n->line, "nullary union constructor `%s passed arg ", ctxstr(st, args[0]));
+        fatal(n, "nullary union constructor `%s passed arg ", ctxstr(st, args[0]));
     else if (uc->etype && n->expr.nargs != 2)
-        fatal(n->line, "union constructor `%s needs arg ", ctxstr(st, args[0]));
+        fatal(n, "union constructor `%s needs arg ", ctxstr(st, args[0]));
     return uc;
 }
 
@@ -504,7 +504,7 @@
     if (!n->decl.isgeneric)
         return;
     if (!n->decl.init)
-        fatal(n->line, "generic %s has no initializer", n->decl);
+        fatal(n, "generic %s has no initializer", n->decl);
 
     st->ingeneric++;
     bt = mkht(strhash, streq);
@@ -544,7 +544,7 @@
             a->traits = mkbs();
         settrait(a, c);
     } else if (!a->traits || !bshas(a->traits, c->uid)) {
-        fatal(ctx->line, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(st, ctx));
+        fatal(ctx, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(st, ctx));
     }
 }
 
@@ -588,7 +588,7 @@
             }
             tyfmt(abuf, sizeof abuf, a);
             tyfmt(bbuf, sizeof bbuf, b);
-            fatal(ctx->line, "%s missing traits %s for %s near %s", bbuf, traitbuf, abuf, ctxstr(st, ctx));
+            fatal(ctx, "%s missing traits %s for %s near %s", bbuf, traitbuf, abuf, ctxstr(st, ctx));
         }
     }
 }
@@ -640,7 +640,7 @@
     int found;
 
     if (u->nmemb != v->nmemb)
-        fatal(ctx->line, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
+        fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
 
     for (i = 0; i < u->nmemb; i++) {
         found = 0;
@@ -653,10 +653,10 @@
             else if (u->udecls[i]->etype && v->udecls[i]->etype)
                 unify(st, ctx, u->udecls[i]->etype, v->udecls[i]->etype);
             else
-                fatal(ctx->line, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
+                fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
         }
         if (!found)
-            fatal(ctx->line, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
+            fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
     }
 }
 
@@ -666,7 +666,7 @@
     int found;
 
     if (u->nmemb != v->nmemb)
-        fatal(ctx->line, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
+        fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
 
     for (i = 0; i < u->nmemb; i++) {
         found = 0;
@@ -677,7 +677,7 @@
             unify(st, u->sdecls[i], type(st, u->sdecls[i]), type(st, v->sdecls[i]));
         }
         if (!found)
-            fatal(ctx->line, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
+            fatal(ctx, "can't unify %s and %s near %s\n", tystr(u), tystr(v), ctxstr(st, ctx));
     }
 }
 
@@ -794,7 +794,7 @@
     }
     for (i = 1; i < n->expr.nargs; i++) {
         if (i == ft->nsub)
-            fatal(n->line, "%s arity mismatch (expected %zd args, got %zd)",
+            fatal(n, "%s arity mismatch (expected %zd args, got %zd)",
                   ctxstr(st, n->expr.args[0]), ft->nsub - 1, n->expr.nargs - 1);
 
         if (ft->sub[i]->type == Tyvalist)
@@ -803,7 +803,7 @@
         unify(st, n->expr.args[0], ft->sub[i], type(st, n->expr.args[i]));
     }
     if (i < ft->nsub && ft->sub[i]->type != Tyvalist)
-        fatal(n->line, "%s arity mismatch (expected %zd args, got %zd)",
+        fatal(n, "%s arity mismatch (expected %zd args, got %zd)",
               ctxstr(st, n->expr.args[0]), ft->nsub - 1, i - 1);
     if (debugopt['u']) {
         ret = tystr(ft->sub[0]);
@@ -831,7 +831,7 @@
         return;
 
     if (a->narg != b->narg)
-        fatal(ctx->line, "Mismatched parameter list sizes: %s with %s near %s", tystr(a), tystr(b), ctxstr(st, ctx));
+        fatal(ctx, "Mismatched parameter list sizes: %s with %s near %s", tystr(a), tystr(b), ctxstr(st, ctx));
     for (i = 0; i < a->narg; i++)
         unify(st, ctx, a->arg[i], b->arg[i]);
 }
@@ -907,13 +907,13 @@
             if (!tg)
                 puttype(globls, nx, tx);
             else
-                fatal(nx->line, "Exported type %s already declared on line %d", namestr(nx), tg->line);
+                fatal(nx, "Exported type %s already declared on line %d", namestr(nx), tg->line);
         } else {
             tg = gettype(globls, nx);
             if (tg)
                 updatetype(exports, nx, tf(st, tg));
             else
-                fatal(nx->line, "Exported type %s not declared", namestr(nx));
+                fatal(nx, "Exported type %s not declared", namestr(nx));
         }
     }
     free(k);
@@ -928,13 +928,13 @@
             if (!trg)
                 puttrait(globls, nx, trx);
             else
-                fatal(nx->line, "Exported trait %s already declared on line %d", namestr(nx), trg->name->line);
+                fatal(nx, "Exported trait %s already declared on line %d", namestr(nx), trg->name->line);
         } else {
             trg = gettrait(globls, nx);
             if (trg && !trg->isproto) {
                 *trx = *trg;
             } else {
-                fatal(nx->line, "Exported trait %s not declared", namestr(nx));
+                fatal(nx, "Exported trait %s not declared", namestr(nx));
             }
         }
         trx->vis = Visexport;
@@ -957,7 +957,7 @@
 
         if (nx->impl.isproto) {
             if (!ng)
-                fatal(nx->line, "Missing trait impl body for %s %s\n", namestr(nx->impl.traitname), tystr(nx->impl.type));
+                fatal(nx, "Missing trait impl body for %s %s\n", namestr(nx->impl.traitname), tystr(nx->impl.type));
             htdel(exports->impl, k[i]);
             putimpl(exports, ng);
             ng->impl.vis = Visexport;
@@ -965,7 +965,7 @@
             if (!ng) {
                 putimpl(globls, nx);
             } else {
-                fatal(nx->line, "Double trait impl body for %s %s on line %d\n",
+                fatal(nx, "Double trait impl body for %s %s on line %d\n",
                       namestr(nx->impl.traitname), tystr(nx->impl.type), ng->line);
             }
         }
@@ -982,9 +982,9 @@
          * body */
         if (ng) {
             if (nx->decl.init)
-                fatal(nx->line, "Export %s double-defined on line %d", ctxstr(st, nx), ng->line);
+                fatal(nx, "Export %s double-defined on line %d", ctxstr(st, nx), ng->line);
             if (nx->decl.isgeneric != ng->decl.isgeneric)
-                fatal(nx->line, "Export %s defined with different genericness on line %d", ctxstr(st, nx), ng->line);
+                fatal(nx, "Export %s defined with different genericness on line %d", ctxstr(st, nx), ng->line);
             mergeattrs(ng, nx);
             mergeattrs(nx, ng);
             unify(st, nx, type(st, ng), type(st, nx));
@@ -991,7 +991,7 @@
         } else {
             if (!nx->decl.isextern && !nx->decl.isimport && !nx->decl.trait)
                 if (!nx->decl.init && (nx->decl.isconst || nx->decl.isgeneric))
-                    fatal(nx->line, "Export %s defined but not implemented", ctxstr(st, nx));
+                    fatal(nx, "Export %s defined but not implemented", ctxstr(st, nx));
             putdcl(globls, nx);
         }
     }
@@ -1007,7 +1007,7 @@
         /* if an export has an initializer, it shouldn't be declared in the
          * body */
         if (ux && ug)
-            fatal(ux->line, "Union constructor double defined on %d", ux->line);
+            lfatal(ux->line, ux->file, "Union constructor double defined on %d", ux->line);
         else if (!ug)
           putucon(globls, ux);
         else
@@ -1023,7 +1023,7 @@
     Type *t;
 
     if (s->decl.ishidden)
-        fatal(n->line, "attempting to refer to hidden decl %s", ctxstr(st, n));
+        fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n));
     if (s->decl.isgeneric)
         t = tyfreshen(st, tf(st, s->decl.type));
     else
@@ -1073,7 +1073,7 @@
     nsname = mknsname(n->line, namestr(name), namestr(args[1]));
     s = getdcl(stab, args[1]);
     if (!s)
-        fatal(n->line, "Undeclared var %s.%s", nsname->name.ns, nsname->name.name);
+        fatal(n, "Undeclared var %s.%s", nsname->name.ns, nsname->name.name);
     var = mkexpr(n->line, Ovar, nsname, NULL);
     initvar(st, var, s);
     *ret = var;
@@ -1176,7 +1176,7 @@
         case Obnot:
             infernode(st, n, NULL, NULL);
             if (!n->expr.isconst)
-                fatal(n->line, "matching against non-constant expression");
+                fatal(n, "matching against non-constant expression");
             break;
         case Oucon:     inferucon(st, n, &n->expr.isconst);     break;
         case Ovar:
@@ -1187,7 +1187,7 @@
                 else if (s->decl.isconst)
                     t = s->decl.type;
                 else
-                    fatal(n->line, "Can't match against non-constant variables near %s", ctxstr(st, n));
+                    fatal(n, "Can't match against non-constant variables near %s", ctxstr(st, n));
             } else {
                 t = mktyvar(n->line);
                 s = mkdecl(n->line, n->expr.args[0], t);
@@ -1199,7 +1199,7 @@
             n->expr.did = s->decl.did;
             break;
         default:
-            fatal(n->line, "invalid pattern");
+            fatal(n, "invalid pattern");
             break;
     }
 }
@@ -1315,7 +1315,7 @@
                 t = unify(st, n, t, type(st, args[i]));
             settype(st, n, t);
             if (args[0]->expr.isconst)
-                fatal(n->line, "Attempting to assign constant \"%s\"", ctxstr(st, args[0]));
+                fatal(n, "Attempting to assign constant \"%s\"", ctxstr(st, args[0]));
             break;
 
         /* operands same type, returning bool */
@@ -1384,7 +1384,7 @@
             if (sawret)
                 *sawret = 1;
             if (!ret)
-                fatal(n->line, "Not allowed to return value here");
+                fatal(n, "Not allowed to return value here");
             if (nargs)
                 t = unify(st, n, ret, type(st, args[0]));
             else
@@ -1409,7 +1409,7 @@
                 return;
             s = getdcl(curstab(), args[0]);
             if (!s)
-                fatal(n->line, "Undeclared var %s", ctxstr(st, args[0]));
+                fatal(n, "Undeclared var %s", ctxstr(st, args[0]));
             initvar(st, n, s);
             break;
         case Oucon:
@@ -1478,7 +1478,7 @@
 
     t = gettrait(curstab(), n->impl.traitname);
     if (!t)
-        fatal(n->line, "No trait %s\n", namestr(n->impl.traitname));
+        fatal(n, "No trait %s\n", namestr(n->impl.traitname));
     n->impl.trait = t;
 
     dcl = NULL;
@@ -1503,7 +1503,7 @@
             }
         }
         if (!proto)
-            fatal(n->line, "Declaration %s missing in %s, near %s\n",
+            fatal(n, "Declaration %s missing in %s, near %s\n",
                   namestr(dcl->decl.name), namestr(t->name), ctxstr(st, n));
 
         /* infer and unify types */
@@ -1542,10 +1542,10 @@
         inferexpr(st, n->decl.init, NULL, NULL);
         unify(st, n, type(st, n), type(st, n->decl.init));
         if (n->decl.isconst && !n->decl.init->expr.isconst)
-            fatal(n->line, "non-const initializer for \"%s\"", ctxstr(st, n));
+            fatal(n, "non-const initializer for \"%s\"", ctxstr(st, n));
     } else {
         if ((n->decl.isconst || n->decl.isgeneric) && !n->decl.isextern)
-            fatal(n->line, "non-extern \"%s\" has no initializer", ctxstr(st, n));
+            fatal(n, "non-extern \"%s\" has no initializer", ctxstr(st, n));
     }
 }
 
@@ -1600,7 +1600,7 @@
             bind(st, n);
             inferdecl(st, n);
             if (type(st, n)->type == Typaram && !st->ingeneric)
-                fatal(n->line, "Generic type %s in non-generic near %s\n", tystr(type(st, n)), ctxstr(st, n));
+                fatal(n, "Generic type %s in non-generic near %s\n", tystr(type(st, n)), ctxstr(st, n));
             unbind(st, n);
             st->indentdepth--;
             if (debugopt['u'])
@@ -1648,7 +1648,7 @@
         case Nmatchstmt:
             infernode(st, n->matchstmt.val, NULL, sawret);
             if (tybase(type(st, n->matchstmt.val))->type == Tyvoid)
-                fatal(n->line, "Can't match against a void type near %s", ctxstr(st, n->matchstmt.val));
+                fatal(n, "Can't match against a void type near %s", ctxstr(st, n->matchstmt.val));
             for (i = 0; i < n->matchstmt.nmatches; i++) {
                 infernode(st, n->matchstmt.matches[i], ret, sawret);
                 unify(st, n, type(st, n->matchstmt.val), type(st, n->matchstmt.matches[i]->match.pat));
@@ -1708,7 +1708,7 @@
         if (t->type == Tyvar)
             t = delayed;
         else if (tybase(t)->type != delayed->type)
-            fatal(ctx->line, "Type %s not compatible with %s near %s\n", tystr(t), tystr(delayed), ctxstr(st, ctx));
+            fatal(ctx, "Type %s not compatible with %s near %s\n", tystr(t), tystr(delayed), ctxstr(st, ctx));
     }
     if (t->type == Tyvar) {
         if (hastrait(t, traittab[Tcint]) && checktraits(t, tyint))
@@ -1737,7 +1737,7 @@
     if (t->type == Tyvar) {
         if (debugopt['T'])
             dump(file, stdout);
-        fatal(t->line, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx));
+        lfatal(t->line, t->file, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx));
     }
     if (debugopt['u'] && !tyeq(orig, t)) {
         from = tystr(orig);
@@ -1797,7 +1797,7 @@
         }
     }
     if (!found)
-        fatal(aggr->line, "Type %s has no member \"%s\" near %s",
+        fatal(aggr, "Type %s has no member \"%s\" near %s",
               tystr(type(st, aggr)), ctxstr(st, memb), ctxstr(st, aggr));
 }
 
@@ -1809,7 +1809,7 @@
 
     t = tybase(tf(st, n->lit.type));
     if (t->type != Tystruct)
-        fatal(n->line, "Type %s for struct literal is not struct near %s", tystr(t), ctxstr(st, n));
+        fatal(n, "Type %s for struct literal is not struct near %s", tystr(t), ctxstr(st, n));
 
     for (i = 0; i < n->expr.nargs; i++) {
         val = n->expr.args[i];
@@ -1824,7 +1824,7 @@
         }
 
         if (!et)
-            fatal(n->line, "Could not find member %s in struct %s, near %s",
+            fatal(n, "Could not find member %s in struct %s, near %s",
                   namestr(name), tystr(t), ctxstr(st, n));
 
         unify(st, val, et, type(st, val));
@@ -1918,11 +1918,11 @@
     if (t->type >= Tyint8 && t->type <= Tylong) {
         sval = n->lit.intval;
         if (sval < svranges[t->type][0] || sval > svranges[t->type][1])
-            fatal(n->line, "Literal value %lld out of range for type \"%s\"", sval, tystr(t));
+            fatal(n, "Literal value %lld out of range for type \"%s\"", sval, tystr(t));
     } else if ((t->type >= Tybyte && t->type <= Tyulong) || t->type == Tychar) {
         uval = n->lit.intval;
         if (uval < uvranges[t->type][0] || uval > uvranges[t->type][1])
-            fatal(n->line, "Literal value %llu out of range for type \"%s\"", uval, tystr(t));
+            fatal(n, "Literal value %llu out of range for type \"%s\"", uval, tystr(t));
     }
 }
 
@@ -2216,7 +2216,7 @@
             n = f->file.stmts[i];
             trait = gettrait(f->file.globls, n->impl.traitname);
             if (!trait)
-                fatal(n->line, "trait %s does not exist near %s", namestr(n->impl.traitname), ctxstr(st, n));
+                fatal(n, "trait %s does not exist near %s", namestr(n->impl.traitname), ctxstr(st, n));
             ty = tf(st, n->impl.type);
             settrait(ty, trait);
         }
--- a/parse/node.c
+++ b/parse/node.c
@@ -34,7 +34,7 @@
     Node *n;
 
     n = mknode(-1, Nfile);
-    n->file.name = strdup(name);
+    lappend(&n->file.files, &n->file.nfiles, strdup(name));
     return n;
 }
 
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -114,6 +114,7 @@
     Ty type;
     int tid;
     int line;
+    int file;
     Vis vis;
 
     int resolved;       /* Have we resolved the subtypes? Prevents infinite recursion. */
@@ -147,6 +148,7 @@
 
 struct Ucon {
     int line;   /* line declared on */
+    int file;   /* file index */
     size_t id;  /* unique id */
     int synth;  /* is it generated? */
     Node *name; /* ucon name */
@@ -169,11 +171,13 @@
 
 struct Node {
     int line;
+    int fid;
     Ntype type;
     int nid;
     union {
         struct {
-            char  *name;
+            char  **files;
+            size_t nfiles;
             size_t nuses;
             Node **uses;
             size_t nlibdeps;
@@ -400,8 +404,10 @@
 void *xalloc(size_t size);
 void *zrealloc(void *p, size_t oldsz, size_t size);
 void *xrealloc(void *p, size_t size);
-void  die(char *msg, ...) FATAL;
-void  fatal(int line, char *fmt, ...) FATAL;
+void die(char *msg, ...) FATAL;
+void fatal(Node *n, char *fmt, ...) FATAL;
+void lfatal(int line, int file, char *fmt, ...) FATAL;
+void lfatalv(int line, int file, char *fmt, va_list ap) FATAL;
 char *strdupn(char *s, size_t len);
 char *strjoin(char *u, char *v);
 void *memdup(void *mem, size_t len);
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -169,7 +169,7 @@
                 if (n->expr.args[0]->name.ns)
                     ns = getns_str(ns, n->expr.args[0]->name.ns);
                 if (!ns)
-                    fatal(n->line, "No namespace %s\n", n->expr.args[0]->name.ns);
+                    fatal(n, "No namespace %s\n", n->expr.args[0]->name.ns);
                 d = getdcl(ns, n->expr.args[0]);
                 if (!d)
                     die("Missing decl %s", namestr(n->expr.args[0]));
@@ -401,7 +401,7 @@
     if (d)
         return d;
     if (n->decl.trait)
-        fatal(n->line, "No trait implemented for for %s\n", namestr(n->decl.name));
+        fatal(n, "No trait implemented for for %s\n", namestr(n->decl.name));
     /* namespaced names need to be looked up in their correct
      * context. */
     if (n->decl.name->name.ns) {
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -201,7 +201,7 @@
 
     d = htget(st->dcl, s->decl.name);
     if (d)
-        fatal(s->line, "%s already declared (on line %d)", namestr(s->decl.name), d->line);
+        fatal(s, "%s already declared (on line %d)", namestr(s->decl.name), d->line);
     forcedcl(st, s);
 }
 
@@ -227,7 +227,7 @@
     Tydefn *td;
 
     if (gettype(st, n))
-        fatal(n->line, "Type %s already defined", tystr(gettype(st, n)));
+        fatal(n, "Type %s already defined", tystr(gettype(st, n)));
     td = xalloc(sizeof(Tydefn));
     td->line = n->line;
     td->name = n;
@@ -240,7 +240,7 @@
 void putucon(Stab *st, Ucon *uc)
 {
     if (getucon(st, uc->name))
-        fatal(uc->line, "union constructor %s already defined", namestr(uc->name));
+        lfatal(uc->line, uc->file, "union constructor %s already defined", namestr(uc->name));
     htput(st->uc, uc->name, uc);
 }
 
@@ -249,9 +249,9 @@
     Traitdefn *td;
 
     if (gettrait(st, n))
-        fatal(n->line, "Trait %s already defined", namestr(n));
+        fatal(n, "Trait %s already defined", namestr(n));
     if (gettype(st, n))
-        fatal(n->line, "Trait %s already defined as a type", namestr(n));
+        fatal(n, "Trait %s already defined as a type", namestr(n));
     td = xalloc(sizeof(Tydefn));
     td->line = n->line;
     td->name = n;
@@ -262,7 +262,7 @@
 void putimpl(Stab *st, Node *n)
 {
     if (getimpl(st, n))
-        fatal(n->line, "Trait %s already implemented over %s", namestr(n->impl.traitname), tystr(n->impl.type));
+        fatal(n, "Trait %s already implemented over %s", namestr(n->impl.traitname), tystr(n->impl.type));
     if (st->name)
         setns(n->impl.traitname, namestr(st->name));
     htput(st->impl, n, n);
@@ -286,7 +286,7 @@
 
     s = getns(st, scope->name);
     if (s)
-        fatal(scope->name->line, "Ns %s already defined", namestr(s->name));
+        fatal(scope->name, "Ns %s already defined", namestr(s->name));
     htput(st->ns, namestr(scope->name), scope);
 }
 
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -110,7 +110,7 @@
                 line++;
                 break;
             case End:
-                fatal(line, "File ended within comment starting at line %d", startln);
+                lfatal(line, 0, "File ended within comment starting at line %d", startln);
                 break;
         }
         if (depth == 0)
@@ -287,7 +287,7 @@
     else if (c < 0x200000)
         charlen = 4;
     else
-        fatal(line, "invalid utf character '\\u{%x}'", c);
+        lfatal(line, 0, "invalid utf character '\\u{%x}'", c);
 
     encode(charbuf, charlen, c);
     for (i = 0; i < charlen; i++)
@@ -316,7 +316,7 @@
         return c - 'A' + 10;
     else if (c >= '0' && c <= '9')
         return c - '0';
-    fatal(line, "passed non-hex value '%c' to where hex was expected", c);
+    lfatal(line, 0, "passed non-hex value '%c' to where hex was expected", c);
     return -1;
 }
 
@@ -328,16 +328,16 @@
 
     /* we've already seen the \u */
     if (next() != '{')
-        fatal(line, "\\u escape sequence without initial '{'");
+        lfatal(line, 0, "\\u escape sequence without initial '{'");
     v = 0;
     while (ishexval(peek())) {
         c = next();
         v = 16*v + hexval(c);
         if (v > 0x10FFFF)
-            fatal(line, "invalid codepoint for \\u escape sequence");
+            lfatal(line, 0, "invalid codepoint for \\u escape sequence");
     }
     if (next() != '}')
-        fatal(line, "\\u escape sequence without ending '}'");
+        lfatal(line, 0, "\\u escape sequence without ending '}'");
     return v;
 }
 
@@ -361,10 +361,10 @@
         case 'x': /* arbitrary hex */
             c1 = next();
             if (!isxdigit(c1))
-                fatal(line, "expected hex digit, got %c", c1);
+                lfatal(line, 0, "expected hex digit, got %c", c1);
             c2 = next();
             if (!isxdigit(c2))
-                fatal(line, "expected hex digit, got %c", c1);
+                lfatal(line, 0, "expected hex digit, got %c", c1);
             v = 16*hexval(c1) + hexval(c2);
             break;
         case 'n': v = '\n'; break;
@@ -376,7 +376,7 @@
         case 'v': v = '\v'; break;
         case '\\': v = '\\'; break;
         case '0': v = '\0'; break;
-        default: fatal(line, "unknown escape code \\%c", c);
+        default: lfatal(line, 0, "unknown escape code \\%c", c);
     }
     append(buf, len, sz, v);
     return v;
@@ -400,9 +400,9 @@
         if (c == '"')
             break;
         else if (c == End)
-            fatal(line, "Unexpected EOF within string");
+            lfatal(line, 0, "Unexpected EOF within string");
         else if (c == '\n')
-            fatal(line, "Newlines not allowed in strings");
+            lfatal(line, 0, "Newlines not allowed in strings");
         else if (c == '\\')
             decode(&buf, &len, &sz);
         else
@@ -428,7 +428,7 @@
     else if ((c & 0xf8) == 0xf0)
         len = 4;
     else
-        fatal(line, "Invalid utf8 encoded character constant");
+        lfatal(line, 0, "Invalid utf8 encoded character constant");
 
     val = c & ((1 << (8 - len)) - 1);
     append(buf, buflen, sz, c);
@@ -435,7 +435,7 @@
     for (i = 1; i < len; i++) {
         c = next();
         if ((c & 0xc0) != 0x80)
-            fatal(line, "Invalid utf8 codepoint in character literal");
+            lfatal(line, 0, "Invalid utf8 codepoint in character literal");
         val = (val << 6) | (c & 0x3f);
         append(buf, buflen, sz, c);
     }
@@ -459,9 +459,9 @@
     val = 0;
     c = next();
     if (c == End)
-        fatal(line, "Unexpected EOF within char lit");
+        lfatal(line, 0, "Unexpected EOF within char lit");
     else if (c == '\n')
-        fatal(line, "Newlines not allowed in char lit");
+        lfatal(line, 0, "Newlines not allowed in char lit");
     else if (c == '\\')
         val = decode(&buf, &len, &sz);
     else
@@ -468,7 +468,7 @@
         val = readutf(c, &buf, &len, &sz);
     append(&buf, &len, &sz, '\0');
     if (next() != '\'')
-        fatal(line, "Character constant with multiple characters");
+        lfatal(line, 0, "Character constant with multiple characters");
 
     t = mktok(Tchrlit);
     t->chrval = val;
@@ -614,7 +614,7 @@
                   break;
         default:
                   tt = Terror;
-                  fatal(line, "Junk character %c", c);
+                  lfatal(line, 0, "Junk character %c", c);
                   break;
     }
     return mktok(tt);
@@ -644,10 +644,10 @@
         if (c == '.')
             isfloat = 1;
         else if (hexval(c) < 0 || hexval(c) > base)
-            fatal(line, "Integer digit '%c' outside of base %d", c, base);
+            lfatal(line, 0, "Integer digit '%c' outside of base %d", c, base);
         if (nbuf >= sizeof buf) {
             buf[nbuf-1] = '\0';
-            fatal(line, "number %s... too long to represent", buf);
+            lfatal(line, 0, "number %s... too long to represent", buf);
         }
         buf[nbuf++] = c;
     }
@@ -674,7 +674,7 @@
         switch (peek()) {
             case 'u':
                 if (unsignedval == 1)
-                    fatal(line, "Duplicate 'u' integer specifier");
+                    lfatal(line, 0, "Duplicate 'u' integer specifier");
                 next();
                 unsignedval = 1;
                 goto nextsuffix;
@@ -708,7 +708,7 @@
                 break;
             default:
                 if (unsignedval)
-                    fatal(line, "Unrecognized character int type specifier after 'u'");
+                    lfatal(line, 0, "Unrecognized character int type specifier after 'u'");
                 break;
         }
     }
@@ -780,7 +780,7 @@
     }
 
     if (!t || t->type == Terror)
-        fatal(line, "Unable to parse token starting with %c", c);
+        lfatal(line, 0, "Unable to parse token starting with %c", c);
     return t;
 }
 
@@ -802,7 +802,7 @@
     while (1) {
         n = read(fd, fbuf + nread, 4096);
         if (n < 0)
-            fatal(errno, "Error reading file %s", file);
+            fatal(0, 0, "Error reading file %s", file);
         if (n == 0)
             break;
         if (!fbuf)
--- a/parse/use.c
+++ b/parse/use.c
@@ -410,7 +410,7 @@
     wrint(fd, n->line);
     switch (n->type) {
         case Nfile:
-            wrstr(fd, n->file.name);
+            wrstr(fd, n->file.files[0]);
             wrint(fd, n->file.nuses);
             for (i = 0; i < n->file.nuses; i++)
                 pickle(fd, n->file.uses[i]);
@@ -540,7 +540,7 @@
     n->line = rdint(fd);
     switch (n->type) {
         case Nfile:
-            n->file.name = rdstr(fd);
+            lappend(&n->file.files, &n->file.nfiles, rdstr(fd));
             n->file.nuses = rdint(fd);
             n->file.uses = zalloc(sizeof(Node*)*n->file.nuses);
             for (i = 0; i < n->file.nuses; i++)
@@ -724,7 +724,7 @@
             continue;
         old = htget(tydedup, t->name);
         if (old && !tyeq(t, old))
-            fatal(-1, "Duplicate definition of type %s", tystr(old));
+            lfatal(t->line, t->file, "Duplicate definition of type %s on %s:%d", tystr(old), file->file.files[old->file], old->line);
     }
     lfree(&typefixdest, &ntypefixdest);
     lfree(&typefixid, &ntypefixid);
@@ -858,7 +858,7 @@
         }
     }
     if (!fd)
-        fatal(use->line, "Could not open %s", use->use.name);
+        fatal(use, "Could not open %s", use->use.name);
 
     if (!loaduse(fd, st))
         die("Could not load usefile %s", use->use.name);
--- a/parse/util.c
+++ b/parse/util.c
@@ -63,15 +63,29 @@
     abort();
 }
 
-void fatal(int line, char *msg, ...)
+void fatal(Node *n, char *msg, ...)
 {
     va_list ap;
 
     va_start(ap, msg);
-    fprintf(stdout, "%s:%d: ", file->file.name, line);
+    lfatalv(n->line, n->fid, msg, ap);
+    va_end(ap);
+}
+
+void lfatal(int line, int file, char *msg, ...)
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    lfatalv(line, file, msg, ap);
+    va_end(ap);
+}
+
+void lfatalv(int line, int fid, char *msg, va_list ap)
+{
+    fprintf(stdout, "%s:%d: ", file->file.files[fid], line);
     vfprintf(stdout, msg, ap);
     fprintf(stdout, "\n");
-    va_end(ap);
     exit(1);
 }