Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
type parameters have unit metadata if they are sized
  • Loading branch information
compiler-errors committed Mar 4, 2022
commit ef0ba1d2cead709f11fe7912e0d2bd8c3f5e1b28
22 changes: 13 additions & 9 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2244,12 +2244,13 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Returns the type of metadata for (potentially fat) pointers to this type.
/// Returns the type of metadata for (potentially fat) pointers to this type,
/// and a boolean signifying if this is conditional on this type being `Sized`.
pub fn ptr_metadata_ty(
self,
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> {
) -> (Ty<'tcx>, bool) {
let tail = tcx.struct_tail_with_normalize(self, normalize);
match tail.kind() {
// Sized types
Expand All @@ -2269,28 +2270,31 @@ impl<'tcx> Ty<'tcx> {
| ty::Closure(..)
| ty::Never
| ty::Error(_)
// Extern types have metadata = ().
| ty::Foreign(..)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail_without_normalization` this is the empty tuple,
// a.k.a. unit type, which is Sized
| ty::Tuple(..) => tcx.types.unit,
| ty::Tuple(..) => (tcx.types.unit, false),

ty::Str | ty::Slice(_) => tcx.types.usize,
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
ty::Dynamic(..) => {
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
(tcx.type_of(dyn_metadata).subst(tcx, &[self.into()]), false)
},

ty::Projection(_)
| ty::Param(_)
| ty::Opaque(..)
// type parameters only have unit metadata if they're sized, so return true
// to make sure we double check this during confirmation
ty::Param(_) | ty::Projection(_) => (tcx.types.unit, true),

ty::Opaque(..)
| ty::Infer(ty::TyVar(_))
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", self)
}
}
}
Expand Down
27 changes: 22 additions & 5 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());

let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation
normalize_with_depth(
selcx,
obligation.param_env,
Expand All @@ -1415,7 +1417,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Foreign(_)
| ty::Str
| ty::Array(..)
| ty::Slice(_)
Expand All @@ -1428,6 +1429,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
Expand All @@ -1436,9 +1439,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// Integers and floats are always Sized, and so have unit type metadata.
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,

ty::Projection(..)
| ty::Opaque(..)
| ty::Param(..)
// type parameters and unnormalized projections have pointer metadata if they're still known to be sized
ty::Param(_) | ty::Projection(..) => tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env),

ty::Opaque(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
Expand Down Expand Up @@ -1657,7 +1661,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());

let mut obligations = vec![];
let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
normalize_with_depth_to(
selcx,
obligation.param_env,
Expand All @@ -1667,6 +1671,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
&mut obligations,
)
});
if check_is_sized {
let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
tcx.require_lang_item(LangItem::Sized, None),
tcx.mk_substs_trait(self_ty, &[]),
))
.without_const()
.to_predicate(tcx);
obligations.push(Obligation::new(
obligation.cause.clone(),
obligation.param_env,
sized_predicate,
));
}

let substs = tcx.mk_substs([self_ty.into()].iter());
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/traits/pointee-tail-is-generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// check-pass

#![feature(ptr_metadata)]

fn a<T>() {
b::<T>();
b::<std::cell::Cell<T>>();
}

fn b<T: std::ptr::Pointee<Metadata = ()>>() {}

fn main() {}