about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/diagnostics.rs6
-rw-r--r--src/librustc/traits/error_reporting.rs21
-rw-r--r--src/librustc_typeck/check/mod.rs36
-rw-r--r--src/librustc_typeck/lib.rs3
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/process.rs5
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/libsyntax/test.rs8
-rw-r--r--src/test/compile-fail/feature-gate-termination_trait_test.rs22
-rw-r--r--src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs (renamed from src/test/compile-fail/feature-gate-termination_trait.rs)5
-rw-r--r--src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs4
-rw-r--r--src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs2
-rw-r--r--src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs2
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs2
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs1
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs2
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs2
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs2
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs (renamed from src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs)4
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr11
20 files changed, 85 insertions, 61 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 2fd875c3447..e22e2b55703 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1764,12 +1764,12 @@ The `main` function was incorrectly declared.
 Erroneous code example:
 
 ```compile_fail,E0580
-fn main() -> i32 { // error: main function has wrong type
-    0
+fn main(x: i32) { // error: main function has wrong type
+    println!("{}", x);
 }
 ```
 
-The `main` function prototype should never take arguments or return type.
+The `main` function prototype should never take arguments.
 Example:
 
 ```
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 79d5cf79359..e640cc315c4 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -595,20 +595,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          trait_ref.to_predicate(), post_message)
                             }));
 
+                        let explanation =
+                            if obligation.cause.code == ObligationCauseCode::MainFunctionType {
+                                "consider using `()`, or a `Result`".to_owned()
+                            } else {
+                                format!("{}the trait `{}` is not implemented for `{}`",
+                                        pre_message,
+                                        trait_ref,
+                                        trait_ref.self_ty())
+                            };
+
                         if let Some(ref s) = label {
                             // If it has a custom "#[rustc_on_unimplemented]"
                             // error message, let's display it as the label!
                             err.span_label(span, s.as_str());
-                            err.help(&format!("{}the trait `{}` is not implemented for `{}`",
-                                              pre_message,
-                                              trait_ref,
-                                              trait_ref.self_ty()));
+                            err.help(&explanation);
                         } else {
-                            err.span_label(span,
-                                           &*format!("{}the trait `{}` is not implemented for `{}`",
-                                                     pre_message,
-                                                     trait_ref,
-                                                     trait_ref.self_ty()));
+                            err.span_label(span, explanation);
                         }
                         if let Some(ref s) = note {
                             // If it has a custom "#[rustc_on_unimplemented]" note, let's display it
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9afa2d42fa4..f820b0ba16b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1130,25 +1130,23 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     }
     fcx.demand_suptype(span, ret_ty, actual_return_ty);
 
-    if fcx.tcx.features().termination_trait {
-        // If the termination trait language item is activated, check that the main return type
-        // implements the termination trait.
-        if let Some(term_id) = fcx.tcx.lang_items().termination() {
-            if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
-                if id == fn_id {
-                    match fcx.sess().entry_type.get() {
-                        Some(config::EntryMain) => {
-                            let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
-                            let trait_ref = ty::TraitRef::new(term_id, substs);
-                            let cause = traits::ObligationCause::new(
-                                span, fn_id, ObligationCauseCode::MainFunctionType);
-
-                            inherited.register_predicate(
-                                traits::Obligation::new(
-                                    cause, param_env, trait_ref.to_predicate()));
-                        },
-                        _ => {},
-                    }
+    // Check that the main return type implements the termination trait.
+    if let Some(term_id) = fcx.tcx.lang_items().termination() {
+        if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
+            if id == fn_id {
+                match fcx.sess().entry_type.get() {
+                    Some(config::EntryMain) => {
+                        let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
+                        let trait_ref = ty::TraitRef::new(term_id, substs);
+                        let return_ty_span = decl.output.span();
+                        let cause = traits::ObligationCause::new(
+                            return_ty_span, fn_id, ObligationCauseCode::MainFunctionType);
+
+                        inherited.register_predicate(
+                            traits::Obligation::new(
+                                cause, param_env, trait_ref.to_predicate()));
+                    },
+                    _ => {},
                 }
             }
         }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 9f98932f24b..cd21d53b837 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -208,8 +208,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             let actual = tcx.fn_sig(main_def_id);
-            let expected_return_type = if tcx.lang_items().termination().is_some()
-                && tcx.features().termination_trait {
+            let expected_return_type = if tcx.lang_items().termination().is_some() {
                 // we take the return type of the given main function, the real check is done
                 // in `check_fn`
                 actual.output().skip_binder()
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 36eb7291822..0b06c5d4d65 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -308,7 +308,6 @@
 #![feature(str_char)]
 #![feature(str_internals)]
 #![feature(str_utf16)]
-#![feature(termination_trait)]
 #![feature(test, rustc_private)]
 #![feature(thread_local)]
 #![feature(toowned_clone_into)]
@@ -325,6 +324,7 @@
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(windows, feature(used))]
 #![cfg_attr(stage0, feature(never_type))]
+#![cfg_attr(stage0, feature(termination_trait))]
 
 #![default_lib_allocator]
 
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index d5ac2d19e83..c877bf6aa35 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1442,8 +1442,9 @@ pub fn id() -> u32 {
 /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
 #[cfg_attr(not(test), lang = "termination")]
 #[unstable(feature = "termination_trait_lib", issue = "43301")]
-#[rustc_on_unimplemented =
-  "`main` can only return types that implement {Termination}, not `{Self}`"]
+#[rustc_on_unimplemented(
+  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.
     /// This status code is returned to the operating system.
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 69612054ae3..35642312e6d 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -428,8 +428,8 @@ declare_features! (
     // `foo.rs` as an alternative to `foo/mod.rs`
     (active, non_modrs_mods, "1.24.0", Some(44660), None),
 
-    // Termination trait in main (RFC 1937)
-    (active, termination_trait, "1.24.0", Some(43301), None),
+    // Termination trait in tests (RFC 1937)
+    (active, termination_trait_test, "1.24.0", Some(48854), None),
 
     // Allows use of the :lifetime macro fragment specifier
     (active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
@@ -565,6 +565,8 @@ declare_features! (
     (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
     // allow `..=` in patterns (RFC 1192)
     (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
+    // Termination trait in main (RFC 1937)
+    (accepted, termination_trait, "1.26.0", Some(43301), None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 5264b627e96..6c01171d100 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -332,7 +332,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
             ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
                 // If the termination trait is active, the compiler will check that the output
                 // type implements the `Termination` trait as `libtest` enforces that.
-                let output_matches = if cx.features.termination_trait {
+                let output_matches = if cx.features.termination_trait_test {
                     true
                 } else {
                     let no_output = match decl.output {
@@ -359,7 +359,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
         match has_test_signature(cx, i) {
             Yes => true,
             No => {
-                if cx.features.termination_trait {
+                if cx.features.termination_trait_test {
                     diag.span_err(i.span, "functions used as tests can not have any arguments");
                 } else {
                     diag.span_err(i.span, "functions used as tests must have signature fn() -> ()");
@@ -388,7 +388,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
 
                 // If the termination trait is active, the compiler will check that the output
                 // type implements the `Termination` trait as `libtest` enforces that.
-                let output_matches = if cx.features.termination_trait {
+                let output_matches = if cx.features.termination_trait_test {
                     true
                 } else {
                     let no_output = match decl.output {
@@ -416,7 +416,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
     if has_bench_attr && !has_bench_signature {
         let diag = cx.span_diagnostic;
 
-        if cx.features.termination_trait {
+        if cx.features.termination_trait_test {
             diag.span_err(i.span, "functions used as benches must have signature \
                                    `fn(&mut Bencher) -> impl Termination`");
         } else {
diff --git a/src/test/compile-fail/feature-gate-termination_trait_test.rs b/src/test/compile-fail/feature-gate-termination_trait_test.rs
new file mode 100644
index 00000000000..4af7e946716
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-termination_trait_test.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --test
+
+fn main() {}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn it_works() -> Result<(), ()> {
+    //~^ ERROR functions used as tests must have signature fn() -> ()
+        Ok(())
+    }
+}
diff --git a/src/test/compile-fail/feature-gate-termination_trait.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs
index 5a56445b64e..0e6ddf7c92f 100644
--- a/src/test/compile-fail/feature-gate-termination_trait.rs
+++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn main() -> i32 { //~ ERROR main function has wrong type [E0580]
+fn main() -> i32 {
+//~^ ERROR `main` has invalid return type `i32`
+//~| NOTE `main` can only return types that implement std::process::Termination
+//~| HELP consider using `()`, or a `Result`
     0
 }
diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs
index e87e0ceebf1..b5f5472b492 100644
--- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs
+++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
-
 struct ReturnType {}
 
-fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied
+fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType`
     ReturnType {}
 }
diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs
index c1dd44a9176..863de85af88 100644
--- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs
+++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
-
 // error-pattern:oh, dear
 
 fn main() -> ! {
diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
index 8ce27c0a062..0c6cb4de956 100644
--- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
+++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs
@@ -11,8 +11,6 @@
 // must-compile-successfully
 // failure-status: 1
 
-#![feature(termination_trait)]
-
 use std::io::{Error, ErrorKind};
 
 fn main() -> Result<(), Box<Error>> {
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs
index 5e534da0128..046d27a9f0f 100644
--- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs
@@ -8,6 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
-
 fn main() {}
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
index 80fa4d17b61..4aa7d8c3a77 100644
--- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
 #![feature(process_exitcode_placeholder)]
 
 use std::process::ExitCode;
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs
index 269ac451cf4..33686ed0b8f 100644
--- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
-
 use std::io::Error;
 
 fn main() -> Result<(), Box<Error>> {
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs
index 751db0fb500..1c87e31e763 100644
--- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(termination_trait)]
-
 use std::io::Error;
 
 fn main() -> Result<(), Error> {
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs
index 494500d522a..11997eb6917 100644
--- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs
@@ -10,7 +10,7 @@
 
 // compile-flags: --test
 
-#![feature(termination_trait)]
+#![feature(termination_trait_test)]
 #![feature(test)]
 
 extern crate test;
diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs
index 93e2561adf7..425f51ca2fb 100644
--- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs
@@ -7,9 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(termination_trait)]
 
-fn main() -> char {
-//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied
+fn main() -> char { //~ ERROR
     ' '
 }
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr
new file mode 100644
index 00000000000..5109d9275c5
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr
@@ -0,0 +1,11 @@
+error[E0277]: `main` has invalid return type `char`
+  --> $DIR/termination-trait-main-wrong-type.rs:11:14
+   |
+LL | fn main() -> char { //~ ERROR
+   |              ^^^^ `main` can only return types that implement std::process::Termination
+   |
+   = help: consider using `()`, or a `Result`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.