diff options
| -rw-r--r-- | compiler/rustc_borrowck/src/type_check/liveness/trace.rs | 57 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs | 51 |
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 |
