Module Name:    src
Committed By:   rillig
Date:           Sun Jun 30 13:01:01 UTC 2024

Modified Files:
        src/usr.bin/make: var.c
        src/usr.bin/make/unit-tests: cond-late.exp cond-late.mk
            varmod-ifelse.exp varmod-ifelse.mk

Log Message:
make: error out on syntax error in conditions in ':?then:else' modifier

The 'Error' function only reports errors but does not affect the exit
status, the 'Parse_Error' function does, while providing more details to
find the cause of the syntax error.


To generate a diff of this commit:
cvs rdiff -u -r1.1123 -r1.1124 src/usr.bin/make/var.c
cvs rdiff -u -r1.5 -r1.6 src/usr.bin/make/unit-tests/cond-late.exp
cvs rdiff -u -r1.6 -r1.7 src/usr.bin/make/unit-tests/cond-late.mk
cvs rdiff -u -r1.20 -r1.21 src/usr.bin/make/unit-tests/varmod-ifelse.exp
cvs rdiff -u -r1.29 -r1.30 src/usr.bin/make/unit-tests/varmod-ifelse.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/var.c
diff -u src/usr.bin/make/var.c:1.1123 src/usr.bin/make/var.c:1.1124
--- src/usr.bin/make/var.c:1.1123	Sun Jun 30 11:44:14 2024
+++ src/usr.bin/make/var.c	Sun Jun 30 13:01:01 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: var.c,v 1.1123 2024/06/30 11:44:14 rillig Exp $	*/
+/*	$NetBSD: var.c,v 1.1124 2024/06/30 13:01:01 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -132,7 +132,7 @@
 #include "metachar.h"
 
 /*	"@(#)var.c	8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.1123 2024/06/30 11:44:14 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1124 2024/06/30 13:01:01 rillig Exp $");
 
 /*
  * Variables are defined using one of the VAR=value assignments.  Their
@@ -262,6 +262,9 @@ typedef struct SepBuf {
 typedef enum {
 	VSK_TARGET,
 	VSK_VARNAME,
+	VSK_COND,
+	VSK_COND_THEN,
+	VSK_COND_ELSE,
 	VSK_EXPR
 } EvalStackElementKind;
 
@@ -375,11 +378,17 @@ EvalStack_Details(void)
 
 	buf->len = 0;
 	for (i = 0; i < evalStack.len; i++) {
+		static const char descr[][42] = {
+			"in target",
+			"while evaluating variable",
+			"while evaluating condition",
+			"while evaluating then-branch of condition",
+			"while evaluating else-branch of condition",
+			"while evaluating",
+		};
 		EvalStackElement *elem = evalStack.elems + i;
-		Buf_AddStr(buf,
-		    elem->kind == VSK_TARGET ? "in target \"" :
-		    elem->kind == VSK_EXPR ? "while evaluating \"" :
-		    "while evaluating variable \"");
+		Buf_AddStr(buf, descr[elem->kind]);
+		Buf_AddStr(buf, " \"");
 		Buf_AddStr(buf, elem->str);
 		Buf_AddStr(buf, "\": ");
 	}
@@ -3443,6 +3452,7 @@ ApplyModifier_IfElse(const char **pp, Mo
 
 	CondResult cond_rc = CR_TRUE;	/* just not CR_ERROR */
 	if (Expr_ShouldEval(expr)) {
+		evalStack.elems[evalStack.len - 1].kind = VSK_COND;
 		cond_rc = Cond_EvalCondition(expr->name);
 		if (cond_rc == CR_TRUE)
 			then_emode = expr->emode;
@@ -3450,11 +3460,13 @@ ApplyModifier_IfElse(const char **pp, Mo
 			else_emode = expr->emode;
 	}
 
+	evalStack.elems[evalStack.len - 1].kind = VSK_COND_THEN;
 	(*pp)++;		/* skip past the '?' */
 	if (!ParseModifierPart(pp, ':', ':', then_emode,
 	    ch, &thenBuf, NULL, NULL))
 		return AMR_CLEANUP;
 
+	evalStack.elems[evalStack.len - 1].kind = VSK_COND_ELSE;
 	if (!ParseModifierPart(pp, ch->endc, ch->endc, else_emode,
 	    ch, &elseBuf, NULL, NULL)) {
 		LazyBuf_Done(&thenBuf);
@@ -3464,12 +3476,8 @@ ApplyModifier_IfElse(const char **pp, Mo
 	(*pp)--;		/* Go back to the ch->endc. */
 
 	if (cond_rc == CR_ERROR) {
-		Substring thenExpr = LazyBuf_Get(&thenBuf);
-		Substring elseExpr = LazyBuf_Get(&elseBuf);
-		Error("Bad conditional expression '%s' before '?%.*s:%.*s'",
-		    expr->name,
-		    (int)Substring_Length(thenExpr), thenExpr.start,
-		    (int)Substring_Length(elseExpr), elseExpr.start);
+		evalStack.elems[evalStack.len - 1].kind = VSK_COND;
+		Parse_Error(PARSE_FATAL, "Bad condition");
 		LazyBuf_Done(&thenBuf);
 		LazyBuf_Done(&elseBuf);
 		return AMR_CLEANUP;

Index: src/usr.bin/make/unit-tests/cond-late.exp
diff -u src/usr.bin/make/unit-tests/cond-late.exp:1.5 src/usr.bin/make/unit-tests/cond-late.exp:1.6
--- src/usr.bin/make/unit-tests/cond-late.exp:1.5	Sun Dec 10 20:12:28 2023
+++ src/usr.bin/make/unit-tests/cond-late.exp	Sun Jun 30 13:01:01 2024
@@ -1,4 +1,6 @@
-make: Bad conditional expression ' != "no"' before '?:'
+make: "cond-late.mk" line 38: while evaluating variable "VAR": while evaluating condition " != "no"": Bad condition
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
 yes
 no
 exit status 0

Index: src/usr.bin/make/unit-tests/cond-late.mk
diff -u src/usr.bin/make/unit-tests/cond-late.mk:1.6 src/usr.bin/make/unit-tests/cond-late.mk:1.7
--- src/usr.bin/make/unit-tests/cond-late.mk:1.6	Sun Dec 10 20:12:28 2023
+++ src/usr.bin/make/unit-tests/cond-late.mk	Sun Jun 30 13:01:01 2024
@@ -1,4 +1,4 @@
-# $NetBSD: cond-late.mk,v 1.6 2023/12/10 20:12:28 rillig Exp $
+# $NetBSD: cond-late.mk,v 1.7 2024/06/30 13:01:01 rillig Exp $
 #
 # Using the :? modifier, expressions can contain conditional
 # expressions that are evaluated late, at expansion time.
@@ -15,7 +15,10 @@
 # actually interpreted as these operators. This is demonstrated below.
 #
 
-all: cond-literal
+all: parse-time cond-literal
+
+parse-time: .PHONY
+	@${MAKE} -f ${MAKEFILE} do-parse-time || true
 
 COND.true=	"yes" == "yes"
 COND.false=	"yes" != "yes"
@@ -29,8 +32,9 @@ cond-literal:
 	@echo ${ ${COND.true} :?yes:no}
 	@echo ${ ${COND.false} :?yes:no}
 
+.if make(do-parse-time)
 VAR=	${${UNDEF} != "no":?:}
-# expect-reset
-# expect: make: Bad conditional expression ' != "no"' before '?:'
-.if empty(VAR:Mpattern)
+# expect+1: while evaluating variable "VAR": while evaluating condition " != "no"": Bad condition
+.  if empty(VAR:Mpattern)
+.  endif
 .endif

Index: src/usr.bin/make/unit-tests/varmod-ifelse.exp
diff -u src/usr.bin/make/unit-tests/varmod-ifelse.exp:1.20 src/usr.bin/make/unit-tests/varmod-ifelse.exp:1.21
--- src/usr.bin/make/unit-tests/varmod-ifelse.exp:1.20	Sat Apr 20 10:18:55 2024
+++ src/usr.bin/make/unit-tests/varmod-ifelse.exp	Sun Jun 30 13:01:01 2024
@@ -1,32 +1,32 @@
-make: Bad conditional expression 'bare words == "literal"' before '?bad:bad'
-make: "varmod-ifelse.mk" line 28: Malformed conditional (${${:Ubare words} == "literal":?bad:bad})
-make: Bad conditional expression ' == ""' before '?bad-assign:bad-assign'
-make: Bad conditional expression ' == ""' before '?bad-cond:bad-cond'
-make: "varmod-ifelse.mk" line 46: Malformed conditional (${${UNDEF} == "":?bad-cond:bad-cond})
-make: Bad conditional expression '1 == == 2' before '?yes:no'
-make: "varmod-ifelse.mk" line 69: Malformed conditional (${1 == == 2:?yes:no} != "")
+make: "varmod-ifelse.mk" line 29: while evaluating condition "bare words == "literal"": Bad condition
+make: "varmod-ifelse.mk" line 29: Malformed conditional (${${:Ubare words} == "literal":?bad:bad})
+make: "varmod-ifelse.mk" line 40: while evaluating condition " == """: Bad condition
+make: "varmod-ifelse.mk" line 49: while evaluating condition " == """: Bad condition
+make: "varmod-ifelse.mk" line 49: Malformed conditional (${${UNDEF} == "":?bad-cond:bad-cond})
+make: "varmod-ifelse.mk" line 73: while evaluating condition "1 == == 2": Bad condition
+make: "varmod-ifelse.mk" line 73: Malformed conditional (${1 == == 2:?yes:no} != "")
 CondParser_Eval: "${1 == == 2:?yes:no}" != ""
 CondParser_Eval: 1 == == 2
 Comparing 1.000000 == 0.000000
-make: Bad conditional expression '1 == == 2' before '?yes:no'
+make: "varmod-ifelse.mk" line 97: while evaluating condition "1 == == 2": Bad condition
 Comparing "" != ""
-make: "varmod-ifelse.mk" line 96: warning: Oops, the parse error should have been propagated.
+make: "varmod-ifelse.mk" line 101: warning: Oops, the parse error should have been propagated.
 CondParser_Eval: ${ ${:U\$}{VAR} == value:?ok:bad} != "ok"
 CondParser_Eval: ${VAR} == value
 Comparing "value" == "value"
 Comparing "ok" != "ok"
-make: "varmod-ifelse.mk" line 158: no.
-make: "varmod-ifelse.mk" line 162: while evaluating variable "string == "literal" || no >= 10": Comparison with '>=' requires both operands 'no' and '10' to be numeric
-make: Bad conditional expression 'string == "literal" || no >= 10' before '?yes:no'
-make: "varmod-ifelse.mk" line 162: .
-make: Bad conditional expression 'string == "literal" &&  >= 10' before '?yes:no'
-make: "varmod-ifelse.mk" line 169: .
-make: Bad conditional expression 'string == "literal" ||  >= 10' before '?yes:no'
-make: "varmod-ifelse.mk" line 172: .
-make: "varmod-ifelse.mk" line 180: <true>
-make: "varmod-ifelse.mk" line 183: <false>
-make: Bad conditional expression '	' before '?true:false'
-make: "varmod-ifelse.mk" line 186: <>
+make: "varmod-ifelse.mk" line 163: no.
+make: "varmod-ifelse.mk" line 167: while evaluating condition "string == "literal" || no >= 10": Comparison with '>=' requires both operands 'no' and '10' to be numeric
+make: "varmod-ifelse.mk" line 167: while evaluating condition "string == "literal" || no >= 10": Bad condition
+make: "varmod-ifelse.mk" line 167: .
+make: "varmod-ifelse.mk" line 174: while evaluating condition "string == "literal" &&  >= 10": Bad condition
+make: "varmod-ifelse.mk" line 174: .
+make: "varmod-ifelse.mk" line 177: while evaluating condition "string == "literal" ||  >= 10": Bad condition
+make: "varmod-ifelse.mk" line 177: .
+make: "varmod-ifelse.mk" line 185: <true>
+make: "varmod-ifelse.mk" line 188: <false>
+make: "varmod-ifelse.mk" line 192: while evaluating condition "	": Bad condition
+make: "varmod-ifelse.mk" line 192: <>
 CondParser_Eval: 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated"
 CondParser_Eval: 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1"
 CondParser_Eval: 0
@@ -36,16 +36,18 @@ CondParser_Eval: 1
 Comparing "then2" != "then2"
 CondParser_Eval: ${DELAYED} == "one"
 Comparing "two" == "one"
-make: "varmod-ifelse.mk" line 282: no
+make: "varmod-ifelse.mk" line 288: no
 CondParser_Eval: ${DELAYED} == "two"
 Comparing "two" == "two"
-make: "varmod-ifelse.mk" line 284: yes
+make: "varmod-ifelse.mk" line 290: yes
 CondParser_Eval: ${DELAYED} == "one"
 Comparing "two" == "one"
-make: "varmod-ifelse.mk" line 287: no
+make: "varmod-ifelse.mk" line 293: no
 CondParser_Eval: ${DELAYED} == "two"
 Comparing "two" == "two"
-make: "varmod-ifelse.mk" line 290: yes
+make: "varmod-ifelse.mk" line 296: yes
+make: "varmod-ifelse.mk" line 318: while evaluating then-branch of condition "1": while evaluating "${:X-then}:${:X-else}}": Unknown modifier "X-then"
+make: "varmod-ifelse.mk" line 318: while evaluating else-branch of condition "1": while evaluating "${:X-else}}": Unknown modifier "X-else"
 make: Fatal errors encountered -- cannot continue
 make: stopped in unit-tests
 exit status 1

Index: src/usr.bin/make/unit-tests/varmod-ifelse.mk
diff -u src/usr.bin/make/unit-tests/varmod-ifelse.mk:1.29 src/usr.bin/make/unit-tests/varmod-ifelse.mk:1.30
--- src/usr.bin/make/unit-tests/varmod-ifelse.mk:1.29	Sun Jun  2 15:31:26 2024
+++ src/usr.bin/make/unit-tests/varmod-ifelse.mk	Sun Jun 30 13:01:01 2024
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-ifelse.mk,v 1.29 2024/06/02 15:31:26 rillig Exp $
+# $NetBSD: varmod-ifelse.mk,v 1.30 2024/06/30 13:01:01 rillig Exp $
 #
 # Tests for the ${cond:?then:else} variable modifier, which evaluates either
 # the then-expression or the else-expression, depending on the condition.
@@ -24,6 +24,7 @@
 # Evaluating the variable name lazily would require additional code in
 # Var_Parse and ParseVarname, it would be more useful and predictable
 # though.
+# expect+2: while evaluating condition "bare words == "literal"": Bad condition
 # expect+1: Malformed conditional (${${:Ubare words} == "literal":?bad:bad})
 .if ${${:Ubare words} == "literal":?bad:bad}
 .  error
@@ -35,6 +36,7 @@
 # Because of the early expansion, the whole condition evaluates to
 # ' == ""' though, which cannot be parsed because the left-hand side looks
 # empty.
+# expect+1: while evaluating condition " == """: Bad condition
 COND:=	${${UNDEF} == "":?bad-assign:bad-assign}
 
 # In a condition, undefined variables generate a "Malformed conditional"
@@ -42,6 +44,7 @@ COND:=	${${UNDEF} == "":?bad-assign:bad-
 # "Undefined variable" error message is generated.
 # The difference to the ':=' variable assignment is the additional
 # "Malformed conditional" error message.
+# expect+2: while evaluating condition " == """: Bad condition
 # expect+1: Malformed conditional (${${UNDEF} == "":?bad-cond:bad-cond})
 .if ${${UNDEF} == "":?bad-cond:bad-cond}
 .  error
@@ -65,6 +68,7 @@ COND:=	${${UNDEF} == "":?bad-assign:bad-
 # conditional therefore returns a parse error from Var_Parse, and this parse
 # error propagates to CondEvalExpression, where the "Malformed conditional"
 # comes from.
+# expect+2: while evaluating condition "1 == == 2": Bad condition
 # expect+1: Malformed conditional (${1 == == 2:?yes:no} != "")
 .if ${1 == == 2:?yes:no} != ""
 .  error
@@ -89,6 +93,7 @@ COND:=	${${UNDEF} == "":?bad-assign:bad-
 # condition should be detected as being malformed before any comparison is
 # done since there is no well-formed comparison in the condition at all.
 .MAKEFLAGS: -dc
+# expect+1: while evaluating condition "1 == == 2": Bad condition
 .if "${1 == == 2:?yes:no}" != ""
 .  error
 .else
@@ -156,18 +161,18 @@ STRING=		string
 NUMBER=		no		# not really a number
 # expect+1: no.
 .info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
-# expect+3: while evaluating variable "string == "literal" || no >= 10": Comparison with '>=' requires both operands 'no' and '10' to be numeric
-# expect: make: Bad conditional expression 'string == "literal" || no >= 10' before '?yes:no'
+# expect+3: while evaluating condition "string == "literal" || no >= 10": Comparison with '>=' requires both operands 'no' and '10' to be numeric
+# expect+2: while evaluating condition "string == "literal" || no >= 10": Bad condition
 # expect+1: .
 .info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
 
 # The following situation occasionally occurs with MKINET6 or similar
 # variables.
 NUMBER=		# empty, not really a number either
-# expect: make: Bad conditional expression 'string == "literal" &&  >= 10' before '?yes:no'
+# expect+2: while evaluating condition "string == "literal" &&  >= 10": Bad condition
 # expect+1: .
 .info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
-# expect: make: Bad conditional expression 'string == "literal" ||  >= 10' before '?yes:no'
+# expect+2: while evaluating condition "string == "literal" ||  >= 10": Bad condition
 # expect+1: .
 .info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
 
@@ -182,6 +187,7 @@ EMPTY=		# empty
 # expect+1: <false>
 .info <${${ASTERISK}	:?true:false}>
 # syntax error since the condition is completely blank.
+# expect+2: while evaluating condition "	": Bad condition
 # expect+1: <>
 .info <${${EMPTY}	:?true:false}>
 
@@ -305,3 +311,9 @@ BOTH=	<${YES}> <${NO}>
 .if ${BOTH} != "<yes> <no>"
 .  error
 .endif
+
+
+# expect+2: while evaluating then-branch of condition "1": while evaluating "${:X-then}:${:X-else}}": Unknown modifier "X-then"
+# expect+1: while evaluating else-branch of condition "1": while evaluating "${:X-else}}": Unknown modifier "X-else"
+.if ${1:?${:X-then}:${:X-else}}
+.endif

Reply via email to