diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 3689896..1c87c96 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -1781,10 +1781,13 @@ class StmtGenCifMixin: if arr_v2 is not None: return self._handle_array_iter(trans, for_node, var_name, arr_v2) - # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) + # 元素类型决定"空值"判定(用户语义:解引用后为空即终止): + # 整数 → ==0;指针(如 i8** 遍历的元素 i8*)→ ==null;浮点 → ==0.0 elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty) - if elem_bits == 0: - self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") + elem_is_ptr2: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty) + elem_fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty) + if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0: + self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数/指针/浮点,无法检查空终止符") i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) @@ -1822,15 +1825,26 @@ class StmtGenCifMixin: # 跳转到 cond llvmlite.build_br(builder, cond_bb) - # cond 块: load index, GEP, load elem, icmp eq 0 + # cond 块: load index, GEP, load elem, 空值判定(整数==0 / 指针==null / 浮点==0.0) llvmlite.position_at_end(builder, cond_bb) cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( builder, elem_ty, ptr_val, cur_idx) cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) - null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) - is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, cur_elem, null_val) + is_null: llvmlite.Value | t.CPtr = None + if elem_is_ptr2 != 0: + null_p: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, elem_ty, "null") + if null_p is not None: + is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_p) + elif elem_fbits2 != 0: + zero_f2: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, elem_ty, 0.0) + if zero_f2 is not None: + is_null = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_f2) + else: + null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) + is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_val) + if is_null is None: + is_null = llvmlite.const_int(pool, 1, 0) llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) # body 块: store elem to var, 翻译循环体 @@ -1947,6 +1961,9 @@ class StmtGenCifMixin: viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "arr.elem.%d", cnt) + elem_check_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt) body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) @@ -1958,19 +1975,46 @@ class StmtGenCifMixin: llvmlite.build_br(builder, cond_bb) - # cond 块: load index, icmp slt idx, elem_count + # cond 块: 先查越界(idx < count,越界时不能 GEP+load 判空) llvmlite.position_at_end(builder, cond_bb) cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count) in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + llvmlite.build_cond_br(builder, in_bounds, elem_check_bb, end_bb) - # body 块: GEP(0, idx) → load elem → store to var → 循环体 - llvmlite.position_at_end(builder, body_bb) + # elem_check 块: GEP(0, idx) → load elem → 空值判定(NULL 终止) + # 用户语义:整数/指针/浮点元素按"解引用为空"提前终止(如 split 尾哨兵 + # 的 str 数组),同时保留长度上限防越界读;聚合元素只按长度迭代。 + llvmlite.position_at_end(builder, elem_check_bb) elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( builder, arr_ty, elem_ty, arr_tmp, cur_idx) cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + elem_bits_a: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty) + elem_ptr_a: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty) + elem_fbits_a: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty) + if elem_bits_a != 0 or elem_ptr_a != 0 or elem_fbits_a != 0: + is_empty_a: llvmlite.Value | t.CPtr = None + if elem_ptr_a != 0: + null_ap: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, elem_ty, "null") + if null_ap is not None: + is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_ap) + elif elem_fbits_a != 0: + zero_af: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, elem_ty, 0.0) + if zero_af is not None: + is_empty_a = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_af) + else: + zero_ai: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits_a, 0) + is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, zero_ai) + if is_empty_a is not None: + llvmlite.build_cond_br(builder, is_empty_a, end_bb, body_bb) + else: + llvmlite.build_br(builder, body_bb) + else: + llvmlite.build_br(builder, body_bb) + + # body 块: store elem to var → 循环体 + llvmlite.position_at_end(builder, body_bb) llvmlite.build_store(builder, cur_elem, var_alloca) old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb