From 7cff6d14ef59d3faa70a0c36a5f75a490a66f2a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 7 Nov 2026 11:57:29 +0100 Subject: [PATCH] Fix #726 (#if: ?: treats a zero condition as true unless it is written exactly as 0) ?: and ! compared the operand with the string "0", so zero values such as 00, -0 and 0L were taken as true. Compare the numeric value instead. --- simplecpp.cpp | 4 ++-- test.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index 91af52ea..60f879cc 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -1305,7 +1305,7 @@ void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok) tok->setstr(tok->next->str()); deleteToken(tok->next); } else if (tok->op == '!' && tok->next && tok->next->number) { - tok->setstr(tok->next->str() == "0" ? "1" : "0"); + tok->setstr(stringToLL(tok->next->str()) == 0 ? "1" : "0"); deleteToken(tok->next); } else if (tok->op == '~' && tok->next && tok->next->number) { tok->setstr(toString(~stringToLL(tok->next->str()))); @@ -1571,7 +1571,7 @@ void simplecpp::TokenList::constFoldQuestionOp(Token *&tok1) deleteToken(trueTok); deleteToken(falseTok); } else { - Token * const result = (condTok->str() != "0" ? trueTok : falseTok); + Token * const result = (stringToLL(condTok->str()) != 0 ? trueTok : falseTok); if (condTok == tok1) tok1 = result; deleteToken(condTok->next); // ? diff --git a/test.cpp b/test.cpp index bd0da227..1296c790 100644 --- a/test.cpp +++ b/test.cpp @@ -2887,6 +2887,32 @@ static void ifShortCircuit() ASSERT_EQUALS("file0,1,syntax_error,failed to evaluate #if condition, division/modulo by zero\n", toString(outputList)); } +static void ifZeroCondition() +{ + // a zero value that is not written as 0 is false + const char * const exprs[] = { + "00 ? 1 : 0", + "-0 ? 1 : 0", + "-X ? 1 : 0", + "0L ? 1 : 0", + "!00 ? 0 : 1", + "!0L ? 0 : 1" + }; + for (const char * const expr : exprs) { + const std::string code = std::string("#if ") + expr + "\n" + "1\n" + "#else\n" + "2\n" + "#endif\n"; + ASSERT_EQUALS("\n\n\n2", preprocess(code.c_str())); + } + + // the selected operand is evaluated + simplecpp::OutputList outputList; + ASSERT_EQUALS("", preprocess("#if 00 ? 1 : 1/0\n#endif\n", &outputList)); + ASSERT_EQUALS("file0,1,syntax_error,failed to evaluate #if condition, division/modulo by zero\n", toString(outputList)); +} + static void ifTrueFalse() { const char code[] = "#if true && !false\n" @@ -5123,6 +5149,7 @@ static void runTests(int argc, char **argv, Input input) TEST_CASE(ifoverflow); TEST_CASE(ifdiv0); TEST_CASE(ifShortCircuit); + TEST_CASE(ifZeroCondition); TEST_CASE(ifTrueFalse); TEST_CASE(ifalt); // using "and", "or", etc TEST_CASE(ifexpr);