about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs230
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs6
2 files changed, 126 insertions, 110 deletions
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.