Module Name:    src
Committed By:   rillig
Date:           Sat Nov 13 18:37:42 UTC 2021

Modified Files:
        src/usr.bin/make/unit-tests: var-op-expand.exp var-op-expand.mk

Log Message:
tests/make: test double indirection in ':=' with undefined variable

Reported by Simon J Gerraty via private mail.

This edge case has been handled in essentially the same way since at
least 2000-05-30, probably several years earlier as well.  The test file
is:

---- snip ----
.undef LATER
.undef later
INDIRECT:=      ${LATER:S,value,replaced,}
indirect:=      ${INDIRECT:C,S,s,}
# expect+1: Unknown modifier "s,value,replaced,"
.if ${indirect} != ""
.  error
.else
.  warning      XXX Neither branch should be taken.
.endif
LATER=  uppercase-value
later=  lowercase-value
# expect+1: Unknown modifier "s,value,replaced,"
.if ${indirect} != "uppercase-replaced"
.  warning      XXX Neither branch should be taken.
.else
.  error
.endif

all:
        @:;
---- snap ----

The output from 'make -r -f later.mk' is:

make-2000.05.30.02.32.21
| make: Unknown modifier 's'
|
| "later.mk", line 9: Need an operator
| make: Unknown modifier 's'
|
| "later.mk", line 15: Need an operator
| Fatal errors encountered -- cannot continue
| exit status 1
make-2000.12.30.16.38.22

The pathnames in the error message gets absolute:

make-2001.01.23.02.48.05
| make: Unknown modifier 's'
|
| ".../later.mk", line 9: Need an operator
| make: Unknown modifier 's'
|
| ".../later.mk", line 15: Need an operator
| Fatal errors encountered -- cannot continue
| exit status 1
make-2001.01.23.02.48.05

All error messages get 'make:' as a common prefix:

make-2001.02.23.21.11.38
| make: Unknown modifier 's'
|
| make: ".../later.mk" line 9: Need an operator
| make: Unknown modifier 's'
|
| make: ".../later.mk" line 15: Need an operator
| make: Fatal errors encountered -- cannot continue
| exit status 1
make-2001.05.29.17.37.52

The 'stopped in' gets added:

make-2001.06.12.23.36.18
| make: Unknown modifier 's'
|
| make: ".../later.mk" line 9: Need an operator
| make: Unknown modifier 's'
|
| make: ".../later.mk" line 15: Need an operator
| make: Fatal errors encountered -- cannot continue
|
| make: stopped in ...
| exit status 1
make-2002.02.21.22.21.34

The empty lines between the error messages get removed.

make-2002.03.21.11.42.21
| make: Unknown modifier 's'
| make: ".../later.mk" line 9: Need an operator
| make: Unknown modifier 's'
| make: ".../later.mk" line 15: Need an operator
| make: Fatal errors encountered -- cannot continue
|
| make: stopped in ...
| exit status 1
make-2009.10.15.02.27.44

The error message for unknown directives gets more helpful:

make-2009.11.19.06.48.37
| make: Unknown modifier 's'
| make: ".../later.mk" line 9: Unknown directive
| make: Unknown modifier 's'
| make: ".../later.mk" line 15: Unknown directive
| make: Fatal errors encountered -- cannot continue
|
| make: stopped in ...
| exit status 1
make-2010.02.22.19.20.33

The directives '.error', '.warning' and '.info' get added:

make-2010.04.29.23.12.21
| make: Unknown modifier 's'
| make: ".../later.mk" line 9: warning: XXX Neither branch should be taken.
| make: Unknown modifier 's'
| make: ".../later.mk" line 15: warning: XXX Neither branch should be taken.
| exit status 0
make-2020.12.20.19.37.23

The error message about an unknown variable modifier gets line number
information:

make-2020.12.20.19.47.34
| make: ".../later.mk" line 6: Unknown modifier 's'
| make: ".../later.mk" line 9: warning: XXX Neither branch should be taken.
| make: ".../later.mk" line 14: Unknown modifier 's'
| make: ".../later.mk" line 15: warning: XXX Neither branch should be taken.
| make: Fatal errors encountered -- cannot continue
| make: stopped in ...
| exit status 1
make-2021.02.23.15.07.58

The error message about an unknown variable modifier gets more context
than only a single letter:

make-2021.02.23.15.19.41
| make: ".../later.mk" line 6: Unknown modifier "s,value,replaced,"
| make: ".../later.mk" line 9: warning: XXX Neither branch should be taken.
| make: ".../later.mk" line 14: Unknown modifier "s,value,replaced,"
| make: ".../later.mk" line 15: warning: XXX Neither branch should be taken.
| make: Fatal errors encountered -- cannot continue
| make: stopped in ...
| exit status 1


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/usr.bin/make/unit-tests/var-op-expand.exp
cvs rdiff -u -r1.11 -r1.12 src/usr.bin/make/unit-tests/var-op-expand.mk

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

