about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-14 02:22:48 +0000
committerbors <bors@rust-lang.org>2022-07-14 02:22:48 +0000
commit8a392a5992fda3f041726fc85e42569497dfd753 (patch)
treec3f6ede91aff837e4b764b0927e35e6457739ed5 /compiler
parentcbb07c27a4d78f95557a6b9cdcc32f98d67a0c22 (diff)
parentb30315d64f75b26fc20d3df975a48cd1e149f28f (diff)
downloadrust-8a392a5992fda3f041726fc85e42569497dfd753.tar.gz
rust-8a392a5992fda3f041726fc85e42569497dfd753.zip
Auto merge of #98754 - jyn514:non-trivial-drop, r=compiler-errors
Fix drop-tracking ICE when a struct containing a field with a significant drop is used across an await

Previously, drop-tracking would incorrectly assume the struct would be dropped immediately, which was not true.

Fixes #98476. Also fixes https://github.com/rust-lang/rust/issues/98477, I think because the parent HIR node for type variables is the whole function instead of the expression where the variable is used.

r? `@eholk`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs28
1 files changed, 25 insertions, 3 deletions
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 6ee989070b4..a0c256bb83d 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use tracing::debug;
@@ -376,6 +376,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
 
         debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
 
+        let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
+        let may_need_drop = |ty: Ty<'tcx>| {
+            // Avoid ICEs in needs_drop.
+            let ty = self.fcx.resolve_vars_if_possible(ty);
+            let ty = self.fcx.tcx.erase_regions(ty);
+            if ty.needs_infer() {
+                return true;
+            }
+            ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
+        };
+
         // Typically, the value produced by an expression is consumed by its parent in some way,
         // so we only have to check if the parent contains a yield (note that the parent may, for
         // 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> {
         // However, in the case of temporary values, we are going to store the value into a
         // temporary on the stack that is live for the current temporary scope and then return a
         // reference to it. That value may be live across the entire temporary scope.
-        let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
+        //
+        // There's another subtlety: if the type has an observable drop, it must be dropped after
+        // the yield, even if it's not borrowed or referenced after the yield. Ideally this would
+        // *only* happen for types with observable drop, not all types which wrap them, but that
+        // doesn't match the behavior of MIR borrowck and causes ICEs. See the FIXME comment in
+        // src/test/ui/generator/drop-tracking-parent-expression.rs.
+        let scope = if self.drop_ranges.is_borrowed_temporary(expr)
+            || ty.map_or(true, |ty| {
+                let needs_drop = may_need_drop(ty);
+                debug!(?needs_drop, ?ty);
+                needs_drop
+            }) {
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
             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> {
 
         // If there are adjustments, then record the final type --
         // this is the actual value that is being produced.
-        if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
+        if let Some(adjusted_ty) = ty {
             self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span);
         }