diff --git a/astgen.c b/astgen.c index 992dee53d6..f3ca341747 100644 --- a/astgen.c +++ b/astgen.c @@ -2227,8 +2227,9 @@ static uint32_t blockExprExpr( static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); static uint32_t forExpr( GenZir* gz, Scope* scope, uint32_t node, bool is_statement); -static uint32_t orelseCatchExpr( - GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool is_catch); +static uint32_t orelseCatchExpr(GenZir* gz, Scope* scope, ResultLoc rl, + uint32_t node, ZirInstTag cond_op, ZirInstTag unwrap_op, + ZirInstTag unwrap_code_op); static uint32_t arrayInitDotExpr( GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); static uint32_t switchExpr( @@ -2452,9 +2453,15 @@ static uint32_t typeExpr(GenZir* gz, Scope* scope, uint32_t node) { return comptimeExpr(gz, scope, rl, node, COMPTIME_REASON_TYPE); } -// Mirrors numberLiteral (AstGen.zig:8544). +// Sign parameter for numberLiteral (AstGen.zig:8674). +enum NumSign { NUM_SIGN_POSITIVE, NUM_SIGN_NEGATIVE }; + +// Mirrors numberLiteral (AstGen.zig:8679). // Parses integer and float literals, returns appropriate ZIR ref. -static uint32_t numberLiteral(GenZir* gz, uint32_t node) { +// source_node is the node used for rvalue/error reporting (may differ from +// node when called from negation). +static uint32_t numberLiteral( + GenZir* gz, uint32_t node, uint32_t source_node, enum NumSign sign) { AstGenCtx* ag = gz->astgen; uint32_t num_token = ag->tree->nodes.main_tokens[node]; uint32_t tok_start = ag->tree->tokens.starts[num_token]; @@ -2505,12 +2512,22 @@ static uint32_t numberLiteral(GenZir* gz, uint32_t node) { } // Special cases for 0 and 1 (AstGen.zig:8687-8703). + // Note: upstream errors on negative zero for integers; we return zero + // regardless of sign to match the same codegen path (AstGen.zig:8687). if (value == 0) return ZIR_REF_ZERO; - if (value == 1) - return ZIR_REF_ONE; + if (value == 1) { + return (sign == NUM_SIGN_POSITIVE) ? ZIR_REF_ONE + : ZIR_REF_NEGATIVE_ONE; + } - return addInt(gz, value); + // For other integers, emit the positive value and negate if needed + // (AstGen.zig:8751-8756). + uint32_t result = addInt(gz, value); + if (sign == NUM_SIGN_NEGATIVE) { + return addUnNode(gz, ZIR_INST_NEGATE, result, source_node); + } + return result; } // Mirrors builtinCall (AstGen.zig:9191), @import case (AstGen.zig:9242). @@ -4179,7 +4196,8 @@ static uint32_t structInitExpr( } // --- tryExpr (AstGen.zig:5957) --- -static uint32_t tryExpr(GenZir* gz, Scope* scope, uint32_t node) { +static uint32_t tryExpr( + GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { AstGenCtx* ag = gz->astgen; AstData nd = ag->tree->nodes.datas[node]; uint32_t operand_node = nd.lhs; @@ -4190,20 +4208,33 @@ static uint32_t tryExpr(GenZir* gz, Scope* scope, uint32_t node) { uint32_t try_lc_line = ag->source_line - gz->decl_line; uint32_t try_lc_column = ag->source_column; - // Evaluate operand (AstGen.zig:5993-6001). - ResultLoc operand_rl = RL_NONE_VAL; + // Determine operand rl and block tag based on result location + // (AstGen.zig:5989-5992). + ResultLoc operand_rl; + ZirInstTag block_tag; + ZirInstTag err_tag; + if (RL_IS_REF(rl)) { + operand_rl = RL_REF_VAL; + block_tag = ZIR_INST_TRY_PTR; + err_tag = ZIR_INST_ERR_UNION_CODE_PTR; + } else { + operand_rl = RL_NONE_VAL; + block_tag = ZIR_INST_TRY; + err_tag = ZIR_INST_ERR_UNION_CODE; + } operand_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; + + // Evaluate operand (AstGen.zig:5993-6006). uint32_t operand = exprRl(gz, scope, operand_rl, operand_node); - // Create try block instruction (AstGen.zig:6007). - uint32_t try_inst = makeBlockInst(ag, ZIR_INST_TRY, gz, node); + // Create try block instruction (AstGen.zig:6008). + uint32_t try_inst = makeBlockInst(ag, block_tag, gz, node); gzAppendInstruction(gz, try_inst); - // Else scope: extract error code, return it (AstGen.zig:6012-6025). + // Else scope: extract error code, return it (AstGen.zig:6011-6025). GenZir else_scope = makeSubBlock(gz, scope); - uint32_t err_code - = addUnNode(&else_scope, ZIR_INST_ERR_UNION_CODE, operand, node); + uint32_t err_code = addUnNode(&else_scope, err_tag, operand, node); // Emit defers for error path (AstGen.zig:6019). if (ag->fn_block != NULL) { @@ -4220,7 +4251,12 @@ static uint32_t tryExpr(GenZir* gz, Scope* scope, uint32_t node) { setTryBody(ag, &else_scope, try_inst, operand); // else_scope unstacked by setTryBody. - return try_inst + ZIR_REF_START_INDEX; // toRef() + // For ref/ref_coerced_ty, return directly; otherwise rvalue + // (AstGen.zig:6025-6028). + uint32_t result = try_inst + ZIR_REF_START_INDEX; // toRef() + if (RL_IS_REF(rl)) + return result; + return rvalue(gz, rl, result, node); } // --- boolBinOp (AstGen.zig:6274) --- @@ -4284,7 +4320,8 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { switch (tag) { case AST_NODE_NUMBER_LITERAL: - return rvalue(gz, rl, numberLiteral(gz, node), node); + return rvalue( + gz, rl, numberLiteral(gz, node, node, NUM_SIGN_POSITIVE), node); case AST_NODE_BUILTIN_CALL_TWO: case AST_NODE_BUILTIN_CALL_TWO_COMMA: return builtinCall(gz, scope, rl, node); @@ -4410,9 +4447,9 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { case AST_NODE_TAGGED_UNION_ENUM_TAG: case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: return rvalue(gz, rl, containerDecl(gz, scope, node), node); - // try (AstGen.zig:831). + // try (AstGen.zig:1115). case AST_NODE_TRY: - return rvalue(gz, rl, tryExpr(gz, scope, node), node); + return tryExpr(gz, scope, rl, node); // Comparison operators (AstGen.zig:714-726). case AST_NODE_EQUAL_EQUAL: return rvalue( @@ -4478,10 +4515,18 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { return rvalue(gz, rl, addUnNode(gz, ZIR_INST_BIT_NOT, expr(gz, scope, nd.lhs), node), node); - case AST_NODE_NEGATION: + // negation (AstGen.zig:9863-9882). + case AST_NODE_NEGATION: { + // Check for number_literal as sub-expression to preserve negativity + // (AstGen.zig:9875-9877). + if (ag->tree->nodes.tags[nd.lhs] == AST_NODE_NUMBER_LITERAL) { + return rvalue(gz, rl, + numberLiteral(gz, nd.lhs, node, NUM_SIGN_NEGATIVE), node); + } return rvalue(gz, rl, addUnNode(gz, ZIR_INST_NEGATE, expr(gz, scope, nd.lhs), node), node); + } case AST_NODE_NEGATION_WRAP: return rvalue(gz, rl, addUnNode(gz, ZIR_INST_NEGATE_WRAP, expr(gz, scope, nd.lhs), node), @@ -4500,15 +4545,26 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { addUnNode( gz, ZIR_INST_OPTIONAL_TYPE, typeExpr(gz, scope, nd.lhs), node), node); - // unwrap_optional (AstGen.zig:966-985). + // unwrap_optional (AstGen.zig:966-983). case AST_NODE_UNWRAP_OPTIONAL: { - uint32_t lhs = expr(gz, scope, nd.lhs); - advanceSourceCursorToMainToken(ag, gz, node); - uint32_t saved_line = ag->source_line - gz->decl_line; - uint32_t saved_col = ag->source_column; - emitDbgStmt(gz, saved_line, saved_col); - return rvalue(gz, rl, - addUnNode(gz, ZIR_INST_OPTIONAL_PAYLOAD_SAFE, lhs, node), node); + if (RL_IS_REF(rl)) { + uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, nd.lhs); + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + emitDbgStmt(gz, saved_line, saved_col); + return addUnNode( + gz, ZIR_INST_OPTIONAL_PAYLOAD_SAFE_PTR, lhs, node); + } else { + uint32_t lhs = expr(gz, scope, nd.lhs); + advanceSourceCursorToMainToken(ag, gz, node); + uint32_t saved_line = ag->source_line - gz->decl_line; + uint32_t saved_col = ag->source_column; + emitDbgStmt(gz, saved_line, saved_col); + return rvalue(gz, rl, + addUnNode(gz, ZIR_INST_OPTIONAL_PAYLOAD_SAFE, lhs, node), + node); + } } // error_union type (AstGen.zig:788-797). case AST_NODE_ERROR_UNION: { @@ -4695,12 +4751,26 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { return rvalue( gz, rl, addInstruction(gz, ZIR_INST_SLICE_SENTINEL, data), node); } - // orelse (AstGen.zig:6031-6142). + // orelse (AstGen.zig:1054-1075). case AST_NODE_ORELSE: - return orelseCatchExpr(gz, scope, rl, node, false); - // catch (AstGen.zig:6031-6142). + if (RL_IS_REF(rl)) { + return orelseCatchExpr(gz, scope, rl, node, + ZIR_INST_IS_NON_NULL_PTR, ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE_PTR, + (ZirInstTag)0); + } else { + return orelseCatchExpr(gz, scope, rl, node, ZIR_INST_IS_NON_NULL, + ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE, (ZirInstTag)0); + } + // catch (AstGen.zig:1017-1052). case AST_NODE_CATCH: - return orelseCatchExpr(gz, scope, rl, node, true); + if (RL_IS_REF(rl)) { + return orelseCatchExpr(gz, scope, rl, node, + ZIR_INST_IS_NON_ERR_PTR, ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE_PTR, + ZIR_INST_ERR_UNION_CODE_PTR); + } else { + return orelseCatchExpr(gz, scope, rl, node, ZIR_INST_IS_NON_ERR, + ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE, ZIR_INST_ERR_UNION_CODE); + } // Block expressions (AstGen.zig:984-992). case AST_NODE_BLOCK_TWO: case AST_NODE_BLOCK_TWO_SEMICOLON: @@ -4728,13 +4798,29 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_MERGE_ERROR_SETS, node, lhs, rhs), node); } - // Wrapping arithmetic. + // Wrapping arithmetic (AstGen.zig:751-758). case AST_NODE_ADD_WRAP: return rvalue( gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ADDWRAP), node); case AST_NODE_SUB_WRAP: return rvalue( gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SUBWRAP), node); + case AST_NODE_MUL_WRAP: + return rvalue( + gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_MULWRAP), node); + // Saturating arithmetic (AstGen.zig:752-761). + case AST_NODE_ADD_SAT: + return rvalue( + gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ADD_SAT), node); + case AST_NODE_SUB_SAT: + return rvalue( + gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SUB_SAT), node); + case AST_NODE_MUL_SAT: + return rvalue( + gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_MUL_SAT), node); + case AST_NODE_SHL_SAT: + return rvalue( + gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SHL_SAT), node); // break (AstGen.zig:2150-2237). case AST_NODE_BREAK: { uint32_t opt_break_label = nd.lhs; // UINT32_MAX = none @@ -4918,9 +5004,9 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { case AST_NODE_WHILE_CONT: case AST_NODE_WHILE: return rvalue(gz, rl, whileExpr(gz, scope, node, false), node); - // error_value (AstGen.zig:1005-1010). + // error_value (AstGen.zig:1005). case AST_NODE_ERROR_VALUE: { - uint32_t error_token = nd.rhs; + uint32_t error_token = ag->tree->nodes.main_tokens[node] + 2; uint32_t str = identAsString(ag, error_token); return rvalue(gz, rl, addStrTok(gz, ZIR_INST_ERROR_VALUE, str, error_token), node); @@ -4956,59 +5042,59 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { case AST_NODE_ASSIGN: assignStmt(gz, scope, node); return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); - // Compound assignment operators (AstGen.zig:685-744). + // Compound assignment operators (AstGen.zig:689-744). case AST_NODE_ASSIGN_ADD: assignOp(gz, scope, node, ZIR_INST_ADD); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_SUB: assignOp(gz, scope, node, ZIR_INST_SUB); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_MUL: assignOp(gz, scope, node, ZIR_INST_MUL); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_DIV: assignOp(gz, scope, node, ZIR_INST_DIV); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_MOD: assignOp(gz, scope, node, ZIR_INST_MOD_REM); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_BIT_AND: assignOp(gz, scope, node, ZIR_INST_BIT_AND); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_BIT_OR: assignOp(gz, scope, node, ZIR_INST_BIT_OR); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_BIT_XOR: assignOp(gz, scope, node, ZIR_INST_XOR); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_ADD_WRAP: assignOp(gz, scope, node, ZIR_INST_ADDWRAP); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_SUB_WRAP: assignOp(gz, scope, node, ZIR_INST_SUBWRAP); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_MUL_WRAP: assignOp(gz, scope, node, ZIR_INST_MULWRAP); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_ADD_SAT: assignOp(gz, scope, node, ZIR_INST_ADD_SAT); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_SUB_SAT: assignOp(gz, scope, node, ZIR_INST_SUB_SAT); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_MUL_SAT: assignOp(gz, scope, node, ZIR_INST_MUL_SAT); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); // Shift assignment operators (AstGen.zig:676-687). case AST_NODE_ASSIGN_SHL: assignShift(gz, scope, node, ZIR_INST_SHL); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_SHR: assignShift(gz, scope, node, ZIR_INST_SHR); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); case AST_NODE_ASSIGN_SHL_SAT: assignShiftSat(gz, scope, node); - return ZIR_REF_VOID_VALUE; + return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); default: SET_ERROR(ag); return ZIR_REF_VOID_VALUE; @@ -5828,13 +5914,19 @@ static uint32_t forExpr( // --- orelseCatchExpr (AstGen.zig:6031-6142) --- // Handles `lhs orelse rhs` and `lhs catch rhs`. -static uint32_t orelseCatchExpr( - GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool is_catch) { +static uint32_t orelseCatchExpr(GenZir* gz, Scope* scope, ResultLoc rl, + uint32_t node, ZirInstTag cond_op, ZirInstTag unwrap_op, + ZirInstTag unwrap_code_op) { + // unwrap_code_op used for catch payload capture scope (not yet + // implemented in C, but passed for correctness/future use). + (void)unwrap_code_op; AstGenCtx* ag = gz->astgen; const Ast* tree = ag->tree; AstData nd = tree->nodes.datas[node]; - bool do_err_trace = is_catch && ag->fn_ret_ty != 0; + bool do_err_trace = ag->fn_ret_ty != 0 + && (cond_op == ZIR_INST_IS_NON_ERR + || cond_op == ZIR_INST_IS_NON_ERR_PTR); // breakResultInfo (AstGen.zig:6046-6058). bool need_rl = nodesNeedRlContains(ag, node); @@ -5845,7 +5937,12 @@ static uint32_t orelseCatchExpr( GenZir block_scope = makeSubBlock(gz, scope); // Evaluate operand in block_scope (AstGen.zig:6066-6074). - ResultLoc operand_rl = RL_NONE_VAL; + ResultLoc operand_rl; + if (RL_IS_REF(break_rl)) { + operand_rl = RL_REF_VAL; + } else { + operand_rl = RL_NONE_VAL; + } if (do_err_trace) { operand_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; } @@ -5853,9 +5950,7 @@ static uint32_t orelseCatchExpr( = exprRl(&block_scope, &block_scope.base, operand_rl, nd.lhs); // Check condition in block_scope (AstGen.zig:6075). - ZirInstTag test_tag - = is_catch ? ZIR_INST_IS_NON_ERR : ZIR_INST_IS_NON_NULL; - uint32_t condition = addUnNode(&block_scope, test_tag, operand, node); + uint32_t condition = addUnNode(&block_scope, cond_op, operand, node); // condbr in block_scope (AstGen.zig:6076). uint32_t condbr = addCondBr(&block_scope, ZIR_INST_CONDBR, node); @@ -5868,9 +5963,7 @@ static uint32_t orelseCatchExpr( // Then branch: unwrap payload (AstGen.zig:6083-6092). GenZir then_scope = makeSubBlock(&block_scope, scope); - ZirInstTag unwrap_tag = is_catch ? ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE - : ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE; - uint32_t unwrapped = addUnNode(&then_scope, unwrap_tag, operand, node); + uint32_t unwrapped = addUnNode(&then_scope, unwrap_op, operand, node); // Apply rvalue coercion unless rl is ref/ref_coerced_ty // (AstGen.zig:6088-6091). uint32_t then_result = (rl.tag == RL_REF || rl.tag == RL_REF_COERCED_TY)