Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make: skip syntactically wrong .for loops



details:   https://anonhg.NetBSD.org/src/rev/cee6b7d43b66
branches:  trunk
changeset: 374667:cee6b7d43b66
user:      rillig <rillig%NetBSD.org@localhost>
date:      Tue May 09 19:43:12 2023 +0000

description:
make: skip syntactically wrong .for loops

When a .for loop cannot be interpreted correctly, for example when there
are no iteration variables or the number of words doesn't match the
iteration variables, skip the body of the .for loop instead of
interpreting it once.

diffstat:

 usr.bin/make/for.c                               |  22 ++---
 usr.bin/make/unit-tests/check-expect.lua         |  40 ++++++++-
 usr.bin/make/unit-tests/directive-for-errors.exp |  34 +++-----
 usr.bin/make/unit-tests/directive-for-errors.mk  |  30 ++++++-
 usr.bin/make/unit-tests/directive-for-escape.exp |  82 ++++++++++-----------
 usr.bin/make/unit-tests/directive-for-escape.mk  |  38 +++++++++-
 usr.bin/make/unit-tests/directive-for.exp        |  62 +++++++---------
 usr.bin/make/unit-tests/directive-for.mk         |  91 +++++++++++++++--------
 8 files changed, 242 insertions(+), 157 deletions(-)

diffs (truncated from 818 to 300 lines):

diff -r 96ff47ac4b6e -r cee6b7d43b66 usr.bin/make/for.c
--- a/usr.bin/make/for.c        Tue May 09 19:22:07 2023 +0000
+++ b/usr.bin/make/for.c        Tue May 09 19:43:12 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: for.c,v 1.173 2023/05/08 10:24:07 rillig Exp $ */
+/*     $NetBSD: for.c,v 1.174 2023/05/09 19:43:12 rillig Exp $ */
 
 /*
  * Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
 #include "make.h"
 
 /*     "@(#)for.c      8.1 (Berkeley) 6/6/93"  */
-MAKE_RCSID("$NetBSD: for.c,v 1.173 2023/05/08 10:24:07 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.174 2023/05/09 19:43:12 rillig Exp $");
 
 
 typedef struct ForLoop {
@@ -145,7 +145,7 @@ IsValidInVarname(char c)
            c != '(' && c != '{' && c != ')' && c != '}';
 }
 
-static bool
+static void
 ForLoop_ParseVarnames(ForLoop *f, const char **pp)
 {
        const char *p = *pp;
@@ -156,7 +156,8 @@ ForLoop_ParseVarnames(ForLoop *f, const 
                cpp_skip_whitespace(&p);
                if (*p == '\0') {
                        Parse_Error(PARSE_FATAL, "missing `in' in for");
-                       return false;
+                       f->vars.len = 0;
+                       return;
                }
 
                for (len = 0; p[len] != '\0' && !ch_isspace(p[len]); len++) {
@@ -165,7 +166,8 @@ ForLoop_ParseVarnames(ForLoop *f, const 
                                    "invalid character '%c' "
                                    "in .for loop variable name",
                                    p[len]);
-                               return false;
+                               f->vars.len = 0;
+                               return;
                        }
                }
 
@@ -180,11 +182,10 @@ ForLoop_ParseVarnames(ForLoop *f, const 
 
        if (f->vars.len == 0) {
                Parse_Error(PARSE_FATAL, "no iteration variables in for");
-               return false;
+               return;
        }
 
        *pp = p;
-       return true;
 }
 
 static bool
@@ -253,11 +254,8 @@ For_Eval(const char *line)
                p += 3;
 
                f = ForLoop_New();
-               if (!ForLoop_ParseVarnames(f, &p)) {
-                       ForLoop_Free(f);
-                       return -1;
-               }
-               if (!ForLoop_ParseItems(f, p))
+               ForLoop_ParseVarnames(f, &p);
+               if (f->vars.len > 0 && !ForLoop_ParseItems(f, p))
                        f->items.len = 0;       /* don't iterate */
 
                accumFor = f;
diff -r 96ff47ac4b6e -r cee6b7d43b66 usr.bin/make/unit-tests/check-expect.lua
--- a/usr.bin/make/unit-tests/check-expect.lua  Tue May 09 19:22:07 2023 +0000
+++ b/usr.bin/make/unit-tests/check-expect.lua  Tue May 09 19:43:12 2023 +0000
@@ -1,17 +1,28 @@
 #!  /usr/bin/lua
--- $NetBSD: check-expect.lua,v 1.3 2022/04/15 09:33:20 rillig Exp $
+-- $NetBSD: check-expect.lua,v 1.4 2023/05/09 19:43:12 rillig Exp $
 
 --[[
 
 usage: lua ./check-expect.lua *.mk
 
-Check that each text from an '# expect: ...' comment in the .mk source files
-occurs in the corresponding .exp file, in the same order as in the .mk file.
+Check that the various 'expect' comments in the .mk files produce the
+expected text in the corresponding .exp file.
+
+# expect: <line>
+        All of these lines must occur in the .exp file, in the same order as
+        in the .mk file.
 
-Check that each text from an '# expect[+-]offset: ...' comment in the .mk
-source files occurs in the corresponding .exp file and refers back to the
-correct line in the .mk file.
+# expect-reset
+        Search the following 'expect:' comments from the top of the .exp
+        file again.
 
+# expect[+-]offset: <message>
+        Each message must occur in the .exp file and refer back to the
+        source line in the .mk file.
+
+# expect-all
+        Each message from the .exp file that can be matched by an
+        'expect[+-]offset' comment must actually be matched.
 ]]
 
 
@@ -68,6 +79,7 @@ local function check_mk(mk_fname)
   if exp_lines == nil then return end
   local by_location = collect_lineno_diagnostics(exp_lines)
   local prev_expect_line = 0
+  local match_all = false
 
   for mk_lineno, mk_line in ipairs(mk_lines) do
     for text in mk_line:gmatch("#%s*expect:%s*(.*)") do
@@ -110,6 +122,22 @@ local function check_mk(mk_fname)
           mk_fname, mk_lineno, exp_fname, text)
       end
     end
