From 0efdc9e1115764d4839a4113680f8ee965557af3 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 2 Oct 2026 22:07:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(expr):=20=E6=95=B4=E5=9E=8B=E4=B8=8E=20None?= =?UTF-8?q?=20=E6=AF=94=E8=BE=83=E7=BB=9F=E4=B8=80=E6=8C=89=20=3D=3D=200?= =?UTF-8?q?=20/=20!=3D=200=20=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HandlesExprOps.py:is / is not / == / != 遇整型与 None 比较时直接与 0 比较, 避免把 i8 当作空指针 load;检查置于类型对齐与指针分支之前 - README.md:同步引用 wiki 第 12 章(12-compilation-system.md) --- README.md | 4 ++-- lib/core/Handles/HandlesExprOps.py | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 33942d0..1e3811d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Viper 语言通过两个核心模块提供类型和操作支持: ## 快速上手 1. **环境**:Python 3.12+、LLVM(llc/clang)、Windows(当前主平台) -2. **构建项目**:在项目目录运行 `python ../Projectrans.py build`(详见 [wiki/12-project.md](wiki/12-project.md)) +2. **构建项目**:在项目目录运行 `python ../Projectrans.py build`(详见 [wiki/12-compilation-system.md](wiki/12-compilation-system.md)) 3. **示例**:参考 [Test/](Test/) 下 30+ 测试项目(AstTest/ZlibTest/NoVTableTest/LLvmLiteTest 等) 4. **写第一个程序**: @@ -72,5 +72,5 @@ def main() -> CInt | CExport: | [09-exceptions.md](wiki/09-exceptions.md) | 异常处理 | | [10-imports.md](wiki/10-imports.md) | 模块与导入系统(存根生成、SHA1 命名空间与导入) | | [11-builtins.md](wiki/11-builtins.md) | 内置函数与运算符 | -| [12-project.md](wiki/12-project.md) | 项目配置与构建(增量编译、SHA1 映射) | +| [12-compilation-system.md](wiki/12-compilation-system.md) | 编译系统(流水线、工程配置 `project.vpj`、`viperbuild` 元编程) | | [13-bootstrapping.md](wiki/13-bootstrapping.md) | 自举可行性分析(当前进展、剩余工作、路径规划) | diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index 956677a..a46eeee 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -397,19 +397,27 @@ class ExprOpsHandle(BaseHandle): } result: bool = cmp_map.get(ComparatorSymbol, False) return ir.Constant(ir.IntType(1), 1 if result else 0) - # is / is not: 值类型(IntType)与 None(空指针常量)比较 - # 值类型(如 i8/i32)永远不可能为 None,因此: - # - 值类型 is None → 恒为 false (i1 0) - # - 值类型 is not None → 恒为 true (i1 1) - # 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃 - if ComparatorSymbol in ('is', 'is not'): + # is / is not / == / != : 整数与 None(空指针常量)比较 + # 整数上的 None 隐式表示 0 ⇒ `x is None` / `x == None` 等价 `x == 0`, + # `x is not None` / `x != None` 等价 `x != 0`(与 TPV 的 ExprGenOps 统一) + # 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃; + # 也必须在下方"指针 vs 整型"特例分支之前,否则 i8 会命中 `Gen._load(null)` + if ComparatorSymbol in ('is', 'is not', '==', '!='): LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType) RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType) LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType) RightIsValueType: bool = isinstance(RightVal.type, ir.IntType) - if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr): - IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0 - return ir.Constant(ir.IntType(1), IsNotResult) + IsNoneNegated: bool = ComparatorSymbol in ('is not', '!=') + if LeftIsValueType and RightIsNullPtr: + IsNoneCmpL: ir.Value = Gen.builder.icmp_signed('==', LeftVal, ir.Constant(LeftVal.type, 0), name="is_none_int") + if IsNoneNegated: + IsNoneCmpL = Gen.builder.not_(IsNoneCmpL, name="is_not_result") + return IsNoneCmpL + if RightIsValueType and LeftIsNullPtr: + IsNoneCmpR: ir.Value = Gen.builder.icmp_signed('==', RightVal, ir.Constant(RightVal.type, 0), name="is_none_int") + if IsNoneNegated: + IsNoneCmpR = Gen.builder.not_(IsNoneCmpR, name="is_not_result") + return IsNoneCmpR if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): if LeftVal.type.width < RightVal.type.width: # 如果宽类型常量值超出窄类型有符号范围,则必须用zext