Rollup merge of #104594 - compiler-errors:dyn-star-rcvr, r=eholk,estebank
Properly handle `Pin<&mut dyn* Trait>` receiver in codegen This ensures we can actually await a `dyn* Future`, which seems important for async fn in dyn trait. Also, disable `dyn*` trait upcasting. It's not exactly complete right now, and can cause strange ICEs for no reason -- nobody's using it either. I thought it was cute to implement when I did it, but I didn't think about how it interacts structurally with `CoerceUnsized` correctly. Fixes #104794, presumably removing `dyn*` upcasting and its `CoerceUnsized` issues does the trick.
This commit is contained in:
commit
b43c2e7cd9
@ -938,7 +938,9 @@ fn codegen_call_terminator(
|
||||
// that is understood elsewhere in the compiler as a method on
|
||||
// `dyn Trait`.
|
||||
// To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
|
||||
// we get a value of a built-in pointer type
|
||||
// we get a value of a built-in pointer type.
|
||||
//
|
||||
// This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
|
||||
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
|
||||
&& !op.layout.ty.is_region_ptr()
|
||||
{
|
||||
@ -980,13 +982,29 @@ fn codegen_call_terminator(
|
||||
continue;
|
||||
}
|
||||
Immediate(_) => {
|
||||
let ty::Ref(_, ty, _) = op.layout.ty.kind() else {
|
||||
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
|
||||
};
|
||||
if !ty.is_dyn_star() {
|
||||
// See comment above explaining why we peel these newtypes
|
||||
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
|
||||
&& !op.layout.ty.is_region_ptr()
|
||||
{
|
||||
for i in 0..op.layout.fields.count() {
|
||||
let field = op.extract_field(bx, i);
|
||||
if !field.layout.is_zst() {
|
||||
// we found the one non-zero-sized field that is allowed
|
||||
// now find *its* non-zero-sized field, or stop if it's a
|
||||
// pointer
|
||||
op = field;
|
||||
continue 'descend_newtypes;
|
||||
}
|
||||
}
|
||||
|
||||
span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
|
||||
}
|
||||
|
||||
// Make sure that we've actually unwrapped the rcvr down
|
||||
// to a pointer or ref to `dyn* Trait`.
|
||||
if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() {
|
||||
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
|
||||
}
|
||||
// FIXME(dyn-star): Make sure this is done on a &dyn* receiver
|
||||
let place = op.deref(bx.cx());
|
||||
let data_ptr = place.project_field(bx, 0);
|
||||
let meta_ptr = place.project_field(bx, 1);
|
||||
|
@ -755,20 +755,9 @@ fn coerce_dyn_star(
|
||||
|
||||
if let ty::Dynamic(a_data, _, _) = a.kind()
|
||||
&& let ty::Dynamic(b_data, _, _) = b.kind()
|
||||
&& a_data.principal_def_id() == b_data.principal_def_id()
|
||||
{
|
||||
if a_data.principal_def_id() == b_data.principal_def_id() {
|
||||
return self.unify_and(a, b, |_| vec![]);
|
||||
} else if !self.tcx().features().trait_upcasting {
|
||||
let mut err = feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::trait_upcasting,
|
||||
self.cause.span,
|
||||
&format!(
|
||||
"cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
|
||||
),
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
return self.unify_and(a, b, |_| vec![]);
|
||||
}
|
||||
|
||||
// Check the obligations of the cast -- for example, when casting
|
||||
@ -796,19 +785,16 @@ fn coerce_dyn_star(
|
||||
])
|
||||
.collect();
|
||||
|
||||
// Enforce that the type is `usize`/pointer-sized. For now, only those
|
||||
// can be coerced to `dyn*`, except for `dyn* -> dyn*` upcasts.
|
||||
if !a.is_dyn_star() {
|
||||
obligations.push(Obligation::new(
|
||||
self.tcx,
|
||||
self.cause.clone(),
|
||||
self.param_env,
|
||||
ty::Binder::dummy(
|
||||
self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
|
||||
)
|
||||
.to_poly_trait_predicate(),
|
||||
));
|
||||
}
|
||||
// Enforce that the type is `usize`/pointer-sized.
|
||||
obligations.push(Obligation::new(
|
||||
self.tcx,
|
||||
self.cause.clone(),
|
||||
self.param_env,
|
||||
ty::Binder::dummy(
|
||||
self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
|
||||
)
|
||||
.to_poly_trait_predicate(),
|
||||
));
|
||||
|
||||
Ok(InferOk {
|
||||
value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
|
||||
|
@ -776,9 +776,7 @@ fn assemble_candidates_for_unsizing(
|
||||
|
||||
match (source.kind(), target.kind()) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::Dynamic(ref data_a, _, dyn_a), &ty::Dynamic(ref data_b, _, dyn_b))
|
||||
if dyn_a == dyn_b =>
|
||||
{
|
||||
(&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => {
|
||||
// Upcast coercions permit several things:
|
||||
//
|
||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||
|
@ -803,9 +803,10 @@ fn confirm_trait_upcasting_unsize_candidate(
|
||||
let upcast_trait_ref;
|
||||
match (source.kind(), target.kind()) {
|
||||
// TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
|
||||
(&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b))
|
||||
if repr_a == repr_b =>
|
||||
{
|
||||
(
|
||||
&ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn),
|
||||
&ty::Dynamic(ref data_b, r_b, ty::Dyn),
|
||||
) => {
|
||||
// See `assemble_candidates_for_unsizing` for more info.
|
||||
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
|
||||
let principal_a = data_a.principal().unwrap();
|
||||
@ -831,7 +832,7 @@ fn confirm_trait_upcasting_unsize_candidate(
|
||||
.map(ty::Binder::dummy),
|
||||
);
|
||||
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
|
||||
let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b);
|
||||
let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a);
|
||||
|
||||
// Require that the traits involved in this upcast are **equal**;
|
||||
// only the **lifetime bound** is changed.
|
||||
|
52
src/test/ui/dyn-star/dispatch-on-pin-mut.rs
Normal file
52
src/test/ui/dyn-star/dispatch-on-pin-mut.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// run-pass
|
||||
// edition:2021
|
||||
// check-run-results
|
||||
|
||||
#![feature(dyn_star)]
|
||||
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
async fn foo(f: dyn* Future<Output = i32>) {
|
||||
println!("value: {}", f.await);
|
||||
}
|
||||
|
||||
async fn async_main() {
|
||||
foo(Box::pin(async { 1 })).await
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Implementation Details Below...
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::task::*;
|
||||
|
||||
pub fn noop_waker() -> Waker {
|
||||
let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
|
||||
|
||||
// SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
|
||||
unsafe { Waker::from_raw(raw) }
|
||||
}
|
||||
|
||||
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
|
||||
|
||||
unsafe fn noop_clone(_p: *const ()) -> RawWaker {
|
||||
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
|
||||
}
|
||||
|
||||
unsafe fn noop(_p: *const ()) {}
|
||||
|
||||
fn main() {
|
||||
let mut fut = async_main();
|
||||
|
||||
// Poll loop, just to test the future...
|
||||
let waker = noop_waker();
|
||||
let ctx = &mut Context::from_waker(&waker);
|
||||
|
||||
loop {
|
||||
match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(()) => break,
|
||||
}
|
||||
}
|
||||
}
|
1
src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
Normal file
1
src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
Normal file
@ -0,0 +1 @@
|
||||
value: 1
|
11
src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
Normal file
11
src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/dispatch-on-pin-mut.rs:5:12
|
||||
|
|
||||
LL | #![feature(dyn_star)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
@ -1,7 +1,8 @@
|
||||
// check-pass
|
||||
// run-pass
|
||||
// check-run-results
|
||||
|
||||
#![feature(dyn_star)]
|
||||
#![allow(incomplete_features)]
|
||||
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
trait AddOne {
|
||||
fn add1(&mut self) -> usize;
|
||||
|
@ -0,0 +1,2 @@
|
||||
43
|
||||
44
|
11
src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
Normal file
11
src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/dont-unsize-coerce-dyn-star.rs:4:12
|
||||
|
|
||||
LL | #![feature(dyn_star)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
13
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
Normal file
13
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#![feature(dyn_star, trait_upcasting)]
|
||||
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
trait A: B {}
|
||||
trait B {}
|
||||
impl A for usize {}
|
||||
impl B for usize {}
|
||||
|
||||
fn main() {
|
||||
let x: Box<dyn* A> = Box::new(1usize as dyn* A);
|
||||
let y: Box<dyn* B> = x;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
23
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
Normal file
23
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
Normal file
@ -0,0 +1,23 @@
|
||||
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
|
||||
|
|
||||
LL | #![feature(dyn_star, trait_upcasting)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/no-unsize-coerce-dyn-trait.rs:11:26
|
||||
|
|
||||
LL | let y: Box<dyn* B> = x;
|
||||
| ----------- ^ expected trait `B`, found trait `A`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `Box<dyn* B>`
|
||||
found struct `Box<dyn* A>`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1,7 +1,6 @@
|
||||
// run-pass
|
||||
// known-bug: #104800
|
||||
|
||||
#![feature(dyn_star, trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo: Bar {
|
||||
fn hello(&self);
|
||||
|
20
src/test/ui/dyn-star/upcast.stderr
Normal file
20
src/test/ui/dyn-star/upcast.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/upcast.rs:3:12
|
||||
|
|
||||
LL | #![feature(dyn_star, trait_upcasting)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: `dyn* Foo` needs to be a pointer-sized type
|
||||
--> $DIR/upcast.rs:30:23
|
||||
|
|
||||
LL | let w: dyn* Bar = w;
|
||||
| ^ `dyn* Foo` needs to be a pointer-sized type
|
||||
|
|
||||
= help: the trait `PointerSized` is not implemented for `dyn* Foo`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user