From 8eaa86ea01bc87be8fb762d8332eed981d01cf33 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 10 Jul 2026 23:52:04 +0100 Subject: [PATCH] Unify incdec-rhs into the compound-rhs node kind --- .../go/controlflow/ControlFlowGraphShared.qll | 29 ++++---- go/ql/lib/semmle/go/controlflow/IR.qll | 72 +++++++------------ .../IntegerOverflow/RangeAnalysis.qll | 22 +++--- .../ControlFlowNode_getASuccessor.expected | 36 +++++----- .../dataflow/FlowSteps/LocalFlowStep.expected | 2 +- .../FunctionOutput_getEntryNode.expected | 2 +- .../semmle/go/dataflow/SSA/VarDefs.expected | 4 +- 7 files changed, 70 insertions(+), 97 deletions(-) diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll index e681f8ff6d6..f62e0d17296 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll @@ -485,8 +485,6 @@ module GoCfg { or n instanceof Go::SendStmt or - n instanceof Go::IncDecStmt - or n instanceof Go::FuncDecl } @@ -543,8 +541,10 @@ module GoCfg { tag = "zero-init:" + i.toString() ) or - // Increment/decrement implicit right-hand side (the `operand + 1` value) - n instanceof Go::IncDecStmt and tag = "incdec-rhs" + // Increment/decrement: a single node computes `operand + 1` (or `- 1`) + // and writes it back, modelled the same as a compound assignment's + // `compound-rhs` node (see `IR::EvalCompoundAssignRhsInstruction`). + n instanceof Go::IncDecStmt and tag = "compound-rhs" or // Result write nodes in return statements exists(int i, Go::ReturnStmt ret | @@ -1154,26 +1154,23 @@ module GoCfg { } /** - * Increment/decrement: operand → incdec-rhs → In(stmt) - * (IncDecStmt is in postOrInOrder, so In(stmt) is its evaluation point) + * Increment/decrement: operand → compound-rhs → After(stmt). * - * The implicit constant `1` operand of the `operand + 1` computation is - * modelled directly on the `incdec-rhs` instruction rather than as its own - * control-flow node. + * `x++` is modelled just like the compound assignment `x += 1`: a single + * `compound-rhs` node computes the updated value and writes it back to the + * operand (see `IR::EvalCompoundAssignRhsInstruction`). The implicit constant + * `1` is modelled directly on that node rather than as its own node. */ private predicate incDecStep(PreControlFlowNode n1, PreControlFlowNode n2) { exists(Go::IncDecStmt s | // Before → Before operand n1.isBefore(s) and n2.isBefore(s.getOperand()) or - // After operand → incdec-rhs - n1.isAfter(s.getOperand()) and n2.isAdditional(s, "incdec-rhs") + // After operand → compound-rhs (the update value + write) + n1.isAfter(s.getOperand()) and n2.isAdditional(s, "compound-rhs") or - // incdec-rhs → In(stmt) (the assignment itself) - n1.isAdditional(s, "incdec-rhs") and n2.isIn(s) - or - // In(stmt) → After(stmt) - n1.isIn(s) and n2.isAfter(s) + // compound-rhs → After(stmt) + n1.isAdditional(s, "compound-rhs") and n2.isAfter(s) ) } diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index 4581378c125..f7fea5b9f1a 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -176,11 +176,6 @@ module IR { or this instanceof ConditionGuardInstruction and result = "condition guard" or - this instanceof IncDecInstruction and result = "increment/decrement" - or - this instanceof EvalIncDecRhsInstruction and - result = "right-hand side of increment/decrement" - or this instanceof ReturnInstruction and result = "return" or this instanceof WriteResultInstruction and result = "result write" @@ -665,23 +660,36 @@ module IR { } /** - * An instruction that computes the (implicit) right-hand side of a compound assignment, - * such as the `x + y` in `x += y`, and writes the resulting value to the assignment's - * left-hand side. + * An instruction that computes the (implicit) right-hand side of a compound + * assignment (the `x + y` in `x += y`) or an increment/decrement (the + * `x + 1` in `x++`), and writes the resulting value to the left-hand side. */ class EvalCompoundAssignRhsInstruction extends WriteInstruction { - CompoundAssignStmt assgn; + AstNode s; - EvalCompoundAssignRhsInstruction() { this.isAdditional(assgn, "compound-rhs") } + EvalCompoundAssignRhsInstruction() { + this.isAdditional(s, "compound-rhs") and + (s instanceof CompoundAssignStmt or s instanceof IncDecStmt) + } - /** Gets the corresponding compound assignment statement. */ - CompoundAssignStmt getAssignment() { result = assgn } + /** Gets the corresponding compound assignment statement, if it is one. */ + CompoundAssignStmt getAssignment() { result = s } + + /** + * Gets the corresponding compound assignment (`x += y`) or increment/decrement + * (`x++`, `x--`) statement. + */ + AstNode getStmt() { result = s } override Instruction getRhs() { result = this } - override Type getResultType() { result = assgn.getRhs().getType() } + override Type getResultType() { + result = s.(CompoundAssignStmt).getRhs().getType() + or + result = s.(IncDecStmt).getOperand().getType() + } - override ControlFlow::Root getRoot() { result.isRootOf(assgn) } + override ControlFlow::Root getRoot() { result.isRootOf(s) } } /** An instruction extracting a component of a tuple value. */ @@ -871,36 +879,6 @@ module IR { override ControlFlow::Root getRoot() { result.isRootOf(go) } } - /** An instruction that corresponds to an increment or decrement statement. */ - class IncDecInstruction extends WriteInstruction { - IncDecStmt ids; - - IncDecInstruction() { this.isIn(ids) } - - override Instruction getRhs() { - result.(EvalIncDecRhsInstruction).isAdditional(ids, "incdec-rhs") - } - - override ControlFlow::Root getRoot() { result.isRootOf(ids) } - } - - /** - * An instruction that computes the (implicit) right-hand side of an increment or - * decrement statement. - */ - class EvalIncDecRhsInstruction extends Instruction { - IncDecStmt ids; - - EvalIncDecRhsInstruction() { this.isAdditional(ids, "incdec-rhs") } - - /** Gets the corresponding increment or decrement statement. */ - IncDecStmt getStmt() { result = ids } - - override Type getResultType() { result = ids.getOperand().getType() } - - override ControlFlow::Root getRoot() { result.isRootOf(ids) } - } - /** An instruction corresponding to a return from a function. */ class ReturnInstruction extends Instruction { ReturnStmt ret; @@ -1104,12 +1082,14 @@ module IR { ) ) or - exists(IncDecStmt ids | write.isIn(ids) | lhs = ids.getOperand().stripParens()) - or exists(CompoundAssignStmt ca | write.isAdditional(ca, "compound-rhs") | lhs = ca.getLhs().stripParens() ) or + exists(IncDecStmt ids | write.isAdditional(ids, "compound-rhs") | + lhs = ids.getOperand().stripParens() + ) + or exists(FuncDef fd, int idx | write.isAdditional(fd.getBody(), "param-init:" + idx.toString()) and lhs = fd.getParameter(idx).getDeclaration() diff --git a/go/ql/src/experimental/IntegerOverflow/RangeAnalysis.qll b/go/ql/src/experimental/IntegerOverflow/RangeAnalysis.qll index f3f4c15f008..5a53342b8af 100644 --- a/go/ql/src/experimental/IntegerOverflow/RangeAnalysis.qll +++ b/go/ql/src/experimental/IntegerOverflow/RangeAnalysis.qll @@ -389,12 +389,13 @@ float getAnSsaUpperBound(SsaDefinition def) { ) else //SSA definition corresponding to an `IncDecStmt` - if explicitDef.getInstruction() instanceof IR::IncDecInstruction + if + explicitDef.getInstruction().(IR::EvalCompoundAssignRhsInstruction).getStmt() instanceof + IncDecStmt then - exists(IncDecStmt incOrDec, IR::IncDecInstruction instr, float exprLB | - instr = explicitDef.getInstruction() and + exists(IncDecStmt incOrDec, float exprLB | + explicitDef.getInstruction().(IR::EvalCompoundAssignRhsInstruction).getStmt() = incOrDec and exprLB = getAnUpperBound(incOrDec.getOperand()) and - instr.getRhs().(IR::EvalIncDecRhsInstruction).getStmt() = incOrDec and ( //IncStmt(x++) exists(IncStmt inc | @@ -475,12 +476,13 @@ float getAnSsaLowerBound(SsaDefinition def) { ) else //IncDecStmt - if explicitDef.getInstruction() instanceof IR::IncDecInstruction + if + explicitDef.getInstruction().(IR::EvalCompoundAssignRhsInstruction).getStmt() instanceof + IncDecStmt then - exists(IncDecStmt incOrDec, IR::IncDecInstruction instr, float exprLB | - instr = explicitDef.getInstruction() and + exists(IncDecStmt incOrDec, float exprLB | + explicitDef.getInstruction().(IR::EvalCompoundAssignRhsInstruction).getStmt() = incOrDec and exprLB = getALowerBound(incOrDec.getOperand()) and - instr.getRhs().(IR::EvalIncDecRhsInstruction).getStmt() = incOrDec and ( //IncStmt(x++) exists(IncStmt inc | @@ -550,9 +552,7 @@ predicate ssaDependsOnSsa(SsaDefinition nextDef, SsaDefinition prevDef) { nextDef .(SsaExplicitDefinition) .getInstruction() - .(IR::IncDecInstruction) - .getRhs() - .(IR::EvalIncDecRhsInstruction) + .(IR::EvalCompoundAssignRhsInstruction) .getStmt() = incDec and ssaDependsOnExpr(prevDef, incDec.getOperand()) ) diff --git a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected index e81985a2fb6..13cb63c59e2 100644 --- a/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected +++ b/go/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/ControlFlowNode_getASuccessor.expected @@ -1279,7 +1279,7 @@ | exprs.go:49:30:54:1 | result-read:0 block statement | exprs.go:49:1:54:1 | Normal Exit | | exprs.go:49:30:54:1 | zero-init:0 block statement | exprs.go:50:2:52:2 | for statement | | exprs.go:50:2:52:2 | After for statement | exprs.go:53:2:53:7 | Before return statement | -| exprs.go:50:2:52:2 | [LoopHeader] for statement | exprs.go:50:27:50:29 | Before increment statement | +| exprs.go:50:2:52:2 | [LoopHeader] for statement | exprs.go:50:27:50:29 | increment statement | | exprs.go:50:2:52:2 | for statement | exprs.go:50:6:50:11 | ... := ... | | exprs.go:50:6:50:11 | ... := ... | exprs.go:50:11:50:11 | Before 0 | | exprs.go:50:6:50:11 | After ... := ... | exprs.go:50:14:50:24 | Before ...<... | @@ -1304,13 +1304,12 @@ | exprs.go:50:22:50:23 | After xs | exprs.go:50:18:50:24 | call to len | | exprs.go:50:22:50:23 | Before xs | exprs.go:50:22:50:23 | xs | | exprs.go:50:22:50:23 | xs | exprs.go:50:22:50:23 | After xs | -| exprs.go:50:27:50:27 | After i | exprs.go:50:27:50:29 | incdec-rhs increment statement | +| exprs.go:50:27:50:27 | After i | exprs.go:50:27:50:29 | compound-rhs increment statement | | exprs.go:50:27:50:27 | Before i | exprs.go:50:27:50:27 | i | | exprs.go:50:27:50:27 | i | exprs.go:50:27:50:27 | After i | | exprs.go:50:27:50:29 | After increment statement | exprs.go:50:14:50:24 | Before ...<... | -| exprs.go:50:27:50:29 | Before increment statement | exprs.go:50:27:50:27 | Before i | -| exprs.go:50:27:50:29 | incdec-rhs increment statement | exprs.go:50:27:50:29 | increment statement | -| exprs.go:50:27:50:29 | increment statement | exprs.go:50:27:50:29 | After increment statement | +| exprs.go:50:27:50:29 | compound-rhs increment statement | exprs.go:50:27:50:29 | After increment statement | +| exprs.go:50:27:50:29 | increment statement | exprs.go:50:27:50:27 | Before i | | exprs.go:50:31:52:2 | After block statement | exprs.go:50:2:52:2 | [LoopHeader] for statement | | exprs.go:50:31:52:2 | block statement | exprs.go:51:3:51:14 | ... += ... | | exprs.go:51:3:51:5 | After res | exprs.go:51:10:51:14 | Before index expression | @@ -2235,7 +2234,7 @@ | main.go:73:7:73:7 | After 1 | main.go:73:2:73:7 | assign:0 ... := ... | | main.go:73:7:73:7 | Before 1 | main.go:73:7:73:7 | 1 | | main.go:74:2:79:2 | After for statement | main.go:80:2:80:13 | expression statement | -| main.go:74:2:79:2 | [LoopHeader] for statement | main.go:74:16:74:18 | Before increment statement | +| main.go:74:2:79:2 | [LoopHeader] for statement | main.go:74:16:74:18 | increment statement | | main.go:74:2:79:2 | for statement | main.go:74:6:74:11 | ... := ... | | main.go:74:6:74:11 | ... := ... | main.go:74:11:74:11 | Before 0 | | main.go:74:6:74:11 | After ... := ... | main.go:74:20:79:2 | block statement | @@ -2243,13 +2242,12 @@ | main.go:74:11:74:11 | 0 | main.go:74:11:74:11 | After 0 | | main.go:74:11:74:11 | After 0 | main.go:74:6:74:11 | assign:0 ... := ... | | main.go:74:11:74:11 | Before 0 | main.go:74:11:74:11 | 0 | -| main.go:74:16:74:16 | After i | main.go:74:16:74:18 | incdec-rhs increment statement | +| main.go:74:16:74:16 | After i | main.go:74:16:74:18 | compound-rhs increment statement | | main.go:74:16:74:16 | Before i | main.go:74:16:74:16 | i | | main.go:74:16:74:16 | i | main.go:74:16:74:16 | After i | | main.go:74:16:74:18 | After increment statement | main.go:74:20:79:2 | block statement | -| main.go:74:16:74:18 | Before increment statement | main.go:74:16:74:16 | Before i | -| main.go:74:16:74:18 | incdec-rhs increment statement | main.go:74:16:74:18 | increment statement | -| main.go:74:16:74:18 | increment statement | main.go:74:16:74:18 | After increment statement | +| main.go:74:16:74:18 | compound-rhs increment statement | main.go:74:16:74:18 | After increment statement | +| main.go:74:16:74:18 | increment statement | main.go:74:16:74:16 | Before i | | main.go:74:20:79:2 | After block statement | main.go:74:2:79:2 | [LoopHeader] for statement | | main.go:74:20:79:2 | block statement | main.go:75:3:77:3 | if statement | | main.go:75:3:77:3 | After if statement | main.go:78:3:78:7 | ... = ... | @@ -2291,7 +2289,7 @@ | main.go:82:7:82:7 | After 1 | main.go:82:2:82:7 | assign:0 ... := ... | | main.go:82:7:82:7 | Before 1 | main.go:82:7:82:7 | 1 | | main.go:83:2:88:2 | After for statement | main.go:89:2:89:13 | expression statement | -| main.go:83:2:88:2 | [LoopHeader] for statement | main.go:83:16:83:18 | Before increment statement | +| main.go:83:2:88:2 | [LoopHeader] for statement | main.go:83:16:83:18 | increment statement | | main.go:83:2:88:2 | for statement | main.go:83:6:83:11 | ... := ... | | main.go:83:6:83:11 | ... := ... | main.go:83:11:83:11 | Before 0 | | main.go:83:6:83:11 | After ... := ... | main.go:83:20:88:2 | block statement | @@ -2299,13 +2297,12 @@ | main.go:83:11:83:11 | 0 | main.go:83:11:83:11 | After 0 | | main.go:83:11:83:11 | After 0 | main.go:83:6:83:11 | assign:0 ... := ... | | main.go:83:11:83:11 | Before 0 | main.go:83:11:83:11 | 0 | -| main.go:83:16:83:16 | After i | main.go:83:16:83:18 | incdec-rhs increment statement | +| main.go:83:16:83:16 | After i | main.go:83:16:83:18 | compound-rhs increment statement | | main.go:83:16:83:16 | Before i | main.go:83:16:83:16 | i | | main.go:83:16:83:16 | i | main.go:83:16:83:16 | After i | | main.go:83:16:83:18 | After increment statement | main.go:83:20:88:2 | block statement | -| main.go:83:16:83:18 | Before increment statement | main.go:83:16:83:16 | Before i | -| main.go:83:16:83:18 | incdec-rhs increment statement | main.go:83:16:83:18 | increment statement | -| main.go:83:16:83:18 | increment statement | main.go:83:16:83:18 | After increment statement | +| main.go:83:16:83:18 | compound-rhs increment statement | main.go:83:16:83:18 | After increment statement | +| main.go:83:16:83:18 | increment statement | main.go:83:16:83:16 | Before i | | main.go:83:20:88:2 | After block statement | main.go:83:2:88:2 | [LoopHeader] for statement | | main.go:83:20:88:2 | block statement | main.go:84:3:84:7 | ... = ... | | main.go:84:3:84:7 | ... = ... | main.go:84:7:84:7 | Before 2 | @@ -3160,7 +3157,7 @@ | stmts.go:23:11:37:2 | After block statement | stmts.go:23:2:37:2 | [LoopHeader] for statement | | stmts.go:23:11:37:2 | block statement | stmts.go:24:3:36:3 | for statement | | stmts.go:24:3:36:3 | After for statement | stmts.go:23:11:37:2 | After block statement | -| stmts.go:24:3:36:3 | [LoopHeader] for statement | stmts.go:24:23:24:25 | Before increment statement | +| stmts.go:24:3:36:3 | [LoopHeader] for statement | stmts.go:24:23:24:25 | increment statement | | stmts.go:24:3:36:3 | for statement | stmts.go:24:7:24:12 | ... := ... | | stmts.go:24:7:24:12 | ... := ... | stmts.go:24:12:24:12 | Before 0 | | stmts.go:24:7:24:12 | After ... := ... | stmts.go:24:15:24:20 | Before ...<... | @@ -3179,13 +3176,12 @@ | stmts.go:24:19:24:20 | 10 | stmts.go:24:19:24:20 | After 10 | | stmts.go:24:19:24:20 | After 10 | stmts.go:24:15:24:20 | ...<... | | stmts.go:24:19:24:20 | Before 10 | stmts.go:24:19:24:20 | 10 | -| stmts.go:24:23:24:23 | After i | stmts.go:24:23:24:25 | incdec-rhs increment statement | +| stmts.go:24:23:24:23 | After i | stmts.go:24:23:24:25 | compound-rhs increment statement | | stmts.go:24:23:24:23 | Before i | stmts.go:24:23:24:23 | i | | stmts.go:24:23:24:23 | i | stmts.go:24:23:24:23 | After i | | stmts.go:24:23:24:25 | After increment statement | stmts.go:24:15:24:20 | Before ...<... | -| stmts.go:24:23:24:25 | Before increment statement | stmts.go:24:23:24:23 | Before i | -| stmts.go:24:23:24:25 | incdec-rhs increment statement | stmts.go:24:23:24:25 | increment statement | -| stmts.go:24:23:24:25 | increment statement | stmts.go:24:23:24:25 | After increment statement | +| stmts.go:24:23:24:25 | compound-rhs increment statement | stmts.go:24:23:24:25 | After increment statement | +| stmts.go:24:23:24:25 | increment statement | stmts.go:24:23:24:23 | Before i | | stmts.go:24:27:36:3 | block statement | stmts.go:25:4:35:4 | if statement | | stmts.go:25:4:35:4 | if statement | stmts.go:25:7:25:16 | ... := ... | | stmts.go:25:7:25:16 | ... := ... | stmts.go:25:12:25:16 | Before ...-... | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected b/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected index 1ebde1b623b..8c8394c0885 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/FlowSteps/LocalFlowStep.expected @@ -20,7 +20,7 @@ | main.go:15:9:15:9 | 0 | main.go:15:2:15:9 | SSA def(acc) | | main.go:16:9:19:2 | SSA def(acc) | main.go:17:3:17:5 | acc | | main.go:17:3:17:7 | SSA def(acc) | main.go:18:10:18:12 | acc | -| main.go:17:3:17:7 | incdec-rhs increment statement | main.go:17:3:17:7 | SSA def(acc) | +| main.go:17:3:17:7 | compound-rhs increment statement | main.go:17:3:17:7 | SSA def(acc) | | main.go:22:42:31:1 | SSA def(b) | main.go:23:5:23:5 | b | | main.go:22:42:31:1 | SSA def(x) | main.go:24:10:24:10 | x | | main.go:22:42:31:1 | SSA def(x) | main.go:26:11:26:11 | x | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected index b95a3cda3f7..6a386f44a9c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/FunctionInputsAndOutputs/FunctionOutput_getEntryNode.expected @@ -16,7 +16,7 @@ | result 1 | main.go:35:1:38:1 | function declaration | main.go:35:29:38:1 | zero-init:1 block statement | | result 1 | main.go:35:1:38:1 | function declaration | main.go:36:9:36:10 | 42 | | result 1 | main.go:40:1:48:1 | function declaration | main.go:40:33:48:1 | zero-init:1 block statement | -| result 1 | main.go:40:1:48:1 | function declaration | main.go:42:3:42:5 | incdec-rhs increment statement | +| result 1 | main.go:40:1:48:1 | function declaration | main.go:42:3:42:5 | compound-rhs increment statement | | result 1 | main.go:40:1:48:1 | function declaration | main.go:45:13:45:13 | 1 | | result 1 | main.go:40:1:48:1 | function declaration | main.go:47:12:47:12 | 4 | | result 1 | tst2.go:8:1:12:1 | function declaration | tst2.go:11:12:11:14 | err | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected index 4f15ddf9a3e..39d02bf15b7 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/SSA/VarDefs.expected @@ -17,11 +17,11 @@ | main.go:59:3:59:7 | assign:0 ... = ... | main.go:57:6:57:6 | x | main.go:59:7:59:7 | 2 | | main.go:63:2:63:7 | assign:0 ... := ... | main.go:63:2:63:2 | y | main.go:63:7:63:7 | 1 | | main.go:64:6:64:11 | assign:0 ... := ... | main.go:64:6:64:6 | i | main.go:64:11:64:11 | 0 | -| main.go:64:16:64:18 | increment statement | main.go:64:6:64:6 | i | main.go:64:16:64:18 | incdec-rhs increment statement | +| main.go:64:16:64:18 | compound-rhs increment statement | main.go:64:6:64:6 | i | main.go:64:16:64:18 | compound-rhs increment statement | | main.go:68:3:68:7 | assign:0 ... = ... | main.go:63:2:63:2 | y | main.go:68:7:68:7 | 2 | | main.go:72:2:72:7 | assign:0 ... := ... | main.go:72:2:72:2 | z | main.go:72:7:72:7 | 1 | | main.go:73:6:73:11 | assign:0 ... := ... | main.go:73:6:73:6 | i | main.go:73:11:73:11 | 0 | -| main.go:73:16:73:18 | increment statement | main.go:73:6:73:6 | i | main.go:73:16:73:18 | incdec-rhs increment statement | +| main.go:73:16:73:18 | compound-rhs increment statement | main.go:73:6:73:6 | i | main.go:73:16:73:18 | compound-rhs increment statement | | main.go:74:3:74:7 | assign:0 ... = ... | main.go:72:2:72:2 | z | main.go:74:7:74:7 | 2 | | main.go:82:36:86:1 | zero-init:0 block statement | main.go:82:18:82:18 | a | main.go:82:36:86:1 | zero-init:0 block statement | | main.go:82:36:86:1 | zero-init:1 block statement | main.go:82:25:82:25 | b | main.go:82:36:86:1 | zero-init:1 block statement |