diff --git a/stage0/astgen.c b/stage0/astgen.c index 288b2ac01c..4342bd7a38 100644 --- a/stage0/astgen.c +++ b/stage0/astgen.c @@ -1089,6 +1089,54 @@ static void strLitAsString(AstGenCtx* ag, uint32_t str_lit_token, ag->string_bytes[ag->string_bytes_len++] = val; break; } + case 'u': { + // \u{NNNNNN} unicode escape (string_literal.zig:194-231). + // Skip past '{'. + i++; + // Parse hex digits until '}'. + uint32_t codepoint = 0; + while (i + 1 < raw_end) { + i++; + char c = source[i]; + if (c >= '0' && c <= '9') { + codepoint = codepoint * 16 + (uint32_t)(c - '0'); + } else if (c >= 'a' && c <= 'f') { + codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'a'); + } else if (c >= 'A' && c <= 'F') { + codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'A'); + } else { + // Must be '}', done. + break; + } + } + // Encode codepoint as UTF-8 (unicode.zig:53-82). + if (codepoint <= 0x7F) { + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)codepoint; + } else if (codepoint <= 0x7FF) { + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0xC0 | (codepoint >> 6)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | (codepoint & 0x3F)); + } else if (codepoint <= 0xFFFF) { + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0xE0 | (codepoint >> 12)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | ((codepoint >> 6) & 0x3F)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | (codepoint & 0x3F)); + } else { + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0xF0 | (codepoint >> 18)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | ((codepoint >> 12) & 0x3F)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | ((codepoint >> 6) & 0x3F)); + ag->string_bytes[ag->string_bytes_len++] + = (uint8_t)(0x80 | (codepoint & 0x3F)); + } + break; + } default: ag->string_bytes[ag->string_bytes_len++] = (uint8_t)source[i]; break; @@ -4251,6 +4299,26 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { char_val = val; break; } + case 'u': { + // \u{NNNNNN} unicode escape (string_literal.zig:194-231). + // Skip past '{'. + ci++; + uint32_t codepoint = 0; + while (true) { + ci++; + char c = src[ci]; + if (c >= '0' && c <= '9') + codepoint = codepoint * 16 + (uint32_t)(c - '0'); + else if (c >= 'a' && c <= 'f') + codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'a'); + else if (c >= 'A' && c <= 'F') + codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'A'); + else + break; // Must be '}'. + } + char_val = codepoint; + break; + } default: char_val = (uint8_t)src[ci]; break; @@ -4762,7 +4830,7 @@ static uint32_t blockExprExpr( } // Labeled block (AstGen.zig:2466-2536). - bool force_comptime = gz->is_comptime; + // Note: upstream blockExpr always passes force_comptime=false. uint32_t label_token = lbrace - 2; // Compute break result info (AstGen.zig:2484-2492). @@ -4771,15 +4839,10 @@ static uint32_t blockExprExpr( bool need_result_rvalue = (break_ri.tag != rl.tag); // Reserve the block instruction (AstGen.zig:2500-2501). - ZirInstTag block_tag - = force_comptime ? ZIR_INST_BLOCK_COMPTIME : ZIR_INST_BLOCK; - uint32_t block_inst = makeBlockInst(ag, block_tag, gz, node); + uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); gzAppendInstruction(gz, block_inst); GenZir block_scope = makeSubBlock(gz, scope); - block_scope.is_inline = force_comptime; // AstGen.zig:2503 - if (force_comptime) - block_scope.is_comptime = true; // Set label on block_scope (AstGen.zig:2504-2508). block_scope.label_token = label_token; block_scope.label_block_inst = block_inst; @@ -4790,29 +4853,19 @@ static uint32_t blockExprExpr( if (!endsWithNoReturn(&block_scope)) { // Emit restore_err_ret_index (AstGen.zig:2515). - if (!force_comptime) { - ZirInstData rdata; - rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX; - rdata.un_node.src_node - = (int32_t)node - (int32_t)gz->decl_node_index; - addInstruction( - gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); - } + ZirInstData rdata; + rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX; + rdata.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; + addInstruction( + gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); // rvalue + break (AstGen.zig:2516-2518). uint32_t result = rvalue( gz, block_scope.break_result_info, ZIR_REF_VOID_VALUE, node); - ZirInstTag break_tag - = force_comptime ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK; - addBreak( - &block_scope, break_tag, block_inst, result, AST_NODE_OFFSET_NONE); + addBreak(&block_scope, ZIR_INST_BREAK, block_inst, result, + AST_NODE_OFFSET_NONE); } - if (force_comptime) { - setBlockComptimeBody( - ag, &block_scope, block_inst, COMPTIME_REASON_COMPTIME_KEYWORD); - } else { - setBlockBody(ag, &block_scope, block_inst); - } + setBlockBody(ag, &block_scope, block_inst); // AstGen.zig:2531-2534. if (need_result_rvalue) @@ -6575,17 +6628,23 @@ static bool addEnsureResult( uint32_t inst = maybe_unused_result - ZIR_REF_START_INDEX; ZirInstTag tag = ag->inst_tags[inst]; switch (tag) { - // For call/field_call/builtin_call: set ensure_result_used flag - // (bit 3 of flags at offset 0). Flags *must* be at offset 0 in all - // three structs (AstGen.zig:2658-2665, Zir.zig:3022). + // For call/field_call: set ensure_result_used flag + // (bit 3 of flags at offset 0). Flags *must* be at offset 0 + // (AstGen.zig:2658-2665, Zir.zig:3022). case ZIR_INST_CALL: - case ZIR_INST_FIELD_CALL: - case ZIR_INST_BUILTIN_CALL: { + case ZIR_INST_FIELD_CALL: { uint32_t pi = ag->inst_datas[inst].pl_node.payload_index; ag->extra[pi] |= (1u << 3); // ensure_result_used elide_check = true; break; } + // For builtin_call: ensure_result_used is at bit 1, not bit 3. + case ZIR_INST_BUILTIN_CALL: { + uint32_t pi = ag->inst_datas[inst].pl_node.payload_index; + ag->extra[pi] |= (1u << 1); // ensure_result_used + elide_check = true; + break; + } // Always noreturn → elide (AstGen.zig:2909). case ZIR_INST_BREAK: case ZIR_INST_BREAK_INLINE: @@ -6602,6 +6661,7 @@ static bool addEnsureResult( case ZIR_INST_TRAP: case ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW: case ZIR_INST_SWITCH_CONTINUE: + case ZIR_INST_COMPILE_ERROR: is_noreturn = true; elide_check = true; break; @@ -9577,7 +9637,7 @@ static bool rlExpr( // defer (AstRlAnnotate.zig:148-151). case AST_NODE_DEFER: - (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); + (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); return false; // container_field (AstRlAnnotate.zig:153-167). diff --git a/stage0/parser.c b/stage0/parser.c index 1aeca2ade5..19c5f63d00 100644 --- a/stage0/parser.c +++ b/stage0/parser.c @@ -711,7 +711,7 @@ static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { const AstTokenIndex comptime_token = eatToken(p, TOKEN_KEYWORD_COMPTIME); if (comptime_token != null_token) { // comptime followed by block => comptime block statement - const AstNodeIndex block = parseBlock(p); + const AstNodeIndex block = parseBlockExpr(p); if (block != 0) { return addNode(&p->nodes, (AstNodeItem) { @@ -1728,8 +1728,7 @@ static AstNodeIndex parseTypeExpr(Parser* p) { const AstNodeIndex condition = expectExpr(p); expectToken(p, TOKEN_R_PAREN); parsePtrPayload(p); - const AstNodeIndex cont_expr - = eatToken(p, TOKEN_COLON) != null_token ? expectExpr(p) : 0; + const AstNodeIndex cont_expr = parseWhileContinueExpr(p); const AstNodeIndex body = parseTypeExpr(p); if (eatToken(p, TOKEN_KEYWORD_ELSE) != null_token) { parsePayload(p);