Skip to content

Commit 6520fdc

Browse files
authored
Rollup merge of rust-lang#104338 - compiler-errors:pointer-sized, r=eholk
Enforce that `dyn*` coercions are actually pointer-sized Implement a perma-unstable, rudimentary `PointerSized` trait to enforce `dyn*` casts are `usize`-sized for now, at least to prevent ICEs and weird codegen issues from cropping up after monomorphization since currently we enforce *nothing*. This probably can/should be removed in favor of a more sophisticated trait for handling `dyn*` conversions when we decide on one, but I just want to get something up for discussion and experimentation for now. r? `@eholk` cc `@tmandry` (though feel free to claim/reassign) Fixes rust-lang#102141 Fixes rust-lang#102173
2 parents 66d26af + 39e076a commit 6520fdc

File tree

13 files changed

+180
-8
lines changed

13 files changed

+180
-8
lines changed

compiler/rustc_hir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ language_item_table! {
270270
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
271271
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
272272

273+
PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0);
274+
273275
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
274276
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
275277

compiler/rustc_hir_typeck/src/coercion.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
775775

776776
// Check the obligations of the cast -- for example, when casting
777777
// `usize` to `dyn* Clone + 'static`:
778-
let obligations = predicates
778+
let mut obligations: Vec<_> = predicates
779779
.iter()
780780
.map(|predicate| {
781781
// For each existential predicate (e.g., `?Self: Clone`) substitute
@@ -785,16 +785,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
785785
let predicate = predicate.with_self_ty(self.tcx, a);
786786
Obligation::new(self.tcx, self.cause.clone(), self.param_env, predicate)
787787
})
788-
// Enforce the region bound (e.g., `usize: 'static`, in our example).
789-
.chain([Obligation::new(
788+
.chain([
789+
// Enforce the region bound (e.g., `usize: 'static`, in our example).
790+
Obligation::new(
791+
self.tcx,
792+
self.cause.clone(),
793+
self.param_env,
794+
ty::Binder::dummy(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
795+
a, b_region,
796+
))),
797+
),
798+
])
799+
.collect();
800+
801+
// Enforce that the type is `usize`/pointer-sized. For now, only those
802+
// can be coerced to `dyn*`, except for `dyn* -> dyn*` upcasts.
803+
if !a.is_dyn_star() {
804+
obligations.push(Obligation::new(
790805
self.tcx,
791806
self.cause.clone(),
792807
self.param_env,
793-
self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
794-
ty::OutlivesPredicate(a, b_region),
795-
))),
796-
)])
797-
.collect();
808+
ty::Binder::dummy(ty::TraitRef::new(
809+
self.tcx.require_lang_item(hir::LangItem::PointerSized, Some(self.cause.span)),
810+
self.tcx.mk_substs_trait(a, &[]),
811+
))
812+
.to_poly_trait_predicate(),
813+
));
814+
}
798815

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

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,7 @@ symbols! {
10671067
plugins,
10681068
pointee_trait,
10691069
pointer,
1070+
pointer_sized,
10701071
poll,
10711072
position,
10721073
post_dash_lto: "post-lto",

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

+28
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
304304
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
305305
} else if lang_items.tuple_trait() == Some(def_id) {
306306
self.assemble_candidate_for_tuple(obligation, &mut candidates);
307+
} else if lang_items.pointer_sized() == Some(def_id) {
308+
self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
307309
} else {
308310
if lang_items.clone_trait() == Some(def_id) {
309311
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -1047,4 +1049,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10471049
| ty::Placeholder(_) => {}
10481050
}
10491051
}
1052+
1053+
fn assemble_candidate_for_ptr_sized(
1054+
&mut self,
1055+
obligation: &TraitObligation<'tcx>,
1056+
candidates: &mut SelectionCandidateSet<'tcx>,
1057+
) {
1058+
// The regions of a type don't affect the size of the type
1059+
let self_ty = self
1060+
.tcx()
1061+
.erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate.self_ty()));
1062+
1063+
// But if there are inference variables, we have to wait until it's resolved.
1064+
if self_ty.has_non_region_infer() {
1065+
candidates.ambiguous = true;
1066+
return;
1067+
}
1068+
1069+
let usize_layout =
1070+
self.tcx().layout_of(ty::ParamEnv::empty().and(self.tcx().types.usize)).unwrap().layout;
1071+
if let Ok(layout) = self.tcx().layout_of(obligation.param_env.and(self_ty))
1072+
&& layout.layout.size() == usize_layout.size()
1073+
&& layout.layout.align().abi == usize_layout.align().abi
1074+
{
1075+
candidates.vec.push(BuiltinCandidate { has_nested: false });
1076+
}
1077+
}
10501078
}

