Skip to content

Commit dbc08cf

Browse files
committed
main-termination
1 parent b711f95 commit dbc08cf

File tree

4 files changed

+63
-35
lines changed

4 files changed

+63
-35
lines changed

compiler/rustc_hir_analysis/src/check/entry.rs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,23 @@ use rustc_infer::infer::TyCtxtInferExt;
77
use rustc_middle::span_bug;
88
use rustc_middle::ty::{self, TyCtxt, TypingMode};
99
use rustc_session::config::EntryFnType;
10-
use rustc_span::Span;
1110
use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
11+
use rustc_span::{ErrorGuaranteed, Span};
1212
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
13+
use rustc_trait_selection::regions::InferCtxtRegionExt;
1314
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
1415

1516
use super::check_function_signature;
1617
use crate::errors;
1718

18-
pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
19+
pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
1920
match tcx.entry_fn(()) {
2021
Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
21-
_ => {}
22+
_ => Ok(()),
2223
}
2324
}
2425

25-
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
26+
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuaranteed> {
2627
let main_fnsig = tcx.fn_sig(main_def_id).instantiate_identity();
2728
let main_span = tcx.def_span(main_def_id);
2829

@@ -87,33 +88,28 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
8788
}
8889
}
8990

90-
let mut error = false;
9191
let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span);
9292

9393
let main_asyncness = tcx.asyncness(main_def_id);
9494
if main_asyncness.is_async() {
9595
let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
96-
tcx.dcx()
97-
.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
98-
error = true;
96+
return Err(tcx
97+
.dcx()
98+
.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span }));
9999
}
100100

101101
if let Some(attr_span) = find_attr!(tcx, main_def_id, TrackCaller(span) => *span) {
102-
tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
103-
error = true;
102+
return Err(tcx
103+
.dcx()
104+
.emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }));
104105
}
105106

106107
if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
107108
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
108109
&& !tcx.sess.target.is_like_wasm
109110
&& !tcx.sess.opts.actually_rustdoc
110111
{
111-
tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
112-
error = true;
113-
}
114-
115-
if error {
116-
return;
112+
return Err(tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span }));
117113
}
118114

119115
// Main should have no WC, so empty param env is OK here.
@@ -123,8 +119,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
123119
let return_ty = main_fnsig.output();
124120
let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
125121
let Some(return_ty) = return_ty.no_bound_vars() else {
126-
tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
127-
return;
122+
return Err(tcx
123+
.dcx()
124+
.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }));
128125
};
129126
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
130127
let cause = traits::ObligationCause::new(
@@ -137,8 +134,16 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
137134
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
138135
let errors = ocx.evaluate_obligations_error_on_ambiguity();
139136
if !errors.is_empty() {
140-
infcx.err_ctxt().report_fulfillment_errors(errors);
141-
error = true;
137+
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
138+
}
139+
140+
let region_errors =
141+
infcx.resolve_regions(main_diagnostics_def_id, param_env, ty::List::empty());
142+
143+
if !region_errors.is_empty() {
144+
return Err(infcx
145+
.err_ctxt()
146+
.report_region_errors(main_diagnostics_def_id, &region_errors));
142147
}
143148
// now we can take the return type of the given main function
144149
expected_return_type = norm_return_ty;
@@ -147,10 +152,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
147152
expected_return_type = tcx.types.unit;
148153
}
149154

150-
if error {
151-
return;
152-
}
153-
154155
let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
155156
[],
156157
expected_return_type,
@@ -159,7 +160,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
159160
ExternAbi::Rust,
160161
));
161162

162-
if check_function_signature(
163+
check_function_signature(
163164
tcx,
164165
ObligationCause::new(
165166
main_span,
@@ -168,26 +169,24 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
168169
),
169170
main_def_id,
170171
expected_sig,
171-
)
172-
.is_err()
173-
{
174-
return;
175-
}
172+
)?;
176173

177174
let main_fn_generics = tcx.generics_of(main_def_id);
178175
let main_fn_predicates = tcx.predicates_of(main_def_id);
179176
if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
180177
let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
181-
tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
178+
return Err(tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
182179
span: generics_param_span.unwrap_or(main_span),
183180
label_span: generics_param_span,
184-
});
181+
}));
185182
} else if !main_fn_predicates.predicates.is_empty() {
186183
// generics may bring in implicit predicates, so we skip this check if generics is present.
187184
let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
188-
tcx.dcx().emit_err(errors::WhereClauseOnMain {
185+
return Err(tcx.dcx().emit_err(errors::WhereClauseOnMain {
189186
span: generics_where_clauses_span.unwrap_or(main_span),
190187
generics_span: generics_where_clauses_span,
191-
});
188+
}));
192189
}
190+
191+
Ok(())
193192
}

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2350,7 +2350,8 @@ pub(super) fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuarante
23502350
}))
23512351
.and(items.par_nested_bodies(|item| tcx.ensure_result().check_well_formed(item)))
23522352
.and(items.par_opaques(|item| tcx.ensure_result().check_well_formed(item)));
2353-
super::entry::check_for_entry_fn(tcx);
2353+
2354+
super::entry::check_for_entry_fn(tcx)?;
23542355

23552356
res
23562357
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This test checks that the compiler correctly handles lifetime requirements
2+
// on the `Termination` trait for the `main` function return type.
3+
// See https://github.com/rust-lang/rust/issues/148421
4+
5+
use std::process::ExitCode;
6+
use std::process::Termination;
7+
8+
trait IsStatic {}
9+
impl<'a: 'static> IsStatic for &'a () {}
10+
11+
struct Thing;
12+
13+
impl Termination for Thing where for<'a> &'a (): IsStatic {
14+
fn report(self) -> ExitCode { panic!() }
15+
}
16+
17+
fn main() -> Thing { Thing } //~ ERROR implementation of `IsStatic` is not general enough
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: implementation of `IsStatic` is not general enough
2+
--> $DIR/main-termination-lifetime-issue-148421.rs:17:14
3+
|
4+
LL | fn main() -> Thing { Thing }
5+
| ^^^^^ implementation of `IsStatic` is not general enough
6+
|
7+
= note: `IsStatic` would have to be implemented for the type `&'0 ()`, for any lifetime `'0`...
8+
= note: ...but `IsStatic` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
9+
10+
error: aborting due to 1 previous error
11+

0 commit comments

Comments
 (0)