Allow dropping dyn principal

This commit is contained in:
Michael Goulet 2023-08-09 00:31:26 +00:00 committed by Maybe Lapkin
parent 3a85d3fa78
commit e3800a1a04
10 changed files with 83 additions and 35 deletions

View File

@ -34,7 +34,9 @@ pub(crate) fn unsized_info<'tcx>(
{ {
let old_info = let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion"); old_info.expect("unsized_info: missing old info for trait upcasting coercion");
if data_a.principal_def_id() == data_b.principal_def_id() { let b_principal_def_id = data_b.principal_def_id();
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
debug_assert!( debug_assert!(
validate_trivial_unsize(fx.tcx, data_a, data_b), validate_trivial_unsize(fx.tcx, data_a, data_b),
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"

View File

@ -147,7 +147,7 @@ pub fn validate_trivial_unsize<'tcx>(
infcx.leak_check(universe, None).is_ok() infcx.leak_check(universe, None).is_ok()
}) })
} }
(None, None) => true, (_, None) => true,
_ => false, _ => false,
} }
} }
@ -175,7 +175,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
{ {
let old_info = let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion"); old_info.expect("unsized_info: missing old info for trait upcasting coercion");
if data_a.principal_def_id() == data_b.principal_def_id() { let b_principal_def_id = data_b.principal_def_id();
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
// Codegen takes advantage of the additional assumption, where if the // Codegen takes advantage of the additional assumption, where if the
// principal trait def id of what's being casted doesn't change, // principal trait def id of what's being casted doesn't change,
// then we don't need to adjust the vtable at all. This // then we don't need to adjust the vtable at all. This

View File

@ -785,7 +785,8 @@ where
let mut responses = vec![]; let mut responses = vec![];
// If the principal def ids match (or are both none), then we're not doing // If the principal def ids match (or are both none), then we're not doing
// trait upcasting. We're just removing auto traits (or shortening the lifetime). // trait upcasting. We're just removing auto traits (or shortening the lifetime).
if a_data.principal_def_id() == b_data.principal_def_id() { let b_principal_def_id = b_data.principal_def_id();
if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
responses.extend(self.consider_builtin_upcast_to_principal( responses.extend(self.consider_builtin_upcast_to_principal(
goal, goal,
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),

View File

@ -1018,7 +1018,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// #2 (region bounds). // #2 (region bounds).
let principal_def_id_a = a_data.principal_def_id(); let principal_def_id_a = a_data.principal_def_id();
let principal_def_id_b = b_data.principal_def_id(); let principal_def_id_b = b_data.principal_def_id();
if principal_def_id_a == principal_def_id_b { if principal_def_id_a == principal_def_id_b || principal_def_id_b.is_none() {
// We may upcast to auto traits that are either explicitly listed in // We may upcast to auto traits that are either explicitly listed in
// the object type's bounds, or implied by the principal trait ref's // the object type's bounds, or implied by the principal trait ref's
// supertraits. // supertraits.

View File

@ -1153,6 +1153,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
let iter = data_a let iter = data_a
.principal() .principal()
.filter(|_| {
// optionally drop the principal, if we're unsizing to no principal
data_b.principal().is_some()
})
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
.into_iter() .into_iter()
.chain( .chain(

View File

@ -1,14 +0,0 @@
error[E0308]: mismatched types
--> $DIR/unsized_coercion5.rs:16:32
|
LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send`
| |
| expected due to this
|
= note: expected struct `Box<dyn Send>`
found struct `Box<dyn Trait + Send>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,16 +1,5 @@
error[E0308]: mismatched types
--> $DIR/unsized_coercion5.rs:16:32
|
LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send`
| |
| expected due to this
|
= note: expected struct `Box<dyn Send>`
found struct `Box<dyn Trait + Send>`
error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
--> $DIR/unsized_coercion5.rs:16:32 --> $DIR/unsized_coercion5.rs:17:32
| |
LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>; LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
| ^ doesn't have a size known at compile-time | ^ doesn't have a size known at compile-time
@ -18,7 +7,6 @@ LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
= help: the trait `Sized` is not implemented for `impl Trait + ?Sized` = help: the trait `Sized` is not implemented for `impl Trait + ?Sized`
= note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>` = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>`
error: aborting due to 2 previous errors error: aborting due to 1 previous error
Some errors have detailed explanations: E0277, E0308. For more information about this error, try `rustc --explain E0277`.
For more information about an error, try `rustc --explain E0277`.

View File

@ -3,6 +3,7 @@
//@ revisions: next old //@ revisions: next old
//@[next] compile-flags: -Znext-solver //@[next] compile-flags: -Znext-solver
//@[next] check-pass
#![feature(trait_upcasting)] #![feature(trait_upcasting)]
@ -15,7 +16,6 @@ fn hello() -> Box<impl Trait + ?Sized> {
let x = hello(); let x = hello();
let y: Box<dyn Send> = x as Box<dyn Trait + Send>; let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
//[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
//~^^ ERROR: mismatched types
} }
Box::new(1u32) Box::new(1u32)
} }

View File

@ -0,0 +1,62 @@
//@ run-pass
//@ check-run-results
use std::any::Any;
const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
x
}
trait Bar: Send + Sync {}
impl<T: Send + Sync> Bar for T {}
const fn yeet_principal_2(x: Box<dyn Bar>) -> Box<dyn Send> {
x
}
struct CallMe<F: FnOnce()>(Option<F>);
impl<F: FnOnce()> CallMe<F> {
fn new(f: F) -> Self {
CallMe(Some(f))
}
}
impl<F: FnOnce()> Drop for CallMe<F> {
fn drop(&mut self) {
(self.0.take().unwrap())();
}
}
fn goodbye() {
println!("goodbye");
}
fn main() {
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Any + Send>;
let y = yeet_principal(x);
println!("before");
drop(y);
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Bar>;
let y = yeet_principal_2(x);
println!("before");
drop(y);
}
// Test that upcast works in `const`
const fn yeet_principal_3(x: &(dyn Any + Send + Sync)) -> &(dyn Send + Sync) {
x
}
#[used]
pub static FOO: &(dyn Send + Sync) = yeet_principal_3(&false);
const fn yeet_principal_4(x: &dyn Bar) -> &(dyn Send + Sync) {
x
}
#[used]
pub static BAR: &(dyn Send + Sync) = yeet_principal_4(&false);

View File

@ -0,0 +1,4 @@
before
goodbye
before
goodbye