]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/coverage.rs
Fix diagnostic issue when using FakeReads in closures
[rust.git] / compiler / rustc_middle / src / mir / coverage.rs
1 //! Metadata from source code coverage analysis and instrumentation.
2
3 use rustc_macros::HashStable;
4 use rustc_span::Symbol;
5
6 use std::cmp::Ord;
7 use std::fmt::{self, Debug, Formatter};
8
9 rustc_index::newtype_index! {
10     /// An ExpressionOperandId value is assigned directly from either a
11     /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
12     /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
13     /// constant value of `0`.
14     pub struct ExpressionOperandId {
15         derive [HashStable]
16         DEBUG_FORMAT = "ExpressionOperandId({})",
17         MAX = 0xFFFF_FFFF,
18     }
19 }
20
21 impl ExpressionOperandId {
22     /// An expression operand for a "zero counter", as described in the following references:
23     ///
24     /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter>
25     /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag>
26     /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
27     ///
28     /// This operand can be used to count two or more separate code regions with a single counter,
29     /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
30     /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
31     /// the coverage map for the other code regions.
32     pub const ZERO: Self = Self::from_u32(0);
33 }
34
35 rustc_index::newtype_index! {
36     pub struct CounterValueReference {
37         derive [HashStable]
38         DEBUG_FORMAT = "CounterValueReference({})",
39         MAX = 0xFFFF_FFFF,
40     }
41 }
42
43 impl CounterValueReference {
44     // Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
45     pub const START: Self = Self::from_u32(1);
46 }
47
48 rustc_index::newtype_index! {
49     /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
50     ///
51     /// Values descend from u32::MAX.
52     pub struct InjectedExpressionId {
53         derive [HashStable]
54         DEBUG_FORMAT = "InjectedExpressionId({})",
55         MAX = 0xFFFF_FFFF,
56     }
57 }
58
59 rustc_index::newtype_index! {
60     /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
61     ///
62     /// Values ascend from 0.
63     pub struct InjectedExpressionIndex {
64         derive [HashStable]
65         DEBUG_FORMAT = "InjectedExpressionIndex({})",
66         MAX = 0xFFFF_FFFF,
67     }
68 }
69
70 rustc_index::newtype_index! {
71     /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
72     /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
73     /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
74     pub struct MappedExpressionIndex {
75         derive [HashStable]
76         DEBUG_FORMAT = "MappedExpressionIndex({})",
77         MAX = 0xFFFF_FFFF,
78     }
79 }
80
81 impl From<CounterValueReference> for ExpressionOperandId {
82     #[inline]
83     fn from(v: CounterValueReference) -> ExpressionOperandId {
84         ExpressionOperandId::from(v.as_u32())
85     }
86 }
87
88 impl From<InjectedExpressionId> for ExpressionOperandId {
89     #[inline]
90     fn from(v: InjectedExpressionId) -> ExpressionOperandId {
91         ExpressionOperandId::from(v.as_u32())
92     }
93 }
94
95 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
96 pub enum CoverageKind {
97     Counter {
98         function_source_hash: u64,
99         id: CounterValueReference,
100     },
101     Expression {
102         id: InjectedExpressionId,
103         lhs: ExpressionOperandId,
104         op: Op,
105         rhs: ExpressionOperandId,
106     },
107     Unreachable,
108 }
109
110 impl CoverageKind {
111     pub fn as_operand_id(&self) -> ExpressionOperandId {
112         use CoverageKind::*;
113         match *self {
114             Counter { id, .. } => ExpressionOperandId::from(id),
115             Expression { id, .. } => ExpressionOperandId::from(id),
116             Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
117         }
118     }
119
120     pub fn is_expression(&self) -> bool {
121         matches!(self, Self::Expression { .. })
122     }
123 }
124
125 impl Debug for CoverageKind {
126     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
127         use CoverageKind::*;
128         match self {
129             Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
130             Expression { id, lhs, op, rhs } => write!(
131                 fmt,
132                 "Expression({:?}) = {} {} {}",
133                 id.index(),
134                 lhs.index(),
135                 if *op == Op::Add { "+" } else { "-" },
136                 rhs.index(),
137             ),
138             Unreachable => write!(fmt, "Unreachable"),
139         }
140     }
141 }
142
143 #[derive(
144     Clone,
145     TyEncodable,
146     TyDecodable,
147     Hash,
148     HashStable,
149     TypeFoldable,
150     PartialEq,
151     Eq,
152     PartialOrd,
153     Ord
154 )]
155 pub struct CodeRegion {
156     pub file_name: Symbol,
157     pub start_line: u32,
158     pub start_col: u32,
159     pub end_line: u32,
160     pub end_col: u32,
161 }
162
163 impl Debug for CodeRegion {
164     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
165         write!(
166             fmt,
167             "{}:{}:{} - {}:{}",
168             self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
169         )
170     }
171 }
172
173 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
174 pub enum Op {
175     Subtract,
176     Add,
177 }