原子式与输入
写于2022年1月21日。
原子式(Atom)
原子式即分析过程中用到的输入信息的分类。
Variable
由用户定义的变量。如let x, y;
中的x
、y
。
Path
结构体、元组、数组等变量的字段访问路径。如a.b
、x.y.z.0
、s[0]
等(数组不区分不同下标)。
Point
控制流图(Control-flow Graph,CFG)中的某个语句。每条语句被拆成Start和Mid两个节点,
Start
:执行该语句前;Mid
:执行该语句时。
Loan
借债,对应Rust中的借用(borrow)概念。如let y = &x;
中的&x
。
Origin
借用源,对应Rust中的生存期(lifetime)概念。如let x: &'a i32;
中的'a
。
Origin
应理解为「所有引用到该Origin
的Loan
集合」。
输入事实(AllFacts
)
输入来源于MIR。主要包含CFG的执行到达关系图;变量的赋值、移动、访问情况;借债的发生、清除、失效信息;因借用产生、或外部定义的笁存期及其约束条件等信息。
cfg_edge
cfg_edge(SourcePoint, TargetPoint)
,一条控制流图的边,表示SourcePoint
的下一条执行点为TargetPoint
。
loan_issued_at
loan_issued_at(Origin, Loan, Point)
表示在位置Point
处发生了借债Loan
,其生存期为Origin
。
placeholder
(与universal_region
)
placeholder(Origin, Loan)
表示外部定义的生存期(如fn max<'a>(a: &'a str, b: &'a str) -> &'a str
中的'a
,及期关联的Loan
。这些生存期也是函数签名的一部份。另外,由于它的Loan
对借债检查而言是未知的,不能作任何假设,因此称之为「占位符」(placeholder)。
universal_region(Origin)
与placeholder
类似,单指由函数签名定义的生存期,不带具体的Loan
。
loan_killed_at
loan_killed_at(Loan, Point)
指某个借债Loan
在位置Point
处被清除。表明该借债Loan
对应的路径Path
在Point
处被赋值或覆写。
例如
#![allow(unused)] fn main() { let mut a = 1; let mut b = 2; let mut q = &mut a; let r = &mut *q; // `Loan` L0,此处借用了`*q` // `q` 不能再使用,只能通过`r`访问 q = &mut b; // L0被清除 // 此后,`q`与`r`可以继续使用 }
q
再次赋值后,Loan L0
被清除。Rustc在进入借用检查之前会将这样的关系计算好,保存在loan_killed_at
中。之后,在借债分析时,loan_killed_at
中的Point
将阻止相应的Loan
在CFG中传播。
subset_base
subset_base(SubOrigin, Origin, Point)
表示,在位置Point
处,有一条SubOrigin: Origin
的约束(即SubOrigin
应当长存于(outlives)Origin
。
loan_invalidated_at
loan_invalidated_at(Point, Loan)
表明在Point
处失效。
借用有共享(shared)与可变(mutable)两种。共享借用只能用于读取,不能写入或修改;可变借用必须独占,保证不能有对同一Path的借用。否则,视为借用失效,失效的借债将保存在loan_invalidated_at
关系中。
known_placeholder_subset
known_placeholder_subset(SubOrigin, Origin)
用于表示函数签名处定义的生存期约束。