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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user