feat(gen): volatile 构造写入落 LLVM volatile(逐字段 store + 构造三方法屏障)

值位置 volatile 前缀(a: int = volatile f() / a: S = volatile S(...))此前只在调用点无落点。LLVM 的 call 指令没有 volatile 限定符,故语义只能落在内存存取上:

- AssignGenMixin:赋值目标的结果槽按 volatile 存取(本次 store 立即带 volatile,并登记 VarEntry.IsVolatile 使后续 load/store 亦带);对已存在的 global/nonlocal/mod_glob 条目在分支前统一登记。

- CallGenCtor:_translate_struct_ctor / _translate_struct_ctor_kw / _translate_renum_construct / _apply_struct_defaults 增加 is_volatile 参数,清零、tag、默认值、逐字段 store 全部带 volatile;_translate_generic_ctor_call 直接从 cl.IsVolatile 取。

- CallGenCall._call_method_on_ptr 增加 is_volatile 参数:__new__/__before_init__/__init__ 的写入发生在被调函数内部,调用点无法逐条附加 volatile,故在调用后对该 self 指针追加一次 i8 volatile load 作为内存屏障,使构造写入不被优化器消除或跨越重排。

- CallGenMixin / CallGenDispatch:结构体、关键字、泛型、REnum 构造调用点统一透传 cl.IsVolatile。
This commit is contained in:
TermiNexus committed 2026-09-27 12:01:22 +08:00
1 parent 7d28c9649e
commit cf815b17de
5 files changed
+104 -39

No files matched your search

