Repository navigation
Fix #718 (# operator drops the space that a comment stands for) - #719
Conversation
'str(a/**/b)' gave "ab" instead of "a b". When comments are removed, mark the previous token as followed by whitespace.
da98bf2 to
2e16061
Compare
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
The PR fixes the reported case, but it breaks stringification when a macro body ends with a comment. In removeComments() a trailing comment in a #define now sets whitespaceahead on the last token of the macro body. expandArg (simplecpp.cpp:2392) passes that flag on to the expansion, so # inserts a space that gcc and clang don't produce:
#define MAJOR 1/*major*/
#define MINOR 2/*minor*/
xstr(MAJOR.MINOR)gives "1 .2" with the PR. Base, gcc and clang all give "1.2". The same bug already exists in base when there is a real space before the end of the body (#define E3(x) x /**/ gives "a b" where gcc gives "ab"). The PR spreads it to all trailing comments that have no space before them. A trailing comment in a #define is common code, so this is a real regression. Whitespace at the end of a replacement list should not count for stringification. No other problems found.
Testing
Build and test suites
make -j8 testrunner simplecpp CXXOPTS=-Werrorin pr/ built cleanly../testrunner: 0 failed.python3 run-tests.py: 176 tests, 0 failed.pytest integration_test.py: 128 passed../selfcheck.sh: exit 0.
I also built base/ and compared /work/{pr,base}/simplecpp with gcc -E -P and clang -E -P.
Cases that now match gcc (base got them wrong):
str(a/**/b)- a block comment that spans lines inside the argument
str(a/**/+/**/b)gives"a + b"str("x"/**/'y')- a comment inside the macro body:
#define F(x) str(x/**/y) xstr(H())with#define H() a/**/bxstr(E(a)/**/b)
These already matched gcc in base and still do: str(/**/a), str(a/**/), xstr(CAT(a,/**/b)).
Regression: macro body that ends with a comment
scratch/t4.c:
#define str(x) #x
#define xstr(x) str(x)
#define MAJOR 1/*major*/
#define MINOR 2/*minor*/
xstr(MAJOR.MINOR)$ /work/pr/simplecpp t4.c -> "1 .2"
$ /work/base/simplecpp t4.c -> "1.2"
$ gcc -E -P t4.c -> "1.2" (clang: "1.2")
More cases (scratch/t3.c), with #define E(x) x/**/, #define E2 a/**/, #define P(x) (x)/**/:
| input | PR | base | gcc / clang |
|---|---|---|---|
xstr(E(a)b) |
"a b" |
"ab" |
"ab" |
xstr(E2;) |
"a ;" |
"a;" |
"a;" |
xstr(P(a)b) |
"(a) b" |
"(a)b" |
"(a)b" |
The same bug already exists in base with an explicit space: #define E3(x) x /**/ then xstr(E3(a)b) gives "a b" in both pr and base, and "ab" in gcc.
Automated review of 2e16061 by Claude. The pull request was built and tested locally.
…fying The last token of an expansion got whitespaceahead from the newline or comment after the replacement list. Use the whitespace after the macro call instead. 'xstr(MAJOR.MINOR)' with '#define MAJOR 1/*major*/' now gives "1.2", and 'xstr(F(a)b)' gives "ab".
'str(a/**/b)' gave "ab" instead of "a b". When comments are removed, mark the previous token as followed by whitespace.