@@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
14
14
use rustc_hir:: intravisit:: { self , Visitor } ;
15
15
use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
16
16
use rustc_middle:: middle:: region:: { self , Scope , ScopeData , YieldData } ;
17
- use rustc_middle:: ty:: { self , RvalueScopes , Ty , TyCtxt } ;
17
+ use rustc_middle:: ty:: { self , RvalueScopes , Ty , TyCtxt , TypeVisitable } ;
18
18
use rustc_span:: symbol:: sym;
19
19
use rustc_span:: Span ;
20
20
use tracing:: debug;
@@ -376,6 +376,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
376
376
377
377
debug ! ( "is_borrowed_temporary: {:?}" , self . drop_ranges. is_borrowed_temporary( expr) ) ;
378
378
379
+ let ty = self . fcx . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( expr) ;
380
+ let may_need_drop = |ty : Ty < ' tcx > | {
381
+ // Avoid ICEs in needs_drop.
382
+ let ty = self . fcx . resolve_vars_if_possible ( ty) ;
383
+ let ty = self . fcx . tcx . erase_regions ( ty) ;
384
+ if ty. needs_infer ( ) {
385
+ return true ;
386
+ }
387
+ ty. needs_drop ( self . fcx . tcx , self . fcx . param_env )
388
+ } ;
389
+
379
390
// Typically, the value produced by an expression is consumed by its parent in some way,
380
391
// so we only have to check if the parent contains a yield (note that the parent may, for
381
392
// example, store the value into a local variable, but then we already consider local
@@ -384,7 +395,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
384
395
// However, in the case of temporary values, we are going to store the value into a
385
396
// temporary on the stack that is live for the current temporary scope and then return a
386
397
// reference to it. That value may be live across the entire temporary scope.
387
- let scope = if self . drop_ranges . is_borrowed_temporary ( expr) {
398
+ //
399
+ // There's another subtlety: if the type has an observable drop, it must be dropped after
400
+ // the yield, even if it's not borrowed or referenced after the yield. Ideally this would
401
+ // *only* happen for types with observable drop, not all types which wrap them, but that
402
+ // doesn't match the behavior of MIR borrowck and causes ICEs. See the FIXME comment in
403
+ // src/test/ui/generator/drop-tracking-parent-expression.rs.
404
+ let scope = if self . drop_ranges . is_borrowed_temporary ( expr)
405
+ || ty. map_or ( true , |ty| {
406
+ let needs_drop = may_need_drop ( ty) ;
407
+ debug ! ( ?needs_drop, ?ty) ;
408
+ needs_drop
409
+ } ) {
388
410
self . rvalue_scopes . temporary_scope ( self . region_scope_tree , expr. hir_id . local_id )
389
411
} else {
390
412
debug ! ( "parent_node: {:?}" , self . fcx. tcx. hir( ) . find_parent_node( expr. hir_id) ) ;
@@ -398,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
398
420
399
421
// If there are adjustments, then record the final type --
400
422
// this is the actual value that is being produced.
401
- if let Some ( adjusted_ty) = self . fcx . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( expr ) {
423
+ if let Some ( adjusted_ty) = ty {
402
424
self . record ( adjusted_ty, expr. hir_id , scope, Some ( expr) , expr. span ) ;
403
425
}
404
426
0 commit comments