Skip to content

Commit ab9a52a

Browse files
committed
coverage: Instrument the RHS value of lazy logical operators
When a lazy logical operator (`&&` or `||`) occurs outside of an `if` condition, it normally doesn't have any associated control-flow branch, so we don't have an existing way to track whether it was true or false. This patch adds special code to handle this case, by inserting extra MIR blocks in a diamond shape after evaluating the RHS. This gives us a place to insert the appropriate marker statements, which can then be given their own counters.
1 parent 68392c9 commit ab9a52a

File tree

3 files changed

+79
-18
lines changed

3 files changed

+79
-18
lines changed

compiler/rustc_mir_build/src/build/coverageinfo.rs

+58-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,64 @@ impl BranchInfoBuilder {
155155
}
156156
}
157157

158-
impl Builder<'_, '_> {
158+
impl<'tcx> Builder<'_, 'tcx> {
159+
/// If condition coverage is enabled, inject extra blocks and marker statements
160+
/// that will let us track the value of the condition in `place`.
161+
pub(crate) fn visit_coverage_standalone_condition(
162+
&mut self,
163+
mut expr_id: ExprId, // Expression giving the span of the condition
164+
place: mir::Place<'tcx>, // Already holds the boolean condition value
165+
block: &mut BasicBlock,
166+
) {
167+
// Bail out if condition coverage is not enabled for this function.
168+
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
169+
if !self.tcx.sess.instrument_coverage_condition() {
170+
return;
171+
};
172+
173+
// Remove any wrappers, so that we can inspect the real underlying expression.
174+
while let ExprKind::Use { source: inner } | ExprKind::Scope { value: inner, .. } =
175+
self.thir[expr_id].kind
176+
{
177+
expr_id = inner;
178+
}
179+
// If the expression is a lazy logical op, it will naturally get branch
180+
// coverage as part of its normal lowering, so we can disregard it here.
181+
if let ExprKind::LogicalOp { .. } = self.thir[expr_id].kind {
182+
return;
183+
}
184+
185+
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
186+
187+
// Using the boolean value that has already been stored in `place`, set up
188+
// control flow in the shape of a diamond, so that we can place separate
189+
// marker statements in the true and false blocks. The coverage MIR pass
190+
// will use those markers to inject coverage counters as appropriate.
191+
//
192+
// block
193+
// / \
194+
// true_block false_block
195+
// (marker) (marker)
196+
// \ /
197+
// join_block
198+
199+
let true_block = self.cfg.start_new_block();
200+
let false_block = self.cfg.start_new_block();
201+
self.cfg.terminate(
202+
*block,
203+
source_info,
204+
mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block),
205+
);
206+
207+
branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
208+
209+
let join_block = self.cfg.start_new_block();
210+
self.cfg.goto(true_block, source_info, join_block);
211+
self.cfg.goto(false_block, source_info, join_block);
212+
// Any subsequent codegen in the caller should use the new join block.
213+
*block = join_block;
214+
}
215+
159216
/// If branch coverage is enabled, inject marker statements into `then_block`
160217
/// and `else_block`, and record their IDs in the table of branch spans.
161218
pub(crate) fn visit_coverage_branch_condition(

compiler/rustc_mir_build/src/build/expr/into.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
181181
const_: Const::from_bool(this.tcx, constant),
182182
},
183183
);
184-
let rhs = unpack!(this.expr_into_dest(destination, continuation, rhs));
184+
let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs));
185+
// Instrument the lowered RHS's value for condition coverage.
186+
// (Does nothing if condition coverage is not enabled.)
187+
this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block);
188+
185189
let target = this.cfg.start_new_block();
186-
this.cfg.goto(rhs, source_info, target);
190+
this.cfg.goto(rhs_block, source_info, target);
187191
this.cfg.goto(short_circuit, source_info, target);
188192
target.unit()
189193
}

