@@ -38,6 +38,7 @@ use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
38
38
use llvm;
39
39
use metadata:: { csearch, encoder, loader} ;
40
40
use middle:: astencode;
41
+ use middle:: cfg;
41
42
use middle:: lang_items:: { LangItem , ExchangeMallocFnLangItem , StartFnLangItem } ;
42
43
use middle:: subst;
43
44
use middle:: weak_lang_items;
@@ -1305,47 +1306,33 @@ pub fn make_return_slot_pointer<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
1305
1306
}
1306
1307
}
1307
1308
1308
- struct CheckForNestedReturnsVisitor {
1309
+ struct FindNestedReturn {
1309
1310
found : bool ,
1310
- in_return : bool
1311
1311
}
1312
1312
1313
- impl CheckForNestedReturnsVisitor {
1314
- fn explicit ( ) -> CheckForNestedReturnsVisitor {
1315
- CheckForNestedReturnsVisitor { found : false , in_return : false }
1316
- }
1317
- fn implicit ( ) -> CheckForNestedReturnsVisitor {
1318
- CheckForNestedReturnsVisitor { found : false , in_return : true }
1313
+ impl FindNestedReturn {
1314
+ fn new ( ) -> FindNestedReturn {
1315
+ FindNestedReturn { found : false }
1319
1316
}
1320
1317
}
1321
1318
1322
- impl < ' v > Visitor < ' v > for CheckForNestedReturnsVisitor {
1319
+ impl < ' v > Visitor < ' v > for FindNestedReturn {
1323
1320
fn visit_expr ( & mut self , e : & ast:: Expr ) {
1324
1321
match e. node {
1325
1322
ast:: ExprRet ( ..) => {
1326
- if self . in_return {
1327
- self . found = true ;
1328
- } else {
1329
- self . in_return = true ;
1330
- visit:: walk_expr ( self , e) ;
1331
- self . in_return = false ;
1332
- }
1323
+ self . found = true ;
1333
1324
}
1334
1325
_ => visit:: walk_expr ( self , e)
1335
1326
}
1336
1327
}
1337
1328
}
1338
1329
1339
- fn has_nested_returns ( tcx : & ty:: ctxt , id : ast:: NodeId ) -> bool {
1340
- match tcx. map . find ( id) {
1330
+ fn build_cfg ( tcx : & ty:: ctxt , id : ast:: NodeId ) -> ( ast :: NodeId , Option < cfg :: CFG > ) {
1331
+ let blk = match tcx. map . find ( id) {
1341
1332
Some ( ast_map:: NodeItem ( i) ) => {
1342
1333
match i. node {
1343
1334
ast:: ItemFn ( _, _, _, _, ref blk) => {
1344
- let mut explicit = CheckForNestedReturnsVisitor :: explicit ( ) ;
1345
- let mut implicit = CheckForNestedReturnsVisitor :: implicit ( ) ;
1346
- visit:: walk_item ( & mut explicit, & * i) ;
1347
- visit:: walk_expr_opt ( & mut implicit, & blk. expr ) ;
1348
- explicit. found || implicit. found
1335
+ blk
1349
1336
}
1350
1337
_ => tcx. sess . bug ( "unexpected item variant in has_nested_returns" )
1351
1338
}
@@ -1355,11 +1342,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
1355
1342
ast:: ProvidedMethod ( ref m) => {
1356
1343
match m. node {
1357
1344
ast:: MethDecl ( _, _, _, _, _, _, ref blk, _) => {
1358
- let mut explicit = CheckForNestedReturnsVisitor :: explicit ( ) ;
1359
- let mut implicit = CheckForNestedReturnsVisitor :: implicit ( ) ;
1360
- visit:: walk_method_helper ( & mut explicit, & * * m) ;
1361
- visit:: walk_expr_opt ( & mut implicit, & blk. expr ) ;
1362
- explicit. found || implicit. found
1345
+ blk
1363
1346
}
1364
1347
ast:: MethMac ( _) => tcx. sess . bug ( "unexpanded macro" )
1365
1348
}
@@ -1379,11 +1362,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
1379
1362
ast:: MethodImplItem ( ref m) => {
1380
1363
match m. node {
1381
1364
ast:: MethDecl ( _, _, _, _, _, _, ref blk, _) => {
1382
- let mut explicit = CheckForNestedReturnsVisitor :: explicit ( ) ;
1383
- let mut implicit = CheckForNestedReturnsVisitor :: implicit ( ) ;
1384
- visit:: walk_method_helper ( & mut explicit, & * * m) ;
1385
- visit:: walk_expr_opt ( & mut implicit, & blk. expr ) ;
1386
- explicit. found || implicit. found
1365
+ blk
1387
1366
}
1388
1367
ast:: MethMac ( _) => tcx. sess . bug ( "unexpanded macro" )
1389
1368
}
@@ -1397,24 +1376,47 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
1397
1376
Some ( ast_map:: NodeExpr ( e) ) => {
1398
1377
match e. node {
1399
1378
ast:: ExprClosure ( _, _, _, ref blk) => {
1400
- let mut explicit = CheckForNestedReturnsVisitor :: explicit ( ) ;
1401
- let mut implicit = CheckForNestedReturnsVisitor :: implicit ( ) ;
1402
- visit:: walk_expr ( & mut explicit, e) ;
1403
- visit:: walk_expr_opt ( & mut implicit, & blk. expr ) ;
1404
- explicit. found || implicit. found
1379
+ blk
1405
1380
}
1406
1381
_ => tcx. sess . bug ( "unexpected expr variant in has_nested_returns" )
1407
1382
}
1408
1383
}
1409
-
1410
- Some ( ast_map:: NodeVariant ( ..) ) | Some ( ast_map:: NodeStructCtor ( ..) ) => false ,
1384
+ Some ( ast_map:: NodeVariant ( ..) ) | Some ( ast_map:: NodeStructCtor ( ..) ) => return ( ast:: DUMMY_NODE_ID , None ) ,
1411
1385
1412
1386
// glue, shims, etc
1413
- None if id == ast:: DUMMY_NODE_ID => false ,
1387
+ None if id == ast:: DUMMY_NODE_ID => return ( ast :: DUMMY_NODE_ID , None ) ,
1414
1388
1415
1389
_ => tcx. sess . bug ( format ! ( "unexpected variant in has_nested_returns: {}" ,
1416
1390
tcx. map. path_to_string( id) ) . as_slice ( ) )
1391
+ } ;
1392
+
1393
+ ( blk. id , Some ( cfg:: CFG :: new ( tcx, & * * blk) ) )
1394
+ }
1395
+
1396
+ fn has_nested_returns ( tcx : & ty:: ctxt , cfg : & cfg:: CFG , blk_id : ast:: NodeId ) -> bool {
1397
+ for n in cfg. graph . depth_traverse ( cfg. entry ) {
1398
+ match tcx. map . find ( n. id ) {
1399
+ Some ( ast_map:: NodeExpr ( ex) ) => {
1400
+ if let ast:: ExprRet ( Some ( ref ret_expr) ) = ex. node {
1401
+ let mut visitor = FindNestedReturn :: new ( ) ;
1402
+ visit:: walk_expr ( & mut visitor, & * * ret_expr) ;
1403
+ if visitor. found {
1404
+ return true ;
1405
+ }
1406
+ }
1407
+ }
1408
+ Some ( ast_map:: NodeBlock ( blk) ) if blk. id == blk_id => {
1409
+ let mut visitor = FindNestedReturn :: new ( ) ;
1410
+ visit:: walk_expr_opt ( & mut visitor, & blk. expr ) ;
1411
+ if visitor. found {
1412
+ return true ;
1413
+ }
1414
+ }
1415
+ _ => { }
1416
+ }
1417
1417
}
1418
+
1419
+ return false ;
1418
1420
}
1419
1421
1420
1422
// NB: must keep 4 fns in sync:
@@ -1453,7 +1455,12 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
1453
1455
ty:: FnDiverging => false
1454
1456
} ;
1455
1457
let debug_context = debuginfo:: create_function_debug_context ( ccx, id, param_substs, llfndecl) ;
1456
- let nested_returns = has_nested_returns ( ccx. tcx ( ) , id) ;
1458
+ let ( blk_id, cfg) = build_cfg ( ccx. tcx ( ) , id) ;
1459
+ let nested_returns = if let Some ( ref cfg) = cfg {
1460
+ has_nested_returns ( ccx. tcx ( ) , cfg, blk_id)
1461
+ } else {
1462
+ false
1463
+ } ;
1457
1464
1458
1465
let mut fcx = FunctionContext {
1459
1466
llfn : llfndecl,
@@ -1472,7 +1479,8 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
1472
1479
block_arena : block_arena,
1473
1480
ccx : ccx,
1474
1481
debug_context : debug_context,
1475
- scopes : RefCell :: new ( Vec :: new ( ) )
1482
+ scopes : RefCell :: new ( Vec :: new ( ) ) ,
1483
+ cfg : cfg
1476
1484
} ;
1477
1485
1478
1486
if has_env {
0 commit comments