From 3abd180b54c7454090cbb57ee8bad099db9ed37a Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:39:46 +0000 Subject: [PATCH 1/6] main-termination --- compiler/rustc_hir_analysis/src/check/entry.rs | 14 ++++++++++++++ tests/ui/issue-148421.rs | 15 +++++++++++++++ tests/ui/issue-148421.stderr | 11 +++++++++++ 3 files changed, 40 insertions(+) create mode 100644 tests/ui/issue-148421.rs create mode 100644 tests/ui/issue-148421.stderr diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index a6dae521db884..8b38536fd30df 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -10,6 +10,7 @@ use rustc_session::config::EntryFnType; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use super::check_function_signature; @@ -140,6 +141,19 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { infcx.err_ctxt().report_fulfillment_errors(errors); error = true; } + let errors = ocx.evaluate_obligations_error_on_ambiguity(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(errors); + error = true; + } + + let region_errors = + infcx.resolve_regions(main_diagnostics_def_id, param_env, tcx.mk_type_list(&[])); + + if !region_errors.is_empty() { + infcx.err_ctxt().report_region_errors(main_diagnostics_def_id, ®ion_errors); + error = true; + } // now we can take the return type of the given main function expected_return_type = norm_return_ty; } else { diff --git a/tests/ui/issue-148421.rs b/tests/ui/issue-148421.rs new file mode 100644 index 0000000000000..2f513fe6e1cda --- /dev/null +++ b/tests/ui/issue-148421.rs @@ -0,0 +1,15 @@ +// check-fail + +use std::process::ExitCode; +use std::process::Termination; + +trait IsStatic {} +impl<'a: 'static> IsStatic for &'a () {} + +struct Thing; + +impl Termination for Thing where for<'a> &'a (): IsStatic { + fn report(self) -> ExitCode { panic!() } +} + +fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough \ No newline at end of file diff --git a/tests/ui/issue-148421.stderr b/tests/ui/issue-148421.stderr new file mode 100644 index 0000000000000..e862d7afed25d --- /dev/null +++ b/tests/ui/issue-148421.stderr @@ -0,0 +1,11 @@ +error: implementation of `IsStatic` is not general enough + --> $DIR/issue-148421.rs:15:14 + | +LL | fn main() -> Thing { Thing } + | ^^^^^ implementation of `IsStatic` is not general enough + | + = note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`... + = note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` + +error: aborting due to 1 previous error + From 884e34062c0a1ed8663dcb179fa4a25f6e1df0c0 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:51:39 +0000 Subject: [PATCH 2/6] moving test files --- .../main-termination-lifetime-issue-148421.rs} | 2 +- .../main-termination-lifetime-issue-148421.stderr} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/{issue-148421.rs => typeck/main-termination-lifetime-issue-148421.rs} (92%) rename tests/ui/{issue-148421.stderr => typeck/main-termination-lifetime-issue-148421.stderr} (100%) diff --git a/tests/ui/issue-148421.rs b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs similarity index 92% rename from tests/ui/issue-148421.rs rename to tests/ui/typeck/main-termination-lifetime-issue-148421.rs index 2f513fe6e1cda..2c11de2883fd2 100644 --- a/tests/ui/issue-148421.rs +++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.rs @@ -12,4 +12,4 @@ impl Termination for Thing where for<'a> &'a (): IsStatic { fn report(self) -> ExitCode { panic!() } } -fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough \ No newline at end of file +fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough diff --git a/tests/ui/issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr similarity index 100% rename from tests/ui/issue-148421.stderr rename to tests/ui/typeck/main-termination-lifetime-issue-148421.stderr From 25506dc94e52b4e0ade5252e1627bbd301bb45b1 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Fri, 23 Jan 2026 11:26:48 +0000 Subject: [PATCH 3/6] remove duplicated content --- compiler/rustc_hir_analysis/src/check/entry.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 8b38536fd30df..0958df4e2ee6d 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -141,11 +141,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { infcx.err_ctxt().report_fulfillment_errors(errors); error = true; } - let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - error = true; - } let region_errors = infcx.resolve_regions(main_diagnostics_def_id, param_env, tcx.mk_type_list(&[])); From b516062f775e3f5c8c8abb6a1dacd1276bf8d70b Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Sat, 7 Feb 2026 13:33:58 +0000 Subject: [PATCH 4/6] bless test --- tests/ui/typeck/main-termination-lifetime-issue-148421.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr index e862d7afed25d..3d46e3df5f4a8 100644 --- a/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr +++ b/tests/ui/typeck/main-termination-lifetime-issue-148421.stderr @@ -1,5 +1,5 @@ error: implementation of `IsStatic` is not general enough - --> $DIR/issue-148421.rs:15:14 + --> $DIR/main-termination-lifetime-issue-148421.rs:15:14 | LL | fn main() -> Thing { Thing } | ^^^^^ implementation of `IsStatic` is not general enough From ce665cdc33caf590d36112fc549fcaa13a4f3cb3 Mon Sep 17 00:00:00 2001 From: xonx4l Date: Sat, 21 Feb 2026 14:14:36 +0530 Subject: [PATCH 5/6] use ErrorGuaranteed --- .../rustc_hir_analysis/src/check/entry.rs | 38 +++++++++---------- .../rustc_hir_analysis/src/check/wfcheck.rs | 34 ++++++++--------- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 0958df4e2ee6d..d9a9352b41324 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -7,8 +7,8 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; -use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -16,14 +16,14 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use super::check_function_signature; use crate::errors; -pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) { +pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { match tcx.entry_fn(()) { Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id), - _ => {} + _ => Ok(()), } } -fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { +fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuaranteed> { let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity(); let main_span = tcx.def_span(main_def_id); @@ -114,7 +114,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } if error { - return; + return Ok(()); } // Main should have no WC, so empty param env is OK here. @@ -125,7 +125,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); let Some(return_ty) = return_ty.no_bound_vars() else { tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }); - return; + return Ok(()); }; let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = traits::ObligationCause::new( @@ -138,16 +138,16 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.evaluate_obligations_error_on_ambiguity(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); - error = true; + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } let region_errors = - infcx.resolve_regions(main_diagnostics_def_id, param_env, tcx.mk_type_list(&[])); + infcx.resolve_regions(main_diagnostics_def_id, param_env, ty::List::empty()); if !region_errors.is_empty() { - infcx.err_ctxt().report_region_errors(main_diagnostics_def_id, ®ion_errors); - error = true; + return Err(infcx + .err_ctxt() + .report_region_errors(main_diagnostics_def_id, ®ion_errors)); } // now we can take the return type of the given main function expected_return_type = norm_return_ty; @@ -156,10 +156,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { expected_return_type = tcx.types.unit; } - if error { - return; - } - let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( [], expected_return_type, @@ -180,23 +176,25 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ) .is_err() { - return; + return Ok(()); } let main_fn_generics = tcx.generics_of(main_def_id); let main_fn_predicates = tcx.predicates_of(main_def_id); if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { let generics_param_span = main_fn_generics_params_span(tcx, main_def_id); - tcx.dcx().emit_err(errors::MainFunctionGenericParameters { + return Err(tcx.dcx().emit_err(errors::MainFunctionGenericParameters { span: generics_param_span.unwrap_or(main_span), label_span: generics_param_span, - }); + })); } else if !main_fn_predicates.predicates.is_empty() { // generics may bring in implicit predicates, so we skip this check if generics is present. let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id); - tcx.dcx().emit_err(errors::WhereClauseOnMain { + return Err(tcx.dcx().emit_err(errors::WhereClauseOnMain { span: generics_where_clauses_span.unwrap_or(main_span), generics_span: generics_where_clauses_span, - }); + })); } + + Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5656c4566d9ff..8de7fb5a784f3 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2334,24 +2334,22 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_crate_items(()); - let res = - items - .par_items(|item| tcx.ensure_result().check_well_formed(item.owner_id.def_id)) - .and( - items.par_impl_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - }), - ) - .and(items.par_trait_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - })) - .and(items.par_foreign_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - })) - .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item))) - .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item))); - super::entry::check_for_entry_fn(tcx); - + let res = items + .par_items(|item| tcx.ensure_result().check_well_formed(item.owner_id.def_id)) + .and(items.par_impl_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + })) + .and(items.par_trait_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + })) + .and(items.par_foreign_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + })) + .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item))) + .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item))); + + super::entry::check_for_entry_fn(tcx)?; + res } From 539a6ef0f5f93b19936149708d871ad3bf9dd55b Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Tue, 24 Mar 2026 06:11:31 +0000 Subject: [PATCH 6/6] Enforce Err(ErrorGuaranteed) --- .../rustc_hir_analysis/src/check/entry.rs | 32 +++++++------------ .../rustc_hir_analysis/src/check/wfcheck.rs | 31 ++++++++++-------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index d9a9352b41324..4c72f5a654e1d 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -88,20 +88,20 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar } } - let mut error = false; let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span); let main_asyncness = tcx.asyncness(main_def_id); if main_asyncness.is_async() { let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); - tcx.dcx() - .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }); - error = true; + return Err(tcx + .dcx() + .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span })); } if let Some(attr_span) = find_attr!(tcx, main_def_id, TrackCaller(span) => *span) { - tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }); - error = true; + return Err(tcx + .dcx() + .emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span })); } if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty() @@ -109,12 +109,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar && !tcx.sess.target.is_like_wasm && !tcx.sess.opts.actually_rustdoc { - tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span }); - error = true; - } - - if error { - return Ok(()); + return Err(tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span })); } // Main should have no WC, so empty param env is OK here. @@ -124,8 +119,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar let return_ty = main_fnsig.output(); let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); let Some(return_ty) = return_ty.no_bound_vars() else { - tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }); - return Ok(()); + return Err(tcx + .dcx() + .emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span })); }; let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = traits::ObligationCause::new( @@ -164,7 +160,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar ExternAbi::Rust, )); - if check_function_signature( + check_function_signature( tcx, ObligationCause::new( main_span, @@ -173,11 +169,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar ), main_def_id, expected_sig, - ) - .is_err() - { - return Ok(()); - } + )?; let main_fn_generics = tcx.generics_of(main_def_id); let main_fn_predicates = tcx.predicates_of(main_def_id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 8de7fb5a784f3..734154238b1f7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2334,22 +2334,25 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_crate_items(()); - let res = items - .par_items(|item| tcx.ensure_result().check_well_formed(item.owner_id.def_id)) - .and(items.par_impl_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - })) - .and(items.par_trait_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - })) - .and(items.par_foreign_items(|item| { - tcx.ensure_result().check_well_formed(item.owner_id.def_id) - })) - .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item))) - .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item))); + let res = + items + .par_items(|item| tcx.ensure_result().check_well_formed(item.owner_id.def_id)) + .and( + items.par_impl_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + }), + ) + .and(items.par_trait_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + })) + .and(items.par_foreign_items(|item| { + tcx.ensure_result().check_well_formed(item.owner_id.def_id) + })) + .and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item))) + .and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item))); super::entry::check_for_entry_fn(tcx)?; - + res }