Skip to content

Commit ef0ba1d

Browse files
type parameters have unit metadata if they are sized
1 parent 6d76841 commit ef0ba1d

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

compiler/rustc_middle/src/ty/sty.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -2244,12 +2244,13 @@ impl<'tcx> Ty<'tcx> {
22442244
}
22452245
}
22462246

2247-
/// Returns the type of metadata for (potentially fat) pointers to this type.
2247+
/// Returns the type of metadata for (potentially fat) pointers to this type,
2248+
/// and a boolean signifying if this is conditional on this type being `Sized`.
22482249
pub fn ptr_metadata_ty(
22492250
self,
22502251
tcx: TyCtxt<'tcx>,
22512252
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
2252-
) -> Ty<'tcx> {
2253+
) -> (Ty<'tcx>, bool) {
22532254
let tail = tcx.struct_tail_with_normalize(self, normalize);
22542255
match tail.kind() {
22552256
// Sized types
@@ -2269,28 +2270,31 @@ impl<'tcx> Ty<'tcx> {
22692270
| ty::Closure(..)
22702271
| ty::Never
22712272
| ty::Error(_)
2273+
// Extern types have metadata = ().
22722274
| ty::Foreign(..)
22732275
// If returned by `struct_tail_without_normalization` this is a unit struct
22742276
// without any fields, or not a struct, and therefore is Sized.
22752277
| ty::Adt(..)
22762278
// If returned by `struct_tail_without_normalization` this is the empty tuple,
22772279
// a.k.a. unit type, which is Sized
2278-
| ty::Tuple(..) => tcx.types.unit,
2280+
| ty::Tuple(..) => (tcx.types.unit, false),
22792281

2280-
ty::Str | ty::Slice(_) => tcx.types.usize,
2282+
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
22812283
ty::Dynamic(..) => {
22822284
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
2283-
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
2285+
(tcx.type_of(dyn_metadata).subst(tcx, &[self.into()]), false)
22842286
},
22852287

2286-
ty::Projection(_)
2287-
| ty::Param(_)
2288-
| ty::Opaque(..)
2288+
// type parameters only have unit metadata if they're sized, so return true
2289+
// to make sure we double check this during confirmation
2290+
ty::Param(_) | ty::Projection(_) => (tcx.types.unit, true),
2291+
2292+
ty::Opaque(..)
22892293
| ty::Infer(ty::TyVar(_))
22902294
| ty::Bound(..)
22912295
| ty::Placeholder(..)
22922296
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2293-
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
2297+
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", self)
22942298
}
22952299
}
22962300
}

compiler/rustc_trait_selection/src/traits/project.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
13991399
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
14001400

14011401
let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
1402+
// We throw away any obligations we get from this, since we normalize
1403+
// and confirm these obligations once again during confirmation
14021404
normalize_with_depth(
14031405
selcx,
14041406
obligation.param_env,
@@ -1415,7 +1417,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14151417
| ty::Int(_)
14161418
| ty::Uint(_)
14171419
| ty::Float(_)
1418-
| ty::Foreign(_)
14191420
| ty::Str
14201421
| ty::Array(..)
14211422
| ty::Slice(_)
@@ -1428,6 +1429,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14281429
| ty::Generator(..)
14291430
| ty::GeneratorWitness(..)
14301431
| ty::Never
1432+
// Extern types have unit metadata, according to RFC 2850
1433+
| ty::Foreign(_)
14311434
// If returned by `struct_tail_without_normalization` this is a unit struct
14321435
// without any fields, or not a struct, and therefore is Sized.
14331436
| ty::Adt(..)
@@ -1436,9 +1439,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14361439
// Integers and floats are always Sized, and so have unit type metadata.
14371440
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
14381441

1439-
ty::Projection(..)
1440-
| ty::Opaque(..)
1441-
| ty::Param(..)
1442+
// type parameters and unnormalized projections have pointer metadata if they're still known to be sized
1443+
ty::Param(_) | ty::Projection(..) => tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env),
1444+
1445+
ty::Opaque(..)
14421446
| ty::Bound(..)
14431447
| ty::Placeholder(..)
14441448
| ty::Infer(..)
@@ -1657,7 +1661,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
16571661
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
16581662

16591663
let mut obligations = vec![];
1660-
let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
1664+
let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
16611665
normalize_with_depth_to(
16621666
selcx,
16631667
obligation.param_env,
@@ -1667,6 +1671,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
16671671
&mut obligations,
16681672
)
16691673
});
1674+
if check_is_sized {
1675+
let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
1676+
tcx.require_lang_item(LangItem::Sized, None),
1677+
tcx.mk_substs_trait(self_ty, &[]),
1678+
))
1679+
.without_const()
1680+
.to_predicate(tcx);
1681+
obligations.push(Obligation::new(
1682+
obligation.cause.clone(),
1683+
obligation.param_env,
1684+
sized_predicate,
1685+
));
1686+
}
16701687

16711688
let substs = tcx.mk_substs([self_ty.into()].iter());
16721689
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// check-pass
2+
3+
#![feature(ptr_metadata)]
4+
5+
fn a<T>() {
6+
b::<T>();
7+
b::<std::cell::Cell<T>>();
8+
}
9+
10+
fn b<T: std::ptr::Pointee<Metadata = ()>>() {}
11+
12+
fn main() {}

0 commit comments

Comments
 (0)