feat(codegen): 模块级 extern 全局生成外部声明(@裸名 = external global T)

注解含 t.CExtern/t.State → is_global_extern:裸名(无 SHA1 头)、Linkage=external、不写初始值、不建 storage

与 export 全局(本模块定义 + 裸名)区分;配合 includes f854f7e 的 export/extern 变量语法
This commit is contained in:
TermiNexus committed 2026-09-27 17:56:51 +08:00
1 parent d82f24e17a
commit 66e697e8df
1 file changed
+22 -7
+22 -7
View File
@@ -896,6 +896,16 @@ novirtual class TranslatorGenMixin:
is_global_cexport: int = 0
if annot_node is not None:
is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExport", 0)
# extern 全局(`extern NAME: T` → 注解含 t.State / t.CExtern):符号定义在
# 外部(C 库 / 汇编 / 其它翻译单元),本模块只生成外部声明
# `@裸名 = external global T`——external linkage、无初始值、无 storage。
# 与 export 的差别:export 是**本模块定义**(裸名导出);extern 是**仅声明**。
# `t.State` = t.CExtern | t.CExport(parser 的 `extern NAME: T` 展开产物)。
is_global_extern: int = 0
if annot_node is not None:
is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExtern", 0)
if is_global_extern == 0:
is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "State", 0)
# 全局变量侧 t.attr.* 属性(`T | t.attr.xxx` 注解联合形态):
# section→gv.Section、aligned→gv.Align、weak→gv.Linkage(见下方应用点)。
# 仅在 AnnAssign(annot_node 非 None)时存在,与 t.CExport 同一条路。
@@ -907,7 +917,7 @@ novirtual class TranslatorGenMixin:
gv_attr_align = self._extract_global_attr_aligned(annot_node, var_name)
gv_attr_weak = self._extract_global_attr_weak(annot_node)
mangled_name: str = var_name
if is_global_cexport == 0:
if is_global_cexport == 0 and is_global_extern == 0:
mangled_name = self.Gen.FuncGenBase._mangle_name(trans, var_name)
gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, mangled_name, var_ty)
if gv is None:
@@ -937,10 +947,14 @@ novirtual class TranslatorGenMixin:
gv.Align = al_entry.Align
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
gv.Linkage = None
# t.attr.weak → weak linkage(须在 Linkage 清空之后设置)。
if gv_attr_weak != 0:
llvmlite.global_set_linkage(gv, "weak")
# extern 全局例外:保持 external(仅外部声明,绝不写初始值 / storage)。
if is_global_extern != 0:
gv.Linkage = "external"
else:
gv.Linkage = None
# t.attr.weak → weak linkage(须在 Linkage 清空之后设置)。
if gv_attr_weak != 0:
llvmlite.global_set_linkage(gv, "weak")
if init_kind == 1:
# 整数初始值
init_buf: str = pool.alloc(48)
@@ -995,7 +1009,7 @@ novirtual class TranslatorGenMixin:
# 此处不覆盖;但 = None 懒初始化全局(is_none_init)既无 storage 也无其他
# Initializer → 必须显式 zeroinitializer(LLVM 对指针类型输出为 null),
# 否则 gv 无初始化器 → 全局声明残缺。
if resolved_stg_ty is None or is_none_init != 0:
if (resolved_stg_ty is None or is_none_init != 0) and is_global_extern == 0:
gv.Initializer = "zeroinitializer"
# 对象类全局:创建静态 storage 全局(BSS)承载对象实例,@g 编译期引用它。
@@ -1003,7 +1017,8 @@ novirtual class TranslatorGenMixin:
# 不再依赖栈 alloca(悬垂);c.Addr(g) load @g 得到 &storage,均非 NULL。
# 豁免:显式 `= None` 初始化(is_none_init)的懒初始化指针全局
# (如 _kw_head/_op_head)不建 storage,保持 NULL 语义。
if resolved_stg_ty is not None and is_none_init == 0:
# extern 全局(is_global_extern)同样不建 storage:外部声明无本模块实例。
if resolved_stg_ty is not None and is_none_init == 0 and is_global_extern == 0:
# 值类型 storage 需要完整 struct 定义(跨模块类默认 opaque →
# @g.stg = global %T zeroinitializer 报 "use of undefined type")
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_stg_ty)