Comment by david2ndaccount

10 hours ago

During translation of source text to a C program, the source text goes through several phases. It turns raw bytes into preprocessor tokens, then preprocessor tokens get expanded into more preprocessor tokens and then preprocessor tokens get translated into C tokens, which are fed into the C parser. There is no “expanded text”, only expanded tokens. Generally this is implemented as a state machine that produces tokens on demand, so there is no expanded text. When GCC shows you that error message, it uses the recorded source location and looks it up in the original source file. This is trivial to do. Expanding just one line of the source file would either require re-invoking the preprocessor from the beginning or storing already consumed preprocessor tokens.

Obviously this is possible, but no one has gotten around to implementing this feature and it’s not clear you would want either solution: buffering preprocessor tokens in case you need to expand a line for an error message greatly increases memory usage and the vast majority of compilations are successful ones with no errors, slowing down the normal case. And re-invoking the preprocessor to show you one line on every error message makes error reporting slow.

> There is no “expanded text”, only expanded tokens.

If the compiler supports "-E", there absolutely is some equivalent of the expanded text, with (somewhat limited) whitespace info available: if you insert whitespace into between "b" and the comma in "b,", then "-E" invocation will dutifully show it. Yes, multiple spaces are collapsed into one, but their presence/absence is tracked already.

> Expanding just one line of the source file would either require re-invoking the preprocessor from the beginning or storing already consumed preprocessor tokens.

Yeah, keep the whole expansion of the latest top-level (not nested) macro. I believe some bytecode-like compression scheme (a replay of that state machine you mentioned) à la LZ would work fairly well, with minor additional memory necessary. Hell, scratch that: since #define/#undef are impossible inside a macro, you don't even need to remember the expansion of the macro, you simply need to keep the current macro definitions and remember what was the last macro you tried to expand — if your error happened inside its expansion, just re-expand again. Zero additional memory needed, since this information is already stored for the current way of error reporting — you can see in the current output that it remembers what macros it expanded and where, the whole path down to the offending token: at 1:21 "in expansion of macro 'W'" which was at 2:18 "in expansion of macro 'X'" which was at 5:13.

> And re-invoking the preprocessor to show you one line on every error message makes error reporting slow.

Eh, it's on the whole faster than making the programmer re-run with "-E" option manually.

  • > If the compiler supports "-E", there absolutely is some equivalent of the expanded text, with (somewhat limited) whitespace info available: if you insert whitespace into between "b" and the comma in "b,", then "-E" invocation will dutifully show it. Yes, multiple spaces are collapsed into one, but their presence/absence is tracked already.

    Whitespace is significant in the preprocessor so of course it tracks whitespace. Whitespace isn’t dropped until phase 7 when pp-tokens are converted to C tokens.

    As I said it’s not impossible, write the patch and see if GCC accepts it.

    • Also the position in the original source code is tracked.

      In fact, this enhancement should be doable. Please file a bug. But the answer why something is not done in a C compiler is usually: Nobody did substantial investments on it in the last two decades. So if you want to see improvements, usually one has to submit a patch.