From c620a972f3bae8171e17eb8a243b419caadd9ab7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 19 Nov 2022 04:48:01 +0000 Subject: [PATCH 1/3] Disable dyn* upcasting --- compiler/rustc_hir_typeck/src/coercion.rs | 38 ++++++------------- .../src/traits/select/candidate_assembly.rs | 4 +- .../src/traits/select/confirmation.rs | 9 +++-- .../ui/dyn-star/no-unsize-coerce-dyn-trait.rs | 13 +++++++ .../no-unsize-coerce-dyn-trait.stderr | 23 +++++++++++ src/test/ui/dyn-star/upcast.rs | 3 +- src/test/ui/dyn-star/upcast.stderr | 20 ++++++++++ 7 files changed, 75 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs create mode 100644 src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr create mode 100644 src/test/ui/dyn-star/upcast.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 3f0d0a76027..ea842af1e7f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -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), diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b107d9570f..9d899da9bba 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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` diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2ec5d925b69..3cffd2bb780 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -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. diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs new file mode 100644 index 00000000000..a4eb669e321 --- /dev/null +++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs @@ -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 = Box::new(1usize as dyn* A); + let y: Box = x; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr new file mode 100644 index 00000000000..2fc751b3b4a --- /dev/null +++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr @@ -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 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 = x; + | ----------- ^ expected trait `B`, found trait `A` + | | + | expected due to this + | + = note: expected struct `Box` + found struct `Box` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs index cee76ada7df..24c077047e9 100644 --- a/src/test/ui/dyn-star/upcast.rs +++ b/src/test/ui/dyn-star/upcast.rs @@ -1,7 +1,6 @@ -// run-pass +// known-bug: unknown #![feature(dyn_star, trait_upcasting)] -#![allow(incomplete_features)] trait Foo: Bar { fn hello(&self); diff --git a/src/test/ui/dyn-star/upcast.stderr b/src/test/ui/dyn-star/upcast.stderr new file mode 100644 index 00000000000..6a95f7754e6 --- /dev/null +++ b/src/test/ui/dyn-star/upcast.stderr @@ -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 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`. From 8f79fc24e36e1a7540a0af6d44a27d11366fe294 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 19 Nov 2022 03:06:21 +0000 Subject: [PATCH 2/3] Properly handle `Pin<&mut dyn* Trait>` receiver in codegen --- compiler/rustc_codegen_ssa/src/mir/block.rs | 30 ++++++++--- src/test/ui/dyn-star/dispatch-on-pin-mut.rs | 51 +++++++++++++++++++ .../ui/dyn-star/dispatch-on-pin-mut.stderr | 11 ++++ 3 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/dyn-star/dispatch-on-pin-mut.rs create mode 100644 src/test/ui/dyn-star/dispatch-on-pin-mut.stderr diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 7822d924c01..03d833fbba8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -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`, 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); diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.rs b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs new file mode 100644 index 00000000000..8eedff87d0d --- /dev/null +++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs @@ -0,0 +1,51 @@ +// build-pass +// edition:2021 + +#![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) { + 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, + } + } +} diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr new file mode 100644 index 00000000000..a73e3400922 --- /dev/null +++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr @@ -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:4:12 + | +LL | #![feature(dyn_star)] + | ^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From b60b76c9dd3ed9bad4db48e80f084353d42c6728 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 24 Nov 2022 02:36:46 +0000 Subject: [PATCH 3/3] Adjust tests --- src/test/ui/dyn-star/dispatch-on-pin-mut.rs | 3 ++- src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout | 1 + src/test/ui/dyn-star/dispatch-on-pin-mut.stderr | 2 +- src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs | 5 +++-- .../dyn-star/dont-unsize-coerce-dyn-star.run.stdout | 2 ++ .../ui/dyn-star/dont-unsize-coerce-dyn-star.stderr | 11 +++++++++++ src/test/ui/dyn-star/upcast.rs | 2 +- 7 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout create mode 100644 src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout create mode 100644 src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.rs b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs index 8eedff87d0d..5774c8b2a67 100644 --- a/src/test/ui/dyn-star/dispatch-on-pin-mut.rs +++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs @@ -1,5 +1,6 @@ -// build-pass +// 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 diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout new file mode 100644 index 00000000000..96c5ca6985f --- /dev/null +++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout @@ -0,0 +1 @@ +value: 1 diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr index a73e3400922..fdf74aa7efe 100644 --- a/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr +++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr @@ -1,5 +1,5 @@ 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:4:12 + --> $DIR/dispatch-on-pin-mut.rs:5:12 | LL | #![feature(dyn_star)] | ^^^^^^^^ diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs index b4ff8a22286..c12b16f1605 100644 --- a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs +++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs @@ -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; diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout new file mode 100644 index 00000000000..b4db3ed707d --- /dev/null +++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout @@ -0,0 +1,2 @@ +43 +44 diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr new file mode 100644 index 00000000000..933c133831a --- /dev/null +++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr @@ -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 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs index 24c077047e9..c667ac143a3 100644 --- a/src/test/ui/dyn-star/upcast.rs +++ b/src/test/ui/dyn-star/upcast.rs @@ -1,4 +1,4 @@ -// known-bug: unknown +// known-bug: #104800 #![feature(dyn_star, trait_upcasting)]