tests/coverage/branch/conditions.cov-map

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Function name: conditions::assign_3
2-
Raw bytes (73): 0x[01, 01, 09, 07, 0b, 05, 09, 0d, 11, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 09, 01, 17, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 22, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02]
2+
Raw bytes (73): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 09, 01, 17, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 22, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02]
33
Number of files: 1
44
- file 0 => global file 1
55
Number of expressions: 9
6-
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
7-
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
8-
- expression 2 operands: lhs = Counter(3), rhs = Counter(4)
6+
- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
7+
- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
8+
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
99
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
1010
- expression 4 operands: lhs = Counter(0), rhs = Counter(1)
1111
- expression 5 operands: lhs = Expression(8, Sub), rhs = Counter(4)
@@ -15,7 +15,7 @@ Number of expressions: 9
1515
Number of file 0 mappings: 9
1616
- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 40)
1717
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
18-
= ((c1 + c2) + (c3 + c4))
18+
= (c1 + ((c2 + c3) + c4))
1919
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
2020
- Branch { true: Counter(1), false: Expression(8, Sub) } at (prev + 0, 13) to (start + 0, 14)
2121
true = c1
@@ -31,7 +31,7 @@ Number of file 0 mappings: 9
3131
true = c2
3232
false = c3
3333
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
34-
= ((c1 + c2) + (c3 + c4))
34+
= (c1 + ((c2 + c3) + c4))
3535

3636
Function name: conditions::assign_3_bis
3737
Raw bytes (69): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 09, 01, 1c, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 1a, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 16, 00, 12, 00, 13, 13, 00, 17, 00, 18, 20, 0d, 11, 00, 17, 00, 18, 03, 01, 05, 01, 02]
@@ -66,18 +66,18 @@ Number of file 0 mappings: 9
6666
= ((c2 + c3) + c4)
6767

6868
Function name: conditions::assign_and
69-
Raw bytes (51): 0x[01, 01, 04, 09, 07, 0d, 0e, 01, 05, 01, 05, 07, 01, 0d, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02]
69+
Raw bytes (51): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 07, 01, 0d, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02]
7070
Number of files: 1
7171
- file 0 => global file 1
7272
Number of expressions: 4
73-
- expression 0 operands: lhs = Counter(2), rhs = Expression(1, Add)
74-
- expression 1 operands: lhs = Counter(3), rhs = Expression(3, Sub)
73+
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(3, Sub)
74+
- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
7575
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
7676
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
7777
Number of file 0 mappings: 7
7878
- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33)
7979
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
80-
= (c2 + (c3 + (c0 - c1)))
80+
= ((c2 + c3) + (c0 - c1))
8181
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
8282
- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14)
8383
true = c1
@@ -87,7 +87,7 @@ Number of file 0 mappings: 7
8787
true = c2
8888
false = c3
8989
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
90-
= (c2 + (c3 + (c0 - c1)))
90+
= ((c2 + c3) + (c0 - c1))
9191

9292
Function name: conditions::assign_or
9393
Raw bytes (51): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 07, 01, 12, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02]
@@ -123,13 +123,13 @@ Number of file 0 mappings: 1
123123
- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2)
124124

125125
Function name: conditions::func_call
126-
Raw bytes (39): 0x[01, 01, 03, 01, 05, 09, 0b, 0d, 02, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 07, 01, 01, 00, 02]
126+
Raw bytes (39): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 07, 01, 01, 00, 02]
127127
Number of files: 1
128128
- file 0 => global file 1
129129
Number of expressions: 3
130130
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
131-
- expression 1 operands: lhs = Counter(2), rhs = Expression(2, Add)
132-
- expression 2 operands: lhs = Counter(3), rhs = Expression(0, Sub)
131+
- expression 1 operands: lhs = Expression(2, Add), rhs = Expression(0, Sub)
132+
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
133133
Number of file 0 mappings: 5
134134
- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 10)
135135
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 10)
@@ -140,7 +140,7 @@ Number of file 0 mappings: 5
140140
true = c2
141141
false = c3
142142
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
143-
= (c2 + (c3 + (c0 - c1)))
143+
= ((c2 + c3) + (c0 - c1))
144144

145145
Function name: conditions::simple_assign
146146
Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02]

0 commit comments

Comments
 (0)