+21
View File
@@ -2167,6 +2167,18 @@ novirtual class AssignGenMixin:
if self.Gen.CallGenLeafKit.register_func_ptr_sig(pool, nm.id, callable_ret, aa) != 0:
return 0
# 值位置 volatile 调用前缀:`a: int = volatile f()` / `a: S = volatile S(...)`
# ⇒ 结果槽按 volatile 存取(下述三条"条目已先存在"的分支——global /
# nonlocal / mod_glob——在此统一登记,使各分支读取 var_is_volatile 时已置位)。
# 函数内**新声明**的局部变量此刻条目尚未建立,由主分支(alloca 就绪后)登记。
# LLVM 的 call 无 volatile 限定符,故语义落在内存存取上:本次 store 带
# volatile,且此后该变量的 load/store 亦带,避免这次调用/构造的往返访问
# 被优化器消除或提升。
if aa.value is not None and aa.value.kind() == ast.ASTKind.Call \
and (ast.Call*(aa.value)).IsVolatile != 0 and nm.id is not None:
if self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) is not None:
self.Gen.VarGen.set_var_volatile(trans.SymTab, nm.id)
# global 变量:写入模块作用域中的全局变量
if GenApi.is_global_name(trans, nm.id) != 0:
mod_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id)
@@ -2565,6 +2577,15 @@ novirtual class AssignGenMixin:
# PointeeVolatile;本 store 写的是指针变量自身,不影响。
if self.Gen.TypeGenErr.has_pointee_volatile_marker(aa.annotation) != 0:
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, nm.id)
# 值位置 volatile 调用前缀:`a: int = volatile f()` /
# `a: S = volatile S(...)`——LLVM 的 call 指令没有 volatile
# 限定符,故语义落在内存存取上:结果槽按 volatile 存取
# (本次 store 立即带 volatile,且此后该变量的 load/store 也带),
# 使"这次调用/构造的往返内存访问"不会被优化器消除或提升。
if aa.value is not None and aa.value.kind() == ast.ASTKind.Call \
and (ast.Call*(aa.value)).IsVolatile != 0:
self.Gen.VarGen.set_var_volatile(trans.SymTab, nm.id)
vol_laa = 1
llvmlite.build_store(builder, rhs_val, alloca, vol_laa)
# FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针
# (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__)
+27 -3
View File
@@ -206,11 +206,16 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
extra_args: sizet*,
extra_count: int,
trans: HT.Translator*,
node: ast.AST* = None) -> llvmlite.Value*:
node: ast.AST* = None,
is_volatile: int = 0) -> llvmlite.Value*:
"""在结构体指针上调用方法,返回 call 结果(void 方法返回 None)
node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error
准确报告出错行号(传 None 时行号显示 0,不利于定位)。"""
准确报告出错行号(传 None 时行号显示 0,不利于定位)。
is_volatile: 值位置 volatile 构造前缀(`a: T = volatile S(...)`)——LLVM
的 call 指令没有 volatile 限定符,故仅对构造三方法(__new__/
__before_init__/__init__)在调用后追加一次 volatile 内存屏障,
使被调函数内部对对象内存的写入不可被优化器消除/跨越。"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None:
@@ -632,7 +637,26 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
head = self.Gen.CallGenLib._coerce_args_to_def_params(pool, builder, call_name, head, total_count, None, 1, trans)
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
call_res_cmop: llvmlite.Value* = llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# 值位置 volatile 构造:call 指令本身无 volatile 限定符,构造语义只能落在
# 内存存取上。逐字段 store 已由调用方(_translate_struct_ctor 等)带 volatile;
# __new__/__before_init__/__init__ 的写入发生在被调函数内部,调用点无法逐条
# 附加 volatile ⇒ 此处追加一次 volatile 屏障(对 self 指针做 i8 volatile load)。
# volatile 访问有副作用:不会被 DCE,且禁止优化器假设其前后内存不变,从而
# 保证本次构造对对象内存的写入不可被消除或跨越重排。仅对构造三方法生效,
# 不给普通方法调用引入额外访存。
if is_volatile != 0 and self_ptr is not None and self_ptr.Ty is not None:
if string.strcmp(method_name, "__new__") == 0 \
or string.strcmp(method_name, "__before_init__") == 0 \
or string.strcmp(method_name, "__init__") == 0:
cmop_i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
cmop_i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, cmop_i8_ty)
cmop_bar_ptr: llvmlite.Value* = self_ptr
if uint64(self_ptr.Ty) != uint64(cmop_i8_ptr_ty):
cmop_bar_ptr = llvmlite.build_bitcast(builder, self_ptr, cmop_i8_ptr_ty)
if cmop_bar_ptr is not None:
llvmlite.build_load(builder, cmop_i8_ty, cmop_bar_ptr, 1)
return call_res_cmop
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)
#
+48 -28
View File
@@ -33,8 +33,12 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
struct_ty: llvmlite.LLVMType*,
class_name: str,
tmp: llvmlite.Value*,
trans: HT.Translator*):
"""应用结构体字段的默认值"""
trans: HT.Translator*,
is_volatile: int = 0):
"""应用结构体字段的默认值
is_volatile=1:`volatile S(...)` 构造——默认值写入也带 LLVM volatile
(构造期对对象内存的写入整体不可被优化器消除/提升)。"""
# 用类型指针定位 entry,规避跨模块同名 find_struct 找错
entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
if entry is None:
@@ -58,7 +62,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if field_ptr_arr2 is not None:
zero_arr2: llvmlite.Value* = llvmlite.ConstZero(pool, fe.Ty)
if zero_arr2 is not None:
llvmlite.build_store(builder, zero_arr2, field_ptr_arr2)
llvmlite.build_store(builder, zero_arr2, field_ptr_arr2, is_volatile)
# owner_ctx 只服务空元素 fail-fast 报文(类名 + 字段名 + 下标)
sd_ctx: str = pool.alloc(192)
if sd_ctx is not None:
@@ -79,7 +83,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
VLogger.error(f"字段 GEP 失败,类型不匹配: {class_name}", "HandlesExprCall")
continue
default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal)
llvmlite.build_store(builder, default_val, field_ptr)
llvmlite.build_store(builder, default_val, field_ptr, is_volatile)
# ============================================================
# _translate_struct_ctor — 结构体构造函数 Point(10, 20)
#
@@ -101,11 +105,17 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
class_name: str,
cargs: list[ast.AST*]*,
can: sizet,
trans: HT.Translator*) -> llvmlite.Value*:
trans: HT.Translator*,
is_volatile: int = 0) -> llvmlite.Value*:
"""结构体构造函数:按字段顺序 store 参数值,返回结构体值
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
普通结构体:alloca → zero + defaults → store 参数 → load
is_volatile=1:`volatile S(...)` 构造——本次构造对对象内存的所有写入
(zero/默认值/逐字段 store)带 LLVM volatile,且 __new__/__before_init__/
__init__ 调用后追加一次 volatile 屏障(见 _call_method_on_ptr),
使构造过程整体不可被优化器消除或提升。
"""
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
@@ -173,7 +183,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
new_arg_vals[new_arg_count] = sizet(new_av)
new_arg_count += 1
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct, is_volatile)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -190,7 +200,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
storage_ptr = nw_bc
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,"__before_init__", storage_ptr, None, 0, trans, diag_node_ct)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,"__before_init__", storage_ptr, None, 0, trans, diag_node_ct, is_volatile)
# 如果有 __init__,调用 __init__(ptr, args...)
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
@@ -214,7 +224,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
arg_vals[real_arg_count] = sizet(av)
real_arg_count += 1
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct, is_volatile)
elif has_new_flag == 0:
# 无 __init__ 且无 __new__:逐字段 store 参数值
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
@@ -253,17 +263,17 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
VLogger.error(f"构造函数字段 GEP 失败: {class_name}", "HandlesExprCall")
continue
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
llvmlite.build_store(builder, arg_val, field_ptr, is_volatile)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return storage_ptr
# 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零)
zero: llvmlite.Value* = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
llvmlite.build_store(builder, zero, tmp, is_volatile)
# 应用默认值(显式参数会覆盖默认值)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans, is_volatile)
# 逐字段 store 参数值(覆盖默认值)
for ai in range(can):
@@ -293,7 +303,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
continue
# 类型转换并 store
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
llvmlite.build_store(builder, arg_val, field_ptr, is_volatile)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
@@ -325,7 +335,8 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
tag_value: int,
cargs: list[ast.AST*]*,
can: sizet,
trans: HT.Translator*) -> llvmlite.Value*:
trans: HT.Translator*,
is_volatile: int = 0) -> llvmlite.Value*:
"""构造 REnum 变体实例,返回指向 alloca 的指针
class_name: REnum 类名(如 "LLVMType")
@@ -333,6 +344,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
tag_value: 变体的 tag 值(变体在类中的索引)
cargs: 参数 AST 列表
can: 参数数量
is_volatile=1:`volatile C.V(...)` 构造——清零/tag/payload 写入带 volatile
"""
if pool is None or builder is None or class_name is None:
return None
@@ -360,7 +372,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
# 清零(确保未赋值的 payload 位置为零)
zero: llvmlite.Value* = llvmlite.ConstZero(pool, renum_ty)
llvmlite.build_store(builder, zero, tmp)
llvmlite.build_store(builder, zero, tmp, is_volatile)
# 写入 __tag 字段(索引 0)
# tag 的类型取 __tag 的**字段声明类型**(FieldEntry.Ty),与 kind()
@@ -378,7 +390,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
tag_name_buf if tag_name_buf is not None else "0")
tag_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, renum_ty, tag_field_ty, tmp, 0)
if tag_ptr is not None:
llvmlite.build_store(builder, tag_const, tag_ptr)
llvmlite.build_store(builder, tag_const, tag_ptr, is_volatile)
# 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...)
# 参数按位置顺序填充 payload,跳过 __tag(索引 0)
@@ -409,7 +421,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
arg_val = casted_arg
# 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce)
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pfe.Ty, arg)
llvmlite.build_store(builder, arg_val, payload_ptr)
llvmlite.build_store(builder, arg_val, payload_ptr, is_volatile)
# 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load)
return tmp
@@ -433,8 +445,13 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
can: sizet,
keywords: list[ast.AST*]*,
kw_count: sizet,
trans: HT.Translator*) -> llvmlite.Value*:
"""结构体构造函数(关键字参数版本)"""
trans: HT.Translator*,
is_volatile: int = 0) -> llvmlite.Value*:
"""结构体构造函数(关键字参数版本)
is_volatile=1:`volatile S(x=1)` 构造——同 _translate_struct_ctor,
写入带 volatile 且 __new__/__before_init__/__init__ 后加 volatile 屏障。
"""
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
@@ -479,12 +496,12 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if is_oop != 0:
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", tmp, None, 0, trans)
"__before_init__", tmp, None, 0, trans, None, is_volatile)
else:
# 普通结构体:store zeroinitializer + 应用默认值
zero: llvmlite.Value* = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
llvmlite.build_store(builder, zero, tmp, is_volatile)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans, is_volatile)
# OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store
# 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行
@@ -528,7 +545,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if new_arg_count < 32:
new_arg_vals[new_arg_count] = sizet(nkw_av)
new_arg_count += 1
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct, is_volatile)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -569,7 +586,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
init_arg_count += 1
# 调用 __init__(storage_ptr, *args)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct, is_volatile)
# 返回指针
return storage_ptr
@@ -594,7 +611,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
field_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None: continue
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
llvmlite.build_store(builder, arg_val, field_ptr, is_volatile)
# 处理关键字参数(按字段名查找)
# SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错)
@@ -614,7 +631,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
field_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None: continue
kw_val = self.Gen.ExprGenBase.coerce_to_type(builder, kw_val, fe.Ty, kw.value)
llvmlite.build_store(builder, kw_val, field_ptr)
llvmlite.build_store(builder, kw_val, field_ptr, is_volatile)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
@@ -1155,6 +1172,9 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if arg_max_filled >= 0:
arg_count = arg_max_filled + 1
# 值位置 volatile 前缀:`a: T = volatile list[int](mb)` —— 构造写入带 volatile
gc_volatile: int = cl.IsVolatile
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
# (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明)
@@ -1163,7 +1183,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if struct_entry is not None:
has_new_flag = struct_entry.HasNew
if has_new_flag != 0:
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__new__", tmp, extra_args, arg_count, trans)
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__new__", tmp, extra_args, arg_count, trans, None, gc_volatile)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -1180,9 +1200,9 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
storage_ptr = nw_bc
# call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans, None, gc_volatile)
# call __init__(storage_ptr, *args)(arg_count = 槽位 0..已填最高槽)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, arg_count, trans)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, arg_count, trans, None, gc_volatile)
return storage_ptr
+1 -1
View File
@@ -1138,7 +1138,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
if self.Gen.ClassGenEnum._is_renum_class_name(st_nm.id) != 0:
rc_tag_sc: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(st_nm.id, func_name)
if rc_tag_sc >= 0:
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, st_nm.id, func_name, rc_tag_sc, cargs, can, trans)
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, st_nm.id, func_name, rc_tag_sc, cargs, can, trans, cl.IsVolatile)
st_res: llvmlite.Value* = self.Gen.CallGenProp._translate_static_class_call(pool, builder, mod, st_nm.id, func_name, cl, trans)
if st_res is not None:
return st_res
+7 -7
View File
@@ -309,7 +309,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
if gen_ctor_entry is not None:
ctor_is_oop = gen_ctor_entry.IsOOP
if ctor_is_oop != 0:
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans)
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans, cl.IsVolatile)
# @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存
# 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解
# (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误
@@ -318,7 +318,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
if gen_ctor_entry is not None:
ctor_is_novt = gen_ctor_entry.IsNoVTable
if ctor_is_novt != 0:
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans)
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans, cl.IsVolatile)
# 普通结构体:检查是否有默认值(用 entry 直接访问)
gen_has_defaults: int = 0
if gen_ctor_entry is not None:
@@ -331,14 +331,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
gen_has_defaults = self.Gen.StructGen.struct_has_defaults(func_name)
if gen_has_defaults == 1:
# 有默认值:走构造函数路径应用默认值
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans)
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans, cl.IsVolatile)
# 无默认值:返回 zeroinitializer
ret: llvmlite.Value* = llvmlite.ConstZero(pool, struct_ty)
return ret
if kw_count > 0:
# 有关键字参数:按字段名赋值
return self.Gen.CallGenCtor._translate_struct_ctor_kw(pool, builder, mod, struct_ty, func_name, cargs, can, keywords, kw_count, trans)
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, can, trans)
return self.Gen.CallGenCtor._translate_struct_ctor_kw(pool, builder, mod, struct_ty, func_name, cargs, can, keywords, kw_count, trans, cl.IsVolatile)
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, can, trans, cl.IsVolatile)
# 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造
# (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5
@@ -437,7 +437,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
f"变体表未注册或变体名不匹配",
"NameError")
if rc_tag >= 0:
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, rc_cls_name, func_name, rc_tag, cargs, can, trans)
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, rc_cls_name, func_name, rc_tag, cargs, can, trans, cl.IsVolatile)
elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute:
# 模块限定 REnum 变体构造: mod.Class.Variant(args...)
# 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。
@@ -467,7 +467,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0:
rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(rc_mq_cls, func_name)
if rc_mq_tag >= 0:
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, rc_mq_cls, func_name, rc_mq_tag, cargs, can, trans)
return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, rc_mq_cls, func_name, rc_mq_tag, cargs, can, trans, cl.IsVolatile)
# async 裸名调用(TPV-M1/M2):普通函数调用 async 函数(如 task(5, 6))→
# 生成 create_<name>(args...) 调用(返回 Ptr(帧),bitcast 成 i8* 供变量存储)。