Skip to content

Commit ba92a7b

Browse files
committed
Merge branch 'stabilize-termination-trait' of https://github.com/tmandry/rust into rollup
2 parents b928781 + 2b13d95 commit ba92a7b

20 files changed

+85
-61
lines changed

src/librustc/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1764,12 +1764,12 @@ The `main` function was incorrectly declared.
17641764
Erroneous code example:
17651765
17661766
```compile_fail,E0580
1767-
fn main() -> i32 { // error: main function has wrong type
1768-
0
1767+
fn main(x: i32) { // error: main function has wrong type
1768+
println!("{}", x);
17691769
}
17701770
```
17711771
1772-
The `main` function prototype should never take arguments or return type.
1772+
The `main` function prototype should never take arguments.
17731773
Example:
17741774
17751775
```

src/librustc/traits/error_reporting.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -595,20 +595,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
595595
trait_ref.to_predicate(), post_message)
596596
}));
597597

598+
let explanation =
599+
if obligation.cause.code == ObligationCauseCode::MainFunctionType {
600+
"consider using `()`, or a `Result`".to_owned()
601+
} else {
602+
format!("{}the trait `{}` is not implemented for `{}`",
603+
pre_message,
604+
trait_ref,
605+
trait_ref.self_ty())
606+
};
607+
598608
if let Some(ref s) = label {
599609
// If it has a custom "#[rustc_on_unimplemented]"
600610
// error message, let's display it as the label!
601611
err.span_label(span, s.as_str());
602-
err.help(&format!("{}the trait `{}` is not implemented for `{}`",
603-
pre_message,
604-
trait_ref,
605-
trait_ref.self_ty()));
612+
err.help(&explanation);
606613
} else {
607-
err.span_label(span,
608-
&*format!("{}the trait `{}` is not implemented for `{}`",
609-
pre_message,
610-
trait_ref,
611-
trait_ref.self_ty()));
614+
err.span_label(span, explanation);
612615
}
613616
if let Some(ref s) = note {
614617
// If it has a custom "#[rustc_on_unimplemented]" note, let's display it

src/librustc_typeck/check/mod.rs

+17-19
Original file line numberDiff line numberDiff line change
@@ -1130,25 +1130,23 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
11301130
}
11311131
fcx.demand_suptype(span, ret_ty, actual_return_ty);
11321132

1133-
if fcx.tcx.features().termination_trait {
1134-
// If the termination trait language item is activated, check that the main return type
1135-
// implements the termination trait.
1136-
if let Some(term_id) = fcx.tcx.lang_items().termination() {
1137-
if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
1138-
if id == fn_id {
1139-
match fcx.sess().entry_type.get() {
1140-
Some(config::EntryMain) => {
1141-
let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
1142-
let trait_ref = ty::TraitRef::new(term_id, substs);
1143-
let cause = traits::ObligationCause::new(
1144-
span, fn_id, ObligationCauseCode::MainFunctionType);
1145-
1146-
inherited.register_predicate(
1147-
traits::Obligation::new(
1148-
cause, param_env, trait_ref.to_predicate()));
1149-
},
1150-
_ => {},
1151-
}
1133+
// Check that the main return type implements the termination trait.
1134+
if let Some(term_id) = fcx.tcx.lang_items().termination() {
1135+
if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() {
1136+
if id == fn_id {
1137+
match fcx.sess().entry_type.get() {
1138+
Some(config::EntryMain) => {
1139+
let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty)));
1140+
let trait_ref = ty::TraitRef::new(term_id, substs);
1141+
let return_ty_span = decl.output.span();
1142+
let cause = traits::ObligationCause::new(
1143+
return_ty_span, fn_id, ObligationCauseCode::MainFunctionType);
1144+
1145+
inherited.register_predicate(
1146+
traits::Obligation::new(
1147+
cause, param_env, trait_ref.to_predicate()));
1148+
},
1149+
_ => {},
11521150
}
11531151
}
11541152
}

src/librustc_typeck/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
208208
}
209209

210210
let actual = tcx.fn_sig(main_def_id);
211-
let expected_return_type = if tcx.lang_items().termination().is_some()
212-
&& tcx.features().termination_trait {
211+
let expected_return_type = if tcx.lang_items().termination().is_some() {
213212
// we take the return type of the given main function, the real check is done
214213
// in `check_fn`
215214
actual.output().skip_binder()

src/libstd/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@
307307
#![feature(str_char)]
308308
#![feature(str_internals)]
309309
#![feature(str_utf16)]
310-
#![feature(termination_trait)]
311310
#![feature(test, rustc_private)]
312311
#![feature(thread_local)]
313312
#![feature(toowned_clone_into)]
@@ -324,6 +323,7 @@
324323
#![cfg_attr(test, feature(update_panic_count))]
325324
#![cfg_attr(windows, feature(used))]
326325
#![cfg_attr(stage0, feature(never_type))]
326+
#![cfg_attr(stage0, feature(termination_trait))]
327327

328328
#![default_lib_allocator]
329329

src/libstd/process.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1442,8 +1442,9 @@ pub fn id() -> u32 {
14421442
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
14431443
#[cfg_attr(not(test), lang = "termination")]
14441444
#[unstable(feature = "termination_trait_lib", issue = "43301")]
1445-
#[rustc_on_unimplemented =
1446-
"`main` can only return types that implement {Termination}, not `{Self}`"]
1445+
#[rustc_on_unimplemented(
1446+
message="`main` has invalid return type `{Self}`",
1447+
label="`main` can only return types that implement {Termination}")]
14471448
pub trait Termination {
14481449
/// Is called to get the representation of the value as status code.
14491450
/// This status code is returned to the operating system.

src/libsyntax/feature_gate.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,8 @@ declare_features! (
425425
// `foo.rs` as an alternative to `foo/mod.rs`
426426
(active, non_modrs_mods, "1.24.0", Some(44660), None),
427427

428-
// Termination trait in main (RFC 1937)
429-
(active, termination_trait, "1.24.0", Some(43301), None),
428+
// Termination trait in tests (RFC 1937)
429+
(active, termination_trait_test, "1.24.0", Some(48854), None),
430430

431431
// Allows use of the :lifetime macro fragment specifier
432432
(active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
@@ -564,6 +564,8 @@ declare_features! (
564564
(accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
565565
// The `i128` type
566566
(accepted, i128_type, "1.26.0", Some(35118), None),
567+
// Termination trait in main (RFC 1937)
568+
(accepted, termination_trait, "1.26.0", Some(43301), None),
567569
);
568570

569571
// If you change this, please modify src/doc/unstable-book as well. You must

src/libsyntax/test.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
332332
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
333333
// If the termination trait is active, the compiler will check that the output
334334
// type implements the `Termination` trait as `libtest` enforces that.
335-
let output_matches = if cx.features.termination_trait {
335+
let output_matches = if cx.features.termination_trait_test {
336336
true
337337
} else {
338338
let no_output = match decl.output {
@@ -359,7 +359,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
359359
match has_test_signature(cx, i) {
360360
Yes => true,
361361
No => {
362-
if cx.features.termination_trait {
362+
if cx.features.termination_trait_test {
363363
diag.span_err(i.span, "functions used as tests can not have any arguments");
364364
} else {
365365
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 {
388388

389389
// If the termination trait is active, the compiler will check that the output
390390
// type implements the `Termination` trait as `libtest` enforces that.
391-
let output_matches = if cx.features.termination_trait {
391+
let output_matches = if cx.features.termination_trait_test {
392392
true
393393
} else {
394394
let no_output = match decl.output {
@@ -416,7 +416,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
416416
if has_bench_attr && !has_bench_signature {
417417
let diag = cx.span_diagnostic;
418418

419-
if cx.features.termination_trait {
419+
if cx.features.termination_trait_test {
420420
diag.span_err(i.span, "functions used as benches must have signature \
421421
`fn(&mut Bencher) -> impl Termination`");
422422
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: --test
12+
13+
fn main() {}
14+
15+
#[cfg(test)]
16+
mod tests {
17+
#[test]
18+
fn it_works() -> Result<(), ()> {
19+
//~^ ERROR functions used as tests must have signature fn() -> ()
20+
Ok(())
21+
}
22+
}

src/test/compile-fail/feature-gate-termination_trait.rs renamed to src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn main() -> i32 { //~ ERROR main function has wrong type [E0580]
11+
fn main() -> i32 {
12+
//~^ ERROR `main` has invalid return type `i32`
13+
//~| NOTE `main` can only return types that implement std::process::Termination
14+
//~| HELP consider using `()`, or a `Result`
1215
0
1316
}

src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
12-
1311
struct ReturnType {}
1412

15-
fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied
13+
fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType`
1614
ReturnType {}
1715
}

