@@ -8,7 +8,10 @@ use hir::{
8
8
} ;
9
9
use rustc_hir as hir;
10
10
use rustc_index:: vec:: IndexVec ;
11
- use rustc_middle:: hir:: map:: Map ;
11
+ use rustc_middle:: {
12
+ hir:: map:: Map ,
13
+ ty:: { TyCtxt , TypeckResults } ,
14
+ } ;
12
15
use std:: mem:: swap;
13
16
14
17
/// Traverses the body to find the control flow graph and locations for the
@@ -18,11 +21,14 @@ use std::mem::swap;
18
21
/// can be done with propagate_to_fixpoint in cfg_propagate.
19
22
pub ( super ) fn build_control_flow_graph < ' tcx > (
20
23
hir : Map < ' tcx > ,
24
+ tcx : TyCtxt < ' tcx > ,
25
+ typeck_results : & TypeckResults < ' tcx > ,
21
26
consumed_borrowed_places : ConsumedAndBorrowedPlaces ,
22
27
body : & ' tcx Body < ' tcx > ,
23
28
num_exprs : usize ,
24
29
) -> DropRangesBuilder {
25
- let mut drop_range_visitor = DropRangeVisitor :: new ( hir, consumed_borrowed_places, num_exprs) ;
30
+ let mut drop_range_visitor =
31
+ DropRangeVisitor :: new ( hir, tcx, typeck_results, consumed_borrowed_places, num_exprs) ;
26
32
intravisit:: walk_body ( & mut drop_range_visitor, body) ;
27
33
28
34
drop_range_visitor. drop_ranges . process_deferred_edges ( ) ;
@@ -36,22 +42,30 @@ pub(super) fn build_control_flow_graph<'tcx>(
36
42
/// We are interested in points where a variables is dropped or initialized, and the control flow
37
43
/// of the code. We identify locations in code by their post-order traversal index, so it is
38
44
/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
39
- struct DropRangeVisitor < ' tcx > {
45
+ struct DropRangeVisitor < ' a , ' tcx > {
40
46
hir : Map < ' tcx > ,
41
47
places : ConsumedAndBorrowedPlaces ,
42
48
drop_ranges : DropRangesBuilder ,
43
49
expr_index : PostOrderId ,
50
+ tcx : TyCtxt < ' tcx > ,
51
+ typeck_results : & ' a TypeckResults < ' tcx > ,
44
52
}
45
53
46
- impl < ' tcx > DropRangeVisitor < ' tcx > {
47
- fn new ( hir : Map < ' tcx > , places : ConsumedAndBorrowedPlaces , num_exprs : usize ) -> Self {
54
+ impl < ' a , ' tcx > DropRangeVisitor < ' a , ' tcx > {
55
+ fn new (
56
+ hir : Map < ' tcx > ,
57
+ tcx : TyCtxt < ' tcx > ,
58
+ typeck_results : & ' a TypeckResults < ' tcx > ,
59
+ places : ConsumedAndBorrowedPlaces ,
60
+ num_exprs : usize ,
61
+ ) -> Self {
48
62
debug ! ( "consumed_places: {:?}" , places. consumed) ;
49
63
let drop_ranges = DropRangesBuilder :: new (
50
64
places. consumed . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
51
65
hir,
52
66
num_exprs,
53
67
) ;
54
- Self { hir, places, drop_ranges, expr_index : PostOrderId :: from_u32 ( 0 ) }
68
+ Self { hir, places, drop_ranges, expr_index : PostOrderId :: from_u32 ( 0 ) , typeck_results , tcx }
55
69
}
56
70
57
71
fn record_drop ( & mut self , hir_id : HirId ) {
@@ -91,9 +105,23 @@ impl<'tcx> DropRangeVisitor<'tcx> {
91
105
debug ! ( "reinitializing {:?} is not supported" , expr) ;
92
106
}
93
107
}
108
+
109
+ /// For an expression with an uninhabited return type (e.g. a function that returns !),
110
+ /// this adds a self edge to to the CFG to model the fact that the function does not
111
+ /// return.
112
+ fn handle_uninhabited_return ( & mut self , expr : & Expr < ' tcx > ) {
113
+ let ty = self . typeck_results . expr_ty ( expr) ;
114
+ let ty = self . tcx . erase_regions ( ty) ;
115
+ let m = self . tcx . parent_module ( expr. hir_id ) . to_def_id ( ) ;
116
+ let param_env = self . tcx . param_env ( m. expect_local ( ) ) ;
117
+ if self . tcx . is_ty_uninhabited_from ( m, ty, param_env) {
118
+ // This function will not return. We model this fact as an infinite loop.
119
+ self . drop_ranges . add_control_edge ( self . expr_index + 1 , self . expr_index + 1 ) ;
120
+ }
121
+ }
94
122
}
95
123
96
- impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' tcx > {
124
+ impl < ' a , ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' a , ' tcx > {
97
125
type Map = intravisit:: ErasedMap < ' tcx > ;
98
126
99
127
fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -109,6 +137,7 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
109
137
110
138
reinit = Some ( lhs) ;
111
139
}
140
+
112
141
ExprKind :: If ( test, if_true, if_false) => {
113
142
self . visit_expr ( test) ;
114
143
@@ -155,6 +184,7 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
155
184
self . drop_ranges . add_control_edge ( arm_end, self . expr_index + 1 )
156
185
} ) ;
157
186
}
187
+
158
188
ExprKind :: Loop ( body, ..) => {
159
189
let loop_begin = self . expr_index + 1 ;
160
190
if body. stmts . is_empty ( ) && body. expr . is_none ( ) {
@@ -172,14 +202,29 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
172
202
self . drop_ranges . add_control_edge_hir_id ( self . expr_index , target) ;
173
203
}
174
204
205
+ ExprKind :: Call ( f, args) => {
206
+ self . visit_expr ( f) ;
207
+ for arg in args {
208
+ self . visit_expr ( arg) ;
209
+ }
210
+
211
+ self . handle_uninhabited_return ( expr) ;
212
+ }
213
+ ExprKind :: MethodCall ( _, _, exprs, _) => {
214
+ for expr in exprs {
215
+ self . visit_expr ( expr) ;
216
+ }
217
+
218
+ self . handle_uninhabited_return ( expr) ;
219
+ }
220
+
175
221
ExprKind :: AddrOf ( ..)
176
222
| ExprKind :: Array ( ..)
177
223
| ExprKind :: AssignOp ( ..)
178
224
| ExprKind :: Binary ( ..)
179
225
| ExprKind :: Block ( ..)
180
226
| ExprKind :: Box ( ..)
181
227
| ExprKind :: Break ( ..)
182
- | ExprKind :: Call ( ..)
183
228
| ExprKind :: Cast ( ..)
184
229
| ExprKind :: Closure ( ..)
185
230
| ExprKind :: ConstBlock ( ..)
@@ -192,7 +237,6 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
192
237
| ExprKind :: Let ( ..)
193
238
| ExprKind :: Lit ( ..)
194
239
| ExprKind :: LlvmInlineAsm ( ..)
195
- | ExprKind :: MethodCall ( ..)
196
240
| ExprKind :: Path ( ..)
197
241
| ExprKind :: Repeat ( ..)
198
242
| ExprKind :: Ret ( ..)
0 commit comments