Skip to content

Fix #731 (#if: an operator with a missing operand silently evaluates to false) - #732

Merged
danmar merged 1 commit into
masterfrom
fix-731
Nov 7, 2026
Merged

danmar merged 1 commit into
masterfrom
fix-731

Conversation

@danmar

@danmar danmar commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator

Report "invalid expression" when the #if expression can not be folded to a single number. This also covers a missing operator ("1 2") and empty parentheses ("()").

…to false)

Report "invalid expression" when the #if expression can not be folded to a
single number. This also covers a missing operator ("1 2") and empty
parentheses ("()").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@dmcppcheck dmcppcheck left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

The new throw makes some valid #if expressions fatal. When evaluate() throws, simplecpp::preprocess clears the whole output and returns. So any valid expression that constFold() can't reduce to one number now loses the whole file, where before that condition was only treated as false.

  • Comma operator (regression): constFold() has no case for the comma operator. #if (1, 0) used to give the same result as gcc and clang (false). Now it's a syntax error and the file isn't preprocessed. gcc gives only a -Wpedantic warning, and clang accepts the parenthesized form. #if 1 ? (2, 3) : 4 was silently false before (wrong) and is now a fatal error.
  • not/compl after a binary operator (C++): isAlternativeUnaryOp() only accepts not/compl at the start of the expression or right after (. So #if 1 && not 0 and #if 1 and not X used to be silently false (also wrong) and now abort the file. g++ and clang++ both give true.

Both are evaluator gaps that the old return 0 hid. Before this check makes them fatal, the comma operator should be supported in constFold() and the alternative unary operators recognised after any operator. The other cases I tried came out the same as in base: the PR's own error cases and about 50 valid expressions (ternaries, unary operators, defined, __has_include, character literals, alternative tokens at the start). Apart from the two problems above, I found no new problems. Nobody has commented on the PR yet.

Testing

Build and test suites: make -j8 testrunner simplecpp CXXOPTS=-Werror built in pr/ without warnings. ./testrunner, python3 run-tests.py (0 failed), python3 -m pytest integration_test.py (128 passed) and ./selfcheck.sh all passed. I also built base/simplecpp to compare against.

Reproducing the comma regression:

// scratch/t2.c
#if (1, 0)
YES
#else
NO
#endif
$ gcc -E -P t2.c        -> NO   (only a -Wpedantic warning about the comma)
$ clang -E -P t2.c      -> NO
$ base/simplecpp t2.c   -> NO
$ pr/simplecpp t2.c     -> t2.c:1: syntax error: failed to evaluate #if condition, invalid expression

For #if 1 ? (2, 3) : 4, gcc and clang give YES, base gave NO, and the PR gives the same syntax error. For #if 1, 2, gcc gives YES (clang rejects it), and the PR gives the error.

Reproducing the not/compl problem (C++):

// scratch/a.cpp
#if 1 && not 0
YES
#else
NO
#endif
$ g++ -E -P a.cpp       -> YES
$ base/simplecpp a.cpp  -> NO
$ pr/simplecpp a.cpp    -> a.cpp:1: syntax error: failed to evaluate #if condition, invalid expression

1 and not 0, 1 or not 0, 1 and compl 0 and 1 bitand compl 0 fail the same way. not 0 and 1 and 1 and (not 0) work.

Other expressions tried: about 50 more expressions, compared with gcc. Ternaries, unary operators, defined, __has_include, character literals, true, __LINE__ and others give the same result as base. I also checked that #elif after a branch that was already taken isn't evaluated, so invalid expressions there don't raise the new error.


Automated review of 7fad448 by Claude. The pull request was built and tested locally.

Comment thread simplecpp.cpp Resolved
@danmar
danmar merged commit 70d7646 into master Nov 7, 2026
47 checks passed
@danmar
danmar deleted the fix-731 branch November 7, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants