Rust: Adjust SSA write node for (compound) assignments

This commit is contained in:
Tom Hvitved
2025-09-16 12:46:03 +02:00
parent 4e77b1b9b8
commit 7cac226ad9
9 changed files with 113 additions and 32 deletions

View File

@@ -16,6 +16,36 @@ class ExitCfgNode = CfgImpl::ExitNode;
class AnnotatedExitCfgNode = CfgImpl::AnnotatedExitNode;
/** A variable access. */
final class VariableAccessCfgNode extends PathExprBaseCfgNode {
private VariableAccess a;
VariableAccessCfgNode() { a = this.getAstNode() }
/** Gets the underlying `VariableAccess`. */
VariableAccess getAccess() { result = a }
}
/** A variable write. */
final class VariableWriteAccessCfgNode extends VariableAccessCfgNode {
private VariableWriteAccess a;
VariableWriteAccessCfgNode() { a = this.getAstNode() }
/** Gets the underlying `VariableWriteAccess`. */
VariableWriteAccess getAccess() { result = a }
}
/** A variable read. */
final class VariableReadAccessCfgNode extends VariableAccessCfgNode {
private VariableReadAccess a;
VariableReadAccessCfgNode() { a = this.getAstNode() }
/** Gets the underlying `VariableReadAccess`. */
VariableReadAccess getAccess() { result = a }
}
/**
* An assignment expression, for example
*
@@ -24,12 +54,42 @@ class AnnotatedExitCfgNode = CfgImpl::AnnotatedExitNode;
* ```
*/
final class AssignmentExprCfgNode extends BinaryExprCfgNode {
AssignmentExpr a;
AssignmentExprChildMapping a;
AssignmentExprCfgNode() { a = this.getBinaryExpr() }
/** Gets the underlying `AssignmentExpr`. */
AssignmentExpr getAssignmentExpr() { result = a }
/**
* Gets a write access that occurs in the left-hand side of this assignment expression.
*/
VariableWriteAccessCfgNode getAWriteAccess() {
a = result.getAccess().getAssignmentExpr() and
any(ChildMapping mapping).hasCfgChild(a, result.getAccess(), this, result)
}
}
/**
* A compound assignment expression, for example:
* ```rust
* x += y;
* ```
*
* Note that compound assignment expressions are syntatic sugar for
* trait invocations, i.e., the above actually means
*
* ```rust
* (&mut x).add_assign(y);
* ```
*/
final class CompoundAssignmentExprCfgNode extends BinaryExprCfgNode {
CompoundAssignmentExpr a;
CompoundAssignmentExprCfgNode() { a = this.getBinaryExpr() }
/** Gets the underlying `CompoundAssignmentExpr`. */
CompoundAssignmentExpr getCompoundAssignmentExpr() { result = a }
}
/**

View File

@@ -81,6 +81,12 @@ class FormatArgsExprChildMapping extends ParentAstNode, CfgImpl::ExprTrees::Form
override predicate relevantChild(AstNode child) { child = this.getChildNode(_) }
}
class AssignmentExprChildMapping extends ParentAstNode, AssignmentExpr {
override predicate relevantChild(AstNode child) {
child.(VariableWriteAccess).getAssignmentExpr() = this
}
}
private class ChildMappingImpl extends ChildMapping {
/** Gets a CFG node for `child`, where `child` is a relevant child node of `parent`. */
private CfgNode getRelevantChildCfgNode(AstNode parent, AstNode child) {

View File

@@ -171,9 +171,20 @@ module Ssa {
private CfgNode write;
WriteDefinition() {
exists(BasicBlock bb, int i, Variable v |
exists(BasicBlock bb, int i, Variable v, CfgNode n |
this.definesAt(v, bb, i) and
SsaImpl::variableWriteActual(bb, i, v, write)
SsaImpl::variableWriteActual(bb, i, v, n)
|
write.(VariableAccessCfgNode).getAccess().getVariable() = v and
(
write = n.(AssignmentExprCfgNode).getAWriteAccess()
or
write = n.(CompoundAssignmentExprCfgNode).getLhs()
)
or
not n instanceof AssignmentExprCfgNode and
not n instanceof CompoundAssignmentExprCfgNode and
write = n
)
}

View File

@@ -263,7 +263,7 @@ module LocalFlow {
or
// An edge from a pattern/expression to its corresponding SSA definition.
nodeFrom.(AstCfgFlowNode).getCfgNode() =
nodeTo.(SsaNode).asDefinition().(Ssa::WriteDefinition).getControlFlowNode()
nodeTo.(SsaNode).asDefinition().(Ssa::WriteDefinition).getWriteAccess()
or
nodeFrom.(SourceParameterNode).getParameter().(ParamCfgNode).getPat() = nodeTo.asPat()
or

View File

@@ -18,23 +18,22 @@ private predicate isInUninitializedLet(Name name) {
)
}
/** Holds if `write` writes to variable `v`. */
predicate variableWrite(AstNode write, Variable v) {
/** Holds if `write` writes to variable `v` via `access`. */
predicate variableWrite(AstNode write, AstNode access, Variable v) {
exists(Name name |
name = write and
access = write and
name = v.getName() and
not isInUninitializedLet(name)
)
or
exists(VariableAccess access |
access = write and
access.getVariable() = v
|
access instanceof VariableWriteAccess
v = access.(VariableAccess).getVariable() and
(
write = access.(VariableWriteAccess).getAssignmentExpr()
or
// Although compound assignments, like `x += y`, may in fact not update `x`,
// it makes sense to treat them as such
access = any(CompoundAssignmentExpr cae).getLhs()
access = write.(CompoundAssignmentExpr).getLhs()
)
}
@@ -226,7 +225,7 @@ private module Cached {
cached
predicate variableWriteActual(BasicBlock bb, int i, Variable v, CfgNode write) {
bb.getNode(i) = write and
variableWrite(write.getAstNode(), v)
variableWrite(write.getAstNode(), _, v)
}
cached

View File

@@ -679,11 +679,11 @@ module Impl {
}
/** Holds if `e` occurs in the LHS of an assignment or compound assignment. */
private predicate assignmentExprDescendant(Expr e) {
e = any(AssignmentExpr ae).getLhs()
private predicate assignmentExprDescendant(AssignmentExpr ae, Expr e) {
e = ae.getLhs()
or
exists(Expr mid |
assignmentExprDescendant(mid) and
assignmentExprDescendant(ae, mid) and
getImmediateParentAdj(e) = mid and
not mid instanceof DerefExpr and
not mid instanceof FieldExpr and
@@ -693,11 +693,16 @@ module Impl {
/** A variable write. */
class VariableWriteAccess extends VariableAccess {
private AssignmentExpr ae;
cached
VariableWriteAccess() {
Cached::ref() and
assignmentExprDescendant(this)
assignmentExprDescendant(ae, this)
}
/** Gets the assignment expression that has this write access in the left-hand side. */
AssignmentExpr getAssignmentExpr() { result = ae }
}
/** A variable read. */

View File

@@ -16,7 +16,7 @@ import UnusedVariable
from AstNode write, Ssa::Variable v
where
variableWrite(write, v) and
variableWrite(_, write, v) and
not v instanceof DiscardVariable and
not write.isInMacroExpansion() and
not isAllowableUnused(v) and

View File

@@ -1,3 +1,3 @@
multipleCallTargets
| main.rs:89:19:89:40 | ...::from(...) |
| main.rs:111:19:111:40 | ...::from(...) |
| main.rs:91:19:91:40 | ...::from(...) |
| main.rs:113:19:113:40 | ...::from(...) |

View File

@@ -198,7 +198,7 @@ read
| main.rs:20:9:20:10 | x1 | main.rs:20:9:20:10 | x1 | main.rs:21:15:21:16 | x1 |
| main.rs:25:13:25:14 | x2 | main.rs:25:13:25:14 | x2 | main.rs:26:15:26:16 | x2 |
| main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:28:15:28:16 | x2 |
| main.rs:29:5:29:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:29:10:29:11 | x2 |
| main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:29:10:29:11 | x2 |
| main.rs:29:5:29:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:30:15:30:16 | x2 |
| main.rs:34:13:34:13 | x | main.rs:34:13:34:13 | x | main.rs:35:20:35:20 | x |
| main.rs:36:5:36:5 | x | main.rs:34:13:34:13 | x | main.rs:37:20:37:20 | x |
@@ -285,14 +285,14 @@ read
| main.rs:367:9:367:10 | c1 | main.rs:367:9:367:10 | c1 | main.rs:372:15:372:16 | c1 |
| main.rs:375:20:375:55 | SSA phi(a9) | main.rs:375:20:375:55 | a9 | main.rs:377:15:377:16 | a9 |
| main.rs:382:13:382:15 | a10 | main.rs:382:13:382:15 | a10 | main.rs:386:15:386:17 | a10 |
| main.rs:382:13:382:15 | a10 | main.rs:382:13:382:15 | a10 | main.rs:395:9:395:11 | a10 |
| main.rs:383:13:383:14 | b4 | main.rs:383:13:383:14 | b4 | main.rs:387:15:387:16 | b4 |
| main.rs:383:13:383:14 | b4 | main.rs:383:13:383:14 | b4 | main.rs:396:9:396:10 | b4 |
| main.rs:384:13:384:14 | c2 | main.rs:384:13:384:14 | c2 | main.rs:388:15:388:16 | c2 |
| main.rs:391:9:391:10 | c2 | main.rs:384:13:384:14 | c2 | main.rs:397:9:397:10 | c2 |
| main.rs:384:13:384:14 | c2 | main.rs:384:13:384:14 | c2 | main.rs:397:9:397:10 | c2 |
| main.rs:391:9:391:10 | c2 | main.rs:384:13:384:14 | c2 | main.rs:401:15:401:16 | c2 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:396:9:396:10 | b4 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:400:15:400:16 | b4 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:414:15:414:16 | b4 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:395:9:395:11 | a10 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:399:15:399:17 | a10 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:413:15:413:17 | a10 |
| main.rs:405:13:405:15 | a10 | main.rs:405:13:405:15 | a10 | main.rs:408:23:408:25 | a10 |
@@ -401,7 +401,7 @@ firstRead
| main.rs:20:9:20:10 | x1 | main.rs:20:9:20:10 | x1 | main.rs:21:15:21:16 | x1 |
| main.rs:25:13:25:14 | x2 | main.rs:25:13:25:14 | x2 | main.rs:26:15:26:16 | x2 |
| main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:28:15:28:16 | x2 |
| main.rs:29:5:29:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:29:10:29:11 | x2 |
| main.rs:29:5:29:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:30:15:30:16 | x2 |
| main.rs:34:13:34:13 | x | main.rs:34:13:34:13 | x | main.rs:35:20:35:20 | x |
| main.rs:36:5:36:5 | x | main.rs:34:13:34:13 | x | main.rs:37:20:37:20 | x |
| main.rs:41:9:41:10 | x3 | main.rs:41:9:41:10 | x3 | main.rs:42:15:42:16 | x3 |
@@ -473,9 +473,9 @@ firstRead
| main.rs:382:13:382:15 | a10 | main.rs:382:13:382:15 | a10 | main.rs:386:15:386:17 | a10 |
| main.rs:383:13:383:14 | b4 | main.rs:383:13:383:14 | b4 | main.rs:387:15:387:16 | b4 |
| main.rs:384:13:384:14 | c2 | main.rs:384:13:384:14 | c2 | main.rs:388:15:388:16 | c2 |
| main.rs:391:9:391:10 | c2 | main.rs:384:13:384:14 | c2 | main.rs:397:9:397:10 | c2 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:396:9:396:10 | b4 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:395:9:395:11 | a10 |
| main.rs:391:9:391:10 | c2 | main.rs:384:13:384:14 | c2 | main.rs:401:15:401:16 | c2 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:400:15:400:16 | b4 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:399:15:399:17 | a10 |
| main.rs:405:13:405:15 | a10 | main.rs:405:13:405:15 | a10 | main.rs:408:23:408:25 | a10 |
| main.rs:406:13:406:14 | b4 | main.rs:406:13:406:14 | b4 | main.rs:409:23:409:24 | b4 |
| main.rs:418:9:418:23 | example_closure | main.rs:418:9:418:23 | example_closure | main.rs:422:9:422:23 | example_closure |
@@ -556,7 +556,7 @@ firstRead
| main.rs:726:20:726:20 | b | main.rs:726:20:726:20 | b | main.rs:728:20:728:20 | b |
| main.rs:732:5:732:13 | <captured exit> x | main.rs:725:13:725:13 | x | main.rs:733:15:733:15 | x |
adjacentReads
| main.rs:29:5:29:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:29:10:29:11 | x2 | main.rs:30:15:30:16 | x2 |
| main.rs:27:5:27:6 | x2 | main.rs:25:13:25:14 | x2 | main.rs:28:15:28:16 | x2 | main.rs:29:10:29:11 | x2 |
| main.rs:41:9:41:10 | x3 | main.rs:41:9:41:10 | x3 | main.rs:42:15:42:16 | x3 | main.rs:44:9:44:10 | x3 |
| main.rs:49:9:49:10 | x4 | main.rs:49:9:49:10 | x4 | main.rs:50:15:50:16 | x4 | main.rs:55:15:55:16 | x4 |
| main.rs:100:9:100:9 | x | main.rs:100:9:100:9 | x | main.rs:102:7:102:7 | x | main.rs:105:13:105:13 | x |
@@ -574,10 +574,10 @@ adjacentReads
| main.rs:334:9:334:9 | x | main.rs:334:9:334:9 | x | main.rs:335:11:335:11 | x | main.rs:343:15:343:15 | x |
| main.rs:348:9:348:9 | x | main.rs:348:9:348:9 | x | main.rs:350:7:350:7 | x | main.rs:355:7:355:7 | x |
| main.rs:348:9:348:9 | x | main.rs:348:9:348:9 | x | main.rs:355:7:355:7 | x | main.rs:359:19:359:19 | x |
| main.rs:391:9:391:10 | c2 | main.rs:384:13:384:14 | c2 | main.rs:397:9:397:10 | c2 | main.rs:401:15:401:16 | c2 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:396:9:396:10 | b4 | main.rs:400:15:400:16 | b4 |
| main.rs:382:13:382:15 | a10 | main.rs:382:13:382:15 | a10 | main.rs:386:15:386:17 | a10 | main.rs:395:9:395:11 | a10 |
| main.rs:383:13:383:14 | b4 | main.rs:383:13:383:14 | b4 | main.rs:387:15:387:16 | b4 | main.rs:396:9:396:10 | b4 |
| main.rs:384:13:384:14 | c2 | main.rs:384:13:384:14 | c2 | main.rs:388:15:388:16 | c2 | main.rs:397:9:397:10 | c2 |
| main.rs:392:9:392:10 | b4 | main.rs:383:13:383:14 | b4 | main.rs:400:15:400:16 | b4 | main.rs:414:15:414:16 | b4 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:395:9:395:11 | a10 | main.rs:399:15:399:17 | a10 |
| main.rs:393:9:393:11 | a10 | main.rs:382:13:382:15 | a10 | main.rs:399:15:399:17 | a10 | main.rs:413:15:413:17 | a10 |
| main.rs:436:9:436:9 | f | main.rs:436:9:436:9 | f | main.rs:439:15:439:15 | f | main.rs:446:15:446:15 | f |
| main.rs:477:5:477:5 | a | main.rs:476:13:476:13 | a | main.rs:478:15:478:15 | a | main.rs:479:11:479:11 | a |