+
+    if mk_line:match("^#%s*expect%-all$") then
+      match_all = true
+    end
+  end
+
+  if match_all then
+    -- XXX: The messages are not sorted in any meaningful way.
+    for location, messages in pairs(by_location) do
+      for _, message in ipairs(messages) do
+        if message ~= "" then
+          print_error("error: %s: missing 'expect' comment for '%s'",
+            location, message)
+        end
+      end
+    end
   end
 end
 
diff -r 96ff47ac4b6e -r cee6b7d43b66 usr.bin/make/unit-tests/directive-for-errors.exp
--- a/usr.bin/make/unit-tests/directive-for-errors.exp  Tue May 09 19:22:07 2023 +0000
+++ b/usr.bin/make/unit-tests/directive-for-errors.exp  Tue May 09 19:43:12 2023 +0000
@@ -1,23 +1,17 @@
-make: "directive-for-errors.mk" line 7: Unknown directive "fori"
-make: "directive-for-errors.mk" line 8: warning: 
-make: "directive-for-errors.mk" line 9: for-less endfor
-make: "directive-for-errors.mk" line 19: Unknown directive "for"
-make: "directive-for-errors.mk" line 20: warning: 
-make: "directive-for-errors.mk" line 21: for-less endfor
-make: "directive-for-errors.mk" line 34: invalid character '$' in .for loop variable name
-make: "directive-for-errors.mk" line 35: Dollar $   and backslash backslash backslash backslash.
-make: "directive-for-errors.mk" line 36: for-less endfor
-make: "directive-for-errors.mk" line 41: no iteration variables in for
-make: "directive-for-errors.mk" line 45: warning: Should not be reached.
-make: "directive-for-errors.mk" line 46: for-less endfor
-make: "directive-for-errors.mk" line 51: Wrong number of words (5) in .for substitution list with 3 variables
-make: "directive-for-errors.mk" line 63: missing `in' in for
-make: "directive-for-errors.mk" line 65: warning: Should not be reached.
-make: "directive-for-errors.mk" line 66: for-less endfor
-make: "directive-for-errors.mk" line 72: Unknown modifier "Z"
-make: "directive-for-errors.mk" line 73: warning: Should not be reached.
-make: "directive-for-errors.mk" line 73: warning: Should not be reached.
-make: "directive-for-errors.mk" line 73: warning: Should not be reached.
+make: "directive-for-errors.mk" line 11: Unknown directive "fori"
+make: "directive-for-errors.mk" line 12: warning: <>
+make: "directive-for-errors.mk" line 13: for-less endfor
+make: "directive-for-errors.mk" line 27: Unknown directive "for"
+make: "directive-for-errors.mk" line 28: warning: <>
+make: "directive-for-errors.mk" line 29: for-less endfor
+make: "directive-for-errors.mk" line 46: invalid character '$' in .for loop variable name
+make: "directive-for-errors.mk" line 54: no iteration variables in for
+make: "directive-for-errors.mk" line 66: Wrong number of words (5) in .for substitution list with 3 variables
+make: "directive-for-errors.mk" line 80: missing `in' in for
+make: "directive-for-errors.mk" line 91: Unknown modifier "Z"
+make: "directive-for-errors.mk" line 92: warning: Should not be reached.
+make: "directive-for-errors.mk" line 92: warning: Should not be reached.
+make: "directive-for-errors.mk" line 92: warning: Should not be reached.
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1
diff -r 96ff47ac4b6e -r cee6b7d43b66 usr.bin/make/unit-tests/directive-for-errors.mk
--- a/usr.bin/make/unit-tests/directive-for-errors.mk   Tue May 09 19:22:07 2023 +0000
+++ b/usr.bin/make/unit-tests/directive-for-errors.mk   Tue May 09 19:43:12 2023 +0000
@@ -1,24 +1,35 @@
-# $NetBSD: directive-for-errors.mk,v 1.4 2023/05/08 10:24:07 rillig Exp $
+# $NetBSD: directive-for-errors.mk,v 1.5 2023/05/09 19:43:12 rillig Exp $
 #
 # Tests for error handling in .for loops.
 
