@@ -8,7 +8,10 @@ use hir::{
88} ;
99use rustc_hir as hir;
1010use rustc_index:: vec:: IndexVec ;
11- use rustc_middle:: hir:: map:: Map ;
11+ use rustc_middle:: {
12+ hir:: map:: Map ,
13+ ty:: { TyCtxt , TypeckResults } ,
14+ } ;
1215use std:: mem:: swap;
1316
1417/// Traverses the body to find the control flow graph and locations for the
@@ -18,11 +21,14 @@ use std::mem::swap;
1821/// can be done with propagate_to_fixpoint in cfg_propagate.
1922pub ( super ) fn build_control_flow_graph < ' tcx > (
2023 hir : Map < ' tcx > ,
24+ tcx : TyCtxt < ' tcx > ,
25+ typeck_results : & TypeckResults < ' tcx > ,
2126 consumed_borrowed_places : ConsumedAndBorrowedPlaces ,
2227 body : & ' tcx Body < ' tcx > ,
2328 num_exprs : usize ,
2429) -> 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) ;
2632 intravisit:: walk_body ( & mut drop_range_visitor, body) ;
2733
2834 drop_range_visitor. drop_ranges . process_deferred_edges ( ) ;
@@ -36,22 +42,30 @@ pub(super) fn build_control_flow_graph<'tcx>(
3642/// We are interested in points where a variables is dropped or initialized, and the control flow
3743/// of the code. We identify locations in code by their post-order traversal index, so it is
3844/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
39- struct DropRangeVisitor < ' tcx > {
45+ struct DropRangeVisitor < ' a , ' tcx > {
4046 hir : Map < ' tcx > ,
4147 places : ConsumedAndBorrowedPlaces ,
4248 drop_ranges : DropRangesBuilder ,
4349 expr_index : PostOrderId ,
50+ tcx : TyCtxt < ' tcx > ,
51+ typeck_results : & ' a TypeckResults < ' tcx > ,
4452}
4553
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 {
4862 debug ! ( "consumed_places: {:?}" , places. consumed) ;
4963 let drop_ranges = DropRangesBuilder :: new (
5064 places. consumed . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
5165 hir,
5266 num_exprs,
5367 ) ;
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 }
5569 }
5670
5771 fn record_drop ( & mut self , hir_id : HirId ) {
@@ -91,9 +105,23 @@ impl<'tcx> DropRangeVisitor<'tcx> {
91105 debug ! ( "reinitializing {:?} is not supported" , expr) ;
92106 }
93107 }
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+ }
94122}
95123
96- impl < ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' tcx > {
124+ impl < ' a , ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' a , ' tcx > {
97125 type Map = intravisit:: ErasedMap < ' tcx > ;
98126
99127 fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -109,6 +137,7 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
109137
110138 reinit = Some ( lhs) ;
111139 }
140+
112141 ExprKind :: If ( test, if_true, if_false) => {
113142 self . visit_expr ( test) ;
114143
@@ -155,6 +184,7 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
155184 self . drop_ranges . add_control_edge ( arm_end, self . expr_index + 1 )
156185 } ) ;
157186 }
187+
158188 ExprKind :: Loop ( body, ..) => {
159189 let loop_begin = self . expr_index + 1 ;
160190 if body. stmts . is_empty ( ) && body. expr . is_none ( ) {
@@ -172,14 +202,29 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
172202 self . drop_ranges . add_control_edge_hir_id ( self . expr_index , target) ;
173203 }
174204
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+
175221 ExprKind :: AddrOf ( ..)
176222 | ExprKind :: Array ( ..)
177223 | ExprKind :: AssignOp ( ..)
178224 | ExprKind :: Binary ( ..)
179225 | ExprKind :: Block ( ..)
180226 | ExprKind :: Box ( ..)
181227 | ExprKind :: Break ( ..)
182- | ExprKind :: Call ( ..)
183228 | ExprKind :: Cast ( ..)
184229 | ExprKind :: Closure ( ..)
185230 | ExprKind :: ConstBlock ( ..)
@@ -192,7 +237,6 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
192237 | ExprKind :: Let ( ..)
193238 | ExprKind :: Lit ( ..)
194239 | ExprKind :: LlvmInlineAsm ( ..)
195- | ExprKind :: MethodCall ( ..)
196240 | ExprKind :: Path ( ..)
197241 | ExprKind :: Repeat ( ..)
198242 | ExprKind :: Ret ( ..)
0 commit comments