Modified files:

Index: src/usr.bin/make/unit-tests/var-op-expand.exp
diff -u src/usr.bin/make/unit-tests/var-op-expand.exp:1.3 src/usr.bin/make/unit-tests/var-op-expand.exp:1.4
--- src/usr.bin/make/unit-tests/var-op-expand.exp:1.3	Sun Dec 27 21:31:27 2020
+++ src/usr.bin/make/unit-tests/var-op-expand.exp	Sat Nov 13 18:37:42 2021
@@ -1 +1,7 @@
-exit status 0
+make: "var-op-expand.mk" line 229: Unknown modifier "s,value,replaced,"
+make: "var-op-expand.mk" line 232: warning: XXX Neither branch should be taken.
+make: "var-op-expand.mk" line 237: Unknown modifier "s,value,replaced,"
+make: "var-op-expand.mk" line 238: warning: XXX Neither branch should be taken.
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+exit status 1

Index: src/usr.bin/make/unit-tests/var-op-expand.mk
diff -u src/usr.bin/make/unit-tests/var-op-expand.mk:1.11 src/usr.bin/make/unit-tests/var-op-expand.mk:1.12
--- src/usr.bin/make/unit-tests/var-op-expand.mk:1.11	Fri Jan  1 23:07:48 2021
+++ src/usr.bin/make/unit-tests/var-op-expand.mk	Sat Nov 13 18:37:42 2021
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-expand.mk,v 1.11 2021/01/01 23:07:48 sjg Exp $
+# $NetBSD: var-op-expand.mk,v 1.12 2021/11/13 18:37:42 rillig Exp $
 #
 # Tests for the := variable assignment operator, which expands its
 # right-hand side.
@@ -174,5 +174,72 @@ VAR_SUBST_${UNDEF}:=	assigned by ':='
 .  error
 .endif
 
+
+# The following test case demonstrates that the variable 'LATER' is preserved
+# in the ':=' assignment since the variable 'LATER' is not yet defined.
+# After the assignment to 'LATER', evaluating the variable 'INDIRECT'
+# evaluates 'LATER' as well.
+#
+.undef LATER
+INDIRECT:=	${LATER:S,value,replaced,}
+.if ${INDIRECT} != ""
+.  error
+.endif
+LATER=	late-value
+.if ${INDIRECT} != "late-replaced"
+.  error
+.endif
+
+
+# Same as the test case above, except for the additional modifier ':tl' when
+# evaluating the variable 'INDIRECT'.  Nothing surprising here.
+.undef LATER
+.undef later
+INDIRECT:=	${LATER:S,value,replaced,}
+.if ${INDIRECT:tl} != ""
+.  error
+.endif
+LATER=	uppercase-value
+later=	lowercase-value
+.if ${INDIRECT:tl} != "uppercase-replaced"
+.  error
+.endif
+
+
+# Similar to the two test cases above, the situation gets a bit more involved
+# here, due to the double indirection.  The variable 'indirect' is supposed to
+# be the lowercase version of the variable 'INDIRECT'.
+#
+# The assignment operator ':=' for the variable 'INDIRECT' could be a '=' as
+# well, it wouldn't make a difference in this case.  The crucial detail is the
+# assignment operator ':=' for the variable 'indirect', though.  During this
+# assignment, the variable modifier ':S,value,replaced,' is converted to
+# lowercase, which turns 'S' into 's', thus producing an unknown modifier.
+# In this case, make issues a warning, but in cases where the modifier
+# includes a '=', the modifier would be interpreted as a SysV-style
+# substitution like '.c=.o', and make would not issue a warning, leading to
+# silent unexpected behavior.
+#
+# As of 2021-11-13, the actual behavior is unexpected though since
+.undef LATER
+.undef later
+INDIRECT:=	${LATER:S,value,replaced,}
+indirect:=	${INDIRECT:tl}
+# expect+1: Unknown modifier "s,value,replaced,"
+.if ${indirect} != ""
+.  error
+.else
+.  warning	XXX Neither branch should be taken.
+.endif
+LATER=	uppercase-value
+later=	lowercase-value
+# expect+1: Unknown modifier "s,value,replaced,"
+.if ${indirect} != "uppercase-replaced"
+.  warning	XXX Neither branch should be taken.
+.else
+.  error
+.endif
+
+
 all:
 	@:;

Reply via email to