Repository navigation
Conversation
When the left operand of ## is a punctuator, check the pasted result after the right operand has been expanded, instead of checking the unexpanded parameter name.
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
The PR fixes #724: -##>, cat(<<,=), cat3(<,<,=), cat(+,), +##__VA_ARGS__ and similar pastes now give the same result as gcc and clang. I found one regression that matters for cppcheck.
Regression: a punctuator pasted with a macro parameter used to be accepted without an error when the result was not a valid token. It is now a hard syntax error. The base version only threw unexpectedToken for unexpectedA in the varargs case and in the non-parameter case. The non-variadic parameter path accepted it. MSVC accepts obj->##m and obj.##m, and these patterns appear in Windows code. With this PR cppcheck reports failed to expand and does not preprocess the file. gcc and clang also reject these pastes, so the new behaviour is "correct". But it is a compatibility change that the PR does not mention, and no test covers it. Other inputs that now fail where base produced output: cat(.,x), cat3(.,.,.), cat(.,.5), F('a') with . ## x, and (##x) with a parameter x.
I found no other wrong results.
Testing
Build and test suites
- Built
make -j8 testrunner simplecpp CXXOPTS=-Werrorin pr/ with no warnings. Also built base/. ./testrunner: no failures.python3 run-tests.py: 176 tests, 0 failed. base gives the same result.python3 -m pytest integration_test.py: 128 passed../selfcheck.sh: exit code 0.
Own inputs
I wrote about 40 small inputs in /work/scratch and compared gcc -E, clang -E, base and pr.
The PR now matches gcc for:
F(x) -##xwithF(>),F(> y)andF()cat3(<,<,=)cat(+,)+##__VA_ARGS__cat(<,:),cat(#,#),cat(:,:),cat(=,=),cat(<, <=).##1.5e+3and.##1a- the GNU
, ## argsand, ## __VA_ARGS__forms (empty and non-empty) [a##b]with an emptya
Invalid pastes that gcc rejects are also rejected now: -##>>, +##+=, -##"x" and +##PP.
Regression (reproduced)
m1.c:
#define GET(obj, m) obj->##m
#define GET2(obj, m) obj.##m
int a = GET(p, x) + GET2(s, y);$ /work/base/simplecpp m1.c
int a = p ->x + s .y ;
$ /work/pr/simplecpp m1.c
m1.c:1: syntax error: failed to expand 'GET', Invalid ## usage when expanding 'GET': Combining '->' and 'x' yields an invalid token.
gcc and clang report an error for this input, but MSVC accepts it. The same change from output to error happens for:
| Input | base output | pr |
|---|---|---|
cat(.,x) |
.x |
error |
cat3(.,.,.) |
... |
error |
cat(.,.5) |
..5 |
error |
#define F(x) (##x with F(a) |
(a ) |
error |
Minor
cat(%:,%:) with digraphs gives %:%: with gcc. base gave the wrong output % :% :. pr gives the error Combining ':' and '%', because simplecpp splits %: into two tokens.
Automated review of f2d2413 by Claude. The pull request was built and tested locally.
When the left operand of ## is a punctuator, check the pasted result after the right operand has been expanded, instead of checking the unexpanded parameter name.