Module Name:    src
Committed By:   rillig
Date:           Mon Aug 30 17:08:13 UTC 2021

Modified Files:
        src/distrib/sets/lists/tests: mi
        src/usr.bin/make/unit-tests: Makefile
Added Files:
        src/usr.bin/make/unit-tests: directive-for-if.exp directive-for-if.mk

Log Message:
tests/make: explain where "${var}" in .for loops comes from


To generate a diff of this commit:
cvs rdiff -u -r1.1119 -r1.1120 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.282 -r1.283 src/usr.bin/make/unit-tests/Makefile
cvs rdiff -u -r0 -r1.1 src/usr.bin/make/unit-tests/directive-for-if.exp \
    src/usr.bin/make/unit-tests/directive-for-if.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1119 src/distrib/sets/lists/tests/mi:1.1120
--- src/distrib/sets/lists/tests/mi:1.1119	Sun Aug 29 09:54:18 2021
+++ src/distrib/sets/lists/tests/mi	Mon Aug 30 17:08:13 2021
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1119 2021/08/29 09:54:18 christos Exp $
+# $NetBSD: mi,v 1.1120 2021/08/30 17:08:13 rillig Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -5423,6 +5423,8 @@
 ./usr/tests/usr.bin/make/unit-tests/directive-for-escape.mk			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/make/unit-tests/directive-for-generating-endif.exp		tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/make/unit-tests/directive-for-generating-endif.mk		tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/make/unit-tests/directive-for-if.exp			tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/make/unit-tests/directive-for-if.mk				tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/make/unit-tests/directive-for-lines.exp			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/make/unit-tests/directive-for-lines.mk			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/make/unit-tests/directive-for-null.exp			tests-usr.bin-tests	compattestfile,atf

Index: src/usr.bin/make/unit-tests/Makefile
diff -u src/usr.bin/make/unit-tests/Makefile:1.282 src/usr.bin/make/unit-tests/Makefile:1.283
--- src/usr.bin/make/unit-tests/Makefile:1.282	Sat Jul 31 20:55:46 2021
+++ src/usr.bin/make/unit-tests/Makefile	Mon Aug 30 17:08:13 2021
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.282 2021/07/31 20:55:46 rillig Exp $
+# $NetBSD: Makefile,v 1.283 2021/08/30 17:08:13 rillig Exp $
 #
 # Unit tests for make(1)
 #
@@ -168,6 +168,7 @@ TESTS+=		directive-for
 TESTS+=		directive-for-errors
 TESTS+=		directive-for-escape
 TESTS+=		directive-for-generating-endif
+TESTS+=		directive-for-if
 TESTS+=		directive-for-lines
 TESTS+=		directive-for-null
 TESTS+=		directive-hyphen-include

Added files:

Index: src/usr.bin/make/unit-tests/directive-for-if.exp
diff -u /dev/null src/usr.bin/make/unit-tests/directive-for-if.exp:1.1
--- /dev/null	Mon Aug 30 17:08:13 2021
+++ src/usr.bin/make/unit-tests/directive-for-if.exp	Mon Aug 30 17:08:13 2021
@@ -0,0 +1,6 @@
+make: "directive-for-if.mk" line 48: if-less endif
+make: "directive-for-if.mk" line 48: if-less endif
+make: "directive-for-if.mk" line 48: if-less endif
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+exit status 1
Index: src/usr.bin/make/unit-tests/directive-for-if.mk
diff -u /dev/null src/usr.bin/make/unit-tests/directive-for-if.mk:1.1
--- /dev/null	Mon Aug 30 17:08:13 2021
+++ src/usr.bin/make/unit-tests/directive-for-if.mk	Mon Aug 30 17:08:13 2021
@@ -0,0 +1,86 @@
+# $NetBSD: directive-for-if.mk,v 1.1 2021/08/30 17:08:13 rillig Exp $
+#
+# Test for a .for directive that contains an .if directive.
+#
+# Before for.c 1.39 from 2008-12-21, when expanding the variables of a .for
+# loop, their values were placed verbatim in the expanded body.  Since then,
+# each variable value expands to an expression of the form ${:Uvalue}.
+#
+# Before that change, the following adventurous code was possible:
+#
+#	.for directive in if ifdef ifndef
+#	.  ${directive} "1" != "0"
+#	.  endif
+#	.endfor
+#
+# A more practical usage of the .for loop that often led to surprises was the
+# following:
+#
+#	.for var in VAR1 VAR2 VAR3
+#	.  if ${var} != "VAR2"
+#	.  endif
+#	.endfor
+#
+# The .for loop body expanded to this string:
+#
+#	.  if VAR1 != "VAR2"
+#	.  endif
+#
+# Since bare words were not allowed at the left-hand side of a condition,
+# make complained about a "Malformed conditional", which was surprising since
+# the code before expanding the .for loop body looked quite well.
+#
+# In cond.c 1.48 from 2008-11-29, just a month before the expansion of .for
+# loops changed from plain textual value to using expressions of the form
+# ${:Uvalue}, this surprising behavior was documented in the code, and a
+# workaround was implemented that allowed bare words when they are followed
+# by either '!' or '=', as part of the operators '!=' or '=='.
+#
+# Since cond.c 1.68 from 2015-05-05, bare words are allowed on the left-hand
+# side of a condition, but that applies only to expression of the form
+# ${${cond} :? then : else}, it does not apply to conditions in ordinary .if
+# directives.
+
+# The following snippet worked in 2005, when the variables from the .for loop
+# expanded to their bare textual value.
+.for directive in if ifdef ifndef
+.  ${directive} "1" != "0"
+.  endif
+.endfor
+# In 2021, the above code does not generate an error message, even though the
+# code looks clearly malformed.  This is due to the '!', which is interpreted
+# as a dependency operator, similar to ':' and '::'.  The parser turns this
+# line into a dependency with the 3 targets '.', 'if', '"1"' and the 2 sources
+# '=' and '"0"'.  Since that line is not interpreted as an '.if' directive,
+# the error message 'if-less endif' makes sense.
+
+# In 2005, make complained:
+#
+#	.if line:	Malformed conditional (VAR1 != "VAR2")
+#	.endif line:	if-less endif
+#	.endif line:	Need an operator
+#
+# 2008.11.30.22.37.55 does not complain about the left-hand side ${var}.
+.for var in VAR1 VAR2 VAR3
+.  if ${var} != "VAR2"
+_!=	echo "${var}" 1>&2; echo # In 2005, '.info' was not invented yet.
+.  endif
+.endfor
+
+# Before for.c 1.39 from 2008-12-21, a common workaround was to surround the
+# variable expression from the .for loop with '"'.  Such a string literal
+# has been allowed since cond.c 1.23 from 2004-04-13.  Between that commit and
+# the one from 2008, the parser would still get confused if the value from the
+# .for loop contained '"', which was effectively a code injection.
+#
+# Surrounding ${var} with quotes disabled the check for typos though.  For
+# ordinary variables, referring to an undefined variable on the left-hand side
+# of the comparison resulted in a "Malformed conditional".  Since the .for
+# loop was usually close to the .if clause, this was not a problem in
+# practice.
+.for var in VAR1 VAR2 VAR3
+.  if "${var}" != "VAR2"
+.  endif
+.endfor
+
+all:

Reply via email to