aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests/directive-for-if.mk
blob: f5a20279cc97cc0ec615b5334d5e2572c4b77ea3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# $NetBSD: directive-for-if.mk,v 1.3 2023/11/19 21:47:52 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"
# expect+3: if-less endif
# expect+2: if-less endif
# expect+1: if-less endif
.  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
# 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: