Skip to content

Fix preprocessor infinite loop with self-referencing object-like macros - #109

Merged
praeclarum merged 2 commits into
masterfrom
copilot/fix-infinite-loop-macro
Mar 31, 2026
Merged

Fix preprocessor infinite loop with self-referencing object-like macros#109
praeclarum merged 2 commits into
masterfrom
copilot/fix-infinite-loop-macro

Conversation

Copilot AI commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

#define FOO FOO causes the preprocessor to loop forever. The non-parameterized macro expansion path lacked the recursion guard that the parameterized path already had.

Changes

  • CLanguage/Parser/Preprocessor.cs: Apply the same expansion pattern used for parameterized macros to object-like macros: pre-process the body with the macro's own name removed from defines, then advance i past the inserted tokens. anotherIterationNeeded is not set since the inner loop already handles chain expansion.

  • CLanguageTests/PreprocessorTests.cs: Add tests for self-referencing defines (#define FOO FOO), mutual recursion (#define A B / #define B A), chain expansion (#define X Y / #define Y 42), and self-reference in expressions.

Before/after

// Before: blindly re-inserts body, outer loop retries forever
tokens.RemoveAt(i);
tokens.InsertRange(i, define.Body);

// After: expand body with self-reference removed, skip past result
var newBody = define.Body.ToList();
var newDefines = new Dictionary<string, Define>(defines);
newDefines.Remove(define.Name);
while (PreprocessIteration(newDefines, include, newBody, report)) { }
tokens.RemoveAt(i);
tokens.InsertRange(i, newBody);
i += newBody.Count;

Apply recursion guard to non-parameterized macro expansion path:
- Pre-process body with macro name removed from defines (prevents self-recursion)
- Advance index past inserted body tokens (prevents re-expansion in same iteration)
- Don't set anotherIterationNeeded since inner loop handles chain expansion

This matches the recursion guard pattern already used for parameterized macros.
Per C standard §6.10.3.4, a macro's own name found during expansion is not re-expanded.

Agent-Logs-Url: https://github.com/praeclarum/CLanguage/sessions/81cfde6c-7cda-4f58-88b2-4e64e91a3ac2

Co-authored-by: praeclarum <323548+praeclarum@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix preprocessor infinite loop with self-referencing macros Fix preprocessor infinite loop with self-referencing object-like macros Mar 31, 2026
Copilot AI requested a review from praeclarum March 31, 2026 20:12
@praeclarum
praeclarum marked this pull request as ready for review March 31, 2026 20:24
@praeclarum
praeclarum merged commit 7940f64 into master Mar 31, 2026
1 check passed
@praeclarum
praeclarum deleted the copilot/fix-infinite-loop-macro branch March 31, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preprocessor infinite loop with self-referencing object-like macros

2 participants