make(1): add tests for really strange edge cases in conditions

This commit is contained in:
rillig 2020-09-11 06:47:42 +00:00
parent ec64646830
commit 56350d0e74
3 changed files with 94 additions and 14 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cond.c,v 1.127 2020/09/11 06:08:10 rillig Exp $ */
/* $NetBSD: cond.c,v 1.128 2020/09/11 06:47:42 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: cond.c,v 1.127 2020/09/11 06:08:10 rillig Exp $";
static char rcsid[] = "$NetBSD: cond.c,v 1.128 2020/09/11 06:47:42 rillig Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
#else
__RCSID("$NetBSD: cond.c,v 1.127 2020/09/11 06:08:10 rillig Exp $");
__RCSID("$NetBSD: cond.c,v 1.128 2020/09/11 06:47:42 rillig Exp $");
#endif
#endif /* not lint */
#endif
@ -985,7 +985,12 @@ CondParser_Expr(CondParser *par, Boolean doEval)
static CondEvalResult
CondParser_Eval(CondParser *par, Boolean *value)
{
Token res = CondParser_Expr(par, TRUE);
Token res;
if (DEBUG(COND))
fprintf(debug_file, "CondParser_Eval: %s\n", par->p);
res = CondParser_Expr(par, TRUE);
if (res != TOK_FALSE && res != TOK_TRUE)
return COND_INVALID;
@ -996,9 +1001,9 @@ CondParser_Eval(CondParser *par, Boolean *value)
return COND_PARSE;
}
/* Evaluate the condition in the passed line, including any side effects from
* the variable expressions in the condition. The condition consists of &&,
* ||, !, function(arg), comparisons and parenthetical groupings thereof.
/* Evaluate the condition, including any side effects from the variable
* expressions in the condition. The condition consists of &&, ||, !,
* function(arg), comparisons and parenthetical groupings thereof.
*
* Results:
* COND_PARSE if the condition was valid grammatically
@ -1007,7 +1012,7 @@ CondParser_Eval(CondParser *par, Boolean *value)
* (*value) is set to the boolean value of the condition
*/
CondEvalResult
Cond_EvalExpression(const struct If *info, const char *line, Boolean *value,
Cond_EvalExpression(const struct If *info, const char *cond, Boolean *value,
int eprint, Boolean strictLHS)
{
static const struct If *dflt_info;
@ -1016,8 +1021,8 @@ Cond_EvalExpression(const struct If *info, const char *line, Boolean *value,
lhsStrict = strictLHS;
while (*line == ' ' || *line == '\t')
line++;
while (*cond == ' ' || *cond == '\t')
cond++;
if (info == NULL && (info = dflt_info) == NULL) {
/* Scan for the entry for .if - it can't be first */
@ -1029,13 +1034,13 @@ Cond_EvalExpression(const struct If *info, const char *line, Boolean *value,
assert(info != NULL);
par.if_info = info;
par.p = line;
par.p = cond;
par.curr = TOK_NONE;
rval = CondParser_Eval(&par, value);
if (rval == COND_INVALID && eprint)
Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
return rval;
}

View File

@ -1 +1,18 @@
CondParser_Eval: ${:Uvalue} != value
lhs = "value", rhs = "value", op = !=
CondParser_Eval: ${:U} != "
lhs = "", rhs = "", op = !=
CondParser_Eval: ${:U#hash} != "#hash"
lhs = "#hash", rhs = "#hash", op = !=
CondParser_Eval: ${:U\\} != "\\
lhs = "\", rhs = "\", op = !=
CondParser_Eval: ${:U#hash} != #hash
lhs = "#hash", rhs = "#hash", op = !=
CondParser_Eval: 0 # This is treated as a comment, but why?
CondParser_Eval: ${0 # comment :?yes:no} != no
CondParser_Eval: 0 # comment
lhs = "no", rhs = "no", op = !=
CondParser_Eval: ${1 # comment :?yes:no} != yes
CondParser_Eval: 1 # comment
lhs = "yes", rhs = "yes", op = !=
exit status 0

View File

@ -1,9 +1,67 @@
# $NetBSD: cond-token-plain.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
# $NetBSD: cond-token-plain.mk,v 1.3 2020/09/11 06:47:42 rillig Exp $
#
# Tests for plain tokens (that is, string literals without quotes)
# in .if conditions.
# TODO: Implementation
.MAKEFLAGS: -dc
.if ${:Uvalue} != value
. error
.endif
# Malformed condition since comment parsing is done in an early phase
# and removes the '#' and everything behind it long before the condition
# parser gets to see it.
#
# XXX: The error message is missing for this malformed condition.
# The right-hand side of the comparison is just a '"'.
.if ${:U} != "#hash"
. error
.endif
# To get a '#' into a condition, it has to be escaped using a backslash.
# This prevents the comment parser from removing it, and in turn, it becomes
# visible to CondParser_String.
.if ${:U\#hash} != "\#hash"
. error
.endif
# Since 2002-12-30, and still as of 2020-09-11, CondParser_Token handles
# the '#' specially, even though at this point, there should be no need for
# comment handling anymore. The comments are supposed to be stripped off
# in a very early parsing phase.
#
# XXX: Missing error message for the malformed condition. The right-hand
# side is double-quotes, backslash, backslash.
# XXX: It is unexpected that the right-hand side evaluates to a single
# backslash.
.if ${:U\\} != "\\#hash"
. error
.endif
# The right-hand side of a comparison is not parsed as a token, therefore
# the code from CondParser_Token does not apply to it.
.if ${:U\#hash} != \#hash
. error
.endif
# XXX: What is the purpose of treating an escaped '#' in the following
# condition as a comment? And why only at the beginning of a token,
# just as in the shell?
.if 0 \# This is treated as a comment, but why?
. error
.endif
# Ah, ok, this can be used to add an end-of-condition comment. But does
# anybody really use this? This is neither documented nor obvious since
# the '#' is escaped. It's much clearer to write a comment in the line
# above the condition.
.if ${0 \# comment :?yes:no} != no
. error
.endif
.if ${1 \# comment :?yes:no} != yes
. error
.endif
all:
@:;