Rollup merge of #103142 - fmease:fix-103052, r=oli-obk

Make diagnostic for unsatisfied `Termination` bounds more precise

Don't blindly emit a diagnostic claiming that “*`main` has an invalid return type*” if we encounter a type that should but doesn't implement `std::process::Termination` and isn't actually the return type of the program entry `main`.

Fixes #103052.

``@rustbot`` label A-diagnostics T-compiler T-libs
r? diagnostics
This commit is contained in:
Yuki Okushi 2022-10-18 21:21:30 +09:00 committed by GitHub
commit 472a8742a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 5 deletions

View File

@ -451,6 +451,7 @@ symbols! {
call_once,
caller_location,
capture_disjoint_fields,
cause,
cdylib,
ceilf32,
ceilf64,

View File

@ -164,6 +164,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
}
if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
flags.push((sym::cause, Some("MainFunctionType".to_string())));
}
// Add all types without trimmed paths.
ty::print::with_no_trimmed_paths!({
let generics = self.tcx.generics_of(def_id);

View File

@ -2154,8 +2154,16 @@ pub fn id() -> u32 {
#[cfg_attr(not(test), lang = "termination")]
#[stable(feature = "termination_trait_lib", since = "1.61.0")]
#[rustc_on_unimplemented(
message = "`main` has invalid return type `{Self}`",
label = "`main` can only return types that implement `{Termination}`"
on(
all(not(bootstrap), cause = "MainFunctionType"),
message = "`main` has invalid return type `{Self}`",
label = "`main` can only return types that implement `{Termination}`"
),
on(
bootstrap,
message = "`main` has invalid return type `{Self}`",
label = "`main` can only return types that implement `{Termination}`"
)
)]
pub trait Termination {
/// Is called to get the representation of the value as status code.

View File

@ -0,0 +1,11 @@
// Check that we don't blindly emit a diagnostic claiming that "`main` has an invalid return type"
// if we encounter a type that doesn't implement `std::process::Termination` and is not actually
// the return type of the program entry `main`.
fn receive(_: impl std::process::Termination) {}
struct Something;
fn main() {
receive(Something); //~ ERROR the trait bound `Something: Termination` is not satisfied
}

View File

@ -0,0 +1,17 @@
error[E0277]: the trait bound `Something: Termination` is not satisfied
--> $DIR/issue-103052-1.rs:10:13
|
LL | receive(Something);
| ------- ^^^^^^^^^ the trait `Termination` is not implemented for `Something`
| |
| required by a bound introduced by this call
|
note: required by a bound in `receive`
--> $DIR/issue-103052-1.rs:5:20
|
LL | fn receive(_: impl std::process::Termination) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `receive`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,18 @@
#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]
mod child {
trait Main {
fn main() -> impl std::process::Termination;
}
struct Something;
impl Main for () {
fn main() -> Something { //~ ERROR the trait bound `Something: Termination` is not satisfied
Something
}
}
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0277]: the trait bound `Something: Termination` is not satisfied
--> $DIR/issue-103052-2.rs:12:22
|
LL | fn main() -> Something {
| ^^^^^^^^^ the trait `Termination` is not implemented for `Something`
|
note: required by a bound in `Main::main::{opaque#0}`
--> $DIR/issue-103052-2.rs:6:27
|
LL | fn main() -> impl std::process::Termination;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::main::{opaque#0}`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,4 +1,4 @@
error[E0277]: `main` has invalid return type `f32`
error[E0277]: the trait bound `f32: Termination` is not satisfied
--> $DIR/termination-trait-test-wrong-type.rs:6:1
|
LL | #[test]
@ -6,9 +6,8 @@ LL | #[test]
LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
LL | | "0".parse()
LL | | }
| |_^ `main` can only return types that implement `Termination`
| |_^ the trait `Termination` is not implemented for `f32`
|
= help: the trait `Termination` is not implemented for `f32`
= note: required for `Result<f32, ParseFloatError>` to implement `Termination`
note: required by a bound in `assert_test_result`
--> $SRC_DIR/test/src/lib.rs:LL:COL