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.
This commit is contained in:
Pietro Albini 2018-11-25 17:04:58 +01:00 committed by GitHub
commit 6c2513c0d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 133 additions and 46 deletions

View File

@ -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 ## By-value trait objects
With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.

View File

@ -208,6 +208,10 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>, 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, // 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 // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
// `FnOnce` closure. In that case, we defer full resolution of the // `FnOnce` closure. In that case, we defer full resolution of the
@ -644,6 +648,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
infcx, infcx,
fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
locals: RefCell::new(Default::default()), locals: RefCell::new(Default::default()),
deferred_sized_obligations: RefCell::new(Vec::new()),
deferred_call_resolutions: RefCell::new(Default::default()), deferred_call_resolutions: RefCell::new(Default::default()),
deferred_cast_checks: RefCell::new(Vec::new()), deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: 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); fcx.closure_analyze(body);
assert!(fcx.deferred_call_resolutions.borrow().is_empty()); assert!(fcx.deferred_call_resolutions.borrow().is_empty());
fcx.resolve_generator_interiors(def_id); 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(); fcx.select_all_obligations_or_error();
if fn_decl.is_some() { 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); 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, pub fn register_bound(&self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
def_id: DefId, def_id: DefId,
@ -3939,6 +3956,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
tcx.types.err 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 // We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation. // a type parameter outlives the moment of instantiation.
let substs = self.tables.borrow().node_substs(expr.hir_id); let substs = self.tables.borrow().node_substs(expr.hir_id);

View File

@ -34,4 +34,5 @@ fn main() {
udrop::<[u8]>((*foo())); udrop::<[u8]>((*foo()));
udrop::<[u8]>((*tfoo()).1); udrop::<[u8]>((*tfoo()).1);
*afoo() + 42; *afoo() + 42;
udrop as fn([u8]);
} }

View File

@ -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`.

View File

@ -13,9 +13,7 @@ pub struct X([u8]);
pub static Y: &'static X = { pub static Y: &'static X = {
const Y: &'static [u8] = b""; const Y: &'static [u8] = b"";
&X(*Y) &X(*Y)
//~^ ERROR cannot move out //~^ ERROR E0277
//~^^ ERROR cannot move a
//~^^^ ERROR cannot move a
}; };
fn main() {} fn main() {}

View File

@ -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 --> $DIR/issue-30355.rs:15:6
| |
LL | &X(*Y) LL | &X(*Y)
| ^^^^^ | ^ doesn't have a size known at compile-time
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) = 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[E0507]: cannot move out of borrowed content error: aborting due to previous error
--> $DIR/issue-30355.rs:15:8
|
LL | &X(*Y)
| ^^ cannot move out of borrowed content
error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`.
Some errors occurred: E0161, E0507.
For more information about an error, try `rustc --explain E0161`.

View File

@ -0,0 +1,3 @@
#![feature(unsized_locals)]
pub fn udrop<T: ?Sized>(_x: T) {}

View File

@ -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
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -23,4 +23,6 @@ fn main() {
//~^ERROR E0277 //~^ERROR E0277
udrop::<A<[u8]>>(A { 0: *foo() }); udrop::<A<[u8]>>(A { 0: *foo() });
//~^ERROR E0277 //~^ERROR E0277
udrop::<A<[u8]>>(A(*foo()));
//~^ERROR E0277
} }

View File

@ -20,6 +20,17 @@ LL | udrop::<A<[u8]>>(A { 0: *foo() });
= note: required because it appears within the type `A<[u8]>` = note: required because it appears within the type `A<[u8]>`
= note: structs must have a statically known size to be initialized = 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`. For more information about this error, try `rustc --explain E0277`.

View File

@ -21,6 +21,4 @@ impl std::ops::Add<i32> for A<[u8]> {
fn main() { fn main() {
udrop::<[u8]>(foo()[..]); udrop::<[u8]>(foo()[..]);
//~^ERROR cannot move out of indexed content //~^ERROR cannot move out of indexed content
// FIXME: should be error
udrop::<A<[u8]>>(A(*foo()));
} }

View File

@ -0,0 +1,10 @@
// aux-build:ufuncs.rs
extern crate ufuncs;
use ufuncs::udrop;
fn main() {
udrop as fn([u8]);
//~^ERROR E0277
}

View File

@ -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`.