src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
12-
1311
// error-pattern:oh, dear
1412

1513
fn main() -> ! {

src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
// must-compile-successfully
1212
// failure-status: 1
1313

14-
#![feature(termination_trait)]
15-
1614
use std::io::{Error, ErrorKind};
1715

1816
fn main() -> Result<(), Box<Error>> {

src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,4 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
12-
1311
fn main() {}

src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
1211
#![feature(process_exitcode_placeholder)]
1312

1413
use std::process::ExitCode;

src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
12-
1311
use std::io::Error;
1412

1513
fn main() -> Result<(), Box<Error>> {

src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(termination_trait)]
12-
1311
use std::io::Error;
1412

1513
fn main() -> Result<(), Error> {

src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// compile-flags: --test
1212

13-
#![feature(termination_trait)]
13+
#![feature(termination_trait_test)]
1414
#![feature(test)]
1515

1616
extern crate test;

src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs renamed to src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10-
#![feature(termination_trait)]
1110

12-
fn main() -> char {
13-
//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied
11+
fn main() -> char { //~ ERROR
1412
' '
1513
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0277]: `main` has invalid return type `char`
2+
--> $DIR/termination-trait-main-wrong-type.rs:11:14
3+
|
4+
LL | fn main() -> char { //~ ERROR
5+
| ^^^^ `main` can only return types that implement std::process::Termination
6+
|
7+
= help: consider using `()`, or a `Result`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)