about summary refs log tree commit diff
diff options
context:
space:
mode:
authorleonardo.yvens <leoyvens@gmail.com>2018-05-11 11:29:04 -0300
committerMark Simulacrum <mark.simulacrum@gmail.com>2018-05-24 14:27:07 -0600
commit31fe67cc069b73b827df925dfa87bc008a6876ee (patch)
tree6fe3f4bf00aa7fd27d3e6e5d20b56918276acbb9
parent4c67e7069cfdc90047058145e420697c04dd1b3f (diff)
downloadrust-31fe67cc069b73b827df925dfa87bc008a6876ee.tar.gz
rust-31fe67cc069b73b827df925dfa87bc008a6876ee.zip
Fix `fn main() -> impl Trait` for non-`Termination` trait
Fixes #50595.

This bug currently affects stable. Why I think we can go for hard error:

- It will in stable for at most one cycle and there is no legitimate
reason to abuse it, nor any known uses in the wild.

- It only affects `bin` crates (which have a `main`), so there is
little practical difference between a hard error or a deny lint, both
are a one line fix.

The fix was to just unshadow a variable. Thanks @nikomatsakis for the
mentoring!

r? @nikomatsakis
-rw-r--r--src/librustc_typeck/check/mod.rs14
-rw-r--r--src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs13
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs13
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr11
4 files changed, 44 insertions, 7 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1443672c161..923f3d7b190 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1035,13 +1035,13 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let mut fcx = FnCtxt::new(inherited, param_env, body.value.id);
     *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
-    let ret_ty = fn_sig.output();
-    fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
-    let ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &ret_ty);
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
+    let declared_ret_ty = fn_sig.output();
+    fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+    let revealed_ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &declared_ret_ty);
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
     fn_sig = fcx.tcx.mk_fn_sig(
         fn_sig.inputs().iter().cloned(),
-        ret_ty,
+        revealed_ret_ty,
         fn_sig.variadic,
         fn_sig.unsafety,
         fn_sig.abi
@@ -1123,7 +1123,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
         actual_return_ty = fcx.next_diverging_ty_var(
             TypeVariableOrigin::DivergingFn(span));
     }
-    fcx.demand_suptype(span, ret_ty, actual_return_ty);
+    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
 
     // Check that the main return type implements the termination trait.
     if let Some(term_id) = fcx.tcx.lang_items().termination() {
@@ -1131,7 +1131,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
             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 substs = fcx.tcx.mk_substs(iter::once(Kind::from(declared_ret_ty)));
                         let trait_ref = ty::TraitRef::new(term_id, substs);
                         let return_ty_span = decl.output.span();
                         let cause = traits::ObligationCause::new(
diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs
new file mode 100644
index 00000000000..5bce3f8045e
--- /dev/null
+++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 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.
+
+#![feature(termination_trait_lib)]
+
+fn main() -> impl std::process::Termination { }
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs
new file mode 100644
index 00000000000..92d21864c74
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 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.
+
+// Tests that an `impl Trait` that is not `impl Termination` will not work.
+fn main() -> impl Copy { }
+//~^ ERROR `main` has invalid return type `impl std::marker::Copy`
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr
new file mode 100644
index 00000000000..7485f3066bb
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr
@@ -0,0 +1,11 @@
+error[E0277]: `main` has invalid return type `impl std::marker::Copy`
+  --> $DIR/termination-trait-impl-trait.rs:12:14
+   |
+LL | fn main() -> impl Copy { }
+   |              ^^^^^^^^^ `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`.