about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-11-25 17:04:58 +0100
committerGitHub <noreply@github.com>2018-11-25 17:04:58 +0100
commit6c2513c0d38c8690ef0d2f9d024fafa2391671db (patch)
treeaeaa819308ab9e8e89dc13360309c302c75ba67f
parent1aa3ffaf9912e2ba60295a28a820c38a78346dc5 (diff)
parentc6a803a286faae901a6ebd35ec222901f691c7ec (diff)
downloadrust-6c2513c0d38c8690ef0d2f9d024fafa2391671db.tar.gz
rust-6c2513c0d38c8690ef0d2f9d024fafa2391671db.zip
Rollup merge of #56045 - qnighy:additional-sizedness, r=cramertj
Check arg/ret sizedness at ExprKind::Path

This PR solves three problems:

- #50940: ICE on casting unsized tuple struct constructors
- Unsized tuple struct constructors were callable in presence of `unsized_locals`.
- https://github.com/rust-lang/rust/issues/48055#issuecomment-437178966: we cannot relax `Sized` bounds on stable functions because of fn ptr casting

These are caused by lack of `Sized`ness checks for arguments/retvals at **reference sites of `FnDef` items** (not call sites of the functions). Therefore we can basically add more `Sized` obligations on typeck. However, adding `Sized` obligations arbitrarily breaks type inference; to prevent that I added a new method `require_type_is_sized_deferred` which doesn't interfere usual type inference.
-rw-r--r--src/doc/unstable-book/src/language-features/unsized-locals.md2
-rw-r--r--src/librustc_typeck/check/mod.rs42
-rw-r--r--src/test/run-pass/unsized-locals/unsized-exprs.rs1
-rw-r--r--src/test/ui/issues/issue-30355.nll.stderr22
-rw-r--r--src/test/ui/issues/issue-30355.rs4
-rw-r--r--src/test/ui/issues/issue-30355.stderr24
-rw-r--r--src/test/ui/unsized-locals/auxiliary/ufuncs.rs3
-rw-r--r--src/test/ui/unsized-locals/issue-50940-with-feature.rs7
-rw-r--r--src/test/ui/unsized-locals/issue-50940-with-feature.stderr14
-rw-r--r--src/test/ui/unsized-locals/issue-50940.rs5
-rw-r--r--src/test/ui/unsized-locals/issue-50940.stderr14
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs.rs2
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs.stderr13
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs2.rs2
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs3.rs10
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs3.stderr14
16 files changed, 133 insertions, 46 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 6f7cf754ae0..1165ab93a14 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.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e36c0ae2a19..e30a79b25de 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<Box<dyn TraitEngine<'tcx>>>,
 
+    // Some additional `Sized` obligations badly affect type inference.
+    // These obligations are added in a later stage of typeck.
+    deferred_sized_obligations: RefCell<Vec<(Ty<'tcx>, 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,
@@ -3939,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/run-pass/unsized-locals/unsized-exprs.rs b/src/test/run-pass/unsized-locals/unsized-exprs.rs
index 4b988f1e72d..bc64fcdec2e 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/issues/issue-30355.nll.stderr b/src/test/ui/issues/issue-30355.nll.stderr
deleted file mode 100644
index fdf8157dcf8..00000000000
--- 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 ee19d040318..8d5eac06c43 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 7e843688035..1b55f20e6b4 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 <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = 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/auxiliary/ufuncs.rs b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs
new file mode 100644
index 00000000000..065563d45a4
--- /dev/null
+++ b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs
@@ -0,0 +1,3 @@
+#![feature(unsized_locals)]
+
+pub fn udrop<T: ?Sized>(_x: T) {}
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 00000000000..3e5d39ab311
--- /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: ?Sized>(X);
+    A as fn(str) -> A<str>;
+    //~^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 00000000000..f4f015fa190
--- /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<str>;
+   |     ^ doesn't have a size known at compile-time
+   |
+   = help: within `main::A<str>`, the trait `std::marker::Sized` is not implemented for `str`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required because it appears within the type `main::A<str>`
+   = 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 00000000000..7ba809b7e83
--- /dev/null
+++ b/src/test/ui/unsized-locals/issue-50940.rs
@@ -0,0 +1,5 @@
+fn main() {
+    struct A<X: ?Sized>(X);
+    A as fn(str) -> A<str>;
+    //~^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 00000000000..9f3669ccf1f
--- /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<str>;
+   |     ^ 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 <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = 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`.
diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs
index 0cf93c78c4a..8ca88edcb6a 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<[u8]>>(A { 0: *foo() });
     //~^ERROR E0277
+    udrop::<A<[u8]>>(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 eb201694177..0ca60e8dea0 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<[u8]>>(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<[u8]>>(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 <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = 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 ae69893a835..3fb5a002e0e 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<i32> for A<[u8]> {
 fn main() {
     udrop::<[u8]>(foo()[..]);
     //~^ERROR cannot move out of indexed content
-    // FIXME: should be error
-    udrop::<A<[u8]>>(A(*foo()));
 }
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 00000000000..2133b01e094
--- /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 00000000000..42f91a946a8
--- /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 <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = 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`.