sema: handle dead comptime branches in zirFieldPtr/zirCall/zirOptionalPayload

Port upstream Zig behavior for dead comptime branches: when the C sema
evaluates branches that the Zig compiler's comptime evaluator would skip,
return void values instead of crashing. Also add enum_literal fallback
in zirDeclLiteralComptime matching upstream's resolveTypeOrPoison path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 22:07:52 +00:00
parent 12cb9899aa
commit 44afa2ea43

View File

@@ -8807,6 +8807,13 @@ static AirInstRef zirCall(
}
if (func_inst == UINT32_MAX) {
// Dead comptime branch: the callee reference chain resolved to void
// because a prior instruction in this dead branch returned a
// placeholder. In upstream Zig, dead branches are never evaluated.
// Return void to continue past the dead path.
if (block->is_comptime) {
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
UNIMPLEMENTED("zirCall: cannot resolve callee");
}
@@ -10651,6 +10658,15 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) {
}
}
if (struct_ty == IP_INDEX_VOID_TYPE) {
// Dead comptime branch: the pointer operand resolved to a non-pointer
// type (e.g. void). In upstream Zig, fieldPtr checks
// object_ptr_ty.zigTypeTag == .pointer and fails otherwise. In the
// upstream comptime evaluator, dead branches are never evaluated, so
// this case never arises. Our C sema evaluates all branches, so we
// return a harmless void value for the dead path.
if (block->is_comptime) {
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
UNIMPLEMENTED("zirFieldPtr: unresolved struct type");
}
@@ -10920,7 +10936,17 @@ static AirInstRef zirDeclLiteralComptime(Sema* sema, uint32_t inst) {
}
}
UNIMPLEMENTED("zirDeclLiteralComptime: field lookup failed");
// Ported from Sema.zig zirDeclLiteral: if resolveTypeOrPoison returns
// null (LHS cannot be coerced to type → generic_poison), treat the
// field name as an enum_literal. This handles dead comptime branches
// where the LHS resolved to a non-type value (e.g. void).
{
InternPoolKey elkey;
memset(&elkey, 0, sizeof(elkey));
elkey.tag = IP_KEY_ENUM_LITERAL;
elkey.data.enum_literal = ipGetOrPutString(sema->ip, field_name);
return AIR_REF_FROM_IP(ipIntern(sema->ip, elkey));
}
}
// --- mergesAppend ---
@@ -12679,6 +12705,11 @@ static AirInstRef zirOptionalPayload(
// Get the optional child type.
InternPoolKey ty_key = sema->ip->items[operand_ty];
if (ty_key.tag != IP_KEY_OPT_TYPE) {
// Dead comptime branch: operand resolved to a non-optional value
// (e.g. void). Upstream Zig doesn't evaluate dead branches.
if (block->is_comptime) {
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
SEMA_FAIL("expected optional type");
}
InternPoolIndex child_type = ty_key.data.opt_type;