Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ac03830

Browse files
authoredOct 18, 2024
Unrolled build for rust-lang#131857
Rollup merge of rust-lang#131857 - WaffleLapkin:dyn-drop-principal-3, r=compiler-errors Allow dropping dyn principal Revival of rust-lang#126660, which was a revival of rust-lang#114679. Fixes rust-lang#126313. Allows dropping principal when coercing trait objects, e.g. `dyn Debug + Send` -> `dyn Send`. cc `@compiler-errors` `@Jules-Bertholet` r? `@lcnr`
2 parents d9c4b8d + c4bce0b commit ac03830

File tree

14 files changed

+167
-35
lines changed

14 files changed

+167
-35
lines changed
 

‎compiler/rustc_codegen_cranelift/src/unsize.rs

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

‎compiler/rustc_codegen_ssa/src/base.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub fn validate_trivial_unsize<'tcx>(
147147
infcx.leak_check(universe, None).is_ok()
148148
})
149149
}
150-
(None, None) => true,
150+
(_, None) => true,
151151
_ => false,
152152
}
153153
}
@@ -175,7 +175,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
175175
{
176176
let old_info =
177177
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
178-
if data_a.principal_def_id() == data_b.principal_def_id() {
178+
let b_principal_def_id = data_b.principal_def_id();
179+
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
179180
// Codegen takes advantage of the additional assumption, where if the
180181
// principal trait def id of what's being casted doesn't change,
181182
// then we don't need to adjust the vtable at all. This

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

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

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

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

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

+4
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11531153
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
11541154
let iter = data_a
11551155
.principal()
1156+
.filter(|_| {
1157+
// optionally drop the principal, if we're unsizing to no principal
1158+
data_b.principal().is_some()
1159+
})
11561160
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
11571161
.into_iter()
11581162
.chain(

‎src/tools/miri/tests/pass/dyn-upcast.rs

+51
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ fn main() {
99
struct_();
1010
replace_vptr();
1111
vtable_nop_cast();
12+
drop_principal();
1213
}
1314

1415
fn vtable_nop_cast() {
@@ -430,3 +431,53 @@ fn replace_vptr() {
430431
let s = S(42);
431432
invoke_outer(&s);
432433
}
434+
435+
fn drop_principal() {
436+
use std::{alloc::Layout, any::Any};
437+
438+
const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
439+
x
440+
}
441+
442+
trait Bar: Send + Sync {}
443+
444+
impl<T: Send + Sync> Bar for T {}
445+
446+
const fn yeet_principal_2(x: Box<dyn Bar>) -> Box<dyn Send> {
447+
x
448+
}
449+
450+
struct CallMe<F: FnOnce()>(Option<F>);
451+
452+
impl<F: FnOnce()> CallMe<F> {
453+
fn new(f: F) -> Self {
454+
CallMe(Some(f))
455+
}
456+
}
457+
458+
impl<F: FnOnce()> Drop for CallMe<F> {
459+
fn drop(&mut self) {
460+
(self.0.take().unwrap())();
461+
}
462+
}
463+
464+
fn goodbye() {
465+
println!("goodbye");
466+
}
467+
468+
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Any + Send>;
469+
let x_layout = Layout::for_value(&*x);
470+
let y = yeet_principal(x);
471+
let y_layout = Layout::for_value(&*y);
472+
assert_eq!(x_layout, y_layout);
473+
println!("before");
474+
drop(y);
475+
476+
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Bar>;
477+
let x_layout = Layout::for_value(&*x);
478+
let y = yeet_principal_2(x);
479+
let y_layout = Layout::for_value(&*y);
480+
assert_eq!(x_layout, y_layout);
481+
println!("before");
482+
drop(y);
483+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
before
2+
goodbye
3+
before
4+
goodbye

‎tests/ui/impl-trait/unsized_coercion5.next.stderr

-14
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
1-
error[E0308]: mismatched types
2-
--> $DIR/unsized_coercion5.rs:16:32
3-
|
4-
LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
5-
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Send`, found trait `Trait + Send`
6-
| |
7-
| expected due to this
8-
|
9-
= note: expected struct `Box<dyn Send>`
10-
found struct `Box<dyn Trait + Send>`
11-
121
error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
13-
--> $DIR/unsized_coercion5.rs:16:32
2+
--> $DIR/unsized_coercion5.rs:17:32
143
|
154
LL | let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
165
| ^ doesn't have a size known at compile-time
176
|
187
= help: the trait `Sized` is not implemented for `impl Trait + ?Sized`
198
= note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>`
209

21-
error: aborting due to 2 previous errors
10+
error: aborting due to 1 previous error
2211

23-
Some errors have detailed explanations: E0277, E0308.
24-
For more information about an error, try `rustc --explain E0277`.
12+
For more information about this error, try `rustc --explain E0277`.

‎tests/ui/impl-trait/unsized_coercion5.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
//@ revisions: next old
55
//@[next] compile-flags: -Znext-solver
6+
//@[next] check-pass
67

78
#![feature(trait_upcasting)]
89

@@ -15,7 +16,6 @@ fn hello() -> Box<impl Trait + ?Sized> {
1516
let x = hello();
1617
let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
1718
//[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
18-
//~^^ ERROR: mismatched types
1919
}
2020
Box::new(1u32)
2121
}

‎tests/ui/traits/dyn-drop-principal.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//@ run-pass
2+
//@ check-run-results
3+
4+
use std::{alloc::Layout, any::Any};
5+
6+
const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
7+
x
8+
}
9+
10+
trait Bar: Send + Sync {}
11+
12+
impl<T: Send + Sync> Bar for T {}
13+
14+
const fn yeet_principal_2(x: Box<dyn Bar>) -> Box<dyn Send> {
15+
x
16+
}
17+
18+
struct CallMe<F: FnOnce()>(Option<F>);
19+
20+
impl<F: FnOnce()> CallMe<F> {
21+
fn new(f: F) -> Self {
22+
CallMe(Some(f))
23+
}
24+
}
25+
26+
impl<F: FnOnce()> Drop for CallMe<F> {
27+
fn drop(&mut self) {
28+
(self.0.take().unwrap())();
29+
}
30+
}
31+
32+
fn goodbye() {
33+
println!("goodbye");
34+
}
35+
36+
fn main() {
37+
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Any + Send>;
38+
let x_layout = Layout::for_value(&*x);
39+
let y = yeet_principal(x);
40+
let y_layout = Layout::for_value(&*y);
41+
assert_eq!(x_layout, y_layout);
42+
println!("before");
43+
drop(y);
44+
45+
let x = Box::new(CallMe::new(goodbye)) as Box<dyn Bar>;
46+
let x_layout = Layout::for_value(&*x);
47+
let y = yeet_principal_2(x);
48+
let y_layout = Layout::for_value(&*y);
49+
assert_eq!(x_layout, y_layout);
50+
println!("before");
51+
drop(y);
52+
}
53+
54+
// Test that upcast works in `const`
55+
56+
const fn yeet_principal_3(x: &(dyn Any + Send + Sync)) -> &(dyn Send + Sync) {
57+
x
58+
}
59+
60+
#[used]
61+
pub static FOO: &(dyn Send + Sync) = yeet_principal_3(&false);
62+
63+
const fn yeet_principal_4(x: &dyn Bar) -> &(dyn Send + Sync) {
64+
x
65+
}
66+
67+
#[used]
68+
pub static BAR: &(dyn Send + Sync) = yeet_principal_4(&false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
before
2+
goodbye
3+
before
4+
goodbye
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(dyn_star)]
2+
#![allow(incomplete_features)]
3+
4+
trait Trait {}
5+
impl Trait for usize {}
6+
7+
fn main() {
8+
// We allow &dyn Trait + Send -> &dyn Send (i.e. dropping principal),
9+
// but we don't (currently?) allow the same for dyn*
10+
let x: dyn* Trait + Send = 1usize;
11+
x as dyn* Send; //~ error: `dyn* Trait + Send` needs to have the same ABI as a pointer
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0277]: `dyn* Trait + Send` needs to have the same ABI as a pointer
2+
--> $DIR/dyn-star-drop-principal.rs:11:5
3+
|
4+
LL | x as dyn* Send;
5+
| ^ `dyn* Trait + Send` needs to be a pointer-like type
6+
|
7+
= help: the trait `PointerLike` is not implemented for `dyn* Trait + Send`
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)
Failed to load comments.