From fc091fd23b53a285be452c84ddacf0d8a5ca6a65 Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Fri, 17 Apr 2026 00:37:05 +0100 Subject: [PATCH] synq: fix stale body_call_length==0 doc for arg-internal sentinel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The public header, internal header, and session.rs test comment all claimed the arg-internal case was signalled by `body_call_length == 0`, but the implementation sets both `body_call_offset` and `body_call_length` to `SYNTAQLITE_MACRO_BODY_CALL_ARG_INTERNAL` (UINT32_MAX) — and that is what the public sentinel macro documents at parser.h:236. Downstream consumers (e.g. google/perfetto#5472) that trusted the stale comment ended up pushing UINT32_MAX offsets into their rewriter and crashing on overflow. Pure doc fix — no behavior change. --- syntaqlite-syntax/csrc/parser_internal.h | 9 +++++---- syntaqlite-syntax/include/syntaqlite/parser.h | 7 ++++--- syntaqlite-syntax/src/parser/session.rs | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/syntaqlite-syntax/csrc/parser_internal.h b/syntaqlite-syntax/csrc/parser_internal.h index 2c421370..ff64cf27 100644 --- a/syntaqlite-syntax/csrc/parser_internal.h +++ b/syntaqlite-syntax/csrc/parser_internal.h @@ -102,10 +102,11 @@ typedef struct SynqExpansionLayer { // Position of this nested call in the *parent's authored body*, // computed by inverting the length shifts from the parent's $param - // substitutions. body_call_length == 0 means the call was tokenized - // from a substituted arg's text (no clean body position) and consumers - // should descend through the matching arg segment instead. Zero for - // top-level layers (parent_layer_id == 0). + // substitutions. Both fields equal SYNTAQLITE_MACRO_BODY_CALL_ARG_INTERNAL + // (UINT32_MAX) when the call was tokenized from a substituted arg's + // text (no clean body position) and consumers should descend through + // the matching arg segment instead. Zero for top-level layers + // (parent_layer_id == 0). uint32_t body_call_offset; uint32_t body_call_length; diff --git a/syntaqlite-syntax/include/syntaqlite/parser.h b/syntaqlite-syntax/include/syntaqlite/parser.h index 397d76ca..14f8ccb5 100644 --- a/syntaqlite-syntax/include/syntaqlite/parser.h +++ b/syntaqlite-syntax/include/syntaqlite/parser.h @@ -278,9 +278,10 @@ typedef struct SyntaqliteMacroRewrite { uint32_t def_col; // Position of this call in the *parent's authored body*, computed by // inverting the length shifts the parent's $param substitutions - // introduced. body_call_length == 0 means the call was tokenized - // from a substituted arg's text (no meaningful body position) and - // consumers should descend through the matching arg segment instead. + // introduced. Both fields equal SYNTAQLITE_MACRO_BODY_CALL_ARG_INTERNAL + // (UINT32_MAX) when the call was tokenized from a substituted arg's + // text (no meaningful body position) and consumers should descend + // through the matching arg segment instead. // // For top-level rewrites (parent_idx == SYNTAQLITE_MACRO_PARENT_SOURCE) // the parent is the authored source, so these equal call_offset / diff --git a/syntaqlite-syntax/src/parser/session.rs b/syntaqlite-syntax/src/parser/session.rs index f5d7c0aa..888877de 100644 --- a/syntaqlite-syntax/src/parser/session.rs +++ b/syntaqlite-syntax/src/parser/session.rs @@ -1030,7 +1030,8 @@ mod tests { // // The inner n!(...) call is tokenized from the substituted text // of m's $x, not from m's authored body — downstream Rewriter - // consumers need body_call_length == 0 to signal "descend via + // consumers need the arg-internal sentinel (u32::MAX on both + // body_call_offset and body_call_length) to signal "descend via // arg segments" instead of "rewrite in the parent's body". let mut parser = Parser::with_config(&ParserConfig::default().with_macro_fallback(true)); let mut reg = TestMacroRegistry::new();