about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <liehr.exchange@gmx.net>2022-10-17 12:04:16 +0200
committerLeón Orell Valerian Liehr <liehr.exchange@gmx.net>2022-10-17 12:08:46 +0200
commit684df4d24ec605a07f1a5789c1d0027d4887103c (patch)
treeff734bbb86f614c3d0ed3b6ec565a4014d5177b5
parentbf286a82e236e065c67909657e3a35d1511d1864 (diff)
downloadrust-684df4d24ec605a07f1a5789c1d0027d4887103c.tar.gz
rust-684df4d24ec605a07f1a5789c1d0027d4887103c.zip
Make diagnostic for unsatisfied Termination bounds more precise
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs4
-rw-r--r--library/std/src/process.rs12
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs11
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr17
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs18
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr15
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr5
8 files changed, 78 insertions, 5 deletions
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c6711b603b6..3fe79370c37 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -451,6 +451,7 @@ symbols! {
         call_once,
         caller_location,
         capture_disjoint_fields,
+        cause,
         cdylib,
         ceilf32,
         ceilf64,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 0f20e02d6ec..5eef54c6330 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -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);
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index b8249a027ad..400d25beb26 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -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.
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs
new file mode 100644
index 00000000000..a75c91cc90d
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs
@@ -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
+}
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr
new file mode 100644
index 00000000000..409dede1a90
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr
@@ -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`.
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs
new file mode 100644
index 00000000000..fa9182b6dee
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr
new file mode 100644
index 00000000000..a700c72ea68
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr
@@ -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`.
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
index 7c1390cdc64..6ee32314607 100644
--- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
@@ -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