Module Name: src Committed By: rillig Date: Thu Dec 30 02:14:55 UTC 2021
Modified Files: src/usr.bin/make: cond.c src/usr.bin/make/unit-tests: cond-token-plain.exp cond-token-plain.mk Log Message: tests/make: demonstrate edge case that evaluates an expression twice To generate a diff of this commit: cvs rdiff -u -r1.320 -r1.321 src/usr.bin/make/cond.c cvs rdiff -u -r1.13 -r1.14 src/usr.bin/make/unit-tests/cond-token-plain.exp cvs rdiff -u -r1.14 -r1.15 src/usr.bin/make/unit-tests/cond-token-plain.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/cond.c diff -u src/usr.bin/make/cond.c:1.320 src/usr.bin/make/cond.c:1.321 --- src/usr.bin/make/cond.c:1.320 Thu Dec 30 01:34:26 2021 +++ src/usr.bin/make/cond.c Thu Dec 30 02:14:55 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: cond.c,v 1.320 2021/12/30 01:34:26 rillig Exp $ */ +/* $NetBSD: cond.c,v 1.321 2021/12/30 02:14:55 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -95,7 +95,7 @@ #include "dir.h" /* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */ -MAKE_RCSID("$NetBSD: cond.c,v 1.320 2021/12/30 01:34:26 rillig Exp $"); +MAKE_RCSID("$NetBSD: cond.c,v 1.321 2021/12/30 02:14:55 rillig Exp $"); /* * The parsing of conditional expressions is based on this grammar: @@ -793,8 +793,8 @@ CondParser_ComparisonOrLeaf(CondParser * * as an expression. */ /* - * XXX: Is it possible to have a variable expression evaluated twice - * at this point? + * XXX: In edge cases, a variable expression may be evaluated twice, + * see cond-token-plain.mk, keyword 'twice'. */ arg = ParseWord(&cp, doEval); assert(arg[0] != '\0'); Index: src/usr.bin/make/unit-tests/cond-token-plain.exp diff -u src/usr.bin/make/unit-tests/cond-token-plain.exp:1.13 src/usr.bin/make/unit-tests/cond-token-plain.exp:1.14 --- src/usr.bin/make/unit-tests/cond-token-plain.exp:1.13 Sun Dec 12 09:36:00 2021 +++ src/usr.bin/make/unit-tests/cond-token-plain.exp Thu Dec 30 02:14:55 2021 @@ -56,6 +56,7 @@ CondParser_Eval: 0 make: "cond-token-plain.mk" line 201: Malformed conditional (${0:?:} || left == right) CondParser_Eval: left == right || ${0:?:} make: "cond-token-plain.mk" line 206: Malformed conditional (left == right || ${0:?:}) +make: "cond-token-plain.mk" line 225: Malformed conditional (VAR.${IF_COUNT::+=1} != "") make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 Index: src/usr.bin/make/unit-tests/cond-token-plain.mk diff -u src/usr.bin/make/unit-tests/cond-token-plain.mk:1.14 src/usr.bin/make/unit-tests/cond-token-plain.mk:1.15 --- src/usr.bin/make/unit-tests/cond-token-plain.mk:1.14 Sun Dec 12 09:36:00 2021 +++ src/usr.bin/make/unit-tests/cond-token-plain.mk Thu Dec 30 02:14:55 2021 @@ -1,4 +1,4 @@ -# $NetBSD: cond-token-plain.mk,v 1.14 2021/12/12 09:36:00 rillig Exp $ +# $NetBSD: cond-token-plain.mk,v 1.15 2021/12/30 02:14:55 rillig Exp $ # # Tests for plain tokens (that is, string literals without quotes) # in .if conditions. These are also called bare words. @@ -209,5 +209,48 @@ ${:U\\\\}= backslash # See cond-token-string.mk for similar tests where the condition is enclosed # in "quotes". -all: - @:; +.MAKEFLAGS: -d0 + + +# As of cond.c 1.320 from 2021-12-30, the code in CondParser_ComparisonOrLeaf +# looks suspicious of evaluating the expression twice: first for parsing a +# bare word and second for parsing the left-hand side of a comparison. +# +# In '.if' directives, the left-hand side of a comparison must not be a bare +# word though, and this keeps CondParser_Leaf from evaluating the expression +# for the second time. The right-hand side of a comparison may be a bare +# word, but that side has no risk of being parsed more than once. +# +# expect+1: Malformed conditional (VAR.${IF_COUNT::+=1} != "") +.if VAR.${IF_COUNT::+=1} != "" +. error +.else +. error +.endif +.if ${IF_COUNT} != "1" +. error +.endif + +# A different situation is when CondParser.leftUnquotedOK is true. This +# situation arises in expressions of the form ${cond:?yes:no}. As of +# 2021-12-30, the condition in such an expression is evaluated before parsing +# the condition, see varmod-ifelse.mk. To pass a variable expression to the +# condition parser, it needs to be escaped. This rarely happens in practice, +# in most cases the conditions are simple enough that it doesn't matter +# whether the condition is first evaluated and then parsed, or vice versa. +# A half-baked attempt at hiding this implementation detail is +# CondParser.leftUnquotedOK, but that is a rather leaky abstraction. + +#.MAKEFLAGS: -dcv +COND= VAR.$${MOD_COUNT::+=1} +.if ${${COND} == "VAR.":?yes:no} != "yes" +. error +.endif + +# The value "1 1" demonstrates that the expression ${MOD_COUNT::+=1} was +# evaluated twice. In practice, expressions that occur in conditions do not +# have side effects, making this problem rather academic, but it is there. +.if ${MOD_COUNT} != "1 1" +. error +.endif +#.MAKEFLAGS: -d0