Here's the diff.  It's a bit longer than expected, because I took the
opportunity to expand a bit on the error-reporting engine.

The actual "new error" is the bit in var.c.
The rest:
- makes the engine record the current "parse location" while expanding
commands in a gnode.
- tests fatal_errors before running the actual command.

That seems to be giving the expected results.

I haven't run this thru a make build yet.  It is likely to uncover various
makefile problems !!! as this effectively turns all runtime Parse_Fatal
errors into actual fatal errors (which they weren't).

(if you think the compat/normal job runner is messy, yes, it is. I have
slated an unification of both in the near future).

Index: engine.c
===================================================================
RCS file: /cvs/src/usr.bin/make/engine.c,v
retrieving revision 1.29
diff -u -p -r1.29 engine.c
--- engine.c    22 Mar 2012 13:47:12 -0000      1.29
+++ engine.c    19 Aug 2012 10:17:55 -0000
@@ -738,6 +739,7 @@ expand_commands(GNode *gn)
        LstNode ln;
        char *cmd;
 
+       Parse_SetLocation(&gn->origin);
        for (ln = Lst_First(&gn->commands); ln != NULL; ln = Lst_Adv(ln)) {
                cmd = Var_Subst(Lst_Datum(ln), &gn->context, false);
                Lst_AtEnd(&gn->expanded, cmd);
@@ -749,6 +751,8 @@ run_gnode(GNode *gn)
 {
        if (gn != NULL && (gn->type & OP_DUMMY) == 0) {
                expand_commands(gn);
+               if (fatal_errors)
+                       exit(1);
                return run_prepared_gnode(gn);
        } else {
                return NOSUCHNODE;
Index: job.c
===================================================================
RCS file: /cvs/src/usr.bin/make/job.c,v
retrieving revision 1.122
diff -u -p -r1.122 job.c
--- job.c       11 Apr 2012 18:27:30 -0000      1.122
+++ job.c       19 Aug 2012 10:17:55 -0000
@@ -779,6 +826,8 @@ prepare_job(GNode *gn, int flags)
         */
        cmdsOK = Job_CheckCommands(gn);
        expand_commands(gn);
+       if (fatal_errors)
+               Punt("can't continue");
 
        if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) {
                /*
Index: lowparse.c
===================================================================
RCS file: /cvs/src/usr.bin/make/lowparse.c,v
retrieving revision 1.27
diff -u -p -r1.27 lowparse.c
--- lowparse.c  22 Mar 2012 13:50:30 -0000      1.27
+++ lowparse.c  19 Aug 2012 10:17:55 -0000
@@ -73,6 +73,9 @@ static struct input_stream *current;  /* 
 static LIST input_stack;       /* Stack of input_stream waiting to be parsed
                                 * (includes and loop reparses) */
 
+/* record gnode location for proper reporting at runtime */
+static Location *post_parse = NULL;
+
 /* input_stream ctors.
  *
  * obj = new_input_file(filename, filehandle);
@@ -433,10 +436,20 @@ Parse_Getfilename(void)
 }
 
 void
+Parse_SetLocation(Location *origin)
+{
+       post_parse = origin;
+}
+
+void
 Parse_FillLocation(Location *origin)
 {
-       origin->lineno = Parse_Getlineno();
-       origin->fname = Parse_Getfilename();
+       if (post_parse) {
+               *origin = *post_parse;
+       } else {
+               origin->lineno = Parse_Getlineno();
+               origin->fname = Parse_Getfilename();
+       }
 }
 
 #ifdef CLEANUP
Index: lowparse.h
===================================================================
RCS file: /cvs/src/usr.bin/make/lowparse.h,v
retrieving revision 1.8
diff -u -p -r1.8 lowparse.h
--- lowparse.h  22 Mar 2012 13:47:12 -0000      1.8
+++ lowparse.h  19 Aug 2012 10:17:55 -0000
@@ -81,6 +81,13 @@ extern const char *Parse_Getfilename(voi
  *     Fill the location pointed by origin with the current location. */
 extern void Parse_FillLocation(Location *);
 
+/* Parse_SetLocation(origin)
+ *     Set the "parse location" to a given origin.
+ *     Used for parse errors that occur during variable expansion at
+ *     runtime.
+ */
+extern void Parse_SetLocation(Location *);
+
 /* continue = Parse_NextFile();
  *     Advance parsing to the next file in the input stack. Returns true
  *     if there is parsing left to do.
Index: var.c
===================================================================
RCS file: /cvs/src/usr.bin/make/var.c,v
retrieving revision 1.89
diff -u -p -r1.89 var.c
--- var.c       22 Mar 2012 13:47:12 -0000      1.89
+++ var.c       19 Aug 2012 10:17:55 -0000
@@ -761,11 +761,12 @@ parse_base_variable_name(const char **ps
        case '{':
                /* Find eventual modifiers in the variable */
                tstr = VarName_Get(str+2, name, ctxt, false, find_pos(str[1]));
-               if (*tstr == ':')
+               if (*tstr == '\0')
+                        Parse_Error(PARSE_FATAL, "Unterminated variable spec 
in %s", *pstr);
+               else if (*tstr == ':')
                        has_modifier = true;
-               else if (*tstr != '\0') {
+               else
                        tstr++;
-               }
                break;
        default:
                name->s = str+1;
Index: varname.c
===================================================================
RCS file: /cvs/src/usr.bin/make/varname.c,v
retrieving revision 1.5
diff -u -p -r1.5 varname.c
--- varname.c   19 Jul 2010 19:46:44 -0000      1.5
+++ varname.c   19 Aug 2012 10:17:55 -0000
@@ -32,7 +32,8 @@
 #include "varname.h"
 
 const char *
-VarName_Get(const char *start, struct Name *name, SymTable *ctxt, bool err, 
const char *(*cont)(const char *))
+VarName_Get(const char *start, struct Name *name, SymTable *ctxt, bool err, 
+    const char *(*cont)(const char *))
 {
        const char *p;
        size_t len;
@@ -41,7 +42,7 @@ VarName_Get(const char *start, struct Na
        /* If we don't want recursive variables, we skip over '$' */
        if (!FEATURES(FEATURE_RECVARS)) {
                while (*p == '$')
-                       p = cont(p);
+                       p = cont(p+1);
        }
        if (*p != '$') {
                name->s = start;

Reply via email to