@@ -272,9 +272,8 @@ void LexerState::clear(uint32_t lineNo_) {
272272 capturing = false ;
273273 captureBuf = nullptr ;
274274
275- disableMacroArgs = false ;
276- disableInterpolation = false ;
277- macroArgScanDistance = 0 ;
275+ disableExpansions = false ;
276+ expansionScanDistance = 0 ;
278277 expandStrings = true ;
279278
280279 expansions.clear ();
@@ -517,13 +516,10 @@ static int nextChar();
517516static uint32_t readDecimalNumber (int initial);
518517
519518static uint32_t readBracketedMacroArgNum () {
520- bool disableMacroArgs = lexerState->disableMacroArgs ;
521- bool disableInterpolation = lexerState->disableInterpolation ;
522- lexerState->disableMacroArgs = false ;
523- lexerState->disableInterpolation = false ;
519+ bool disableExpansions = lexerState->disableExpansions ;
520+ lexerState->disableExpansions = false ;
524521 Defer restoreExpansions{[&] {
525- lexerState->disableMacroArgs = disableMacroArgs;
526- lexerState->disableInterpolation = disableInterpolation;
522+ lexerState->disableExpansions = disableExpansions;
527523 }};
528524
529525 int32_t num = 0 ;
@@ -713,15 +709,17 @@ static std::shared_ptr<std::string> readInterpolation(size_t depth);
713709static int peek () {
714710 int c = lexerState->peekChar ();
715711
716- if (lexerState->macroArgScanDistance > 0 ) {
712+ if (lexerState->expansionScanDistance > 0 ) {
717713 return c;
718714 }
719715
720- ++lexerState->macroArgScanDistance ; // Do not consider again
716+ ++lexerState->expansionScanDistance ; // Do not consider again
721717
722- if (c == ' \\ ' && !lexerState->disableMacroArgs ) {
718+ if (lexerState->disableExpansions ) {
719+ return c;
720+ } else if (c == ' \\ ' ) {
723721 // If character is a backslash, check for a macro arg
724- ++lexerState->macroArgScanDistance ;
722+ ++lexerState->expansionScanDistance ;
725723 if (!isMacroChar (lexerState->peekCharAhead ())) {
726724 return c;
727725 }
@@ -734,11 +732,11 @@ static int peek() {
734732 // Mark the entire macro arg expansion as "painted blue"
735733 // so that macro args can't be recursive
736734 // https://en.wikipedia.org/wiki/Painted_blue
737- lexerState->macroArgScanDistance += str->length ();
735+ lexerState->expansionScanDistance += str->length ();
738736 }
739737
740738 return peek (); // Tail recursion
741- } else if (c == ' {' && !lexerState-> disableInterpolation ) {
739+ } else if (c == ' {' ) {
742740 // If character is an open brace, do symbol interpolation
743741 shiftChar ();
744742 if (std::shared_ptr<std::string> str = readInterpolation (0 ); str) {
@@ -759,7 +757,7 @@ static void shiftChar() {
759757 ++lexerState->captureSize ;
760758 }
761759
762- --lexerState->macroArgScanDistance ;
760+ --lexerState->expansionScanDistance ;
763761
764762 for (;;) {
765763 if (!lexerState->expansions .empty ()) {
@@ -811,11 +809,9 @@ static void handleCRLF(int c) {
811809}
812810
813811static auto scopedDisableExpansions () {
814- lexerState->disableMacroArgs = true ;
815- lexerState->disableInterpolation = true ;
812+ lexerState->disableExpansions = true ;
816813 return Defer{[&] {
817- lexerState->disableMacroArgs = false ;
818- lexerState->disableInterpolation = false ;
814+ lexerState->disableExpansions = false ;
819815 }};
820816}
821817
@@ -1217,21 +1213,19 @@ static std::shared_ptr<std::string> readInterpolation(size_t depth) {
12171213 std::string fmtBuf;
12181214 FormatSpec fmt{};
12191215
1220- // In a context where `lexerState->disableInterpolation` is true, `peek` will expand
1221- // nested interpolations itself, which can lead to stack overflow. This lets
1222- // `readInterpolation` handle its own nested expansions, increasing `depth` each time.
1223- bool disableInterpolation = lexerState->disableInterpolation ;
1224- lexerState->disableInterpolation = true ;
1225-
1226- // Reset `lexerState->disableInterpolation` when exiting this loop
1227- for (Defer reset{[&] { lexerState->disableInterpolation = disableInterpolation; }};;) {
1228- if (int c = peek (); c == ' {' ) { // Nested interpolation
1216+ for (;;) {
1217+ // If `lexerState->disableExpansions` is false, `peek()` will expand nested interpolations
1218+ // and recursively call `readInterpolation()`, which can cause stack overflow.
1219+ // `lexerState->peekChar()` lets `readInterpolation()` handle its own nested expansions,
1220+ // increasing `depth` each time.
1221+ if (lexerState->peekChar () == ' {' ) {
1222+ ++lexerState->expansionScanDistance ; // Prevent `shiftChar()` from calling `peek()`
12291223 shiftChar ();
12301224 if (std::shared_ptr<std::string> str = readInterpolation (depth + 1 ); str) {
12311225 beginExpansion (str, *str);
12321226 }
12331227 continue ; // Restart, reading from the new buffer
1234- } else if (c == EOF || c == ' \r ' || c == ' \n ' || c == ' "' ) {
1228+ } else if (int c = peek (); c == EOF || c == ' \r ' || c == ' \n ' || c == ' "' ) {
12351229 error (" Missing }" );
12361230 break ;
12371231 } else if (c == ' }' ) {
@@ -1329,12 +1323,11 @@ static void appendCharInLiteral(std::string &str, int c) {
13291323 // Symbol interpolation
13301324 if (c == ' {' ) {
13311325 // We'll be exiting the string/character scope, so re-enable expansions
1332- // (Not interpolations, since they're handled by the function itself...)
1333- lexerState->disableMacroArgs = false ;
1326+ lexerState->disableExpansions = false ;
13341327 if (std::shared_ptr<std::string> interpolation = readInterpolation (0 ); interpolation) {
13351328 appendExpandedString (str, *interpolation);
13361329 }
1337- lexerState->disableMacroArgs = true ;
1330+ lexerState->disableExpansions = true ;
13381331 return ;
13391332 }
13401333
0 commit comments