mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
main-termination
This commit is contained in:
@@ -7,22 +7,23 @@
|
||||
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);
|
||||
|
||||
@@ -87,20 +88,20 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -108,12 +109,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
&& !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.
|
||||
@@ -123,8 +119,9 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
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(
|
||||
@@ -137,8 +134,16 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
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, ®ion_errors));
|
||||
}
|
||||
// now we can take the return type of the given main function
|
||||
expected_return_type = norm_return_ty;
|
||||
@@ -147,10 +152,6 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
expected_return_type = tcx.types.unit;
|
||||
}
|
||||
|
||||
if error {
|
||||
return;
|
||||
}
|
||||
|
||||
let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
[],
|
||||
expected_return_type,
|
||||
@@ -159,7 +160,7 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
ExternAbi::Rust,
|
||||
));
|
||||
|
||||
if check_function_signature(
|
||||
check_function_signature(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
main_span,
|
||||
@@ -168,26 +169,24 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
|
||||
),
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// This test checks that the compiler correctly handles lifetime requirements
|
||||
// on the `Termination` trait for the `main` function return type.
|
||||
// See https://github.com/rust-lang/rust/issues/148421
|
||||
|
||||
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
|
||||
@@ -0,0 +1,11 @@
|
||||
error: implementation of `IsStatic` is not general enough
|
||||
--> $DIR/main-termination-lifetime-issue-148421.rs:17: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
|
||||
|
||||
Reference in New Issue
Block a user