astgen: add anyframe handlers, fix switch err capture tracking

- Add AST_NODE_ANYFRAME_LITERAL and AST_NODE_ANYFRAME_TYPE handlers
  in exprRl, matching upstream AstGen.zig:1008-1016.
- Fix error capture usage detection in switchExprErrUnion: replace
  broken instruction-scanning heuristic with proper scope tracking
  via is_used_or_discarded field on ScopeLocalVal. This fixes 42
  missing dbg_var_val emissions in switch_on_captured_error.zig.
- Remove temporary debug output (fprintf, stdio.h).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 22:04:10 +00:00
parent 7eb8459981
commit cdd9968359

View File

@@ -111,7 +111,9 @@ typedef struct {
bool fn_var_args; // AstGen.zig:46
} AstGenCtx;
#define SET_ERROR(ag) (ag)->has_compile_errors = true
#define SET_ERROR(ag) do { \
(ag)->has_compile_errors = true; \
} while(0)
// Set fn_block pointer on AstGenCtx. The caller is responsible for saving
// and restoring the previous value before the pointed-to GenZir goes out
@@ -2924,9 +2926,12 @@ static uint32_t comptimeExpr(
case AST_NODE_MULTILINE_STRING_LITERAL:
case AST_NODE_ENUM_LITERAL:
case AST_NODE_ERROR_VALUE:
case AST_NODE_ANYFRAME_LITERAL:
case AST_NODE_ERROR_SET_DECL:
// Type expressions that force comptime eval of sub-expressions
// (AstGen.zig:2017-2042).
case AST_NODE_ERROR_UNION:
case AST_NODE_ANYFRAME_TYPE:
case AST_NODE_MERGE_ERROR_SETS:
case AST_NODE_OPTIONAL_TYPE:
case AST_NODE_PTR_TYPE_ALIGNED:
@@ -7544,6 +7549,19 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
return rvalue(gz, rl,
addStrTok(gz, ZIR_INST_ERROR_VALUE, str, error_token), node);
}
// anyframe_literal (AstGen.zig:1008-1011).
case AST_NODE_ANYFRAME_LITERAL: {
uint32_t result = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE,
ZIR_REF_VOID_TYPE, node);
return rvalue(gz, rl, result, node);
}
// anyframe_type (AstGen.zig:1012-1016).
case AST_NODE_ANYFRAME_TYPE: {
uint32_t return_type = typeExpr(gz, scope, nd.rhs);
uint32_t result = addUnNode(gz, ZIR_INST_ANYFRAME_TYPE,
return_type, node);
return rvalue(gz, rl, result, node);
}
// error_set_decl (AstGen.zig:5905-5955).
case AST_NODE_ERROR_SET_DECL: {
AstData esd = ag->tree->nodes.datas[node];
@@ -9455,6 +9473,7 @@ static uint32_t switchExprErrUnion(GenZir* parent_gz, Scope* scope,
memset(&err_scope, 0, sizeof(err_scope));
memset(&capture_scope_val, 0, sizeof(capture_scope_val));
bool err_scope_used = false;
err_scope = (ScopeLocalVal) {
.base = { .tag = SCOPE_LOCAL_VAL },
.parent = &case_scope.base,
@@ -9462,6 +9481,7 @@ static uint32_t switchExprErrUnion(GenZir* parent_gz, Scope* scope,
.inst = err_inst + ZIR_REF_START_INDEX,
.token_src = error_payload,
.name = err_name,
.is_used_or_discarded = &err_scope_used,
};
Scope* sub_scope = &err_scope.base;
@@ -9556,26 +9576,9 @@ static uint32_t switchExprErrUnion(GenZir* parent_gz, Scope* scope,
block_scope.break_result_info, body_node);
// Track err capture usage (AstGen.zig:7489-7494).
// The upstream tracks scope usage via used/discarded fields.
// We approximate: err capture is "used" if the err_scope was
// found during identifier lookup (i.e., the err name was
// referenced in the body). Since we don't track scope usage
// in C, we check if any instruction in the body references
// the err_inst placeholder.
bool uses_err = false;
{
uint32_t rbl = gzInstructionsLen(&case_scope);
const uint32_t* rbody = gzInstructionsSlice(&case_scope);
for (uint32_t bi = 0; bi < rbl; bi++) {
uint32_t inst = rbody[bi];
// Check if any instruction data references err_inst.
ZirInstData d = ag->inst_datas[inst];
if (d.un_node.operand == err_inst + ZIR_REF_START_INDEX) {
uses_err = true;
break;
}
}
}
// Uses scope tracking: is_used_or_discarded on err_scope is set
// to true during identifier lookup when the err name is resolved.
bool uses_err = err_scope_used;
if (uses_err) {
addDbgVar(&case_scope, ZIR_INST_DBG_VAR_VAL, err_name,
err_inst + ZIR_REF_START_INDEX);