]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bmake/unit-tests/varparse-undef-partial.mk
Update to bmake-20201101
[FreeBSD/FreeBSD.git] / contrib / bmake / unit-tests / varparse-undef-partial.mk
1 # $NetBSD: varparse-undef-partial.mk,v 1.2 2020/09/27 09:53:41 rillig Exp $
2
3 # When an undefined variable is expanded in a ':=' assignment, only the
4 # initial '$' of the variable expression is skipped by the parser, while
5 # the remaining expression is evaluated.  In edge cases this can lead to
6 # a completely different interpretation of the partially expanded text.
7
8 LIST=   ${DEF} ${UNDEF} ${VAR.${PARAM}} end
9 DEF=    defined
10 PARAM=  :Q
11
12 # The expression ${VAR.{PARAM}} refers to the variable named "VAR.:Q",
13 # with the ":Q" being part of the name.  This variable is not defined,
14 # therefore the initial '$' of that whole expression is skipped by the
15 # parser (see Var_Subst, the Buf_AddByte in the else branch) and the rest
16 # of the expression is expanded as usual.
17 #
18 # The resulting variable expression is ${VAR.:Q}, which means that the
19 # interpretation of the ":Q" has changed from being part of the variable
20 # name to being a variable modifier.  This is a classical code injection.
21 EVAL:=  ${LIST}
22 .if ${EVAL} != "defined   end"
23 .  error ${EVAL}
24 .endif
25
26 # Define the possible outcomes, to see which of them gets expanded.
27 VAR.=           var-dot without parameter
28 ${:UVAR.\:Q}=   var-dot with parameter :Q
29
30 # At this point, the variable "VAR." is defined, therefore the expression
31 # ${VAR.:Q} is expanded as usual.
32 .if ${EVAL} != "defined  var-dot\\ without\\ parameter end"
33 .  error ${EVAL}
34 .endif
35
36 # In contrast to the previous line, evaluating the original LIST again now
37 # produces a different result since the ":Q" has already been inserted
38 # literally into the expression.  The variable named "VAR.:Q" is defined,
39 # therefore it is resolved as usual.  The ":Q" is interpreted as part of the
40 # variable name, as would be expected from reading the variable expression.
41 EVAL:=  ${LIST}
42 .if ${EVAL} != "defined  var-dot with parameter :Q end"
43 .  error ${EVAL}
44 .endif
45
46 # It's difficult to decide what the best behavior is in this situation.
47 # Should the whole expression be skipped for now, or should the inner
48 # subexpressions be expanded already?
49 #
50 # Example 1:
51 # CFLAGS:=      ${CFLAGS:N-W*} ${COPTS.${COMPILER}}
52 #
53 # The variable COMPILER typically contains an identifier and the variable is
54 # not modified later.  In this practical case, it does not matter whether the
55 # expression is expanded early, or whether the whole ${COPTS.${COMPILER}} is
56 # expanded as soon as the variable COPTS.${COMPILER} becomes defined.  The
57 # expression ${COMPILER} would be expanded several times, but in this simple
58 # scenario there would not be any side effects.
59 #
60 # TODO: Add a practical example where early/lazy expansion actually makes a
61 # difference.
62
63 all:
64         @: