Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 33 additions & 34 deletions compiler/rustc_hir_analysis/src/check/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ 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};

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);

Expand Down Expand Up @@ -87,33 +88,28 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
}

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()
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
&& !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;
return Err(tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span }));
}

// Main should have no WC, so empty param env is OK here.
Expand All @@ -123,8 +119,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
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;
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(
Expand All @@ -137,8 +134,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, ty::List::empty());

if !region_errors.is_empty() {
return Err(infcx
.err_ctxt()
.report_region_errors(main_diagnostics_def_id, &region_errors));
}
// now we can take the return type of the given main function
expected_return_type = norm_return_ty;
Expand All @@ -147,10 +152,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,
Expand All @@ -159,7 +160,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
ExternAbi::Rust,
));

if check_function_signature(
check_function_signature(
tcx,
ObligationCause::new(
main_span,
Expand All @@ -168,26 +169,24 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
),
main_def_id,
expected_sig,
)
.is_err()
{
return;
}
)?;

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(())
}
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2350,7 +2350,8 @@ pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuarante
}))
.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);

super::entry::check_for_entry_fn(tcx)?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not part of the and 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept it separate to make sure error is propagated.


res
}
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/typeck/main-termination-lifetime-issue-148421.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// check-fail
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check-fail isn't necessary.

Can you add a comment for what this is testing (and link to the issue in the file (and not necessarily in the test name))

Copy link
Copy Markdown
Contributor Author

@xonx4l xonx4l Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay will add.


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
11 changes: 11 additions & 0 deletions tests/ui/typeck/main-termination-lifetime-issue-148421.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: implementation of `IsStatic` is not general enough
--> $DIR/main-termination-lifetime-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

Loading