Skip to content

Commit 6c2513c

Browse files
authored
Rollup merge of rust-lang#56045 - qnighy:additional-sizedness, r=cramertj
Check arg/ret sizedness at ExprKind::Path This PR solves three problems: - rust-lang#50940: ICE on casting unsized tuple struct constructors - Unsized tuple struct constructors were callable in presence of `unsized_locals`. - rust-lang#48055 (comment): 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.
2 parents 1aa3ffa + c6a803a commit 6c2513c

16 files changed

+133
-46
lines changed

src/doc/unstable-book/src/language-features/unsized-locals.md

-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ fn main() {
8080
}
8181
```
8282

83-
However, the current implementation allows `MyTupleStruct(..)` to be unsized. This will be fixed in the future.
84-
8583
## By-value trait objects
8684

8785
With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.

src/librustc_typeck/check/mod.rs

+42
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
208208

209209
fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
210210

211+
// Some additional `Sized` obligations badly affect type inference.
212+
// These obligations are added in a later stage of typeck.
213+
deferred_sized_obligations: RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
214+
211215
// When we process a call like `c()` where `c` is a closure type,
212216
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
213217
// `FnOnce` closure. In that case, we defer full resolution of the
@@ -644,6 +648,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
644648
infcx,
645649
fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
646650
locals: RefCell::new(Default::default()),
651+
deferred_sized_obligations: RefCell::new(Vec::new()),
647652
deferred_call_resolutions: RefCell::new(Default::default()),
648653
deferred_cast_checks: RefCell::new(Vec::new()),
649654
deferred_generator_interiors: RefCell::new(Vec::new()),
@@ -907,6 +912,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
907912
fcx.closure_analyze(body);
908913
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
909914
fcx.resolve_generator_interiors(def_id);
915+
916+
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
917+
fcx.require_type_is_sized(ty, span, code);
918+
}
910919
fcx.select_all_obligations_or_error();
911920

912921
if fn_decl.is_some() {
@@ -2345,6 +2354,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
23452354
self.require_type_meets(ty, span, code, lang_item);
23462355
}
23472356

2357+
pub fn require_type_is_sized_deferred(&self,
2358+
ty: Ty<'tcx>,
2359+
span: Span,
2360+
code: traits::ObligationCauseCode<'tcx>)
2361+
{
2362+
self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
2363+
}
2364+
23482365
pub fn register_bound(&self,
23492366
ty: Ty<'tcx>,
23502367
def_id: DefId,
@@ -3939,6 +3956,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
39393956
tcx.types.err
39403957
};
39413958

3959+
if let ty::FnDef(..) = ty.sty {
3960+
let fn_sig = ty.fn_sig(tcx);
3961+
if !tcx.features().unsized_locals {
3962+
// We want to remove some Sized bounds from std functions,
3963+
// but don't want to expose the removal to stable Rust.
3964+
// i.e. we don't want to allow
3965+
//
3966+
// ```rust
3967+
// drop as fn(str);
3968+
// ```
3969+
//
3970+
// to work in stable even if the Sized bound on `drop` is relaxed.
3971+
for i in 0..fn_sig.inputs().skip_binder().len() {
3972+
let input = tcx.erase_late_bound_regions(&fn_sig.input(i));
3973+
self.require_type_is_sized_deferred(input, expr.span,
3974+
traits::SizedArgumentType);
3975+
}
3976+
}
3977+
// Here we want to prevent struct constructors from returning unsized types.
3978+
// There were two cases this happened: fn pointer coercion in stable
3979+
// and usual function call in presense of unsized_locals.
3980+
let output = tcx.erase_late_bound_regions(&fn_sig.output());
3981+
self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
3982+
}
3983+
39423984
// We always require that the type provided as the value for
39433985
// a type parameter outlives the moment of instantiation.
39443986
let substs = self.tables.borrow().node_substs(expr.hir_id);

src/test/run-pass/unsized-locals/unsized-exprs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ fn main() {
3434
udrop::<[u8]>((*foo()));
3535
udrop::<[u8]>((*tfoo()).1);
3636
*afoo() + 42;
37+
udrop as fn([u8]);
3738
}

src/test/ui/issues/issue-30355.nll.stderr

-22
This file was deleted.

src/test/ui/issues/issue-30355.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ pub struct X([u8]);
1313
pub static Y: &'static X = {
1414
const Y: &'static [u8] = b"";
1515
&X(*Y)
16-
//~^ ERROR cannot move out
17-
//~^^ ERROR cannot move a
18-
//~^^^ ERROR cannot move a
16+
//~^ ERROR E0277
1917
};
2018

