Enforce that dyn* casts are actually pointer-sized
This commit is contained in:
parent
fd3bfb3551
commit
da3c5397a6
10 changed files with 131 additions and 8 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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),
|
||||
|
|
|
@ -1067,6 +1067,7 @@ symbols! {
|
|||
plugins,
|
||||
pointee_trait,
|
||||
pointer,
|
||||
pointer_sized,
|
||||
poll,
|
||||
position,
|
||||
post_dash_lto: "post-lto",
|
||||
|
|
|
@ -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
|
||||
|
@ -1047,4 +1049,29 @@ 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().bytes() == usize_layout.size().bytes()
|
||||
{
|
||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
15
src/test/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
Normal file
15
src/test/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
Normal file
|
@ -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() {}
|
|
@ -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
src/test/ui/dyn-star/check-size-at-cast-polymorphic.rs
Normal file
16
src/test/ui/dyn-star/check-size-at-cast-polymorphic.rs
Normal file
|
@ -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
src/test/ui/dyn-star/check-size-at-cast.rs
Normal file
10
src/test/ui/dyn-star/check-size-at-cast.rs
Normal file
|
@ -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
src/test/ui/dyn-star/check-size-at-cast.stderr
Normal file
11
src/test/ui/dyn-star/check-size-at-cast.stderr
Normal file
|
@ -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`.
|
Loading…
Reference in a new issue