From 6d5f8092a78963794db3fbf41643aa25bfcbb5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sun, 7 Jun 2026 18:03:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20for=E5=BE=AA=E7=8E=AF=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E4=BD=9C=E7=94=A8=E5=9F=9F=20+=20=E5=88=97=E8=A1=A8=E6=8E=A8?= =?UTF-8?q?=E5=AF=BCcrash=20(=E4=B8=A4=E4=B8=AA=E5=B7=B2=E7=9F=A5bug)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1 - For循环变量作用域: - AST_BLOCK 在 sema 中未创建子作用域 → 连续 for 循环用同名变量报"重复定义" - 修复: sema AST_BLOCK 创建 block_scope (scope_new) - 修复: codegen AST_BLOCK 保存/恢复 var_table 实现块级变量隔离 Bug 2 - 列表推导 >2元素 crash: - sema 对 TYPE_ARRAY 标注跳过 init 分析 → 列表推导表达式未被semantize - 导致 codegen 处 element_type=0, array_size=0 → LLVM alloca 崩溃 - 修复: 仅自引用 (= 变量名) 跳过分析,列表推导等正常分析 - 修复: cg_list_comp 使用 to_llvm_type(elem) 而非 type_info_to_llvm(full_array) Co-Authored-By: Claude Opus 4.7 --- src/codegen/cg_expr.c | 5 +++-- src/codegen/codegen.c | 4 +++- src/sema/sema.c | 12 +++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/codegen/cg_expr.c b/src/codegen/cg_expr.c index bbe08bc..6b6e95e 100644 --- a/src/codegen/cg_expr.c +++ b/src/codegen/cg_expr.c @@ -476,8 +476,9 @@ static AstDispatch cg_dispatch; static LLVMValueRef cg_list_comp_impl(CgCtx* ctx, AstNode* node) { TypeInfo* ti = &node->type; - LLVMTypeRef elem_ty = type_info_to_llvm(ctx, ti); - LLVMTypeRef arr_ty = LLVMArrayType(elem_ty, (unsigned)ti->array_size); + LLVMTypeRef elem_ty = to_llvm_type(ctx, ti->element_type); + LLVMTypeRef arr_ty = LLVMArrayType(elem_ty, + ti->array_size > 0 ? (unsigned)ti->array_size : 1); LLVMValueRef result = LLVMBuildAlloca(ctx->builder, arr_ty, "list"); // 初始化为零 LLVMBuildStore(ctx->builder, LLVMConstNull(arr_ty), result); diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 8b68e7d..ff307c6 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -205,10 +205,12 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) { case AST_BLOCK: { if (++codegen_depth > MAX_CODEGEN_DEPTH) { codegen_depth--; return; } size_t block_mark = ctx->cleanup_count; + VarEntry* saved_table = ctx->var_table; for (size_t i = 0; i < node->as.block.stmt_count; i++) { codegen_stmt(ctx, node->as.block.stmts[i]); } - cleanup_emit(ctx, block_mark); // 作用域退出: 释放块内 str 堆分配 + ctx->var_table = saved_table; + cleanup_emit(ctx, block_mark); codegen_depth--; break; } diff --git a/src/sema/sema.c b/src/sema/sema.c index 1a0b76a..b7e58f1 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -223,9 +223,10 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) { break; } - case AST_BLOCK: + case AST_BLOCK: { + Scope* block_scope = scope_new(a, scope); for (size_t i = 0; i < node->as.block.stmt_count; i++) { - analyze_node(node->as.block.stmts[i], scope, errors, a); + analyze_node(node->as.block.stmts[i], block_scope, errors, a); } // 表达式作为值: 块类型 = 最后一条产生值的语句类型 if (node->as.block.stmt_count > 0) { @@ -245,6 +246,7 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) { } } break; + } case AST_LET_STMT: { TypeKind var_type; @@ -253,9 +255,13 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) { if (node->as.let_stmt.has_type_annot) { if (node->as.let_stmt.annot_type == TYPE_ARRAY) { - // 数组类型标注: 跳过 init 分析 (init 是自引用的占位符) is_array_type = true; var_type = TYPE_ARRAY; + // 分析 init — 除非是自引用 (如 let a: i64[3] = a;) + bool self_ref = (node->as.let_stmt.init->kind == AST_IDENT_EXPR + && strcmp(node->as.let_stmt.init->as.ident.name, + node->as.let_stmt.name) == 0); + if (!self_ref) analyze_expr(node->as.let_stmt.init, scope, errors, a); } else { analyze_expr(node->as.let_stmt.init, scope, errors, a); TypeKind inferred = node->as.let_stmt.init->type.kind;