Repository navigation
Fix #716 (#if: && and || are evaluated with the same precedence) - #717
Conversation
'#if 1 || 1 && 0' was evaluated as '(1 || 1) && 0'. Fold && before ||.
69897c5 to
9ff6576
Compare
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
I found no new problems in this PR. && is now folded before ||, and when I compared #if expressions built only from numbers, parentheses, !, && and || against gcc, the results matched in every case. Among the expressions I fuzzed, there were no cases where base agreed with gcc and the PR did not.
One related bug is still there, but it was already in base and the PR does not touch it. simplifyName (simplecpp.cpp:2877-2890) replaces and/or with 0 when the next token is !, -, ~ or not, because isAlternativeBinaryOp only accepts a number, a name or ( after the operator. So #if 1 or 0 and !0 gives no output, while gcc keeps the line, and the alternative-token form of this PR's precedence case is still wrong there. It could be a follow-up.
The other differences from gcc that the fuzzing found also happen on base: chained </==, !!x | ..., and some nested ?: expressions.
The extra pass over the expression costs very little.
Testing
Build and test suites: make -j8 testrunner simplecpp CXXOPTS=-Werror built in pr/ without warnings. Results:
./testrunner: 0 failures.python3 run-tests.py: 176 tests, 0 failed.python3 -m pytest integration_test.py: 128 passed../selfcheck.sh: exit code 0.
I also built base/ to compare against.
Differential fuzzing: I generated random #if expressions (values 0/1/2, parentheses, !, &&, ||, ?:, and in some runs also == | + <), wrote one expression per file, and compared gcc -E -P with the pr and base simplecpp binaries:
- Only
&&,||,!and parentheses, 300 expressions: the PR had 0 mismatches, base had 22. - Adding
?:, 400 expressions: the PR had 13 mismatches, base had 28. - With
==and|as well, 400 expressions: the PR had 9 mismatches, base had 12. - With
== | + <as well, 300 expressions: the PR had 6 mismatches, base had 15.
In none of these runs was there a regression (a case where base matched gcc and the PR did not). The remaining mismatches also happen on base.
Bug that was already in base:
printf '#if 1 or 0 and !0\nY\n#endif\n' > a.cpp
/work/pr/simplecpp a.cpp # prints nothing (also on base)
gcc -E -P a.cpp # prints Y
The same happens with 0 and !0 or 1 and 0 and not 0 or 1. 0 and (!0) or 1 and 1 || 0 && !0 work. The cause is that simplifyName replaces and with 0 when ! follows it.
Automated review of 9ff6576 by Claude. The pull request was built and tested locally.
'#if 1 || 1 && 0' was evaluated as '(1 || 1) && 0'. Fold && before ||.