+# expect-all
+
+
 # A .for directive must be followed by whitespace, everything else results
 # in a parse error.
+# expect+1: Unknown directive "fori"
 .fori in 1 2 3
-.  warning ${i}
+.  warning <${i}>
 .endfor
+# expect-2: <>
+# expect-2: for-less endfor
+
 
 # A slash is not whitespace, therefore this is not parsed as a .for loop.
 #
 # XXX: The error message is misleading though.  As of 2020-12-31, it says
-# "Unknown directive "for"", but that directive is actually known.  This is
+# 'Unknown directive "for"', but that directive is actually known.  This is
 # because ForEval does not detect the .for loop as such, so parsing
 # continues in ParseLine > ParseDependencyLine > ParseDependency >
 # ParseDependencyTargets > ParseErrorNoDependency, and there the directive
 # name is parsed a bit differently.
+# expect+1: Unknown directive "for"
 .for/i in 1 2 3
-.  warning ${i}
+.  warning <${i}>
 .endfor
+# expect-2: warning: <>
+# expect-2: for-less endfor
+
 
 # Before for.c 1.173 from 2023-05-08, the variable name could be an arbitrary
 # word, it only needed to be separated by whitespace.  Even '$' and '\' were
@@ -31,6 +42,7 @@
 # error everywhere outside a .for loop.
 ${:U\$}=       dollar          # see whether the "variable" '$' is local
 ${:U\\}=       backslash       # see whether the "variable" '\' is local
+# expect+1: invalid character '$' in .for loop variable name
 .for $ \ in 1 2 3 4
 .  info Dollar $$ ${$} $($) and backslash $\ ${\} $(\).
 .endfor
@@ -38,6 +50,7 @@
 # If there are no variables, there is no point in expanding the .for loop
 # since this would end up in an endless loop, consuming 0 of the 3 values in
 # each iteration.
+# expect+1: no iteration variables in for
 .for in 1 2 3
 # XXX: This should not be reached.  It should be skipped, as already done
 # when the number of values is not a multiple of the number of variables,
@@ -45,19 +58,23 @@
 .  warning Should not be reached.
 .endfor
 
+
 # There are 3 variables and 5 values.  These 5 values cannot be split evenly
 # among the variables, therefore the loop is not expanded at all, it is
 # skipped instead.
+# expect+1: Wrong number of words (5) in .for substitution list with 3 variables
 .for a b c in 1 2 3 4 5
 .  warning Should not be reached.
 .endfor
 
+
 # The list of values after the 'in' may be empty, no matter if this emptiness
 # comes from an empty expansion or even from a syntactically empty line.
 .for i in
 .  info Would be reached if there were items to loop over.
 .endfor
 
+
 # A missing 'in' should parse the .for loop but skip the body.
 # expect+1: missing `in' in for
 .for i over k
@@ -65,10 +82,15 @@
 .  warning Should not be reached.
 .endfor
 
+
 # A malformed modifier should be detected and skip the body of the loop.
 #
 # XXX: As of 2020-12-31, Var_Subst doesn't report any errors, therefore
 # the loop body is expanded as if no error had happened.
+# expect+1: Unknown modifier "Z"
 .for i in 1 2 ${:U3:Z} 4
 .  warning Should not be reached.
 .endfor
+# expect-2: Should not be reached.
+# expect-3: Should not be reached.
+# expect-4: Should not be reached.
diff -r 96ff47ac4b6e -r cee6b7d43b66 usr.bin/make/unit-tests/directive-for-escape.exp
--- a/usr.bin/make/unit-tests/directive-for-escape.exp  Tue May 09 19:22:07 2023 +0000
+++ b/usr.bin/make/unit-tests/directive-for-escape.exp  Tue May 09 19:43:12 2023 +0000
@@ -2,28 +2,28 @@ For: end for 1
 For: loop body:
 .  info ${:U!"#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
 make: Unclosed variable expression, expecting '}' for modifier "U!"" of variable "" with value "!""
-make: "directive-for-escape.mk" line 19: !"
+make: "directive-for-escape.mk" line 21: !"
 For: end for 1
 For: loop body:
 .  info ${:U!"\\\\#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
 make: Unclosed variable expression, expecting '}' for modifier "U!"\\\\" of variable "" with value "!"\\"
-make: "directive-for-escape.mk" line 29: !"\\
+make: "directive-for-escape.mk" line 32: !"\\
 For: end for 1
 For: loop body:



Home | Main Index | Thread Index | Old Index