diff --git a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md new file mode 100644 index 000000000000..c243737e1be5 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md @@ -0,0 +1,27 @@ +# `unsized_tuple_coercion` + +The tracking issue for this feature is: [#XXXXX] + +[#XXXXX]: https://github.com/rust-lang/rust/issues/XXXXX + +------------------------ + +This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: + +```rust +impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {} +``` + +This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this: + +```rust +#![feature(unsized_tuple_coercion)] + +fn main() { + let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]); + let y : &([i32; 3], [i32]) = &x; + assert_eq!(y.1[0], 4); +} +``` + +[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 81aa59e956ab..968e893b9a00 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use errors::DiagnosticBuilder; use syntax::abi; +use syntax::feature_gate; use syntax::ptr::P; use syntax_pos; @@ -520,6 +521,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_source, &[coerce_target])); + let mut has_unsized_tuple_coercion = false; + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where // inference might unify those two inner type variables later. @@ -527,7 +530,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { while let Some(obligation) = queue.pop_front() { debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + if unsize_did == tr.def_id() { + if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty { + debug!("coerce_unsized: found unsized tuple coercion"); + has_unsized_tuple_coercion = true; + } + } + tr.clone() + } _ => { coercion.obligations.push(obligation); continue; @@ -557,6 +568,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } + if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, + "unsized_tuple_coercion", + self.cause.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION); + } + Ok(coercion) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 74bf19b841e8..5de9062de748 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -357,6 +357,9 @@ declare_features! ( // Allows a test to fail without failing the whole suite (active, allow_fail, "1.19.0", Some(42219)), + + // Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", None), ); declare_features! ( @@ -1041,6 +1044,9 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_PLACEMENT_IN: &'static str = "placement-in expression syntax is experimental and subject to change."; +pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = + "Unsized tuple coercion is not stable enough for use and is subject to change"; + struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index 3c089edf0013..1c3bad5ba564 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -10,6 +10,8 @@ // Forbid assignment into a dynamically sized type. +#![feature(unsized_tuple_coercion)] + type Fat = (isize, &'static str, T); //~^ WARNING trait bounds are not (yet) enforced diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index 722ff8f25d61..b0de84a53007 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -10,6 +10,8 @@ // Attempt to change the type as well as unsizing. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs index 4dedae9331bc..35a147c15bb4 100644 --- a/src/test/compile-fail/dst-bad-coerce3.rs +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -10,6 +10,8 @@ // Attempt to extend the lifetime as well as unsizing. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs index 2e78108a8dea..874b7588ff9b 100644 --- a/src/test/compile-fail/dst-bad-coerce4.rs +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -10,6 +10,8 @@ // Attempt to coerce from unsized to sized. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 831afd27153a..0c812b1d815a 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -13,6 +13,8 @@ // because it would require stack allocation of an unsized temporary (*g in the // test). +#![feature(unsized_tuple_coercion)] + pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; diff --git a/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs b/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs new file mode 100644 index 000000000000..4ddde0112636 --- /dev/null +++ b/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _ : &(Send,) = &((),); + //~^ ERROR Unsized tuple coercion is not stable enough +} diff --git a/src/test/run-pass-valgrind/dst-dtor-3.rs b/src/test/run-pass-valgrind/dst-dtor-3.rs index b21f6434b540..1ae66a28a849 100644 --- a/src/test/run-pass-valgrind/dst-dtor-3.rs +++ b/src/test/run-pass-valgrind/dst-dtor-3.rs @@ -10,6 +10,8 @@ // no-prefer-dynamic +#![feature(unsized_tuple_coercion)] + static mut DROP_RAN: bool = false; struct Foo; diff --git a/src/test/run-pass-valgrind/dst-dtor-4.rs b/src/test/run-pass-valgrind/dst-dtor-4.rs index 810589de7708..e416f25bc03a 100644 --- a/src/test/run-pass-valgrind/dst-dtor-4.rs +++ b/src/test/run-pass-valgrind/dst-dtor-4.rs @@ -10,6 +10,8 @@ // no-prefer-dynamic +#![feature(unsized_tuple_coercion)] + static mut DROP_RAN: isize = 0; struct Foo; diff --git a/src/test/run-pass/dst-irrefutable-bind.rs b/src/test/run-pass/dst-irrefutable-bind.rs index bd6ad9207adc..b1d6c732e7fb 100644 --- a/src/test/run-pass/dst-irrefutable-bind.rs +++ b/src/test/run-pass/dst-irrefutable-bind.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unsized_tuple_coercion)] + struct Test(T); fn main() { diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index c82cbd75044f..9ebfbee8a330 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -11,6 +11,8 @@ // Test DST raw pointers +#![feature(unsized_tuple_coercion)] + trait Trait { fn foo(&self) -> isize; } diff --git a/src/test/run-pass/dst-trait-tuple.rs b/src/test/run-pass/dst-trait-tuple.rs index ab60e95c74e8..9803e26f5f85 100644 --- a/src/test/run-pass/dst-trait-tuple.rs +++ b/src/test/run-pass/dst-trait-tuple.rs @@ -11,6 +11,7 @@ #![allow(unused_features)] #![feature(box_syntax)] +#![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); diff --git a/src/test/run-pass/dst-tuple-sole.rs b/src/test/run-pass/dst-tuple-sole.rs index d3901a7555fd..a788e25218eb 100644 --- a/src/test/run-pass/dst-tuple-sole.rs +++ b/src/test/run-pass/dst-tuple-sole.rs @@ -11,6 +11,8 @@ // As dst-tuple.rs, but the unsized field is the only field in the tuple. +#![feature(unsized_tuple_coercion)] + type Fat = (T,); // x is a fat pointer diff --git a/src/test/run-pass/dst-tuple.rs b/src/test/run-pass/dst-tuple.rs index 130294feb6ca..2f5b28495b8a 100644 --- a/src/test/run-pass/dst-tuple.rs +++ b/src/test/run-pass/dst-tuple.rs @@ -11,6 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] +#![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T);