diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_data_structures/src/sync.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_data_structures/src/sync/parallel.rs | 29 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 230 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/query.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/hir/map/mod.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/hir/mod.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/plumbing.rs | 58 | ||||
| -rw-r--r-- | compiler/rustc_span/src/lib.rs | 19 |
10 files changed, 281 insertions, 130 deletions
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 62fff604f81..f957734b04d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -54,7 +54,7 @@ pub use worker_local::{Registry, WorkerLocal}; mod parallel; #[cfg(parallel_compiler)] pub use parallel::scope; -pub use parallel::{join, par_for_each_in, par_map, parallel_guard}; +pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in}; pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 1944ddfb710..39dddb59569 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -77,6 +77,15 @@ mod disabled { }) } + pub fn try_par_for_each_in<T: IntoIterator, E: Copy>( + t: T, + mut for_each: impl FnMut(T::Item) -> Result<(), E>, + ) -> Result<(), E> { + parallel_guard(|guard| { + t.into_iter().fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) + }) + } + pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>( t: T, mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R, @@ -167,6 +176,26 @@ mod enabled { }); } + pub fn try_par_for_each_in< + T: IntoIterator + IntoParallelIterator<Item = <T as IntoIterator>::Item>, + E: Copy + Send, + >( + t: T, + for_each: impl Fn(<T as IntoIterator>::Item) -> Result<(), E> + DynSync + DynSend, + ) -> Result<(), E> { + parallel_guard(|guard| { + if mode::is_dyn_thread_safe() { + let for_each = FromDyn::from(for_each); + t.into_par_iter() + .fold_with(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) + .reduce(|| Ok(()), |a, b| a.and(b)) + } else { + t.into_iter() + .fold(Ok(()), |ret, i| guard.run(|| for_each(i)).unwrap_or(ret).and(ret)) + } + }) + } + pub fn par_map< I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 34c28bce5d8..3f31ce7aa58 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -92,7 +92,8 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( span: Span, body_def_id: LocalDefId, f: F, -) where +) -> Result<(), ErrorGuaranteed> +where F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), { let param_env = tcx.param_env(body_def_id); @@ -106,40 +107,46 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( } f(&mut wfcx); - let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id) - { - Ok(wf_types) => wf_types, - Err(_guar) => return, - }; + let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - return; + let err = infcx.err_ctxt().report_fulfillment_errors(errors); + if tcx.sess.err_count() > 0 { + return Err(err); + } else { + // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs causes an + // error (delay_span_bug) during normalization, without reporting an error, so we need to act as if + // no error happened, in order to let our callers continue and report an error later in + // check_impl_items_against_trait. + return Ok(()); + } } let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); + wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?; + infcx.tainted_by_errors().error_reported() } -fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { +fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { let node = tcx.hir().owner(def_id); - match node { - hir::OwnerNode::Crate(_) => {} + let mut res = match node { + hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), hir::OwnerNode::Item(item) => check_item(tcx, item), hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - } + }; if let Some(generics) = node.generics() { for param in generics.params { - check_param_wf(tcx, param) + res = res.and(check_param_wf(tcx, param)); } } + res } /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are @@ -156,7 +163,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. #[instrument(skip(tcx), level = "debug")] -fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -186,31 +193,32 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { let is_auto = tcx .impl_trait_ref(def_id) .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); + let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default"); err.span_labels(impl_.defaultness_span, "default because of this"); err.span_label(sp, "auto trait"); - err.emit(); + res = Err(err.emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); + res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait)); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? if let hir::Defaultness::Default { .. } = impl_.defaultness { let mut spans = vec![span]; spans.extend(impl_.defaultness_span); - struct_span_err!( + res = Err(struct_span_err!( tcx.sess, spans, E0750, "negative impls cannot be default impls" ) - .emit(); + .emit()); } } (ty::ImplPolarity::Reservation, _) => { @@ -218,49 +226,52 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } _ => unreachable!(), } + res } hir::ItemKind::Fn(ref sig, ..) => { - check_item_fn(tcx, def_id, item.ident, item.span, sig.decl); + check_item_fn(tcx, def_id, item.ident, item.span, sig.decl) } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) } hir::ItemKind::Struct(_, ast_generics) => { - check_type_defn(tcx, item, false); + let res = check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Union(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } hir::ItemKind::Enum(_, ast_generics) => { - check_type_defn(tcx, item, true); + let res = check_type_defn(tcx, item, true); check_variances_for_type_defn(tcx, item, ast_generics); + res } - hir::ItemKind::Trait(..) => { - check_trait(tcx, item); - } - hir::ItemKind::TraitAlias(..) => { - check_trait(tcx, item); - } + hir::ItemKind::Trait(..) => check_trait(tcx, item), + hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), // `ForeignItem`s are handled separately. - hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::ForeignMod { .. } => Ok(()), hir::ItemKind::TyAlias(hir_ty, ast_generics) => { if tcx.type_alias_is_lazy(item.owner_id) { // Bounds of lazy type aliases and of eager ones that contain opaque types are respected. // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`. - check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); check_variances_for_type_defn(tcx, item, ast_generics); + res + } else { + Ok(()) } } - _ => {} + _ => Ok(()), } } -fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { +fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> { let def_id = item.owner_id.def_id; debug!( @@ -275,11 +286,14 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { hir::ForeignItemKind::Static(ty, ..) => { check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) } - hir::ForeignItemKind::Type => (), + hir::ForeignItemKind::Type => Ok(()), } } -fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { +fn check_trait_item( + tcx: TyCtxt<'_>, + trait_item: &hir::TraitItem<'_>, +) -> Result<(), ErrorGuaranteed> { let def_id = trait_item.owner_id.def_id; let (method_sig, span) = match trait_item.kind { @@ -288,18 +302,19 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { _ => (None, trait_item.span), }; check_object_unsafe_self_trait_by_name(tcx, trait_item); - check_associated_item(tcx, def_id, span, method_sig); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { - check_associated_item( + res = res.and(check_associated_item( tcx, assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, - ); + )); } } + res } /// Require that the user writes where clauses on GATs for the implicit @@ -826,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem } } -fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { +fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> Result<(), ErrorGuaranteed> { let (method_sig, span) = match impl_item.kind { hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`. @@ -834,13 +849,13 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig); + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } -fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { +fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { match param.kind { // We currently only check wf of const params here. - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (), + hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. hir::GenericParamKind::Const { ty: hir_ty, default: _ } => { @@ -860,68 +875,66 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ty, trait_def_id, ); - }); + }) } else { - let diag = match ty.kind() { - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, - ty::FnPtr(_) => Some(tcx.sess.struct_span_err( + let mut diag = match ty.kind() { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()), + ty::FnPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using function pointers as const generic parameters is forbidden", - )), - ty::RawPtr(_) => Some(tcx.sess.struct_span_err( + ), + ty::RawPtr(_) => tcx.sess.struct_span_err( hir_ty.span, "using raw pointers as const generic parameters is forbidden", - )), - _ => Some(tcx.sess.struct_span_err( + ), + _ => tcx.sess.struct_span_err( hir_ty.span, format!("`{}` is forbidden as the type of a const generic parameter", ty), - )), + ), }; - if let Some(mut diag) = diag { - diag.note("the only supported types are integers, `bool` and `char`"); + diag.note("the only supported types are integers, `bool` and `char`"); - let cause = ObligationCause::misc(hir_ty.span, param.def_id); - let may_suggest_feature = match type_allowed_to_implement_const_param_ty( - tcx, - tcx.param_env(param.def_id), - ty, - cause, - ) { - // Can never implement `ConstParamTy`, don't suggest anything. - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, - // May be able to implement `ConstParamTy`. Only emit the feature help - // if the type is local, since the user may be able to fix the local type. - Err(ConstParamTyImplementationError::InfrigingFields(..)) => { - fn ty_is_local(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(adt_def, ..) => adt_def.did().is_local(), - // Arrays and slices use the inner type's `ConstParamTy`. - ty::Array(ty, ..) => ty_is_local(*ty), - ty::Slice(ty) => ty_is_local(*ty), - // `&` references use the inner type's `ConstParamTy`. - // `&mut` are not supported. - ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), - // Say that a tuple is local if any of its components are local. - // This is not strictly correct, but it's likely that the user can fix the local component. - ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), - _ => false, - } + let cause = ObligationCause::misc(hir_ty.span, param.def_id); + let may_suggest_feature = match type_allowed_to_implement_const_param_ty( + tcx, + tcx.param_env(param.def_id), + ty, + cause, + ) { + // Can never implement `ConstParamTy`, don't suggest anything. + Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, + // May be able to implement `ConstParamTy`. Only emit the feature help + // if the type is local, since the user may be able to fix the local type. + Err(ConstParamTyImplementationError::InfrigingFields(..)) => { + fn ty_is_local(ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Adt(adt_def, ..) => adt_def.did().is_local(), + // Arrays and slices use the inner type's `ConstParamTy`. + ty::Array(ty, ..) => ty_is_local(*ty), + ty::Slice(ty) => ty_is_local(*ty), + // `&` references use the inner type's `ConstParamTy`. + // `&mut` are not supported. + ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), + // Say that a tuple is local if any of its components are local. + // This is not strictly correct, but it's likely that the user can fix the local component. + ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)), + _ => false, } - - ty_is_local(ty) } - // Implments `ConstParamTy`, suggest adding the feature to enable. - Ok(..) => true, - }; - if may_suggest_feature && tcx.sess.is_nightly_build() { - diag.help( + + ty_is_local(ty) + } + // Implments `ConstParamTy`, suggest adding the feature to enable. + Ok(..) => true, + }; + if may_suggest_feature && tcx.sess.is_nightly_build() { + diag.help( "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", ); - } - - diag.emit(); } + + Err(diag.emit()) } } } @@ -933,7 +946,7 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, -) { +) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { let item = tcx.associated_item(item_id); @@ -985,7 +998,11 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> { } /// In a type definition, we check that to ensure that the types of the fields are well-formed. -fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) { +fn check_type_defn<'tcx>( + tcx: TyCtxt<'tcx>, + item: &hir::Item<'tcx>, + all_sized: bool, +) -> Result<(), ErrorGuaranteed> { let _ = tcx.representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); @@ -1080,11 +1097,11 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + }) } #[instrument(skip(tcx, item))] -fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { +fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuaranteed> { debug!(?item.owner_id); let def_id = item.owner_id.def_id; @@ -1103,7 +1120,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } } - enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { + let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { check_where_clauses(wfcx, item.span, def_id) }); @@ -1111,6 +1128,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { if let hir::ItemKind::Trait(..) = item.kind { check_gat_where_clauses(tcx, item.owner_id.def_id); } + res } /// Checks all associated type defaults of trait `trait_def_id`. @@ -1142,7 +1160,7 @@ fn check_item_fn( ident: Ident, span: Span, decl: &hir::FnDecl<'_>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, ident.span, sig, decl, def_id); @@ -1160,7 +1178,7 @@ fn check_item_type( item_id: LocalDefId, ty_span: Span, unsized_handling: UnsizedHandling, -) { +) -> Result<(), ErrorGuaranteed> { debug!("check_item_type: {:?}", item_id); enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { @@ -1200,7 +1218,7 @@ fn check_item_type( tcx.require_lang_item(LangItem::Sync, Some(ty_span)), ); } - }); + }) } #[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] @@ -1209,7 +1227,7 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option<hir::TraitRef<'_>>, -) { +) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { match ast_trait_ref { Some(ast_trait_ref) => { @@ -1258,7 +1276,7 @@ fn check_impl<'tcx>( } check_where_clauses(wfcx, item.span, item.owner_id.def_id); - }); + }) } /// Checks where-clauses and inline bounds that are declared on `def_id`. @@ -1879,12 +1897,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) { +fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))) } fn error_392( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index c7b3648099c..88f3db03a4e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -205,10 +205,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; } - tcx.sess.track_errors(|| { - tcx.sess.time("wf_checking", || { - tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) - }); + tcx.sess.time("wf_checking", || { + tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) })?; // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index d0d41c614d6..d8a695b131b 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -114,6 +114,11 @@ struct QueryModifiers { /// Generate a `feed` method to set the query's value from another query. feedable: Option<Ident>, + + /// Forward the result on ensure if the query gets recomputed, and + /// return `Ok(())` otherwise. Only applicable to queries returning + /// `Result<(), ErrorGuaranteed>` + ensure_forwards_result_if_red: Option<Ident>, } fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { @@ -128,6 +133,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { let mut depth_limit = None; let mut separate_provide_extern = None; let mut feedable = None; + let mut ensure_forwards_result_if_red = None; while !input.is_empty() { let modifier: Ident = input.parse()?; @@ -187,6 +193,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { try_insert!(separate_provide_extern = modifier); } else if modifier == "feedable" { try_insert!(feedable = modifier); + } else if modifier == "ensure_forwards_result_if_red" { + try_insert!(ensure_forwards_result_if_red = modifier); } else { return Err(Error::new(modifier.span(), "unknown query modifier")); } @@ -206,6 +214,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { depth_limit, separate_provide_extern, feedable, + ensure_forwards_result_if_red, }) } @@ -325,6 +334,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { eval_always, depth_limit, separate_provide_extern, + ensure_forwards_result_if_red, ); if modifiers.cache.is_some() { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3ca26ec98c6..58c0c6bab49 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; +use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -16,7 +16,7 @@ use rustc_index::Idx; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::spec::abi::Abi; #[inline] @@ -632,6 +632,17 @@ impl<'hir> Map<'hir> { }) } + #[inline] + pub fn try_par_for_each_module( + self, + f: impl Fn(LocalModDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + let crate_items = self.tcx.hir_crate_items(()); + try_par_for_each_in(&crate_items.submodules[..], |module| { + f(LocalModDefId::new_unchecked(module.def_id)) + }) + } + /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 0da8fe9cca7..f28ec771169 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -9,12 +9,12 @@ pub mod place; use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; +use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; -use rustc_span::{ExpnId, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, ExpnId, DUMMY_SP}; /// Top-level HIR node for current owner. This only contains the node for which /// `HirId::local_id == 0`, and excludes bodies. @@ -78,20 +78,32 @@ impl ModuleItems { self.owners().map(|id| id.def_id) } - pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) { - par_for_each_in(&self.items[..], |&id| f(id)) + pub fn par_items( + &self, + f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.items[..], |&id| f(id)) } - pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) { - par_for_each_in(&self.trait_items[..], |&id| f(id)) + pub fn par_trait_items( + &self, + f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.trait_items[..], |&id| f(id)) } - pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) { - par_for_each_in(&self.impl_items[..], |&id| f(id)) + pub fn par_impl_items( + &self, + f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.impl_items[..], |&id| f(id)) } - pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) { - par_for_each_in(&self.foreign_items[..], |&id| f(id)) + pub fn par_foreign_items( + &self, + f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.foreign_items[..], |&id| f(id)) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cd5206a837f..23d77a1ebe4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -25,7 +25,9 @@ use crate::mir::interpret::{ use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::query::erase::{erase, restore, Erase}; -use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery}; +use crate::query::plumbing::{ + query_ensure, query_ensure_error_guaranteed, query_get_at, CyclePlaceholder, DynamicQuery, +}; use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, @@ -965,8 +967,9 @@ rustc_queries! { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } } - query check_mod_type_wf(key: LocalModDefId) -> () { + query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } + ensure_forwards_result_if_red } query collect_mod_item_types(key: LocalModDefId) -> () { @@ -1499,8 +1502,9 @@ rustc_queries! { feedable } - query check_well_formed(key: hir::OwnerId) -> () { + query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } + ensure_forwards_result_if_red } // The `DefId`s of all non-generic functions and statics in the given crate diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 34e5b02ba5b..f4a8ada8f68 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -173,6 +173,45 @@ pub fn query_ensure<'tcx, Cache>( } } +#[inline] +pub fn query_ensure_error_guaranteed<'tcx, Cache>( + tcx: TyCtxt<'tcx>, + execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, + query_cache: &Cache, + key: Cache::Key, + check_cache: bool, +) -> Result<(), ErrorGuaranteed> +where + Cache: QueryCache<Value = super::erase::Erase<Result<(), ErrorGuaranteed>>>, +{ + let key = key.into_query_param(); + if let Some(res) = try_get_cached(tcx, query_cache, &key) { + super::erase::restore(res) + } else { + execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache }) + .map(super::erase::restore) + // Either we actually executed the query, which means we got a full `Result`, + // or we can just assume the query succeeded, because it was green in the + // incremental cache. If it is green, that means that the previous compilation + // that wrote to the incremental cache compiles successfully. That is only + // possible if the cache entry was `Ok(())`, so we emit that here, without + // actually encoding the `Result` in the cache or loading it from there. + .unwrap_or(Ok(())) + } +} + +macro_rules! query_ensure { + ([]$($args:tt)*) => { + query_ensure($($args)*) + }; + ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => { + query_ensure_error_guaranteed($($args)*) + }; + ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { + query_ensure!([$($modifiers)*]$($args)*) + }; +} + macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam<DefId> }; (LocalDefId) => { impl IntoQueryParam<LocalDefId> }; @@ -220,6 +259,18 @@ macro_rules! separate_provide_extern_decl { }; } +macro_rules! ensure_result { + ([][$ty:ty]) => { + () + }; + ([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => { + Result<(), ErrorGuaranteed> + }; + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + ensure_result!([$($modifiers)*][$($args)*]) + }; +} + macro_rules! separate_provide_extern_default { ([][$name:ident]) => { () @@ -343,14 +394,15 @@ macro_rules! define_callbacks { impl<'tcx> TyCtxtEnsure<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - query_ensure( + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) { + query_ensure!( + [$($modifiers)*] self.tcx, self.tcx.query_system.fns.engine.$name, &self.tcx.query_system.caches.$name, key.into_query_param(), false, - ); + ) })* } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8bb64aa5f12..1a94b7e98fd 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2247,7 +2247,7 @@ where /// Useful type to use with `Result<>` indicate that an error has already /// been reported to the user, so no need to continue checking. -#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable_Generic)] pub struct ErrorGuaranteed(()); @@ -2259,3 +2259,20 @@ impl ErrorGuaranteed { ErrorGuaranteed(()) } } + +impl<E: rustc_serialize::Encoder> Encodable<E> for ErrorGuaranteed { + #[inline] + fn encode(&self, _e: &mut E) { + panic!( + "should never serialize an `ErrorGuaranteed`, as we do not write metadata or incremental caches in case errors occurred" + ) + } +} +impl<D: rustc_serialize::Decoder> Decodable<D> for ErrorGuaranteed { + #[inline] + fn decode(_d: &mut D) -> ErrorGuaranteed { + panic!( + "`ErrorGuaranteed` should never have been serialized to metadata or incremental caches" + ) + } +} |
