@@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
1414use rustc_hir:: intravisit:: { self , Visitor } ;
1515use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
1616use 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 } ;
1818use rustc_span:: symbol:: sym;
1919use rustc_span:: Span ;
2020use tracing:: debug;
@@ -376,6 +376,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
376376
377377 debug ! ( "is_borrowed_temporary: {:?}" , self . drop_ranges. is_borrowed_temporary( expr) ) ;
378378
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+
379390 // Typically, the value produced by an expression is consumed by its parent in some way,
380391 // so we only have to check if the parent contains a yield (note that the parent may, for
381392 // 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> {
384395 // However, in the case of temporary values, we are going to store the value into a
385396 // temporary on the stack that is live for the current temporary scope and then return a
386397 // 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+ } ) {
388410 self . rvalue_scopes . temporary_scope ( self . region_scope_tree , expr. hir_id . local_id )
389411 } else {
390412 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> {
398420
399421 // If there are adjustments, then record the final type --
400422 // 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 {
402424 self . record ( adjusted_ty, expr. hir_id , scope, Some ( expr) , expr. span ) ;
403425 }
404426
0 commit comments