2119
fn main() {}

src/test/ui/issues/issue-30355.stderr

+8-16
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
1-
error[E0161]: cannot move a value of type X: the size of X cannot be statically determined
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
22
--> $DIR/issue-30355.rs:15:6
33
|
44
LL | &X(*Y)
5-
| ^^^^^
6-
7-
error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined
8-
--> $DIR/issue-30355.rs:15:8
5+
| ^ doesn't have a size known at compile-time
96
|
10-
LL | &X(*Y)
11-
| ^^
12-
13-
error[E0507]: cannot move out of borrowed content
14-
--> $DIR/issue-30355.rs:15:8
15-
|
16-
LL | &X(*Y)
17-
| ^^ cannot move out of borrowed content
7+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
8+
= 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>
9+
= note: all function arguments must have a statically known size
10+
= help: unsized locals are gated as an unstable feature
1811

19-
error: aborting due to 3 previous errors
12+
error: aborting due to previous error
2013

21-
Some errors occurred: E0161, E0507.
22-
For more information about an error, try `rustc --explain E0161`.
14+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#![feature(unsized_locals)]
2+
3+
pub fn udrop<T: ?Sized>(_x: T) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(unsized_locals)]
2+
3+
fn main() {
4+
struct A<X: ?Sized>(X);
5+
A as fn(str) -> A<str>;
6+
//~^ERROR the size for values of type `str` cannot be known at compilation time
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the size for values of type `str` cannot be known at compilation time
2+
--> $DIR/issue-50940-with-feature.rs:5:5
3+
|
4+
LL | A as fn(str) -> A<str>;
5+
| ^ doesn't have a size known at compile-time
6+
|
7+
= help: within `main::A<str>`, the trait `std::marker::Sized` is not implemented for `str`
8+
= 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>
9+
= note: required because it appears within the type `main::A<str>`
10+
= note: the return type of a function must have a statically known size
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
struct A<X: ?Sized>(X);
3+
A as fn(str) -> A<str>;
4+
//~^ERROR the size for values of type `str` cannot be known at compilation time
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the size for values of type `str` cannot be known at compilation time
2+
--> $DIR/issue-50940.rs:3:5
3+
|
4+
LL | A as fn(str) -> A<str>;
5+
| ^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `std::marker::Sized` is not implemented for `str`
8+
= 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>
9+
= note: all function arguments must have a statically known size
10+
= help: unsized locals are gated as an unstable feature
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/unsized-locals/unsized-exprs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ fn main() {
2323
//~^ERROR E0277
2424
udrop::<A<[u8]>>(A { 0: *foo() });
2525
//~^ERROR E0277
26+
udrop::<A<[u8]>>(A(*foo()));
27+
//~^ERROR E0277
2628
}

src/test/ui/unsized-locals/unsized-exprs.stderr

+12-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ LL | udrop::<A<[u8]>>(A { 0: *foo() });
2020
= note: required because it appears within the type `A<[u8]>`
2121
= note: structs must have a statically known size to be initialized
2222

23-
error: aborting due to 2 previous errors
23+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
24+
--> $DIR/unsized-exprs.rs:26:22
25+
|
26+
LL | udrop::<A<[u8]>>(A(*foo()));
27+
| ^ doesn't have a size known at compile-time
28+
|
29+
= help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
30+
= 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>
31+
= note: required because it appears within the type `A<[u8]>`
32+
= note: the return type of a function must have a statically known size
33+
34+
error: aborting due to 3 previous errors
2435

2536
For more information about this error, try `rustc --explain E0277`.

src/test/ui/unsized-locals/unsized-exprs2.rs

-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,4 @@ impl std::ops::Add<i32> for A<[u8]> {
2121
fn main() {
2222
udrop::<[u8]>(foo()[..]);
2323
//~^ERROR cannot move out of indexed content
24-
// FIXME: should be error
25-
udrop::<A<[u8]>>(A(*foo()));
2624
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// aux-build:ufuncs.rs
2+
3+
extern crate ufuncs;
4+
5+
use ufuncs::udrop;
6+
7+
fn main() {
8+
udrop as fn([u8]);
9+
//~^ERROR E0277
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2+
--> $DIR/unsized-exprs3.rs:8:5
3+
|
4+
LL | udrop as fn([u8]);
5+
| ^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
8+
= 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>
9+
= note: all function arguments must have a statically known size
10+
= help: unsized locals are gated as an unstable feature
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)