Skip to content

Commit b43c2e7

Browse files
authored
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.
2 parents 1e0df88 + b60b76c commit b43c2e7

14 files changed

+179
-43
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
938938
// that is understood elsewhere in the compiler as a method on
939939
// `dyn Trait`.
940940
// To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
941-
// we get a value of a built-in pointer type
941+
// we get a value of a built-in pointer type.
942+
//
943+
// This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
942944
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
943945
&& !op.layout.ty.is_region_ptr()
944946
{
@@ -980,13 +982,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
980982
continue;
981983
}
982984
Immediate(_) => {
983-
let ty::Ref(_, ty, _) = op.layout.ty.kind() else {
984-
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
985-
};
986-
if !ty.is_dyn_star() {
985+
// See comment above explaining why we peel these newtypes
986+
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
987+
&& !op.layout.ty.is_region_ptr()
988+
{
989+
for i in 0..op.layout.fields.count() {
990+
let field = op.extract_field(bx, i);
991+
if !field.layout.is_zst() {
992+
// we found the one non-zero-sized field that is allowed
993+
// now find *its* non-zero-sized field, or stop if it's a
994+
// pointer
995+
op = field;
996+
continue 'descend_newtypes;
997+
}
998+
}
999+
1000+
span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
1001+
}
1002+
1003+
// Make sure that we've actually unwrapped the rcvr down
1004+
// to a pointer or ref to `dyn* Trait`.
1005+
if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() {
9871006
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
9881007
}
989-
// FIXME(dyn-star): Make sure this is done on a &dyn* receiver
9901008
let place = op.deref(bx.cx());
9911009
let data_ptr = place.project_field(bx, 0);
9921010
let meta_ptr = place.project_field(bx, 1);

compiler/rustc_hir_typeck/src/coercion.rs

+12-26
Original file line numberDiff line numberDiff line change
@@ -755,20 +755,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
755755

756756
if let ty::Dynamic(a_data, _, _) = a.kind()
757757
&& let ty::Dynamic(b_data, _, _) = b.kind()
758+
&& a_data.principal_def_id() == b_data.principal_def_id()
758759
{
759-
if a_data.principal_def_id() == b_data.principal_def_id() {
760-
return self.unify_and(a, b, |_| vec![]);
761-
} else if !self.tcx().features().trait_upcasting {
762-
let mut err = feature_err(
763-
&self.tcx.sess.parse_sess,
764-
sym::trait_upcasting,
765-
self.cause.span,
766-
&format!(
767-
"cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
768-
),
769-
);
770-
err.emit();
771-
}
760+
return self.unify_and(a, b, |_| vec![]);
772761
}
773762

774763
// Check the obligations of the cast -- for example, when casting
@@ -796,19 +785,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
796785
])
797786
.collect();
798787

799-
// Enforce that the type is `usize`/pointer-sized. For now, only those
800-
// can be coerced to `dyn*`, except for `dyn* -> dyn*` upcasts.
801-
if !a.is_dyn_star() {
802-
obligations.push(Obligation::new(
803-
self.tcx,
804-
self.cause.clone(),
805-
self.param_env,
806-
ty::Binder::dummy(
807-
self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
808-
)
809-
.to_poly_trait_predicate(),
810-
));
811-
}
788+
// Enforce that the type is `usize`/pointer-sized.
789+
obligations.push(Obligation::new(
790+
self.tcx,
791+
self.cause.clone(),
792+
self.param_env,
793+
ty::Binder::dummy(
794+
self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
795+
)
796+
.to_poly_trait_predicate(),
797+
));
812798

