From 682b33a1103695de3c6520d55204b3c3d45f68ec Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:15:41 +0900 Subject: [PATCH 1/5] Add require_type_is_sized_deferred. --- src/librustc_typeck/check/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aabef5c323483..b882d982c1fe5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -208,6 +208,10 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fulfillment_cx: RefCell>>, + // Some additional `Sized` obligations badly affect type inference. + // These obligations are added in a later stage of typeck. + deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, + // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or // `FnOnce` closure. In that case, we defer full resolution of the @@ -644,6 +648,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { infcx, fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), locals: RefCell::new(Default::default()), + deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), @@ -907,6 +912,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.closure_analyze(body); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); + + for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { + fcx.require_type_is_sized(ty, span, code); + } fcx.select_all_obligations_or_error(); if fn_decl.is_some() { @@ -2345,6 +2354,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.require_type_meets(ty, span, code, lang_item); } + pub fn require_type_is_sized_deferred(&self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>) + { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } + pub fn register_bound(&self, ty: Ty<'tcx>, def_id: DefId, From 8b426232eef0629265bbfd0bc81fab75e113762b Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:18:13 +0900 Subject: [PATCH 2/5] Check arg/ret sizedness at ExprKind::Path. --- src/librustc_typeck/check/mod.rs | 25 +++++++++++++++++++ src/test/ui/issues/issue-30355.nll.stderr | 22 ---------------- src/test/ui/issues/issue-30355.rs | 4 +-- src/test/ui/issues/issue-30355.stderr | 24 ++++++------------ src/test/ui/unsized-locals/unsized-exprs.rs | 2 ++ .../ui/unsized-locals/unsized-exprs.stderr | 13 +++++++++- src/test/ui/unsized-locals/unsized-exprs2.rs | 2 -- 7 files changed, 48 insertions(+), 44 deletions(-) delete mode 100644 src/test/ui/issues/issue-30355.nll.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b882d982c1fe5..572979d063d2f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3956,6 +3956,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.types.err }; + if let ty::FnDef(..) = ty.sty { + let fn_sig = ty.fn_sig(tcx); + if !tcx.features().unsized_locals { + // We want to remove some Sized bounds from std functions, + // but don't want to expose the removal to stable Rust. + // i.e. we don't want to allow + // + // ```rust + // drop as fn(str); + // ``` + // + // to work in stable even if the Sized bound on `drop` is relaxed. + for i in 0..fn_sig.inputs().skip_binder().len() { + let input = tcx.erase_late_bound_regions(&fn_sig.input(i)); + self.require_type_is_sized_deferred(input, expr.span, + traits::SizedArgumentType); + } + } + // Here we want to prevent struct constructors from returning unsized types. + // There were two cases this happened: fn pointer coercion in stable + // and usual function call in presense of unsized_locals. + let output = tcx.erase_late_bound_regions(&fn_sig.output()); + self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType); + } + // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. let substs = self.tables.borrow().node_substs(expr.hir_id); diff --git a/src/test/ui/issues/issue-30355.nll.stderr b/src/test/ui/issues/issue-30355.nll.stderr deleted file mode 100644 index fdf8157dcf833..0000000000000 --- a/src/test/ui/issues/issue-30355.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0161]: cannot move a value of type X: the size of X cannot be statically determined - --> $DIR/issue-30355.rs:15:6 - | -LL | &X(*Y) - | ^^^^^ - -error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ - -error[E0508]: cannot move out of type `[u8]`, a non-copy slice - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ cannot move out of here - -error: aborting due to 3 previous errors - -Some errors occurred: E0161, E0508. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/issues/issue-30355.rs b/src/test/ui/issues/issue-30355.rs index ee19d04031893..8d5eac06c4379 100644 --- a/src/test/ui/issues/issue-30355.rs +++ b/src/test/ui/issues/issue-30355.rs @@ -13,9 +13,7 @@ pub struct X([u8]); pub static Y: &'static X = { const Y: &'static [u8] = b""; &X(*Y) - //~^ ERROR cannot move out - //~^^ ERROR cannot move a - //~^^^ ERROR cannot move a + //~^ ERROR E0277 }; fn main() {} diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 7e843688035af..1b55f20e6b431 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -1,22 +1,14 @@ -error[E0161]: cannot move a value of type X: the size of X cannot be statically determined +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/issue-30355.rs:15:6 | LL | &X(*Y) - | ^^^^^ - -error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined - --> $DIR/issue-30355.rs:15:8 + | ^ doesn't have a size known at compile-time | -LL | &X(*Y) - | ^^ - -error[E0507]: cannot move out of borrowed content - --> $DIR/issue-30355.rs:15:8 - | -LL | &X(*Y) - | ^^ cannot move out of borrowed content + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0161, E0507. -For more information about an error, try `rustc --explain E0161`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index 0cf93c78c4abe..8ca88edcb6add 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -23,4 +23,6 @@ fn main() { //~^ERROR E0277 udrop::>(A { 0: *foo() }); //~^ERROR E0277 + udrop::>(A(*foo())); + //~^ERROR E0277 } diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index eb2016941770c..0ca60e8dea0d9 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -20,6 +20,17 @@ LL | udrop::>(A { 0: *foo() }); = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized -error: aborting due to 2 previous errors +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-exprs.rs:26:22 + | +LL | udrop::>(A(*foo())); + | ^ doesn't have a size known at compile-time + | + = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: required because it appears within the type `A<[u8]>` + = note: the return type of a function must have a statically known size + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index ae69893a83577..3fb5a002e0e3c 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -21,6 +21,4 @@ impl std::ops::Add for A<[u8]> { fn main() { udrop::<[u8]>(foo()[..]); //~^ERROR cannot move out of indexed content - // FIXME: should be error - udrop::>(A(*foo())); } From 8ab5be13a31261317c0e4b52bd4743da03e5bf74 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:19:14 +0900 Subject: [PATCH 3/5] Add tests verifying #50940. --- .../ui/unsized-locals/issue-50940-with-feature.rs | 7 +++++++ .../unsized-locals/issue-50940-with-feature.stderr | 14 ++++++++++++++ src/test/ui/unsized-locals/issue-50940.rs | 5 +++++ src/test/ui/unsized-locals/issue-50940.stderr | 14 ++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 src/test/ui/unsized-locals/issue-50940-with-feature.rs create mode 100644 src/test/ui/unsized-locals/issue-50940-with-feature.stderr create mode 100644 src/test/ui/unsized-locals/issue-50940.rs create mode 100644 src/test/ui/unsized-locals/issue-50940.stderr diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.rs b/src/test/ui/unsized-locals/issue-50940-with-feature.rs new file mode 100644 index 0000000000000..3e5d39ab31150 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.rs @@ -0,0 +1,7 @@ +#![feature(unsized_locals)] + +fn main() { + struct A(X); + A as fn(str) -> A; + //~^ERROR the size for values of type `str` cannot be known at compilation time +} diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr new file mode 100644 index 0000000000000..f4f015fa19065 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-50940-with-feature.rs:5:5 + | +LL | A as fn(str) -> A; + | ^ doesn't have a size known at compile-time + | + = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + = note: required because it appears within the type `main::A` + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/issue-50940.rs b/src/test/ui/unsized-locals/issue-50940.rs new file mode 100644 index 0000000000000..7ba809b7e83e3 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940.rs @@ -0,0 +1,5 @@ +fn main() { + struct A(X); + A as fn(str) -> A; + //~^ERROR the size for values of type `str` cannot be known at compilation time +} diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr new file mode 100644 index 0000000000000..9f3669ccf1f15 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-50940.rs:3:5 + | +LL | A as fn(str) -> A; + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 2ff6ffc872645bf6f5bc7dda4a817a1fc7789684 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:26:05 +0900 Subject: [PATCH 4/5] Add tests for unsized-locals functions stability. --- src/test/run-pass/unsized-locals/unsized-exprs.rs | 1 + src/test/ui/unsized-locals/auxiliary/ufuncs.rs | 3 +++ src/test/ui/unsized-locals/unsized-exprs3.rs | 10 ++++++++++ src/test/ui/unsized-locals/unsized-exprs3.stderr | 14 ++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 src/test/ui/unsized-locals/auxiliary/ufuncs.rs create mode 100644 src/test/ui/unsized-locals/unsized-exprs3.rs create mode 100644 src/test/ui/unsized-locals/unsized-exprs3.stderr diff --git a/src/test/run-pass/unsized-locals/unsized-exprs.rs b/src/test/run-pass/unsized-locals/unsized-exprs.rs index 4b988f1e72d5a..bc64fcdec2e39 100644 --- a/src/test/run-pass/unsized-locals/unsized-exprs.rs +++ b/src/test/run-pass/unsized-locals/unsized-exprs.rs @@ -34,4 +34,5 @@ fn main() { udrop::<[u8]>((*foo())); udrop::<[u8]>((*tfoo()).1); *afoo() + 42; + udrop as fn([u8]); } diff --git a/src/test/ui/unsized-locals/auxiliary/ufuncs.rs b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs new file mode 100644 index 0000000000000..065563d45a472 --- /dev/null +++ b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs @@ -0,0 +1,3 @@ +#![feature(unsized_locals)] + +pub fn udrop(_x: T) {} diff --git a/src/test/ui/unsized-locals/unsized-exprs3.rs b/src/test/ui/unsized-locals/unsized-exprs3.rs new file mode 100644 index 0000000000000..2133b01e09480 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-exprs3.rs @@ -0,0 +1,10 @@ +// aux-build:ufuncs.rs + +extern crate ufuncs; + +use ufuncs::udrop; + +fn main() { + udrop as fn([u8]); + //~^ERROR E0277 +} diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr new file mode 100644 index 0000000000000..42f91a946a851 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-exprs3.rs:8:5 + | +LL | udrop as fn([u8]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From c6a803a286faae901a6ebd35ec222901f691c7ec Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 19 Nov 2018 00:27:16 +0900 Subject: [PATCH 5/5] Modify doc to reflect the unsized-locals improvement. --- src/doc/unstable-book/src/language-features/unsized-locals.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index 6f7cf754ae083..1165ab93a1469 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -80,8 +80,6 @@ fn main() { } ``` -However, the current implementation allows `MyTupleStruct(..)` to be unsized. This will be fixed in the future. - ## By-value trait objects With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.