Skip to content

Commit

Permalink
Rollup merge of #104338 - compiler-errors:pointer-sized, r=eholk
Browse files Browse the repository at this point in the history
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 #102141
Fixes #102173
  • Loading branch information
Manishearth authored Nov 18, 2022
2 parents 3181006 + 39e076a commit 24ee599
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 8 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ language_item_table! {
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;

PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0);

PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;

Expand Down
33 changes: 25 additions & 8 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {

// Check the obligations of the cast -- for example, when casting
// `usize` to `dyn* Clone + 'static`:
let obligations = predicates
let mut obligations: Vec<_> = predicates
.iter()
.map(|predicate| {
// For each existential predicate (e.g., `?Self: Clone`) substitute
Expand All @@ -785,16 +785,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let predicate = predicate.with_self_ty(self.tcx, a);
Obligation::new(self.tcx, self.cause.clone(), self.param_env, predicate)
})
// Enforce the region bound (e.g., `usize: 'static`, in our example).
.chain([Obligation::new(
.chain([
// Enforce the region bound (e.g., `usize: 'static`, in our example).
Obligation::new(
self.tcx,
self.cause.clone(),
self.param_env,
ty::Binder::dummy(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
a, b_region,
))),
),
])
.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,
self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
ty::OutlivesPredicate(a, b_region),
))),
)])
.collect();
ty::Binder::dummy(ty::TraitRef::new(
self.tcx.require_lang_item(hir::LangItem::PointerSized, Some(self.cause.span)),
self.tcx.mk_substs_trait(a, &[]),
))
.to_poly_trait_predicate(),
));
}

Ok(InferOk {
value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ symbols! {
plugins,
pointee_trait,
pointer,
pointer_sized,
poll,
position,
post_dash_lto: "post-lto",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else if lang_items.tuple_trait() == Some(def_id) {
self.assemble_candidate_for_tuple(obligation, &mut candidates);
} else if lang_items.pointer_sized() == Some(def_id) {
self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
Expand Down Expand Up @@ -1047,4 +1049,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Placeholder(_) => {}
}
}

fn assemble_candidate_for_ptr_sized(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
// The regions of a type don't affect the size of the type
let self_ty = self
.tcx()
.erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate.self_ty()));

// But if there are inference variables, we have to wait until it's resolved.
if self_ty.has_non_region_infer() {
candidates.ambiguous = true;
return;
}

let usize_layout =
self.tcx().layout_of(ty::ParamEnv::empty().and(self.tcx().types.usize)).unwrap().layout;
if let Ok(layout) = self.tcx().layout_of(obligation.param_env.and(self_ty))
&& layout.layout.size() == usize_layout.size()
&& layout.layout.align().abi == usize_layout.align().abi
{
candidates.vec.push(BuiltinCandidate { has_nested: false });
}
}
}
9 changes: 9 additions & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,15 @@ pub trait Destruct {}
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
pub trait Tuple {}

/// A marker for things
#[unstable(feature = "pointer_sized_trait", issue = "none")]
#[cfg_attr(not(bootstrap), lang = "pointer_sized")]
#[rustc_on_unimplemented(
message = "`{Self}` needs to be a pointer-sized type",
label = "`{Self}` needs to be a pointer-sized type"
)]
pub trait PointerSized {}

/// Implementations of `Copy` for primitive types.
///
/// Implementations that cannot be described in Rust
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/dyn-star/align.normal.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/align.rs:4:12
|
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted

20 changes: 20 additions & 0 deletions src/test/ui/dyn-star/align.over_aligned.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/align.rs:4:12
|
LL | #![feature(dyn_star)]
| ^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default

error[E0277]: `AlignedUsize` needs to be a pointer-sized type
--> $DIR/align.rs:15:13
|
LL | let x = AlignedUsize(12) as dyn* Debug;
| ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
|
= help: the trait `PointerSized` is not implemented for `AlignedUsize`

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0277`.
17 changes: 17 additions & 0 deletions src/test/ui/dyn-star/align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// revisions: normal over_aligned
//[normal] check-pass

#![feature(dyn_star)]
//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes

use std::fmt::Debug;

#[cfg_attr(over_aligned, repr(C, align(1024)))]
#[cfg_attr(not(over_aligned), repr(C))]
#[derive(Debug)]
struct AlignedUsize(usize);

fn main() {
let x = AlignedUsize(12) as dyn* Debug;
//[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
}
15 changes: 15 additions & 0 deletions src/test/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(dyn_star)]
#![allow(incomplete_features)]

use std::fmt::Debug;

fn dyn_debug(_: (dyn* Debug + '_)) {

}

fn polymorphic<T: Debug + ?Sized>(t: &T) {
dyn_debug(t);
//~^ ERROR `&T` needs to be a pointer-sized type
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0277]: `&T` needs to be a pointer-sized type
--> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
|
LL | dyn_debug(t);
| ^ `&T` needs to be a pointer-sized type
|
= help: the trait `PointerSized` is not implemented for `&T`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
| ++++++++++++++++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
16 changes: 16 additions & 0 deletions src/test/ui/dyn-star/check-size-at-cast-polymorphic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// check-pass

#![feature(dyn_star)]
#![allow(incomplete_features)]

use std::fmt::Debug;

fn dyn_debug(_: (dyn* Debug + '_)) {

}

fn polymorphic<T: Debug>(t: &T) {
dyn_debug(t);
}

fn main() {}
10 changes: 10 additions & 0 deletions src/test/ui/dyn-star/check-size-at-cast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(dyn_star)]
#![allow(incomplete_features)]

use std::fmt::Debug;

fn main() {
let i = [1, 2, 3, 4] as dyn* Debug;
//~^ ERROR `[i32; 4]` needs to be a pointer-sized type
dbg!(i);
}
11 changes: 11 additions & 0 deletions src/test/ui/dyn-star/check-size-at-cast.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0277]: `[i32; 4]` needs to be a pointer-sized type
--> $DIR/check-size-at-cast.rs:7:13
|
LL | let i = [1, 2, 3, 4] as dyn* Debug;
| ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
|
= help: the trait `PointerSized` is not implemented for `[i32; 4]`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 24ee599

Please sign in to comment.