Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check arg/ret sizedness at ExprKind::Path #56045

Merged
merged 5 commits into from
Nov 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/doc/unstable-book/src/language-features/unsized-locals.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
42 changes: 42 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/test/run-pass/unsized-locals/unsized-exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ fn main() {
udrop::<[u8]>((*foo()));
udrop::<[u8]>((*tfoo()).1);
*afoo() + 42;
udrop as fn([u8]);
}
22 changes: 0 additions & 22 deletions src/test/ui/issues/issue-30355.nll.stderr

This file was deleted.

4 changes: 1 addition & 3 deletions src/test/ui/issues/issue-30355.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
24 changes: 8 additions & 16 deletions src/test/ui/issues/issue-30355.stderr
Original file line number Diff line number Diff line change
@@ -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`.
3 changes: 3 additions & 0 deletions src/test/ui/unsized-locals/auxiliary/ufuncs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![feature(unsized_locals)]

pub fn udrop<T: ?Sized>(_x: T) {}
7 changes: 7 additions & 0 deletions src/test/ui/unsized-locals/issue-50940-with-feature.rs
Original file line number Diff line number Diff line change
@@ -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
}
14 changes: 14 additions & 0 deletions src/test/ui/unsized-locals/issue-50940-with-feature.stderr
Original file line number Diff line number Diff line change
@@ -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`.
5 changes: 5 additions & 0 deletions src/test/ui/unsized-locals/issue-50940.rs
Original file line number Diff line number Diff line change
@@ -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
}
14 changes: 14 additions & 0 deletions src/test/ui/unsized-locals/issue-50940.stderr
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 2 additions & 0 deletions src/test/ui/unsized-locals/unsized-exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ fn main() {
//~^ERROR E0277
udrop::<A<[u8]>>(A { 0: *foo() });
//~^ERROR E0277
udrop::<A<[u8]>>(A(*foo()));
//~^ERROR E0277
}
13 changes: 12 additions & 1 deletion src/test/ui/unsized-locals/unsized-exprs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
2 changes: 0 additions & 2 deletions src/test/ui/unsized-locals/unsized-exprs2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
10 changes: 10 additions & 0 deletions src/test/ui/unsized-locals/unsized-exprs3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// aux-build:ufuncs.rs

extern crate ufuncs;

use ufuncs::udrop;

fn main() {
udrop as fn([u8]);
//~^ERROR E0277
}
14 changes: 14 additions & 0 deletions src/test/ui/unsized-locals/unsized-exprs3.stderr
Original file line number Diff line number Diff line change
@@ -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`.