library/core/src/marker.rs

+9
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,15 @@ pub trait Destruct {}
809809
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
810810
pub trait Tuple {}
811811

812+
/// A marker for things
813+
#[unstable(feature = "pointer_sized_trait", issue = "none")]
814+
#[cfg_attr(not(bootstrap), lang = "pointer_sized")]
815+
#[rustc_on_unimplemented(
816+
message = "`{Self}` needs to be a pointer-sized type",
817+
label = "`{Self}` needs to be a pointer-sized type"
818+
)]
819+
pub trait PointerSized {}
820+
812821
/// Implementations of `Copy` for primitive types.
813822
///
814823
/// Implementations that cannot be described in Rust
+11
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/align.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,20 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/align.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+
error[E0277]: `AlignedUsize` needs to be a pointer-sized type
11+
--> $DIR/align.rs:15:13
12+
|
13+
LL | let x = AlignedUsize(12) as dyn* Debug;
14+
| ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
15+
|
16+
= help: the trait `PointerSized` is not implemented for `AlignedUsize`
17+
18+
error: aborting due to previous error; 1 warning emitted
19+
20+
For more information about this error, try `rustc --explain E0277`.

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

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// revisions: normal over_aligned
2+
//[normal] check-pass
3+
4+
#![feature(dyn_star)]
5+
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
6+
7+
use std::fmt::Debug;
8+
9+
#[cfg_attr(over_aligned, repr(C, align(1024)))]
10+
#[cfg_attr(not(over_aligned), repr(C))]
11+
#[derive(Debug)]
12+
struct AlignedUsize(usize);
13+
14+
fn main() {
15+
let x = AlignedUsize(12) as dyn* Debug;
16+
//[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(dyn_star)]
2+
#![allow(incomplete_features)]
3+
4+
use std::fmt::Debug;
5+
6+
fn dyn_debug(_: (dyn* Debug + '_)) {
7+
8+
}
9+
10+
fn polymorphic<T: Debug + ?Sized>(t: &T) {
11+
dyn_debug(t);
12+
//~^ ERROR `&T` needs to be a pointer-sized type
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0277]: `&T` needs to be a pointer-sized type
2+
--> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
3+
|
4+
LL | dyn_debug(t);
5+
| ^ `&T` needs to be a pointer-sized type
6+
|
7+
= help: the trait `PointerSized` is not implemented for `&T`
8+
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
9+
|
10+
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
11+
| ++++++++++++++++++++++
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// check-pass
2+
3+
#![feature(dyn_star)]
4+
#![allow(incomplete_features)]
5+
6+
use std::fmt::Debug;
7+
8+
fn dyn_debug(_: (dyn* Debug + '_)) {
9+
10+
}
11+
12+
fn polymorphic<T: Debug>(t: &T) {
13+
dyn_debug(t);
14+
}
15+
16+
fn main() {}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(dyn_star)]
2+
#![allow(incomplete_features)]
3+
4+
use std::fmt::Debug;
5+
6+
fn main() {
7+
let i = [1, 2, 3, 4] as dyn* Debug;
8+
//~^ ERROR `[i32; 4]` needs to be a pointer-sized type
9+
dbg!(i);
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0277]: `[i32; 4]` needs to be a pointer-sized type
2+
--> $DIR/check-size-at-cast.rs:7:13
3+
|
4+
LL | let i = [1, 2, 3, 4] as dyn* Debug;
5+
| ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
6+
|
7+
= help: the trait `PointerSized` is not implemented for `[i32; 4]`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)