aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bmake/unit-tests')
-rw-r--r--contrib/bmake/unit-tests/Makefile6
-rw-r--r--contrib/bmake/unit-tests/cond-func.mk12
-rw-r--r--contrib/bmake/unit-tests/cond-late.mk15
-rwxr-xr-xcontrib/bmake/unit-tests/dep-var.mk7
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.exp33
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.mk57
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.exp84
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.mk62
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.exp63
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.mk149
-rw-r--r--contrib/bmake/unit-tests/forloop.exp20
-rw-r--r--contrib/bmake/unit-tests/forloop.mk53
-rw-r--r--contrib/bmake/unit-tests/parse.mk32
-rw-r--r--contrib/bmake/unit-tests/var-eval-short.exp8
-rw-r--r--contrib/bmake/unit-tests/var-eval-short.mk12
-rw-r--r--contrib/bmake/unit-tests/var-scope-local.exp54
-rw-r--r--contrib/bmake/unit-tests/var-scope-local.mk101
-rw-r--r--contrib/bmake/unit-tests/varmod-gmtime.exp20
-rw-r--r--contrib/bmake/unit-tests/varmod-gmtime.mk33
-rw-r--r--contrib/bmake/unit-tests/varmod-localtime.exp20
-rw-r--r--contrib/bmake/unit-tests/varmod-localtime.mk33
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.exp1
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.mk30
-rw-r--r--contrib/bmake/unit-tests/varmod-path.mk14
24 files changed, 550 insertions, 369 deletions
diff --git a/contrib/bmake/unit-tests/Makefile b/contrib/bmake/unit-tests/Makefile
index bcfe853642a5..a3f069133739 100644
--- a/contrib/bmake/unit-tests/Makefile
+++ b/contrib/bmake/unit-tests/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.193 2023/02/25 20:03:25 sjg Exp $
+# $Id: Makefile,v 1.195 2023/05/10 18:26:24 sjg Exp $
#
-# $NetBSD: Makefile,v 1.333 2023/02/25 19:30:32 sjg Exp $
+# $NetBSD: Makefile,v 1.335 2023/05/10 13:03:06 rillig Exp $
#
# Unit tests for make(1)
#
@@ -211,7 +211,6 @@ TESTS+= export
TESTS+= export-all
TESTS+= export-env
TESTS+= export-variants
-TESTS+= forloop
TESTS+= forsubst
TESTS+= gnode-submake
TESTS+= hanoi-include
@@ -375,6 +374,7 @@ TESTS+= varmod-loop-delete
TESTS+= varmod-loop-varname
TESTS+= varmod-match
TESTS+= varmod-match-escape
+TESTS+= varmod-mtime
TESTS+= varmod-no-match
TESTS+= varmod-order
TESTS+= varmod-order-numeric
diff --git a/contrib/bmake/unit-tests/cond-func.mk b/contrib/bmake/unit-tests/cond-func.mk
index 959367f5c6ab..e09b363edb64 100644
--- a/contrib/bmake/unit-tests/cond-func.mk
+++ b/contrib/bmake/unit-tests/cond-func.mk
@@ -1,12 +1,12 @@
-# $NetBSD: cond-func.mk,v 1.11 2022/01/07 19:30:17 rillig Exp $
+# $NetBSD: cond-func.mk,v 1.12 2023/05/10 15:53:32 rillig Exp $
#
# Tests for those parts of the functions in .if conditions that are common
# among several functions.
#
-# The below test uses the function defined(...) since it has no side-effects,
-# the other functions (except empty(...)) would work equally well. The
-# function empty is special because it uses a different parsing algorithm for
-# its argument.
+# The below test uses the 'defined' function since it has no side-effects.
+# The other functions would work equally well, except for 'empty', which
+# parses its argument differently from the other functions.
+#
DEF= defined
${:UA B}= variable name with spaces
@@ -74,7 +74,7 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
# There may be spaces around the operators and parentheses, and even
# inside the parentheses. The spaces inside the parentheses are not
-# allowed for the empty() function (see cond-func-empty.mk), therefore
+# allowed for the 'empty' function (see cond-func-empty.mk), therefore
# they are typically omitted for the other functions as well.
.if ! defined ( DEF )
. error
diff --git a/contrib/bmake/unit-tests/cond-late.mk b/contrib/bmake/unit-tests/cond-late.mk
index 4df3df2cf1d4..1cfaaa2ee4e9 100644
--- a/contrib/bmake/unit-tests/cond-late.mk
+++ b/contrib/bmake/unit-tests/cond-late.mk
@@ -1,11 +1,12 @@
-# $NetBSD: cond-late.mk,v 1.3 2020/11/15 14:07:53 rillig Exp $
+# $NetBSD: cond-late.mk,v 1.4 2023/05/10 15:53:32 rillig Exp $
#
# Using the :? modifier, variable expressions can contain conditional
# expressions that are evaluated late, at expansion time.
#
-# Any variables appearing in these
-# conditions are expanded before parsing the condition. This is
-# different from many other places.
+# Any expressions appearing in these conditions are expanded before parsing
+# the condition. This is different from conditions in .if directives, where
+# expressions are evaluated individually and only as far as necessary, see
+# cond-short.mk.
#
# Because of this, variables that are used in these lazy conditions
# should not contain double-quotes, or the parser will probably fail.
@@ -22,10 +23,14 @@ COND.false= "yes" != "yes"
# If the order of evaluation were to change to first parse the condition
# and then expand the variables, the output would change from the
# current "yes no" to "yes yes", since both variables are non-empty.
+# expect: yes
+# expect: no
cond-literal:
@echo ${ ${COND.true} :?yes:no}
@echo ${ ${COND.false} :?yes:no}
-VAR+= ${${UNDEF} != "no":?:}
+VAR= ${${UNDEF} != "no":?:}
+# expect-reset
+# expect: make: Bad conditional expression ' != "no"' in ' != "no"?:'
.if empty(VAR:Mpattern)
.endif
diff --git a/contrib/bmake/unit-tests/dep-var.mk b/contrib/bmake/unit-tests/dep-var.mk
index f4a724f0ce7c..16f7498fd5cc 100755
--- a/contrib/bmake/unit-tests/dep-var.mk
+++ b/contrib/bmake/unit-tests/dep-var.mk
@@ -1,4 +1,4 @@
-# $NetBSD: dep-var.mk,v 1.7 2023/02/13 21:01:46 rillig Exp $
+# $NetBSD: dep-var.mk,v 1.8 2023/05/10 15:53:32 rillig Exp $
#
# Tests for variable references in dependency declarations.
#
@@ -91,5 +91,6 @@ undef1 def2 a-def2-b 1-2-$$INDIRECT_2-2-1 ${:U\$)}:
.MAKEFLAGS: -d0
-# XXX: Why is the exit status still 0, even though Parse_Error is called
-# with PARSE_FATAL in SuffExpandChildren?
+# XXX: The exit status is still 0, even though Parse_Error is called with
+# PARSE_FATAL in SuffExpandChildren. The exit status is only affected by
+# parse errors when they occur in the parsing phase, see Parse_File.
diff --git a/contrib/bmake/unit-tests/directive-for-errors.exp b/contrib/bmake/unit-tests/directive-for-errors.exp
index da5eee473ec2..36ed569c7932 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.exp
+++ b/contrib/bmake/unit-tests/directive-for-errors.exp
@@ -1,22 +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 37: Dollar $ 1 1 and backslash 2 2 2.
-make: "directive-for-errors.mk" line 37: Dollar $ 3 3 and backslash 4 4 4.
-make: "directive-for-errors.mk" line 43: no iteration variables in for
-make: "directive-for-errors.mk" line 47: warning: Should not be reached.
-make: "directive-for-errors.mk" line 48: for-less endfor
-make: "directive-for-errors.mk" line 53: Wrong number of words (5) in .for substitution list with 3 variables
-make: "directive-for-errors.mk" line 64: missing `in' in for
-make: "directive-for-errors.mk" line 66: warning: Should not be reached.
-make: "directive-for-errors.mk" line 67: for-less endfor
-make: "directive-for-errors.mk" line 73: Unknown modifier "Z"
-make: "directive-for-errors.mk" line 74: warning: Should not be reached.
-make: "directive-for-errors.mk" line 74: warning: Should not be reached.
-make: "directive-for-errors.mk" line 74: 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 --git a/contrib/bmake/unit-tests/directive-for-errors.mk b/contrib/bmake/unit-tests/directive-for-errors.mk
index 602ecbf32e4e..24df5e131839 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.mk
+++ b/contrib/bmake/unit-tests/directive-for-errors.mk
@@ -1,45 +1,56 @@
-# $NetBSD: directive-for-errors.mk,v 1.3 2021/04/04 10:13:09 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
-# As of 2020-12-31, the variable name can be an arbitrary word, it just needs
-# to be separated by whitespace. Even '$' and '\' are valid variable names,
-# which is not useful in practice.
-#
-# The '$$' is not replaced with the values '1' or '3' from the .for loop,
-# instead it is kept as-is, and when the .info directive expands its argument,
-# each '$$' gets replaced with a single '$'. The "long variable expression"
-# ${$} gets replaced though, even though this would be a parse error everywhere
-# outside a .for loop.
+
+# 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
+# valid variable names, which was not useful in practice.
#
-# The '\' on the other hand is treated as a normal variable name.
+# The '$$' was not replaced with the values '1' or '3' from the .for loop,
+# instead it was kept as-is, and when the .info directive expanded its
+# argument, each '$$' got replaced with a single '$'. The "long variable
+# expression" ${$} got replaced though, even though this would be a parse
+# 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
# If there are no variables, there is no point in expanding the .for loop
-# since this would end up in an endless loop, each time consuming 0 of the
-# 3 values.
+# 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,
@@ -47,29 +58,39 @@ ${:U\\}= backslash # see whether the "variable" '\' is local
. 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
-# rather skipped.
+# 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.
-.for i : k
+# expect+1: missing `in' in for
+.for i over k
# XXX: As of 2020-12-31, this line is reached once.
. 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 --git a/contrib/bmake/unit-tests/directive-for-escape.exp b/contrib/bmake/unit-tests/directive-for-escape.exp
index d679e0756e33..0326b62377f3 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.exp
+++ b/contrib/bmake/unit-tests/directive-for-escape.exp
@@ -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:
. info ${:U\$}
-make: "directive-for-escape.mk" line 43: $
+make: "directive-for-escape.mk" line 47: $
For: loop body:
. info ${:U${V}}
-make: "directive-for-escape.mk" line 43: value
+make: "directive-for-escape.mk" line 47: value
For: loop body:
. info ${:U${V:=-with-modifier}}
-make: "directive-for-escape.mk" line 43: value-with-modifier
+make: "directive-for-escape.mk" line 47: value-with-modifier
For: loop body:
. info ${:U$(V)}
-make: "directive-for-escape.mk" line 43: value
+make: "directive-for-escape.mk" line 47: value
For: loop body:
. info ${:U$(V:=-with-modifier)}
-make: "directive-for-escape.mk" line 43: value-with-modifier
+make: "directive-for-escape.mk" line 47: value-with-modifier
For: end for 1
For: loop body:
# ${:U\${UNDEF\:U\\$\\$}
@@ -34,29 +34,25 @@ For: loop body:
For: end for 1
For: loop body:
. info ${:U\${UNDEF\:U\\$\\$}
-make: "directive-for-escape.mk" line 92: ${UNDEF:U\backslash$
+make: "directive-for-escape.mk" line 101: ${UNDEF:U\backslash$
For: loop body:
. info ${:U{{\}\}}
-make: "directive-for-escape.mk" line 92: {{}}
+make: "directive-for-escape.mk" line 101: {{}}
For: loop body:
. info ${:Uend\}}
-make: "directive-for-escape.mk" line 92: end}
+make: "directive-for-escape.mk" line 101: end}
For: end for 1
For: loop body:
. info ${:Ubegin<${UNDEF:Ufallback:N{{{}}}}>end}
-make: "directive-for-escape.mk" line 113: begin<fallback>end
+make: "directive-for-escape.mk" line 122: begin<fallback>end
For: end for 1
For: loop body:
. info ${:U\$}
-make: "directive-for-escape.mk" line 121: $
+make: "directive-for-escape.mk" line 131: $
+make: "directive-for-escape.mk" line 140: invalid character ':' in .for loop variable name
For: end for 1
-For: loop body:
-. info ${NUMBERS} ${:Ureplaced}
-make: "directive-for-escape.mk" line 129: one two three replaced
+make: "directive-for-escape.mk" line 150: invalid character '}' in .for loop variable name
For: end for 1
-For: loop body:
-. info ${:Ureplaced}
-make: "directive-for-escape.mk" line 139: replaced
For: end for 1
For: loop body:
. info . $$i: ${:Uinner}
@@ -69,46 +65,42 @@ For: loop body:
. info . $${i2}: ${i2}
. info . $${i,}: ${i,}
. info . adjacent: ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
-make: "directive-for-escape.mk" line 147: . $i: inner
-make: "directive-for-escape.mk" line 148: . ${i}: inner
-make: "directive-for-escape.mk" line 149: . ${i:M*}: inner
-make: "directive-for-escape.mk" line 150: . $(i): inner
-make: "directive-for-escape.mk" line 151: . $(i:M*): inner
-make: "directive-for-escape.mk" line 152: . ${i${:U}}: outer
-make: "directive-for-escape.mk" line 153: . ${i\}}: inner}
-make: "directive-for-escape.mk" line 154: . ${i2}: two
-make: "directive-for-escape.mk" line 155: . ${i,}: comma
-make: "directive-for-escape.mk" line 156: . adjacent: innerinnerinnerinner
-For: end for 1
-For: loop body:
-. info eight $$$$$$$$ and no cents.
-. info eight ${:Udollar}${:Udollar}${:Udollar}${:Udollar} and no cents.
-make: "directive-for-escape.mk" line 164: eight $$$$ and no cents.
-make: "directive-for-escape.mk" line 165: eight dollardollardollardollar and no cents.
-make: "directive-for-escape.mk" line 174: eight and no cents.
-For: end for 1
-make: "directive-for-escape.mk" line 181: newline in .for value
-make: "directive-for-escape.mk" line 181: newline in .for value
+make: "directive-for-escape.mk" line 159: . $i: inner
+make: "directive-for-escape.mk" line 160: . ${i}: inner
+make: "directive-for-escape.mk" line 161: . ${i:M*}: inner
+make: "directive-for-escape.mk" line 162: . $(i): inner
+make: "directive-for-escape.mk" line 163: . $(i:M*): inner
+make: "directive-for-escape.mk" line 164: . ${i${:U}}: outer
+make: "directive-for-escape.mk" line 165: . ${i\}}: inner}
+make: "directive-for-escape.mk" line 166: . ${i2}: two
+make: "directive-for-escape.mk" line 167: . ${i,}: comma
+make: "directive-for-escape.mk" line 168: . adjacent: innerinnerinnerinner
+make: "directive-for-escape.mk" line 187: invalid character '$' in .for loop variable name
+For: end for 1
+make: "directive-for-escape.mk" line 199: eight and no cents.
+For: end for 1
+make: "directive-for-escape.mk" line 212: newline in .for value
+make: "directive-for-escape.mk" line 212: newline in .for value
For: loop body:
. info short: ${:U" "}
. info long: ${:U" "}
-make: "directive-for-escape.mk" line 182: short: " "
-make: "directive-for-escape.mk" line 183: long: " "
+make: "directive-for-escape.mk" line 213: short: " "
+make: "directive-for-escape.mk" line 214: long: " "
For: end for 1
For: loop body:
For: end for 1
-Parse_PushInput: .for loop in directive-for-escape.mk, line 196
-make: "directive-for-escape.mk" line 196: newline in .for value
- in .for loop from directive-for-escape.mk:196 with i = "
+Parse_PushInput: .for loop in directive-for-escape.mk, line 230
+make: "directive-for-escape.mk" line 230: newline in .for value
+ in .for loop from directive-for-escape.mk:230 with i = "
"
For: loop body:
: ${:U" "}
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
-Parsing line 197: : ${:U" "}
+Parsing line 231: : ${:U" "}
ParseDependency(: " ")
-ParseEOF: returning to file directive-for-escape.mk, line 199
+ParseEOF: returning to file directive-for-escape.mk, line 233
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
-Parsing line 199: .MAKEFLAGS: -d0
+Parsing line 233: .MAKEFLAGS: -d0
ParseDependency(.MAKEFLAGS: -d0)
For: end for 1
For: loop body:
diff --git a/contrib/bmake/unit-tests/directive-for-escape.mk b/contrib/bmake/unit-tests/directive-for-escape.mk
index fe704c453046..7fbd09131d2c 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.mk
+++ b/contrib/bmake/unit-tests/directive-for-escape.mk
@@ -1,9 +1,10 @@
-# $NetBSD: directive-for-escape.mk,v 1.16 2022/06/12 16:09:21 rillig Exp $
+# $NetBSD: directive-for-escape.mk,v 1.18 2023/05/09 19:43:12 rillig Exp $
#
# Test escaping of special characters in the iteration values of a .for loop.
# These values get expanded later using the :U variable modifier, and this
-# escaping and unescaping must pass all characters and strings effectively
-# unmodified.
+# escaping and unescaping must pass all characters and strings unmodified.
+
+# expect-all
.MAKEFLAGS: -df
@@ -12,12 +13,14 @@
# This could be considered a bug.
ASCII= !"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
+
# XXX: As of 2020-12-31, the '#' is not preserved in the expanded body of
# the loop. Not only would it need the escaping for the variable modifier
# ':U' but also the escaping for the line-end comment.
.for chars in ${ASCII}
. info ${chars}
.endfor
+# expect-2: !"
# As of 2020-12-31, using 2 backslashes before be '#' would treat the '#'
# as comment character. Using 3 backslashes doesn't help either since
@@ -28,6 +31,7 @@ ASCII.2020-12-31= !"\\\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
.for chars in ${ASCII.2020-12-31}
. info ${chars}
.endfor
+# expect-2: !"\\
# Cover the code in ExprLen.
#
@@ -42,6 +46,11 @@ VALUES= $$ $${V} $${V:=-with-modifier} $$(V) $$(V:=-with-modifier)
.for i in ${VALUES}
. info $i
.endfor
+# expect-2: $
+# expect-3: value
+# expect-4: value-with-modifier
+# expect-5: value
+# expect-6: value-with-modifier
# Try to cover the code for nested '{}' in ExprLen, without success.
@@ -112,6 +121,7 @@ VALUES= begin<$${UNDEF:Ufallback:N{{{}}}}>end
.for i in ${VALUES}
. info $i
.endfor
+# expect-2: begin<fallback>end
# A single trailing dollar doesn't happen in practice.
# The dollar sign is correctly passed through to the body of the .for loop.
@@ -120,21 +130,23 @@ VALUES= begin<$${UNDEF:Ufallback:N{{{}}}}>end
.for i in ${:U\$}
. info ${i}
.endfor
+# expect-2: $
-# As of 2020-12-31, the name of the iteration variable can even contain
-# colons, which then affects variable expressions having this exact modifier.
-# This is clearly an unintended side effect of the implementation.
+# Before for.c 1.173 from 2023-05-08, the name of the iteration variable
+# could contain colons, which affected variable expressions having this exact
+# modifier. This possibility was neither intended nor documented.
NUMBERS= one two three
+# expect+1: invalid character ':' in .for loop variable name
.for NUMBERS:M*e in replaced
. info ${NUMBERS} ${NUMBERS:M*e}
.endfor
-# As of 2020-12-31, the name of the iteration variable can contain braces,
-# which gets even more surprising than colons, since it allows to replace
-# sequences of variable expressions. There is no practical use case for
-# this, though.
+# Before for.c 1.173 from 2023-05-08, the name of the iteration variable
+# could contain braces, which allowed to replace sequences of variable
+# expressions. This possibility was neither intended nor documented.
BASENAME= one
EXT= .c
+# expect+1: invalid character '}' in .for loop variable name
.for BASENAME}${EXT in replaced
. info ${BASENAME}${EXT}
.endfor
@@ -155,11 +167,23 @@ i,= comma
. info . $${i,}: ${i,}
. info . adjacent: $i${i}${i:M*}$i
.endfor
+# expect-11: . $i: inner
+# expect-11: . ${i}: inner
+# expect-11: . ${i:M*}: inner
+# expect-11: . $(i): inner
+# expect-11: . $(i:M*): inner
+# expect-11: . ${i${:U}}: outer
+# expect-11: . ${i\}}: inner}
+# expect-11: . ${i2}: two
+# expect-11: . ${i,}: comma
+# expect-11: . adjacent: innerinnerinnerinner
-# The variable name can be a single '$' since there is no check on valid
-# variable names. ForLoop_SubstVarShort skips "stupid" variable names though,
-# but ForLoop_SubstVarLong naively parses the body of the loop, substituting
-# each '${$}' with an actual 'dollar'.
+# Before for.c 1.173 from 2023-05-08, the variable name could be a single '$'
+# since there was no check on valid variable names. ForLoop_SubstVarShort
+# skipped "stupid" variable names though, but ForLoop_SubstVarLong naively
+# parsed the body of the loop, substituting each '${$}' with an actual
+# '${:Udollar}'.
+# expect+1: invalid character '$' in .for loop variable name
.for $ in dollar
. info eight $$$$$$$$ and no cents.
. info eight ${$}${$}${$}${$} and no cents.
@@ -171,6 +195,7 @@ i,= comma
# evaluates to an empty string.
closing-brace= } # guard against an
${closing-brace}= <closing-brace> # alternative interpretation
+# expect+1: eight and no cents.
.info eight ${$}${$}${$}${$} and no cents.
# What happens if the values from the .for loop contain a literal newline?
@@ -178,10 +203,18 @@ ${closing-brace}= <closing-brace> # alternative interpretation
# body of the .for loop, where it was then interpreted as a literal newline,
# leading to syntax errors such as "Unclosed variable expression" in the upper
# line and "Invalid line type" in the lower line.
+#
+# The error message occurs in the line of the .for loop since that's the place
+# where the body of the .for loop is constructed, and at this point the
+# newline character gets replaced with a plain space.
+# expect+2: newline in .for value
+# expect+1: newline in .for value
.for i in "${.newline}"
. info short: $i
. info long: ${i}
.endfor
+# expect-3: short: " "
+# expect-3: long: " "
# No error since the newline character is not actually used.
.for i in "${.newline}"
@@ -193,6 +226,7 @@ ${closing-brace}= <closing-brace> # alternative interpretation
# loop is assembled, and at that point, ForLoop.nextItem had already been
# advanced.
.MAKEFLAGS: -dp
+# expect+1: newline in .for value
.for i in "${.newline}"
: $i
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for.exp b/contrib/bmake/unit-tests/directive-for.exp
index dda487917e68..97878ee49f44 100755
--- a/contrib/bmake/unit-tests/directive-for.exp
+++ b/contrib/bmake/unit-tests/directive-for.exp
@@ -1,42 +1,41 @@
-make: "directive-for.mk" line 108: outer
-make: "directive-for.mk" line 133: a:\ a:\file.txt
-make: "directive-for.mk" line 133: d:\\
-make: "directive-for.mk" line 133: d:\\file.txt
-make: "directive-for.mk" line 140: ( ( (
-make: "directive-for.mk" line 140: [ [ [
-make: "directive-for.mk" line 140: { { {
-make: "directive-for.mk" line 140: ) ) )
-make: "directive-for.mk" line 140: ] ] ]
-make: "directive-for.mk" line 140: } } }
-make: "directive-for.mk" line 140: (()) (()) (())
-make: "directive-for.mk" line 140: [[]] [[]] [[]]
-make: "directive-for.mk" line 140: {{}} {{}} {{}}
-make: "directive-for.mk" line 140: )( )( )(
-make: "directive-for.mk" line 140: ][ ][ ][
-make: "directive-for.mk" line 140: }{ }{ }{
-make: "directive-for.mk" line 148: outer value value
-make: "directive-for.mk" line 148: outer "quoted" \"quoted\"
-make: "directive-for.mk" line 154: Unknown modifier "Z"
-make: "directive-for.mk" line 155: XXX: Not reached word1
-make: "directive-for.mk" line 155: XXX: Not reached word3
-make: "directive-for.mk" line 160: no iteration variables in for
-make: "directive-for.mk" line 162: Missing argument for ".error"
-make: "directive-for.mk" line 163: for-less endfor
-make: "directive-for.mk" line 187: 1 open conditional
-make: "directive-for.mk" line 203: for-less endfor
-make: "directive-for.mk" line 204: if-less endif
-make: "directive-for.mk" line 212: if-less endif
+make: "directive-for.mk" line 119: outer
+make: "directive-for.mk" line 137: a:\ a:\file.txt
+make: "directive-for.mk" line 137: d:\\
+make: "directive-for.mk" line 137: d:\\file.txt
+make: "directive-for.mk" line 148: ( ( (
+make: "directive-for.mk" line 148: [ [ [
+make: "directive-for.mk" line 148: { { {
+make: "directive-for.mk" line 148: ) ) )
+make: "directive-for.mk" line 148: ] ] ]
+make: "directive-for.mk" line 148: } } }
+make: "directive-for.mk" line 148: (()) (()) (())
+make: "directive-for.mk" line 148: [[]] [[]] [[]]
+make: "directive-for.mk" line 148: {{}} {{}} {{}}
+make: "directive-for.mk" line 148: )( )( )(
+make: "directive-for.mk" line 148: ][ ][ ][
+make: "directive-for.mk" line 148: }{ }{ }{
+make: "directive-for.mk" line 168: invalid character ':' in .for loop variable name
+make: "directive-for.mk" line 175: invalid character '$' in .for loop variable name
+make: "directive-for.mk" line 187: invalid character '$' in .for loop variable name
+make: "directive-for.mk" line 198: Unknown modifier "Z"
+make: "directive-for.mk" line 199: XXX: Not reached word1
+make: "directive-for.mk" line 199: XXX: Not reached word3
+make: "directive-for.mk" line 206: no iteration variables in for
+make: "directive-for.mk" line 232: 1 open conditional
+make: "directive-for.mk" line 248: for-less endfor
+make: "directive-for.mk" line 249: if-less endif
+make: "directive-for.mk" line 257: if-less endif
+For: new loop 2
+For: end for 2
For: end for 1
For: loop body:
.\
for inner in i
.\
endfor
-make: "directive-for.mk" line 229: Unexpected end of file in .for loop
+For: end for 1
For: loop body:
-.\
- endfor
-make: "directive-for.mk" line 227: for-less endfor
+make: "directive-for.mk" line 305: newline-item=(a)
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-for.mk b/contrib/bmake/unit-tests/directive-for.mk
index 95171c68031f..224a466a7709 100755
--- a/contrib/bmake/unit-tests/directive-for.mk
+++ b/contrib/bmake/unit-tests/directive-for.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for.mk,v 1.15 2022/10/01 09:23:04 rillig Exp $
+# $NetBSD: directive-for.mk,v 1.20 2023/05/10 13:03:06 rillig Exp $
#
# Tests for the .for directive.
#
@@ -8,11 +8,15 @@
# .for _FILE_ in values
# .for .FILE. in values
# .for _f_ in values
-
-# Using the .for loop, lists of values can be produced.
-# In simple cases, the :@var@${var}@ variable modifier can be used to
-# achieve the same effects.
#
+# See also:
+# varmod-loop.mk The ':@var@...@' modifier
+
+# expect-all
+
+# A typical use case for a .for loop is to populate a variable with a list of
+# values depending on other variables. In simple cases, the same effect can
+# be achieved using the ':@var@${var}@' modifier.
.undef NUMBERS
.for num in 1 2 3
NUMBERS+= ${num}
@@ -21,8 +25,9 @@ NUMBERS+= ${num}
. error
.endif
+
# The .for loop also works for multiple iteration variables.
-# This is something that the variable modifier :@ cannot do.
+# This is something that the modifier :@ cannot do.
.for name value in VARNAME value NAME2 value2
${name}= ${value}
.endfor
@@ -30,12 +35,12 @@ ${name}= ${value}
. error
.endif
+
# The .for loop splits the items at whitespace, taking quotes into account,
-# just like the :M or :S variable modifiers.
-#
-# Until 2012-06-03, it had split the items exactly at whitespace, without
-# taking the quotes into account. This had resulted in 10 words.
+# just like the :M or :S modifiers.
#
+# Until 2012-06-03, the .for loop had split the items exactly at whitespace,
+# without taking the quotes into account. This had resulted in 10 words.
.undef WORDS
.for var in one t\ w\ o "three three" 'four four' `five six`
WORDS+= counted
@@ -44,16 +49,19 @@ WORDS+= counted
. error
.endif
+
# In the body of the .for loop, the iteration variables can be accessed
# like normal variables, even though they are not really variables.
#
-# Instead, the expression ${var} is transformed into ${:U1}, ${:U2} and so
-# on, before the loop body is evaluated.
+# Instead, before interpreting the body of the .for loop, the body is
+# generated by replacing each expression ${var} with ${:U1}, ${:U2} and so
+# on.
#
-# A notable effect of this implementation technique is that the .for
+# A noticeable effect of this implementation technique is that the .for
# iteration variables and the normal global variables live in separate
-# namespaces and do not influence each other.
-#
+# namespaces and do not influence each other. The "scope" of the .for loop
+# variables is restricted to the current makefile, it does not reach over to
+# any included makefiles.
var= value before
var2= value before
.for var var2 in 1 2 3 4
@@ -66,9 +74,8 @@ var2= value before
.endif
# Everything from the paragraph above also applies if the loop body is
-# empty, even if there is no actual iteration since the loop items are
-# also empty.
-#
+# empty. In this particular example, the items to be iterated are empty as
+# well.
var= value before
var2= value before
.for var var2 in ${:U}
@@ -82,11 +89,13 @@ var2= value before
# Until 2008-12-21, the values of the iteration variables were simply
# inserted as plain text and then parsed as usual, which made it possible
-# to achieve all kinds of strange effects.
+# to achieve all kinds of strange effects, such as generating '.if'
+# directives or inserting '$' characters in random places, thereby changing
+# how following '$' are interpreted.
#
-# Before that date, the .for loop expanded to:
+# Before that date, the .for loop below expanded to:
# EXPANSION+= value
-# Since that date, the .for loop expands to:
+# Since that date, the .for loop below expands to:
# EXPANSION${:U+}= value
#
EXPANSION= before
@@ -102,13 +111,16 @@ EXPANSION${plus}= value
.endif
# When the outer .for loop is expanded, it sees the expression ${i} and
-# expands it. The inner loop then has nothing more to expand.
+# expands it. The inner loop then only sees the expression ${:Uouter} and
+# has nothing more to expand.
.for i in outer
. for i in inner
+# expect+1: outer
. info ${i}
. endfor
.endfor
+
# From https://gnats.netbsd.org/29985.
#
# Until 2008-12-21, the .for loop was expanded by replacing the variable
@@ -121,17 +133,13 @@ EXPANSION${plus}= value
# like "a:\ a:\file.txt" that ended in a single backslash. Since then, the
# variable values have been replaced with expressions of the form ${:U...},
# which are not interpreted as code anymore.
-#
-# As of 2020-09-22, a comment in for.c says that it may be possible to
-# produce an "unwanted substitution", but there is no demonstration code yet.
-#
-# The above changes prevent a backslash at the end of a word from being
-# interpreted as part of the code. Because of this, the trailingBackslash
-# hack in Var_Subst is no longer needed and as of 2020-09-22, has been
-# removed.
.for path in a:\ a:\file.txt d:\\ d:\\file.txt
. info ${path}
.endfor
+# expect-2: a:\ a:\file.txt
+# expect-3: d:\\
+# expect-4: d:\\file.txt
+
# Ensure that braces and parentheses are properly escaped by the .for loop.
# Each line must print the same word 3 times.
@@ -139,28 +147,65 @@ EXPANSION${plus}= value
.for v in ( [ { ) ] } (()) [[]] {{}} )( ][ }{
. info $v ${v} $(v)
.endfor
+# expect-02: ( ( (
+# expect-03: [ [ [
+# expect-04: { { {
+# expect-05: ) ) )
+# expect-06: ] ] ]
+# expect-07: } } }
+# expect-08: (()) (()) (())
+# expect-09: [[]] [[]] [[]]
+# expect-10: {{}} {{}} {{}}
+# expect-11: )( )( )(
+# expect-12: ][ ][ ][
+# expect-13: }{ }{ }{
-# As of 2020-10-25, the variable names may contain arbitrary characters,
-# except for whitespace. This allows for creative side effects. Hopefully
-# nobody is misusing this "feature".
+# Before 2023-05-09, the variable names could contain arbitrary characters,
+# except for whitespace, allowing for creative side effects, as usual for
+# arbitrary code injection.
var= outer
+# expect+1: invalid character ':' in .for loop variable name
.for var:Q in value "quoted"
-. info ${var} ${var:Q} ${var:Q:Q}
+. info <${var}> <${var:Q}> <${var:Q:Q}>
+.endfor
+
+# Before 2023-05-09, when variable names could contain '$', the short
+# expression '$$' was preserved, the long expressions were substituted.
+# expect+1: invalid character '$' in .for loop variable name
+.for $ in value
+. info <$$> <${$}> <$($)>
+.endfor
+
+
+# https://gnats.netbsd.org/53146 mentions the idea of using a dynamic
+# variable name in .for loops, based on some other variable. The .for loops
+# are already tricky enough to understand in detail, even without this
+# possibility, therefore the variable names are restricted to using harmless
+# characters only.
+INDIRECT= direct
+# expect+1: invalid character '$' in .for loop variable name
+.for $(INDIRECT) in value
+# If the variable name could be chosen dynamically, the iteration variable
+# might have been 'direct', thereby expanding the expression '${direct}'.
+. info <$(INDIRECT)> <$(direct)> <$($(INDIRECT))>
.endfor
# XXX: A parse error or evaluation error in the items of the .for loop
-# should skip the whole loop. As of 2020-12-27, the loop is expanded twice.
+# should skip the whole loop. As of 2023-05-09, the loop is expanded as
+# usual.
+# expect+1: Unknown modifier "Z"
.for var in word1 ${:Uword2:Z} word3
. info XXX: Not reached ${var}
.endfor
+# expect-2: XXX: Not reached word1
+# expect-3: XXX: Not reached word3
# An empty list of variables to the left of the 'in' is a parse error.
.for in value # expect+0: no iteration variables in for
-# XXX: The loop body is evaluated once, even with the parse error above.
-. error # expect+0: Missing argument for ".error"
-.endfor # expect+0: for-less endfor
+. error
+.endfor
# An empty list of iteration values to the right of the 'in' is accepted.
# Unlike in the shell, it is not a parse error.
@@ -214,12 +259,19 @@ var= outer
.endif # no 'if-less endif'
-# When make parses a .for loop, it assumes that there is no line break between
-# the '.' and the 'for' or 'endfor', as there is no practical reason to break
-# the line at this point. When make scans the outer .for loop, it does not
-# recognize the inner directives as such. When make scans the inner .for
-# loop, it recognizes the '.\n for' but does not recognize the '.\n endfor',
-# as LK_FOR_BODY preserves the backslash-newline sequences.
+# Before for.c 1.172 from 2023-05-08, when make parsed a .for loop, it
+# assumed that there was no line continuation between the '.' and the 'for'
+# or 'endfor', as there is no practical reason to break the line at this
+# point.
+#
+# When make scanned the outer .for loop, it did not recognize the inner .for
+# loop as such and instead treated it as an unknown directive. The body of
+# the outer .for loop thus ended above the '.endfor'.
+#
+# When make scanned the inner .for loop, it did not recognize the inner
+# .endfor as such, which led to a parse error 'Unexpected end of file in .for
+# loop' from the '.endfor' line, followed by a second parse error 'for-less
+# .endfor' from the '.\\n endfor' line.
.MAKEFLAGS: -df
.for outer in o
.\
@@ -244,3 +296,12 @@ var= outer
. error
. endif
.endfor
+
+
+# Since at least 1993, iteration stops at the first newline.
+# Back then, the .newline variable didn't exist, therefore it was unlikely
+# that a newline ever occurred.
+.for var in a${.newline}b${.newline}c
+. info newline-item=(${var})
+.endfor
+# expect-2: newline-item=(a)
diff --git a/contrib/bmake/unit-tests/forloop.exp b/contrib/bmake/unit-tests/forloop.exp
deleted file mode 100644
index 422711b41247..000000000000
--- a/contrib/bmake/unit-tests/forloop.exp
+++ /dev/null
@@ -1,20 +0,0 @@
-make: "forloop.mk" line 14: x=one
-make: "forloop.mk" line 14: x="two and three"
-make: "forloop.mk" line 14: x=four
-make: "forloop.mk" line 14: x="five"
-make: "forloop.mk" line 20: x=-I/this
-make: "forloop.mk" line 20: x=-I"This or that"
-make: "forloop.mk" line 20: x=-Ithat
-make: "forloop.mk" line 20: x="-DTHIS=\"this and that\""
-make: "forloop.mk" line 27: cfl=-I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
-make: "forloop.mk" line 41: newline-item=(a)
-make: "forloop.mk" line 47: a=one b="two and three"
-make: "forloop.mk" line 47: a=four b="five"
-make: "forloop.mk" line 47: a=ONE b="TWO AND THREE"
-make: "forloop.mk" line 47: a=FOUR b="FIVE"
-We expect an error next:
-make: "forloop.mk" line 46: Wrong number of words (9) in .for substitution list with 2 variables
-make: Fatal errors encountered -- cannot continue
-make: stopped in unit-tests
-OK
-exit status 0
diff --git a/contrib/bmake/unit-tests/forloop.mk b/contrib/bmake/unit-tests/forloop.mk
deleted file mode 100644
index cef05cbe4c61..000000000000
--- a/contrib/bmake/unit-tests/forloop.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# $NetBSD: forloop.mk,v 1.7 2020/11/03 17:37:57 rillig Exp $
-
-all: for-loop
-
-LIST= one "two and three" four "five"
-
-.if make(for-fail)
-for-fail:
-
-XTRA_LIST= xtra
-.else
-
-. for x in ${LIST}
-. info x=$x
-. endfor
-
-CFL= -I/this -I"This or that" -Ithat "-DTHIS=\"this and that\""
-cfl=
-. for x in ${CFL}
-. info x=$x
-. if empty(cfl)
-cfl= $x
-. else
-cfl+= $x
-. endif
-. endfor
-. info cfl=${cfl}
-
-. if ${cfl} != ${CFL}
-. error ${.newline}${cfl} != ${.newline}${CFL}
-. endif
-
-. for a b in ${EMPTY}
-. info a=$a b=$b
-. endfor
-
-# Since at least 1993, iteration stops at the first newline.
-# Back then, the .newline variable didn't exist, therefore it was unlikely
-# that a newline ever occurred.
-. for var in a${.newline}b${.newline}c
-. info newline-item=(${var})
-. endfor
-
-.endif # for-fail
-
-.for a b in ${LIST} ${LIST:tu} ${XTRA_LIST}
-. info a=$a b=$b
-.endfor
-
-for-loop:
- @echo We expect an error next:
- @(cd ${.CURDIR} && ${.MAKE} -f ${MAKEFILE} for-fail) && \
- { echo "Oops that should have failed!"; exit 1; } || echo OK
diff --git a/contrib/bmake/unit-tests/parse.mk b/contrib/bmake/unit-tests/parse.mk
index 986c303083bf..551dc98aaf24 100644
--- a/contrib/bmake/unit-tests/parse.mk
+++ b/contrib/bmake/unit-tests/parse.mk
@@ -1,4 +1,4 @@
-# $NetBSD: parse.mk,v 1.3 2022/07/24 20:25:23 rillig Exp $
+# $NetBSD: parse.mk,v 1.4 2023/04/28 13:09:48 rillig Exp $
#
# Test those parts of the parsing that do not belong in any of the other
# categories.
@@ -22,3 +22,33 @@
#
# https://bugs.freebsd.org/265119
one-target ${:U }
+
+
+# Since parse.c 1.656 from 2022-01-27 and before parse.c 1.662 from
+# 2022-02-05, there was an out-of-bounds read in Parse_IsVar when looking for
+# a variable assignment in a dependency line with trailing whitespace. Lines
+# without trailing whitespace were not affected. Global variable assignments
+# were guaranteed to have no trailing whitespace and were thus not affected.
+#
+# Try to reproduce some variants that may lead to a crash, depending on the
+# memory allocator. To get a crash, the terminating '\0' of the line must be
+# the last byte of a memory page. The expression '${:U}' forces this trailing
+# whitespace.
+
+# On FreeBSD x86_64, a crash could in some cases be forced using the following
+# line, which has length 47, and if the memory for the expanded line starts at
+# 0xXXXX_XXd0, the terminating '\0' may end up at 0xXXXX_Xfff:
+Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx: 12345 ${:U}
+
+# The following line has length 4095 after being expanded, so line[4095] ==
+# '\0'. If the line is
+# allocated on a page boundary and the following page is not mapped, this line
+# leads to a segmentation fault.
+${:U:range=511:@_@1234567@:ts.}: 12345 ${:U}
+
+# The following line has length 8191, so line[8191] == '\0'. If the line is
+# allocated on a page boundary and the following page is not mapped, this line
+# leads to a segmentation fault.
+${:U:range=1023:@_@1234567@:ts.}: 12345 ${:U}
+
+12345:
diff --git a/contrib/bmake/unit-tests/var-eval-short.exp b/contrib/bmake/unit-tests/var-eval-short.exp
index 34380ec61c41..ea6e0d7485f9 100644
--- a/contrib/bmake/unit-tests/var-eval-short.exp
+++ b/contrib/bmake/unit-tests/var-eval-short.exp
@@ -1,9 +1,5 @@
make: "var-eval-short.mk" line 44: In the :@ modifier of "", the variable name "${FAIL}" must not contain a dollar
make: "var-eval-short.mk" line 44: Malformed conditional (0 && ${:Uword:@${FAIL}@expr@})
-make: "var-eval-short.mk" line 84: Invalid time value at "${FAIL}}"
-make: "var-eval-short.mk" line 84: Malformed conditional (0 && ${:Uword:gmtime=${FAIL}})
-make: "var-eval-short.mk" line 98: Invalid time value at "${FAIL}}"
-make: "var-eval-short.mk" line 98: Malformed conditional (0 && ${:Uword:localtime=${FAIL}})
CondParser_Eval: 0 && ${0:?${FAIL}then:${FAIL}else}
Var_Parse: ${0:?${FAIL}then:${FAIL}else} (parse-only)
Parsing modifier ${0:?...}
@@ -12,7 +8,7 @@ Modifier part: "${FAIL}then"
Var_Parse: ${FAIL}else} (parse-only)
Modifier part: "${FAIL}else"
Result of ${0:?${FAIL}then:${FAIL}else} is "" (parse-only, defined)
-Parsing line 163: DEFINED= defined
+Parsing line 165: DEFINED= defined
Global: DEFINED = defined
CondParser_Eval: 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
Var_Parse: ${DEFINED:L:?${FAIL}then:${FAIL}else} (parse-only)
@@ -24,7 +20,7 @@ Modifier part: "${FAIL}then"
Var_Parse: ${FAIL}else} (parse-only)
Modifier part: "${FAIL}else"
Result of ${DEFINED:?${FAIL}then:${FAIL}else} is "defined" (parse-only, regular)
-Parsing line 166: .MAKEFLAGS: -d0
+Parsing line 168: .MAKEFLAGS: -d0
ParseDependency(.MAKEFLAGS: -d0)
Global: .MAKEFLAGS = -r -k -d cpv -d
Global: .MAKEFLAGS = -r -k -d cpv -d 0
diff --git a/contrib/bmake/unit-tests/var-eval-short.mk b/contrib/bmake/unit-tests/var-eval-short.mk
index a099b6871d1e..7faf1cc5d154 100644
--- a/contrib/bmake/unit-tests/var-eval-short.mk
+++ b/contrib/bmake/unit-tests/var-eval-short.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-eval-short.mk,v 1.8 2021/12/27 18:54:19 rillig Exp $
+# $NetBSD: var-eval-short.mk,v 1.9 2023/05/09 16:27:00 rillig Exp $
#
# Tests for each variable modifier to ensure that they only do the minimum
# necessary computations. If the result of the expression is irrelevant,
@@ -79,8 +79,9 @@ DEFINED= # defined
.if 0 && ${:Uword:E}
.endif
-# As of 2021-03-14, the error 'Invalid time value: ${FAIL}}' is ok since
-# ':gmtime' does not expand its argument.
+# Before var.c 1.1050 from 2023-05-09, the ':gmtime' modifier produced the
+# error message 'Invalid time value: ${FAIL}}' since it did not expand its
+# argument.
.if 0 && ${:Uword:gmtime=${FAIL}}
.endif
@@ -93,8 +94,9 @@ DEFINED= # defined
.if 0 && ${value:L}
.endif
-# As of 2021-03-14, the error 'Invalid time value: ${FAIL}}' is ok since
-# ':localtime' does not expand its argument.
+# Before var.c 1.1050 from 2023-05-09, the ':localtime' modifier produced the
+# error message 'Invalid time value: ${FAIL}}' since it did not expand its
+# argument.
.if 0 && ${:Uword:localtime=${FAIL}}
.endif
diff --git a/contrib/bmake/unit-tests/var-scope-local.exp b/contrib/bmake/unit-tests/var-scope-local.exp
index 403bf83884f7..a9a947a620c7 100644
--- a/contrib/bmake/unit-tests/var-scope-local.exp
+++ b/contrib/bmake/unit-tests/var-scope-local.exp
@@ -1,5 +1,5 @@
-Global: .ALLTARGETS = one
-Global: .ALLTARGETS = one two
+Global: .ALLTARGETS = all target-rule.ext dir/subdir/target-rule.ext target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from inference-rule.ir-to dir/subdir/inference-rule.ir-to inference-rule.ir-from dir/subdir/inference-rule.ir-from inference-rule-chain.ir-to dir/subdir/inference-rule-chain.ir-to inference-rule-chain.ir-gen-from dir/subdir/inference-rule-chain.ir-gen-from one
+Global: .ALLTARGETS = all target-rule.ext dir/subdir/target-rule.ext target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from inference-rule.ir-to dir/subdir/inference-rule.ir-to inference-rule.ir-from dir/subdir/inference-rule.ir-from inference-rule-chain.ir-to dir/subdir/inference-rule-chain.ir-to inference-rule-chain.ir-gen-from dir/subdir/inference-rule-chain.ir-gen-from one two
Var_Parse: ${.MAKE.TARGET_LOCAL_VARIABLES} (eval)
Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
@@ -7,6 +7,56 @@ Global: one two = # (empty)
Global: one two = three
Global: .MAKEFLAGS = -r -k -d v -d
Global: .MAKEFLAGS = -r -k -d v -d 0
+target-rule.ext: @ = <target-rule.ext>
+target-rule.ext: % = <undefined>
+target-rule.ext: ? = <>
+target-rule.ext: < = <undefined>
+target-rule.ext: * = <target-rule.ext>
+dir/subdir/target-rule.ext: @ = <dir/subdir/target-rule.ext>
+dir/subdir/target-rule.ext: % = <undefined>
+dir/subdir/target-rule.ext: ? = <>
+dir/subdir/target-rule.ext: < = <undefined>
+dir/subdir/target-rule.ext: * = <dir/subdir/target-rule.ext>
+target-rule.ir-gen-from: @ = <target-rule.ir-gen-from>
+target-rule.ir-gen-from: % = <undefined>
+target-rule.ir-gen-from: ? = <>
+target-rule.ir-gen-from: < = <undefined>
+target-rule.ir-gen-from: * = <target-rule>
+dir/subdir/target-rule-dir.ir-gen-from: @ = <dir/subdir/target-rule-dir.ir-gen-from>
+dir/subdir/target-rule-dir.ir-gen-from: % = <undefined>
+dir/subdir/target-rule-dir.ir-gen-from: ? = <>
+dir/subdir/target-rule-dir.ir-gen-from: < = <undefined>
+dir/subdir/target-rule-dir.ir-gen-from: * = <dir/subdir/target-rule-dir>
+inference-rule.ir-to: @ = <inference-rule.ir-to>
+inference-rule.ir-to: % = <undefined>
+inference-rule.ir-to: ? = <inference-rule.ir-from>
+inference-rule.ir-to: < = <inference-rule.ir-from>
+inference-rule.ir-to: * = <inference-rule>
+dir/subdir/inference-rule.ir-to: @ = <dir/subdir/inference-rule.ir-to>
+dir/subdir/inference-rule.ir-to: % = <undefined>
+dir/subdir/inference-rule.ir-to: ? = <dir/subdir/inference-rule.ir-from>
+dir/subdir/inference-rule.ir-to: < = <dir/subdir/inference-rule.ir-from>
+dir/subdir/inference-rule.ir-to: * = <dir/subdir/inference-rule>
+inference-rule-chain.ir-from: @ = <inference-rule-chain.ir-from>
+inference-rule-chain.ir-from: % = <undefined>
+inference-rule-chain.ir-from: ? = <inference-rule-chain.ir-gen-from>
+inference-rule-chain.ir-from: < = <inference-rule-chain.ir-gen-from>
+inference-rule-chain.ir-from: * = <inference-rule-chain>
+inference-rule-chain.ir-to: @ = <inference-rule-chain.ir-to>
+inference-rule-chain.ir-to: % = <undefined>
+inference-rule-chain.ir-to: ? = <inference-rule-chain.ir-from>
+inference-rule-chain.ir-to: < = <inference-rule-chain.ir-from>
+inference-rule-chain.ir-to: * = <inference-rule-chain>
+dir/subdir/inference-rule-chain.ir-from: @ = <dir/subdir/inference-rule-chain.ir-from>
+dir/subdir/inference-rule-chain.ir-from: % = <undefined>
+dir/subdir/inference-rule-chain.ir-from: ? = <dir/subdir/inference-rule-chain.ir-gen-from>
+dir/subdir/inference-rule-chain.ir-from: < = <dir/subdir/inference-rule-chain.ir-gen-from>
+dir/subdir/inference-rule-chain.ir-from: * = <dir/subdir/inference-rule-chain>
+dir/subdir/inference-rule-chain.ir-to: @ = <dir/subdir/inference-rule-chain.ir-to>
+dir/subdir/inference-rule-chain.ir-to: % = <undefined>
+dir/subdir/inference-rule-chain.ir-to: ? = <dir/subdir/inference-rule-chain.ir-from>
+dir/subdir/inference-rule-chain.ir-to: < = <dir/subdir/inference-rule-chain.ir-from>
+dir/subdir/inference-rule-chain.ir-to: * = <dir/subdir/inference-rule-chain>
: Making var-scope-local.c out of nothing.
: Making var-scope-local.o from var-scope-local.c.
: Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".".
diff --git a/contrib/bmake/unit-tests/var-scope-local.mk b/contrib/bmake/unit-tests/var-scope-local.mk
index ed1362444504..2cfeda044c40 100644
--- a/contrib/bmake/unit-tests/var-scope-local.mk
+++ b/contrib/bmake/unit-tests/var-scope-local.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-scope-local.mk,v 1.5 2022/02/09 21:09:24 rillig Exp $
+# $NetBSD: var-scope-local.mk,v 1.7 2023/04/29 10:16:24 rillig Exp $
#
# Tests for target-local variables, such as ${.TARGET} or $@. These variables
# are relatively short-lived as they are created just before making the
@@ -12,6 +12,64 @@
.MAIN: all
+# Target-local variables in a target rule
+#
+# In target rules, '$*' only strips the extension off the pathname if the
+# extension is listed in '.SUFFIXES'.
+#
+# expect: target-rule.ext: * = <target-rule.ext>
+all: target-rule.ext dir/subdir/target-rule.ext
+target-rule.ext dir/subdir/target-rule.ext: .PHONY
+ @echo '$@: @ = <${@:Uundefined}>'
+ @echo '$@: % = <${%:Uundefined}>'
+ @echo '$@: ? = <${?:Uundefined}>'
+ @echo '$@: < = <${<:Uundefined}>'
+ @echo '$@: * = <${*:Uundefined}>'
+
+.SUFFIXES: .ir-gen-from .ir-from .ir-to
+
+# In target rules, '$*' strips the extension off the pathname of the target
+# if the extension is listed in '.SUFFIXES'.
+#
+# expect: target-rule.ir-gen-from: * = <target-rule>
+all: target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from
+target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from:
+ @echo '$@: @ = <${@:Uundefined}>'
+ @echo '$@: % = <${%:Uundefined}>'
+ @echo '$@: ? = <${?:Uundefined}>'
+ @echo '$@: < = <${<:Uundefined}>'
+ @echo '$@: * = <${*:Uundefined}>'
+
+.ir-from.ir-to:
+ @echo '$@: @ = <${@:Uundefined}>'
+ @echo '$@: % = <${%:Uundefined}>'
+ @echo '$@: ? = <${?:Uundefined}>'
+ @echo '$@: < = <${<:Uundefined}>'
+ @echo '$@: * = <${*:Uundefined}>'
+.ir-gen-from.ir-from:
+ @echo '$@: @ = <${@:Uundefined}>'
+ @echo '$@: % = <${%:Uundefined}>'
+ @echo '$@: ? = <${?:Uundefined}>'
+ @echo '$@: < = <${<:Uundefined}>'
+ @echo '$@: * = <${*:Uundefined}>'
+
+# Target-local variables in an inference rule
+all: inference-rule.ir-to dir/subdir/inference-rule.ir-to
+inference-rule.ir-from: .PHONY
+dir/subdir/inference-rule.ir-from: .PHONY
+
+# Target-local variables in a chain of inference rules
+all: inference-rule-chain.ir-to dir/subdir/inference-rule-chain.ir-to
+inference-rule-chain.ir-gen-from: .PHONY
+dir/subdir/inference-rule-chain.ir-gen-from: .PHONY
+
+# The run-time 'check' directives from above happen after the parse-time
+# 'check' directives from below.
+#
+# expect-reset
+
+# Deferred evaluation during parsing
+#
# The target-local variables can be used in expressions, just like other
# variables. When these expressions are evaluated outside of a target, these
# expressions are not yet expanded, instead their text is preserved, to allow
@@ -20,8 +78,8 @@
#
# Conditions from .if directives are evaluated in the scope of the command
# line, which means that variables from the command line, from the global
-# scope and from the environment are resolved, in this order (but see the
-# command line option '-e'). In that phase, expressions involving
+# scope and from the environment are resolved, in this precedence order (but
+# see the command line option '-e'). In that phase, expressions involving
# target-local variables need to be preserved, including the exact names of
# the variables.
#
@@ -77,13 +135,17 @@
.endif
+# Custom local variables
+#
# Additional target-local variables may be defined in dependency lines.
.MAKEFLAGS: -dv
# In the following line, the ':=' may either be interpreted as an assignment
# operator or as the dependency operator ':', followed by an empty variable
# name and the assignment operator '='. It is the latter since in an
-# assignment, the left-hand side must be at most a single word. The empty
-# variable name is expanded twice, once for 'one' and once for 'two'.
+# assignment, the left-hand side must be a single word or empty.
+#
+# The empty variable name is expanded twice, once for 'one' and once for
+# 'two'.
# expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
# expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
one two:=three
@@ -205,32 +267,3 @@ a_use: .USE VAR=use
all: var-scope-local-use.o
var-scope-local-use.o: a_use
-
-
-# Since parse.c 1.656 from 2022-01-27 and before parse.c 1.662 from
-# 2022-02-05, there was an out-of-bounds read in Parse_IsVar when looking for
-# a variable assignment in a dependency line with trailing whitespace. Lines
-# without trailing whitespace were not affected. Global variable assignments
-# were guaranteed to have no trailing whitespace and were thus not affected.
-#
-# Try to reproduce some variants that may lead to a crash, depending on the
-# memory allocator. To get a crash, the terminating '\0' of the line must be
-# the last byte of a memory page. The expression '${:U}' forces this trailing
-# whitespace.
-
-# On FreeBSD x86_64, a crash could in some cases be forced using the following
-# line, which has length 47, so the terminating '\0' may end up at an address
-# of the form 0xXXXX_XXXX_XXXX_Xfff:
-Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx: 12345 ${:U}
-
-# The following line has length 4095, so line[4095] == '\0'. If the line is
-# allocated on a page boundary and the following page is not mapped, this line
-# leads to a segmentation fault.
-${:U:range=511:@_@1234567@:ts.}: 12345 ${:U}
-
-# The following line has length 8191, so line[8191] == '\0'. If the line is
-# allocated on a page boundary and the following page is not mapped, this line
-# leads to a segmentation fault.
-${:U:range=1023:@_@1234567@:ts.}: 12345 ${:U}
-
-12345:
diff --git a/contrib/bmake/unit-tests/varmod-gmtime.exp b/contrib/bmake/unit-tests/varmod-gmtime.exp
index fdc9a2170e2f..916e471c462b 100644
--- a/contrib/bmake/unit-tests/varmod-gmtime.exp
+++ b/contrib/bmake/unit-tests/varmod-gmtime.exp
@@ -1,13 +1,13 @@
-make: "varmod-gmtime.mk" line 57: Invalid time value at "${:U1593536400}} != "mtime=11593536400}""
-make: "varmod-gmtime.mk" line 57: Malformed conditional (${%Y:L:gmtime=${:U1593536400}} != "mtime=11593536400}")
-make: "varmod-gmtime.mk" line 67: Invalid time value at "-1} != """
-make: "varmod-gmtime.mk" line 67: Malformed conditional (${:L:gmtime=-1} != "")
-make: "varmod-gmtime.mk" line 76: Invalid time value at " 1} != """
-make: "varmod-gmtime.mk" line 76: Malformed conditional (${:L:gmtime= 1} != "")
-make: "varmod-gmtime.mk" line 119: Invalid time value at "10000000000000000000000000000000} != """
-make: "varmod-gmtime.mk" line 119: Malformed conditional (${:L:gmtime=10000000000000000000000000000000} != "")
-make: "varmod-gmtime.mk" line 130: Invalid time value at "error} != """
-make: "varmod-gmtime.mk" line 130: Malformed conditional (${:L:gmtime=error} != "")
+make: "varmod-gmtime.mk" line 59: Invalid time value "-1"
+make: "varmod-gmtime.mk" line 59: Malformed conditional (${:L:gmtime=-1} != "")
+make: "varmod-gmtime.mk" line 68: Invalid time value " 1"
+make: "varmod-gmtime.mk" line 68: Malformed conditional (${:L:gmtime= 1} != "")
+make: "varmod-gmtime.mk" line 114: Invalid time value "10000000000000000000000000000000"
+make: "varmod-gmtime.mk" line 114: Malformed conditional (${:L:gmtime=10000000000000000000000000000000} != "")
+make: "varmod-gmtime.mk" line 125: Invalid time value "error"
+make: "varmod-gmtime.mk" line 125: Malformed conditional (${:L:gmtime=error} != "")
+make: "varmod-gmtime.mk" line 134: Invalid time value "100000S,1970,bad,"
+make: "varmod-gmtime.mk" line 134: Malformed conditional (${%Y:L:gmtime=100000S,1970,bad,} != "bad")
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-gmtime.mk b/contrib/bmake/unit-tests/varmod-gmtime.mk
index cb3d4e7eb241..639c95b24f6b 100644
--- a/contrib/bmake/unit-tests/varmod-gmtime.mk
+++ b/contrib/bmake/unit-tests/varmod-gmtime.mk
@@ -1,7 +1,10 @@
-# $NetBSD: varmod-gmtime.mk,v 1.10 2021/01/19 05:26:34 rillig Exp $
+# $NetBSD: varmod-gmtime.mk,v 1.14 2023/05/10 15:53:32 rillig Exp $
#
# Tests for the :gmtime variable modifier, which formats a timestamp
# using strftime(3) in UTC.
+#
+# See also:
+# varmod-localtime.mk
.if ${TZ:Uundefined} != "undefined" # see unit-tests/Makefile
. error
@@ -41,20 +44,9 @@
.endif
-# As of 2020-08-16, it is not possible to pass the seconds via a
-# variable expression. This is because parsing of the :gmtime
-# modifier stops at the '$' and returns to ApplyModifiers.
-#
-# There, a colon would be skipped but not a dollar.
-# Parsing therefore continues at the '$' of the ${:U159...}, looking
-# for an ordinary variable modifier.
-#
-# At this point, the ${:U} is expanded and interpreted as a variable
-# modifier, which results in the error message "Unknown modifier '1'".
-#
-# If ApplyModifier_Gmtime were to pass its argument through
-# ParseModifierPart, this would work.
-.if ${%Y:L:gmtime=${:U1593536400}} != "mtime=11593536400}"
+# Before var.c 1.1050 from 2023-05-09, it was not possible to pass the
+# seconds via a variable expression.
+.if ${%Y:L:gmtime=${:U1593536400}} != "2020"
. error
.endif
@@ -75,6 +67,8 @@
# because it would make sense but just as a side-effect from using strtoul.
.if ${:L:gmtime= 1} != ""
. error
+.else
+. error
.endif
@@ -115,7 +109,8 @@
# ULONG_MAX, which got converted to -1. This resulted in a time stamp of
# the second before 1970.
#
-# Since var.c 1.631, the overflow is detected and produces a parse error.
+# Since var.c 1.631 from 2020-10-31, the overflow is detected and produces a
+# parse error.
.if ${:L:gmtime=10000000000000000000000000000000} != ""
. error
.else
@@ -133,5 +128,11 @@
. error
.endif
+# Before var.c 1.1050 from 2023-05-09, the timestamp could be directly
+# followed by the next modifier, without a ':' separator. This was the same
+# bug as for the ':L' and ':P' modifiers.
+.if ${%Y:L:gmtime=100000S,1970,bad,} != "bad"
+. error
+.endif
all:
diff --git a/contrib/bmake/unit-tests/varmod-localtime.exp b/contrib/bmake/unit-tests/varmod-localtime.exp
index 494f160b766e..c734c234f083 100644
--- a/contrib/bmake/unit-tests/varmod-localtime.exp
+++ b/contrib/bmake/unit-tests/varmod-localtime.exp
@@ -1,13 +1,13 @@
-make: "varmod-localtime.mk" line 57: Invalid time value at "${:U1593536400}} != "mtime=11593536400}""
-make: "varmod-localtime.mk" line 57: Malformed conditional (${%Y:L:localtime=${:U1593536400}} != "mtime=11593536400}")
-make: "varmod-localtime.mk" line 67: Invalid time value at "-1} != """
-make: "varmod-localtime.mk" line 67: Malformed conditional (${:L:localtime=-1} != "")
-make: "varmod-localtime.mk" line 76: Invalid time value at " 1} != """
-make: "varmod-localtime.mk" line 76: Malformed conditional (${:L:localtime= 1} != "")
-make: "varmod-localtime.mk" line 119: Invalid time value at "10000000000000000000000000000000} != """
-make: "varmod-localtime.mk" line 119: Malformed conditional (${:L:localtime=10000000000000000000000000000000} != "")
-make: "varmod-localtime.mk" line 130: Invalid time value at "error} != """
-make: "varmod-localtime.mk" line 130: Malformed conditional (${:L:localtime=error} != "")
+make: "varmod-localtime.mk" line 59: Invalid time value "-1"
+make: "varmod-localtime.mk" line 59: Malformed conditional (${:L:localtime=-1} != "")
+make: "varmod-localtime.mk" line 68: Invalid time value " 1"
+make: "varmod-localtime.mk" line 68: Malformed conditional (${:L:localtime= 1} != "")
+make: "varmod-localtime.mk" line 114: Invalid time value "10000000000000000000000000000000"
+make: "varmod-localtime.mk" line 114: Malformed conditional (${:L:localtime=10000000000000000000000000000000} != "")
+make: "varmod-localtime.mk" line 125: Invalid time value "error"
+make: "varmod-localtime.mk" line 125: Malformed conditional (${:L:localtime=error} != "")
+make: "varmod-localtime.mk" line 134: Invalid time value "100000S,1970,bad,"
+make: "varmod-localtime.mk" line 134: Malformed conditional (${%Y:L:localtime=100000S,1970,bad,} != "bad")
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-localtime.mk b/contrib/bmake/unit-tests/varmod-localtime.mk
index ffa09a0bc5fc..7d66745aae8e 100644
--- a/contrib/bmake/unit-tests/varmod-localtime.mk
+++ b/contrib/bmake/unit-tests/varmod-localtime.mk
@@ -1,7 +1,10 @@
-# $NetBSD: varmod-localtime.mk,v 1.8 2021/01/19 05:26:34 rillig Exp $
+# $NetBSD: varmod-localtime.mk,v 1.12 2023/05/10 15:53:32 rillig Exp $
#
# Tests for the :localtime variable modifier, which formats a timestamp
# using strftime(3) in local time.
+#
+# See also:
+# varmod-gmtime.mk
.if ${TZ:Uno:NEurope/Berlin:NUTC-1} != "" # see unit-tests/Makefile
. error
@@ -41,20 +44,9 @@
.endif
-# As of 2020-08-16, it is not possible to pass the seconds via a
-# variable expression. This is because parsing of the :localtime
-# modifier stops at the '$' and returns to ApplyModifiers.
-#
-# There, a colon would be skipped but not a dollar.
-# Parsing therefore continues at the '$' of the ${:U159...}, looking
-# for an ordinary variable modifier.
-#
-# At this point, the ${:U} is expanded and interpreted as a variable
-# modifier, which results in the error message "Unknown modifier '1'".
-#
-# If ApplyModifier_Localtime were to pass its argument through
-# ParseModifierPart, this would work.
-.if ${%Y:L:localtime=${:U1593536400}} != "mtime=11593536400}"
+# Before var.c 1.1050 from 2023-05-09, it was not possible to pass the
+# seconds via a variable expression.
+.if ${%Y:L:localtime=${:U1593536400}} != "2020"
. error
.endif
@@ -75,6 +67,8 @@
# because it would make sense but just as a side-effect from using strtoul.
.if ${:L:localtime= 1} != ""
. error
+.else
+. error
.endif
@@ -115,7 +109,8 @@
# ULONG_MAX, which got converted to -1. This resulted in a time stamp of
# the second before 1970.
#
-# Since var.c 1.631, the overflow is detected and produces a parse error.
+# Since var.c 1.631 from 2020-10-31, the overflow is detected and produces a
+# parse error.
.if ${:L:localtime=10000000000000000000000000000000} != ""
. error
.else
@@ -133,5 +128,11 @@
. error
.endif
+# Before var.c 1.1050 from 2023-05-09, the timestamp could be directly
+# followed by the next modifier, without a ':' separator. This was the same
+# bug as for the ':L' and ':P' modifiers.
+.if ${%Y:L:localtime=100000S,1970,bad,} != "bad"
+. error
+.endif
all:
diff --git a/contrib/bmake/unit-tests/varmod-mtime.exp b/contrib/bmake/unit-tests/varmod-mtime.exp
new file mode 100644
index 000000000000..39a9383953dd
--- /dev/null
+++ b/contrib/bmake/unit-tests/varmod-mtime.exp
@@ -0,0 +1 @@
+exit status 0
diff --git a/contrib/bmake/unit-tests/varmod-mtime.mk b/contrib/bmake/unit-tests/varmod-mtime.mk
new file mode 100644
index 000000000000..dd57ef3f0f31
--- /dev/null
+++ b/contrib/bmake/unit-tests/varmod-mtime.mk
@@ -0,0 +1,30 @@
+# $NetBSD: varmod-mtime.mk,v 1.1 2023/05/09 20:14:27 sjg Exp $
+#
+# Tests for the :mtime variable modifier, which provides mtime
+# of variable value assumed to be a pathname.
+
+all:
+
+# mtime of this makefile
+mtime:= ${MAKEFILE:mtime}
+
+# if pathname does not exist and timestamp is provided
+# that is the result
+.if ${no/such:L:mtime=0} != "0"
+. error
+.endif
+
+.if ${no/such:L:mtime=42} != "42"
+. error
+.endif
+
+# if no timestamp is provided and stat(2) fails use current time
+.if ${no/such:L:mtime} < ${mtime}
+. error no/such:L:mtime ${no/such:L:mtime} < ${mtime}
+.endif
+
+COOKIE = ${TMPDIR}/varmod-mtime.cookie
+x!= touch ${COOKIE}
+.if ${COOKIE:mtime=0} < ${mtime}
+. error COOKIE:mtime=0 ${COOKIE:mtime=0} < ${mtime}
+.endif
diff --git a/contrib/bmake/unit-tests/varmod-path.mk b/contrib/bmake/unit-tests/varmod-path.mk
index ebbf755ddbec..25d4e3899b99 100644
--- a/contrib/bmake/unit-tests/varmod-path.mk
+++ b/contrib/bmake/unit-tests/varmod-path.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-path.mk,v 1.3 2020/08/23 08:10:49 rillig Exp $
+# $NetBSD: varmod-path.mk,v 1.4 2023/05/10 15:53:32 rillig Exp $
#
# Tests for the :P variable modifier, which looks up the path for a given
# target.
@@ -7,11 +7,12 @@
# as of 2020-08-23 it is nevertheless resolved to a path. This is probably
# unintended.
#
-# The real target is located in a subdirectory, and its full path is returned.
-# If it had been in the current directory, the difference between its path and
-# its name would not be visible.
+# In this test, the real target is located in a subdirectory, and its full
+# path is returned. If it had been in the current directory, the difference
+# between its path and its name would not be visible.
#
-# The enoent target does not exist, therefore the target name is returned.
+# The enoent target does not exist, therefore the plain name of the target
+# is returned.
.MAIN: all
@@ -20,7 +21,8 @@ _!= mkdir varmod-path.subdir
_!= > varmod-path.subdir/varmod-path.phony
_!= > varmod-path.subdir/varmod-path.real
-# To have an effect, this .PATH declaration must be after the directory is created.
+# To have an effect, this .PATH declaration must be processed after the
+# directory has been created.
.PATH: varmod-path.subdir
varmod-path.phony: .PHONY