feat(obs): first-class &T / &mut T references
In __obs__ files references are ordinary pointer values (no call-site auto-address), &T is read-only and &mut T writable. A reference borrows its owner: the owner cannot be del-ed while the reference variable is still in scope, references are never owners, and reassigning a reference drops the old borrow. Outside __obs__, &mut T is rejected.
This commit is contained in:
1 parent
dbee021cd1
commit
b9d84c6bda
7 files changed
+191
-11
No files matched your search
@@ -1057,6 +1057,24 @@ novirtual class AssignGenMixin:
|
||||
|
||||
# _is_ptr_element_annotation - check whether an annotation is bytes* or str*
|
||||
# bytes*/str* => 8-byte element stride (i8**); char*/int8* => 1-byte stride.
|
||||
def _RefKindOf(self, annot: ast.AST*) -> int:
|
||||
"""OBS reference kind of an annotation: 0=none, 1=`&T` (read-only), 2=`&mut T`."""
|
||||
if annot is None: return 0
|
||||
if GenApi.strict_obs() == 0: return 0
|
||||
return self.Gen.TypeGenResolve.ref_kind(annot)
|
||||
|
||||
def _BorrowOwnerName(self, expr: ast.AST*) -> str:
|
||||
"""Borrowed variable of `r: &T = x` / `r: &T = &x`; None when the source is not a binding."""
|
||||
if expr is None: return None
|
||||
if expr.kind() == ast.ASTKind.Name:
|
||||
return (ast.Name*)(expr).id
|
||||
if expr.kind() == ast.ASTKind.UnaryOp:
|
||||
uo_b: ast.UnaryOp* = ast.UnaryOp*(expr)
|
||||
if uo_b.op == ast.OpKind.AddrOf and uo_b.operand is not None \
|
||||
and uo_b.operand.kind() == ast.ASTKind.Name:
|
||||
return (ast.Name*)(uo_b.operand).id
|
||||
return None
|
||||
|
||||
def _is_ptr_element_annotation(self, annot: ast.AST*) -> int:
|
||||
"""Return 1 if the annotation is a bytes* or str* form."""
|
||||
if annot is None: return 0
|
||||
@@ -1739,6 +1757,9 @@ novirtual class AssignGenMixin:
|
||||
# 出口只释放 q 一次。不转移的话,`p = None` 会把 q 指向的对象提前释放 → q 悬垂。
|
||||
if src_slot is not None:
|
||||
if self.Gen.VarGen._SlifeOwned(src_slot) != 0:
|
||||
# A reference borrows: no ownership transfer, no shadow ownership.
|
||||
if target_name is not None and self.Gen.VarGen.var_ref_kind(trans.SymTab, target_name) != 0:
|
||||
return 0
|
||||
# The source owns a heap pointer: a value-typed target cannot receive it
|
||||
# implicitly (same rule as `new T()` into `T`).
|
||||
if target_slot.Ty is None or target_slot.Ty.Pointee == 0 or self.Gen.ExprGenBase.is_ptr_type(target_slot.Ty.Pointee) == 0:
|
||||
@@ -1755,7 +1776,9 @@ novirtual class AssignGenMixin:
|
||||
# Move semantics: the source no longer owns the value. Applies to
|
||||
# explicit `own` bindings in any file, and to every OBS move.
|
||||
if trans.StrictOBS != 0 or (target_name is not None and self.Gen.VarGen.var_is_own(trans.SymTab, target_name) != 0):
|
||||
self.Gen.VarGen._FreedMark(src_slot)
|
||||
# A reference borrows the object; it never takes ownership.
|
||||
if target_name is None or self.Gen.VarGen.var_ref_kind(trans.SymTab, target_name) == 0:
|
||||
self.Gen.VarGen._FreedMark(src_slot)
|
||||
return 1
|
||||
self._SlifeDropOwned(pool, builder, mod, trans, target_slot)
|
||||
return 0
|
||||
@@ -2702,6 +2725,13 @@ novirtual class AssignGenMixin:
|
||||
alloca: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, var_ty)
|
||||
if alloca is not None:
|
||||
if self.Gen.VarGen.define_var(trans.SymTab, nm.id, alloca) == 0:
|
||||
# OBS reference: remember the read-only / mutable kind and the borrowed owner.
|
||||
rk_decl: int = self._RefKindOf(annot)
|
||||
if rk_decl != 0:
|
||||
self.Gen.VarGen.set_var_ref_kind(trans.SymTab, nm.id, rk_decl)
|
||||
owner_b: str = self._BorrowOwnerName(aa.value)
|
||||
if owner_b is not None:
|
||||
self.Gen.StmtGen._BorrowAdd(trans, owner_b, nm.id)
|
||||
# Store the annotation's class name; pass pool so generic Subscript yields the mangled name
|
||||
if annot is not None:
|
||||
cls_nm_ps: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(annot, trans._imported_modules, pool, trans._from_imports)
|
||||
@@ -3580,9 +3610,21 @@ novirtual class AssignGenMixin:
|
||||
return 0
|
||||
if self.Gen.VarGen.var_is_const(ve_c) != 0:
|
||||
self.const_assign_fail(tgt_c, "assignment", nm_c.id, self.Gen.VarGen.var_annot_class_name(ve_c))
|
||||
# Reassigning a reference drops its old borrow (a fresh borrow is re-registered).
|
||||
if self.Gen.VarGen.var_ref_kind(trans.SymTab, nm_c.id) != 0:
|
||||
self.Gen.StmtGen._BorrowDrop(trans, nm_c.id)
|
||||
owner_rb: str = self._BorrowOwnerName(asgn.value)
|
||||
if owner_rb is not None:
|
||||
self.Gen.StmtGen._BorrowAdd(trans, owner_rb, nm_c.id)
|
||||
elif tgt_c.kind() == ast.ASTKind.Attribute:
|
||||
at_c: ast.Attribute* = ast.Attribute*(tgt_c)
|
||||
if at_c.attr is None: continue
|
||||
# OBS: writing through an immutable `&T` reference is forbidden.
|
||||
if at_c.value is not None and at_c.value.kind() == ast.ASTKind.Name:
|
||||
rf_bn: ast.Name* = ast.Name*(at_c.value)
|
||||
if rf_bn.id is not None and self.Gen.VarGen.var_ref_kind(trans.SymTab, rf_bn.id) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(tgt_c, f"cannot assign '.{at_c.attr}' through the immutable reference '{rf_bn.id}': declare it as `&mut T` to mutate the value", "TypeError")
|
||||
return 0
|
||||
if self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, tgt_c) != 0:
|
||||
self.const_assign_fail(tgt_c, "field assignment", at_c.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, tgt_c))
|
||||
if trans.StrictOBS != 0 and asgn.value is not None:
|
||||
@@ -3598,6 +3640,9 @@ novirtual class AssignGenMixin:
|
||||
if sub_c.value.kind() == ast.ASTKind.Name:
|
||||
nm_c2: ast.Name* = ast.Name*(sub_c.value)
|
||||
if nm_c2.id is None: continue
|
||||
if self.Gen.VarGen.var_ref_kind(trans.SymTab, nm_c2.id) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(tgt_c, f"cannot assign through the immutable reference '{nm_c2.id}': declare it as `&mut T` to mutate the value", "TypeError")
|
||||
return 0
|
||||
ve_c2: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_c2.id)
|
||||
if self.Gen.VarGen.var_is_const(ve_c2) != 0:
|
||||
self.const_assign_fail(tgt_c, "element assignment", nm_c2.id, self.Gen.VarGen.var_annot_class_name(ve_c2))
|
||||
|
||||
@@ -436,6 +436,9 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
alloca: mlirlite.Value* = mlirlite.build_alloca(builder, param_ty2)
|
||||
if alloca is None: continue
|
||||
self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca)
|
||||
if GenApi.strict_obs() != 0 and arg2.annotation is not None:
|
||||
rk_p: int = self.Gen.TypeGenResolve.ref_kind(arg2.annotation)
|
||||
if rk_p != 0: self.Gen.VarGen.set_var_ref_kind(trans.SymTab, arg2.arg, rk_p)
|
||||
# Store the raw annotation class name (method-call detection falls back from Ptr(i8) to the class).
|
||||
if arg2.annotation is not None:
|
||||
cls_nm: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(arg2.annotation, trans._imported_modules, pool, trans._from_imports)
|
||||
|
||||
@@ -158,6 +158,9 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
p_alloca: mlirlite.Value* = mlirlite.build_alloca(func_builder, pty2_n)
|
||||
if p_alloca is not None:
|
||||
self.Gen.VarGen.define_var(trans.SymTab, arg_p.arg, p_alloca)
|
||||
if GenApi.strict_obs() != 0 and arg_p.annotation is not None:
|
||||
rk_np: int = self.Gen.TypeGenResolve.ref_kind(arg_p.annotation)
|
||||
if rk_np != 0: self.Gen.VarGen.set_var_ref_kind(trans.SymTab, arg_p.arg, rk_np)
|
||||
if arg_p.annotation is not None:
|
||||
cls_nm_p: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(arg_p.annotation, imported_modules, pool, trans._from_imports)
|
||||
if cls_nm_p is not None: self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, arg_p.arg, cls_nm_p)
|
||||
|
||||
@@ -83,6 +83,9 @@ class VarEntry:
|
||||
# 0=native (no marker), 1=BigEndian, 2=LittleEndian. Appended at the end so existing field offsets
|
||||
# are unchanged; local loads/stores bswap when 1 (16/32/64-bit ints only). Mirrors FieldEntry.ByteOrder.
|
||||
ByteOrder: int
|
||||
# Reference kind in an `__obs__` file: 0=not a reference, 1=`&T` (read-only), 2=`&mut T`.
|
||||
# Appended at the end so existing field offsets are unchanged.
|
||||
RefKind: int
|
||||
# 注:P2 的"已失效"状态**不放在这里** —— 给这个热结构加字段会改变布局、牵连整条变量注册
|
||||
# 路径(现场:任何工程编译时都在"函数形参注册刚结束"处 access-violation)。改由
|
||||
# VarGenMixin 的独立失效槽表 _g_freed_slots 保存(键 = 变量槽 alloca,槽本身唯一)。
|
||||
|
||||
@@ -13,6 +13,57 @@ import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
# OBS borrow table: (function, owner, borrower) triples for `r: &T = x` / `r: &T = &x`.
|
||||
# Entries are function-scoped; a borrow counts as alive while its reference variable is still
|
||||
# declared in the current symbol table.
|
||||
define BORROW_MAX = 128
|
||||
_g_borrow_funcs: sizet* = None
|
||||
_g_borrow_owners: str* = None
|
||||
_g_borrow_borrowers: str* = None
|
||||
_g_borrow_count: int = 0
|
||||
|
||||
def _BorrowTableAdd(func: mlirlite.Function*, owner: str, borrower: str) -> int:
|
||||
global _g_borrow_funcs, _g_borrow_owners, _g_borrow_borrowers, _g_borrow_count
|
||||
if func is None or owner is None or borrower is None: return 0
|
||||
if _g_borrow_funcs is None:
|
||||
_g_borrow_funcs = sizet*(stdlib.malloc(BORROW_MAX * 8))
|
||||
_g_borrow_owners = str*(stdlib.malloc(BORROW_MAX * 8))
|
||||
_g_borrow_borrowers = str*(stdlib.malloc(BORROW_MAX * 8))
|
||||
if _g_borrow_funcs is None or _g_borrow_owners is None or _g_borrow_borrowers is None: return 0
|
||||
# Refresh an existing (func, owner, borrower) entry instead of growing the table.
|
||||
i: int = 0
|
||||
while i < _g_borrow_count:
|
||||
if _g_borrow_funcs[i] == sizet(func) and _g_borrow_borrowers[i] is not None \
|
||||
and string.strcmp(_g_borrow_borrowers[i], borrower) == 0:
|
||||
_g_borrow_owners[i] = owner
|
||||
return 1
|
||||
i += 1
|
||||
if _g_borrow_count >= BORROW_MAX: return 0
|
||||
_g_borrow_funcs[_g_borrow_count] = sizet(func)
|
||||
_g_borrow_owners[_g_borrow_count] = owner
|
||||
_g_borrow_borrowers[_g_borrow_count] = borrower
|
||||
_g_borrow_count += 1
|
||||
return 1
|
||||
|
||||
def _BorrowTableDrop(func: mlirlite.Function*, borrower: str) -> int:
|
||||
"""Forget every borrow held by `borrower` (the reference was reassigned)."""
|
||||
global _g_borrow_count
|
||||
if func is None or borrower is None or _g_borrow_funcs is None: return 0
|
||||
i: int = 0
|
||||
while i < _g_borrow_count:
|
||||
if _g_borrow_funcs[i] == sizet(func) and _g_borrow_borrowers[i] is not None \
|
||||
and string.strcmp(_g_borrow_borrowers[i], borrower) == 0:
|
||||
j: int = i
|
||||
while j + 1 < _g_borrow_count:
|
||||
_g_borrow_funcs[j] = _g_borrow_funcs[j + 1]
|
||||
_g_borrow_owners[j] = _g_borrow_owners[j + 1]
|
||||
_g_borrow_borrowers[j] = _g_borrow_borrowers[j + 1]
|
||||
j += 1
|
||||
_g_borrow_count -= 1
|
||||
continue
|
||||
i += 1
|
||||
return 1
|
||||
import lib.core.Gen.Stmt.StmtGenDeclMixin as StmtGenDeclMixin
|
||||
import lib.core.Gen.DebugInfoGen as DebugInfoGen
|
||||
|
||||
@@ -24,6 +75,31 @@ import lib.core.Gen.DebugInfoGen as DebugInfoGen
|
||||
novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
"""Statement/flow translation Mixin (top level, extends Decl)"""
|
||||
|
||||
def _BorrowAdd(self, trans: HT.Translator*, owner: str, borrower: str) -> int:
|
||||
"""Record that reference `borrower` refers to `owner` inside the current function."""
|
||||
if trans is None: return 0
|
||||
return _BorrowTableAdd(trans._cur_func, owner, borrower)
|
||||
|
||||
def _BorrowDrop(self, trans: HT.Translator*, borrower: str) -> int:
|
||||
"""Forget the borrows held by `borrower` (it was reassigned)."""
|
||||
if trans is None: return 0
|
||||
return _BorrowTableDrop(trans._cur_func, borrower)
|
||||
|
||||
def _BorrowLiveBorrower(self, trans: HT.Translator*, owner: str) -> str:
|
||||
"""Name of a still-declared reference that borrows `owner` (None when none)."""
|
||||
global _g_borrow_count
|
||||
if trans is None or owner is None or _g_borrow_funcs is None: return None
|
||||
i: int = 0
|
||||
while i < _g_borrow_count:
|
||||
if _g_borrow_funcs[i] == sizet(trans._cur_func):
|
||||
own_n: str = _g_borrow_owners[i]
|
||||
if own_n is not None and string.strcmp(own_n, owner) == 0:
|
||||
b_n: str = _g_borrow_borrowers[i]
|
||||
if b_n is not None and self.Gen.VarGen.lookup_var_entry(trans.SymTab, b_n) is not None:
|
||||
return b_n
|
||||
i += 1
|
||||
return None
|
||||
|
||||
def translate_stmt(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
"""Translate a single statement with a depth guard; returns the number of new variables"""
|
||||
if trans is not None:
|
||||
@@ -132,6 +208,15 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
if self.Gen.VarGen._FreedCheck(del_slot) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(tgt, f"cannot `del {nm_del.id}`: it was already released", "LifetimeError")
|
||||
continue
|
||||
# OBS references: a borrow is not an owner, and the owner cannot be released while
|
||||
# a reference to it is still alive.
|
||||
if self.Gen.VarGen.var_ref_kind(trans.SymTab, nm_del.id) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(tgt, f"cannot `del {nm_del.id}`: it is a reference ('&T' / '&mut T'), not an owner", "LifetimeError")
|
||||
continue
|
||||
live_b: str = self._BorrowLiveBorrower(trans, nm_del.id)
|
||||
if live_b is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(tgt, f"cannot `del {nm_del.id}`: the reference '{live_b}' is still in scope; reassign it (or delete after it is gone) first", "LifetimeError")
|
||||
continue
|
||||
del_var_ty: mlirlite.LLVMType* = del_slot.Ty.Pointee
|
||||
del_struct_ty: mlirlite.LLVMType* = None
|
||||
if self.Gen.ExprGenBase.is_ptr_type(del_var_ty) != 0: del_struct_ty = del_var_ty.Pointee
|
||||
|
||||
@@ -1366,7 +1366,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if ei >= 3 and tr[ei - 3] == '_' and tr[ei - 2] == 'b' and tr[ei - 1] == 'e': return 1
|
||||
return 0
|
||||
def _ref_marker_name_mode(self, node: ast.AST*) -> int:
|
||||
"""Syntactic value-reference marker test (no import context): 0=none / 1=RefT / 2=TempRefT."""
|
||||
"""Syntactic value-reference marker test (no import context): 0=none / 1=RefT / 2=TempRefT / 3=MutRefT."""
|
||||
if node is None: return 0
|
||||
if node.kind() != ast.ASTKind.Subscript: return 0
|
||||
sub_r: ast.Subscript* = ast.Subscript*(node)
|
||||
@@ -1376,13 +1376,33 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if nm is None: return 0
|
||||
if string.strcmp(nm, "RefT") == 0: return 1
|
||||
if string.strcmp(nm, "TempRefT") == 0: return 2
|
||||
if string.strcmp(nm, "MutRefT") == 0: return 3
|
||||
return 0
|
||||
def ref_param_mode(self, node: ast.AST*, imported_modules: str) -> int:
|
||||
"""Value-reference mode of a parameter annotation: 0=none / 1=ref (&T) / 2=temp (&temp T)."""
|
||||
return self._ref_marker_name_mode(node)
|
||||
"""Value-reference mode of a parameter annotation: 0=none / 1=ref (&T) / 2=temp (&temp T).
|
||||
|
||||
In an `__obs__` file `&T` / `&mut T` are first-class reference values, so no call-site
|
||||
auto-address is applied and the parameter is a plain pointer.
|
||||
"""
|
||||
if GenApi.strict_obs() != 0: return 0
|
||||
m: int = self._ref_marker_name_mode(node)
|
||||
if m == 3: return 0
|
||||
return m
|
||||
def ref_kind(self, node: ast.AST*) -> int:
|
||||
"""Reference kind of an annotation: 0=none / 1=`&T` / 2=`&mut T`."""
|
||||
m: int = self._ref_marker_name_mode(node)
|
||||
if m == 1: return 1
|
||||
if m == 3: return 2
|
||||
return 0
|
||||
def reject_ref_marker_position(self, node: ast.AST*, imported_modules: str, where: str) -> int:
|
||||
"""Fail fast when a value-reference marker (&T / &temp T) is used outside a parameter position."""
|
||||
if self.ref_param_mode(node, imported_modules) == 0: return 0
|
||||
"""Fail fast when a reference marker is used where it is not allowed."""
|
||||
mode: int = self._ref_marker_name_mode(node)
|
||||
if mode == 0: return 0
|
||||
# OBS references are ordinary types in every annotation position.
|
||||
if GenApi.strict_obs() != 0: return 0
|
||||
if mode == 3:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "mutable references (`&mut T`) require `from __future__ import __obs__`", "TypeError")
|
||||
return 1
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"value-reference parameter annotation '&T' / '&temp T' is only allowed in function parameter position, not for {where}", "TypeError")
|
||||
return 1
|
||||
def _is_cattr_marker(self, node: ast.AST*) -> int:
|
||||
@@ -1417,7 +1437,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
or string.strcmp(sw_nm.id, "StaticT") == 0 or string.strcmp(sw_nm.id, "ExportT") == 0 \
|
||||
or string.strcmp(sw_nm.id, "ExternT") == 0 or string.strcmp(sw_nm.id, "State") == 0 \
|
||||
or string.strcmp(sw_nm.id, "DefineT") == 0 or string.strcmp(sw_nm.id, "RefT") == 0 \
|
||||
or string.strcmp(sw_nm.id, "TempRefT") == 0 or string.strcmp(sw_nm.id, "AutoPtrT") == 0):
|
||||
or string.strcmp(sw_nm.id, "TempRefT") == 0 or string.strcmp(sw_nm.id, "MutRefT") == 0 \
|
||||
or string.strcmp(sw_nm.id, "AutoPtrT") == 0):
|
||||
if sub_v.slice is not None: return self._is_cvoid_marker(sub_v.slice, imported_modules)
|
||||
return 0
|
||||
def annotation_to_str(self, annot: ast.AST*) -> str:
|
||||
@@ -1465,10 +1486,13 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
viperlib.snprintf(cp_buf, string.strlen(inner_cp) + 2, "%s*", inner_cp)
|
||||
return cp_buf
|
||||
return "<subscript>"
|
||||
if string.strcmp(sv_nm.id, "RefT") == 0 or string.strcmp(sv_nm.id, "TempRefT") == 0:
|
||||
if string.strcmp(sv_nm.id, "RefT") == 0 or string.strcmp(sv_nm.id, "TempRefT") == 0 \
|
||||
or string.strcmp(sv_nm.id, "MutRefT") == 0:
|
||||
inner_rf: str = self.annotation_to_str(sub.slice)
|
||||
if inner_rf is not None:
|
||||
rf_prefix: str = "&temp " if string.strcmp(sv_nm.id, "TempRefT") == 0 else "&"
|
||||
rf_prefix: str = "&"
|
||||
if string.strcmp(sv_nm.id, "TempRefT") == 0: rf_prefix = "&temp "
|
||||
elif string.strcmp(sv_nm.id, "MutRefT") == 0: rf_prefix = "&mut "
|
||||
rf_buf: str = stdlib.malloc(string.strlen(inner_rf) + string.strlen(rf_prefix) + 1)
|
||||
if rf_buf is not None:
|
||||
viperlib.snprintf(rf_buf, string.strlen(inner_rf) + string.strlen(rf_prefix) + 1, "%s%s", rf_prefix, inner_rf)
|
||||
@@ -1610,7 +1634,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
or string.strcmp(rp_nm.id, "StaticT") == 0 or string.strcmp(rp_nm.id, "ExportT") == 0 \
|
||||
or string.strcmp(rp_nm.id, "ExternT") == 0 or string.strcmp(rp_nm.id, "State") == 0 \
|
||||
or string.strcmp(rp_nm.id, "DefineT") == 0 or string.strcmp(rp_nm.id, "RefT") == 0 \
|
||||
or string.strcmp(rp_nm.id, "TempRefT") == 0 or string.strcmp(rp_nm.id, "AutoPtrT") == 0:
|
||||
or string.strcmp(rp_nm.id, "TempRefT") == 0 or string.strcmp(rp_nm.id, "MutRefT") == 0 \
|
||||
or string.strcmp(rp_nm.id, "AutoPtrT") == 0:
|
||||
if sub.slice is not None: return self.extract_class_name_from_annotation(sub.slice, imported_modules, pool, from_imports)
|
||||
return None
|
||||
# When recursing into base, from_imports must be passed down too, else the mangled
|
||||
@@ -2313,7 +2338,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
or string.strcmp(gen_nm.id, "DefineT") == 0 or string.strcmp(gen_nm.id, "AutoPtrT") == 0:
|
||||
return self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
# Value-reference parameters use the pointer ABI: &T / &temp T -> T*.
|
||||
if string.strcmp(gen_nm.id, "RefT") == 0 or string.strcmp(gen_nm.id, "TempRefT") == 0:
|
||||
if string.strcmp(gen_nm.id, "RefT") == 0 or string.strcmp(gen_nm.id, "TempRefT") == 0 \
|
||||
or string.strcmp(gen_nm.id, "MutRefT") == 0:
|
||||
ref_inner: mlirlite.LLVMType* = self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if ref_inner is None: return None
|
||||
return mlirlite.Ptr(pool, ref_inner)
|
||||
|
||||
@@ -449,6 +449,21 @@ novirtual class VarGenMixin:
|
||||
if symtab is None or name is None: return 0
|
||||
return self._OwnCheck(self.lookup_var(symtab, name))
|
||||
|
||||
def set_var_ref_kind(self, symtab: GenTypes.SymbolTable*, name: str, kind: int) -> int:
|
||||
"""Record the OBS reference kind of a variable: 0=none, 1=`&T`, 2=`&mut T`."""
|
||||
if symtab is None or name is None: return 0
|
||||
ve: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
|
||||
if ve is None: return 0
|
||||
ve.RefKind = kind
|
||||
return 1
|
||||
|
||||
def var_ref_kind(self, symtab: GenTypes.SymbolTable*, name: str) -> int:
|
||||
"""OBS reference kind of the variable: 0=none, 1=`&T` (read-only), 2=`&mut T`."""
|
||||
if symtab is None or name is None: return 0
|
||||
ve: GenTypes.VarEntry* = self.lookup_var_entry(symtab, name)
|
||||
if ve is None: return 0
|
||||
return ve.RefKind
|
||||
|
||||
# ---- P2 willFree:失效槽表的控制流汇合(与 life_capture/life_restore/life_join 同点位) ----
|
||||
# 背景:失效表是"平坦、单调"的全局表(_FreedMark 只插入),原本无分支合流语义,
|
||||
# 于是"分支体内 free(x)"会把失效态泄漏到合流之后 → `if c: free(p); return` 之后的
|
||||
|
||||
Reference in new issue
Block a user