about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs51
2 files changed, 86 insertions, 22 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 62d49a62744..75897ba540e 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -3,7 +3,7 @@ use rustc_index::bit_set::DenseBitSet;
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::for_liveness;
-use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
+use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
 use rustc_middle::traits::query::DropckOutlivesResult;
 use rustc_middle::ty::relate::Relate;
 use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
@@ -11,7 +11,10 @@ use rustc_mir_dataflow::ResultsCursor;
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
-use rustc_span::DUMMY_SP;
+use rustc_span::{DUMMY_SP, Span};
+use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
+use rustc_trait_selection::traits::ObligationCtxt;
+use rustc_trait_selection::traits::query::dropck_outlives;
 use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, TypeOpOutput};
 use tracing::debug;
 
@@ -162,9 +165,10 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
     fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
         for local in boring_locals {
             let local_ty = self.cx.body.local_decls[local].ty;
+            let local_span = self.cx.body.local_decls[local].source_info.span;
             let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
                 let typeck = &self.cx.typeck;
-                move || LivenessContext::compute_drop_data(typeck, local_ty)
+                move || LivenessContext::compute_drop_data(typeck, local_ty, local_span)
             });
 
             drop_data.dropck_result.report_overflows(
@@ -522,9 +526,10 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
             values::pretty_print_points(self.location_map, live_at.iter()),
         );
 
+        let local_span = self.body.local_decls()[dropped_local].source_info.span;
         let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
             let typeck = &self.typeck;
-            move || Self::compute_drop_data(typeck, dropped_ty)
+            move || Self::compute_drop_data(typeck, dropped_ty, local_span)
         });
 
         if let Some(data) = &drop_data.region_constraint_data {
@@ -589,19 +594,45 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
         }
     }
 
-    fn compute_drop_data(typeck: &TypeChecker<'_, 'tcx>, dropped_ty: Ty<'tcx>) -> DropData<'tcx> {
-        debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
+    fn compute_drop_data(
+        typeck: &TypeChecker<'_, 'tcx>,
+        dropped_ty: Ty<'tcx>,
+        span: Span,
+    ) -> DropData<'tcx> {
+        debug!("compute_drop_data(dropped_ty={:?})", dropped_ty);
+
+        let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty });
 
-        match typeck
-            .infcx
-            .param_env
-            .and(DropckOutlives { dropped_ty })
-            .fully_perform(typeck.infcx, DUMMY_SP)
-        {
+        match op.fully_perform(typeck.infcx, DUMMY_SP) {
             Ok(TypeOpOutput { output, constraints, .. }) => {
                 DropData { dropck_result: output, region_constraint_data: constraints }
             }
-            Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None },
+            Err(_) => {
+                // We don't run dropck on HIR, and dropck looks inside fields of
+                // types, so there's no guarantee that it succeeds. We also
+                // can't rely on the the `ErrorGuaranteed` from `fully_perform` here
+                // because it comes from delay_span_bug.
+                let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx);
+                let errors = match dropck_outlives::compute_dropck_outlives_with_errors(
+                    &ocx, op, span, true,
+                ) {
+                    Ok(_) => ocx.select_all_or_error(),
+                    Err(e) => {
+                        if e.is_empty() {
+                            ocx.select_all_or_error()
+                        } else {
+                            e
+                        }
+                    }
+                };
+
+                if !errors.is_empty() {
+                    typeck.infcx.err_ctxt().report_fulfillment_errors(errors);
+                } else {
+                    rustc_middle::span_bug!(span, "Rerunning drop data query produced no error.");
+                }
+                DropData { dropck_result: Default::default(), region_constraint_data: None }
+            }
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 92098e20448..03a2e1adda2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -2,12 +2,13 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_infer::traits::query::type_op::DropckOutlives;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::Span;
 use tracing::{debug, instrument};
 
+use crate::solve::NextSolverError;
 use crate::traits::query::NoSolution;
 use crate::traits::query::normalize::QueryNormalizeExt;
-use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
+use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt};
 
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
@@ -93,6 +94,21 @@ pub fn compute_dropck_outlives_inner<'tcx>(
     goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
     span: Span,
 ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
+    match compute_dropck_outlives_with_errors(ocx, goal, span, false) {
+        Ok(r) => Ok(r),
+        Err(_) => Err(NoSolution),
+    }
+}
+
+pub fn compute_dropck_outlives_with_errors<'tcx, E>(
+    ocx: &ObligationCtxt<'_, 'tcx, E>,
+    goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
+    span: Span,
+    report_errors: bool,
+) -> Result<DropckOutlivesResult<'tcx>, Vec<E>>
+where
+    E: FromSolverError<'tcx, NextSolverError<'tcx>>,
+{
     let tcx = ocx.infcx.tcx;
     let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
 
@@ -146,14 +162,17 @@ pub fn compute_dropck_outlives_inner<'tcx>(
             result.overflows.len(),
             ty_stack.len()
         );
-        dtorck_constraint_for_ty_inner(
+        match dtorck_constraint_for_ty_inner(
             tcx,
             ocx.infcx.typing_env(param_env),
-            DUMMY_SP,
+            span,
             depth,
             ty,
             &mut constraints,
-        )?;
+        ) {
+            Err(_) => return Err(Vec::new()),
+            _ => (),
+        };
 
         // "outlives" represent types/regions that may be touched
         // by a destructor.
@@ -173,11 +192,25 @@ pub fn compute_dropck_outlives_inner<'tcx>(
         // do not themselves define a destructor", more or less. We have
         // to push them onto the stack to be expanded.
         for ty in constraints.dtorck_types.drain(..) {
-            let Normalized { value: ty, obligations } =
-                ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
-            ocx.register_obligations(obligations);
+            let ty = if report_errors {
+                let normalized_ty = ocx.deeply_normalize(&cause, param_env, ty)?;
 
-            debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+                let errors = ocx.select_where_possible();
+                if !errors.is_empty() {
+                    debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}");
+                    return Err(errors);
+                }
+                normalized_ty
+            } else if let Ok(Normalized { value: ty, obligations }) =
+                ocx.infcx.at(&cause, param_env).query_normalize(ty)
+            {
+                ocx.register_obligations(obligations);
+
+                debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+                ty
+            } else {
+                return Err(Vec::new());
+            };
 
             match ty.kind() {
                 // All parameters live for the duration of the