diff --git a/ast/parser.vp b/ast/parser.vp index a37422b..4b5ffc4 100644 --- a/ast/parser.vp +++ b/ast/parser.vp @@ -2631,7 +2631,23 @@ def _parse_type_ann(ps: rawptr[Parser]) -> rawptr[AST]: # 与 const / volatile 同位置、同顺序自由、可混写;每个实参 desugar 成 # `t.attr.`(带调用则保留实参)后并入同一 markers 列表,由 # _PrependDescriptorMarkers 贴到类型联合最左(与 TPC 文本展开同形)。 - ac_node: rawptr[AST] = _parse_test(ps) + # + # ⚠ 只用 _parse_call 解析**这个调用本身**,绝不能用 _parse_test:后者是 + # 通用表达式解析器,解析完 `__attribute__(...)` 会继续吃 postfix trailer, + # 把紧随的 C 风格前置数组 `[]T` 的 `[]` 当作**合法空下标**吞掉 + # (_parse_slice 显式支持空下标 `T[]`,见其注释)——全程**零报错**, + # 但 ac_node 已不是 Call ⇒ 本循环 break、markers 一个都没收集,且 + # `_match_op(Lsqb)` 此时看到的是元素类型 ⇒ 数组分支被跳过 ⇒ 注解整体 + # 退化成裸元素类型。现场:main.vp:44 + # V_TPV_VERSION: __attribute__(section(".PRVERSN")) []char = "…" + # 被解析成 `char`(stub 记 `V_TPV_VERSION: char`、IR 出 + # `global i8 ` 非法、段名 ".PRVERSN" 丢失)。 + mka_lineno: int = _cur_lineno(ps) + mka_col: int = _cur_col(ps) + mka_fn: rawptr[AST] = Name(ps.pool, "__attribute__", ASTCtx.Load) + _set_pos(mka_fn, mka_lineno, mka_col, 0, 0) + _advance(ps) # 消费 `__attribute__` + ac_node: rawptr[AST] = _parse_call(ps, mka_fn) # 只解析 `( 实参表 )` if ac_node is None: break if ac_node.kind() != ASTKind.Call: