@ могут заставить rustc жрать десятки гигабайт памяти.Автор копался в macro expansion и заметил, что парсер declarative macros в
rustc ведёт себя как упрощённый Earley parser: он одновременно держит несколько возможных вариантов разбора макроса.Обычно это нормально.
Но если сделать макрос с вложенными повторениями, количество промежуточных вариантов начинает резко расти. Формально ожидался кубический рост, но в тесте всё выглядело ещё хуже.
Результат:
- валидный Rust-код
- всего несколько десятков токенов
@- компиляция на
n = 41 заняла около 80 секунд- пиковая память дошла до 44 ГБ
Самое интересное: код не использует сложные выражения, типы или гигантские зависимости. Только macro_rules и фиксированные токены.
Главная мысль не в том, что «Rust сломан».
Главная мысль в другом: макросы в Rust - это почти отдельный язык внутри языка, и даже маленький паттерн может внезапно превратиться в тяжёлую задачу для компилятора.
Автор предлагает смотреть в сторону packrat-подхода с memoization, где состояние парсинга можно кэшировать и гарантировать линейное число шагов по
input.len() * arm.len().Красивый пример того, как в системном языке проблемы иногда прячутся не в unsafe, не в borrow checker и не в LLVM.
А в маленьком macro_rules, который выглядит безобидно.
Хорошее чтиво на выходные 🦀
bal-e.org/blog/2026/oops-cubic-macro/
