Skip to content

Commit a64cd26

Browse files
committed
Rollup merge of #49162 - tmandry:stabilize-termination-trait, r=nikomatsakis
Stabilize termination_trait, split out termination_trait_test For #48453. First time contribution, so I'd really appreciate any feedback on how this PR can be better. Not sure exactly what kind of documentation update is needed. If there is no PR to update the reference, I can try doing that this week as I have time.
2 parents 8d2792e + 2b13d95 commit a64cd26

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
@@ -308,7 +308,6 @@
308308
#![feature(str_char)]
309309
#![feature(str_internals)]
310310
#![feature(str_utf16)]
311-
#![feature(termination_trait)]
312311
#![feature(test, rustc_private)]
313312
#![feature(thread_local)]
314313
#![feature(toowned_clone_into)]
@@ -325,6 +324,7 @@
325324
#![cfg_attr(test, feature(update_panic_count))]
326325
#![cfg_attr(windows, feature(used))]
327326
#![cfg_attr(stage0, feature(never_type))]
327+
#![cfg_attr(stage0, feature(termination_trait))]
328328

329329
#![default_lib_allocator]
330330

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
@@ -428,8 +428,8 @@ declare_features! (
428428
// `foo.rs` as an alternative to `foo/mod.rs`
429429
(active, non_modrs_mods, "1.24.0", Some(44660), None),
430430

431-
// Termination trait in main (RFC 1937)
432-
(active, termination_trait, "1.24.0", Some(43301), None),
431+
// Termination trait in tests (RFC 1937)
432+
(active, termination_trait_test, "1.24.0", Some(48854), None),
433433

434434
// Allows use of the :lifetime macro fragment specifier
435435
(active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
@@ -565,6 +565,8 @@ declare_features! (
565565
(accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
566566
// allow `..=` in patterns (RFC 1192)
567567
(accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
568+
// Termination trait in main (RFC 1937)
569+
(accepted, termination_trait, "1.26.0", Some(43301), None),
568570
);
569571

570572
// 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)