813799
Ok(InferOk {
814800
value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -776,9 +776,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
776776

777777
match (source.kind(), target.kind()) {
778778
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
779-
(&ty::Dynamic(ref data_a, _, dyn_a), &ty::Dynamic(ref data_b, _, dyn_b))
780-
if dyn_a == dyn_b =>
781-
{
779+
(&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => {
782780
// Upcast coercions permit several things:
783781
//
784782
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -803,9 +803,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
803803
let upcast_trait_ref;
804804
match (source.kind(), target.kind()) {
805805
// TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
806-
(&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b))
807-
if repr_a == repr_b =>
808-
{
806+
(
807+
&ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn),
808+
&ty::Dynamic(ref data_b, r_b, ty::Dyn),
809+
) => {
809810
// See `assemble_candidates_for_unsizing` for more info.
810811
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
811812
let principal_a = data_a.principal().unwrap();
@@ -831,7 +832,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
831832
.map(ty::Binder::dummy),
832833
);
833834
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
834-
let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b);
835+
let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a);
835836

836837
// Require that the traits involved in this upcast are **equal**;
837838
// only the **lifetime bound** is changed.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// run-pass
2+
// edition:2021
3+
// check-run-results
4+
5+
#![feature(dyn_star)]
6+
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
7+
8+
use std::future::Future;
9+
10+
async fn foo(f: dyn* Future<Output = i32>) {
11+
println!("value: {}", f.await);
12+
}
13+
14+
async fn async_main() {
15+
foo(Box::pin(async { 1 })).await
16+
}
17+
18+
// ------------------------------------------------------------------------- //
19+
// Implementation Details Below...
20+
21+
use std::pin::Pin;
22+
use std::task::*;
23+
24+
pub fn noop_waker() -> Waker {
25+
let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
26+
27+
// SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
28+
unsafe { Waker::from_raw(raw) }
29+
}
30+
31+
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
32+
33+
unsafe fn noop_clone(_p: *const ()) -> RawWaker {
34+
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
35+
}
36+
37+
unsafe fn noop(_p: *const ()) {}
38+
39+
fn main() {
40+
let mut fut = async_main();
41+
42+
// Poll loop, just to test the future...
43+
let waker = noop_waker();
44+
let ctx = &mut Context::from_waker(&waker);
45+
46+
loop {
47+
match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
48+
Poll::Pending => {}
49+
Poll::Ready(()) => break,
50+
}
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
value: 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/dispatch-on-pin-mut.rs:5:12
3+
|
4+
LL | #![feature(dyn_star)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+

src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// check-pass
1+
// run-pass
2+
// check-run-results
23

34
#![feature(dyn_star)]
4-
#![allow(incomplete_features)]
5+
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
56

67
trait AddOne {
78
fn add1(&mut self) -> usize;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
43
2+
44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/dont-unsize-coerce-dyn-star.rs:4:12
3+
|
4+
LL | #![feature(dyn_star)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(dyn_star, trait_upcasting)]
2+
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
3+
4+
trait A: B {}
5+
trait B {}
6+
impl A for usize {}
7+
impl B for usize {}
8+
9+
fn main() {
10+
let x: Box<dyn* A> = Box::new(1usize as dyn* A);
11+
let y: Box<dyn* B> = x;
12+
//~^ ERROR mismatched types
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
3+
|
4+
LL | #![feature(dyn_star, trait_upcasting)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/no-unsize-coerce-dyn-trait.rs:11:26
12+
|
13+
LL | let y: Box<dyn* B> = x;
14+
| ----------- ^ expected trait `B`, found trait `A`
15+
| |
16+
| expected due to this
17+
|
18+
= note: expected struct `Box<dyn* B>`
19+
found struct `Box<dyn* A>`
20+
21+
error: aborting due to previous error; 1 warning emitted
22+
23+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/dyn-star/upcast.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
// run-pass
1+
// known-bug: #104800
22

33
#![feature(dyn_star, trait_upcasting)]
4-
#![allow(incomplete_features)]
54

65
trait Foo: Bar {
76
fn hello(&self);

src/test/ui/dyn-star/upcast.stderr

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/upcast.rs:3:12
3+
|
4+
LL | #![feature(dyn_star, trait_upcasting)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: `dyn* Foo` needs to be a pointer-sized type
11+
--> $DIR/upcast.rs:30:23
12+
|
13+
LL | let w: dyn* Bar = w;
14+
| ^ `dyn* Foo` needs to be a pointer-sized type
15+
|
16+
= help: the trait `PointerSized` is not implemented for `dyn* Foo`
17+
18+
error: aborting due to previous error; 1 warning emitted
19+
20+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)