Skip to content

Commit 47082f5

Browse files
author
Lukas Markeffsky
committed
normalize better
1 parent cd6d8f2 commit 47082f5

File tree

5 files changed

+129
-44
lines changed

5 files changed

+129
-44
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,10 +1973,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
19731973

19741974
match in_elem.kind() {
19751975
ty::RawPtr(p) => {
1976-
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
1976+
let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
19771977
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
19781978
});
1979-
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
19801979
require!(
19811980
metadata.is_unit(),
19821981
InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
@@ -1988,10 +1987,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
19881987
}
19891988
match out_elem.kind() {
19901989
ty::RawPtr(p) => {
1991-
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
1990+
let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
19921991
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
19931992
});
1994-
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
19951993
require!(
19961994
metadata.is_unit(),
19971995
InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
372372
};
373373
if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) {
374374
// This is okay if they have the same metadata type.
375-
let meta_ty = |ty: Ty<'tcx>| {
376-
let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, |ty| ty);
377-
assert!(
378-
!only_if_sized,
379-
"there should be no more 'maybe has that metadata' types during interpretation"
380-
);
381-
meta
382-
};
375+
let meta_ty = |ty: Ty<'tcx>| ty.ptr_metadata_ty(*self.tcx, |ty| ty);
383376
return Ok(meta_ty(caller) == meta_ty(callee));
384377
}
385378

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,12 +2710,12 @@ impl<'tcx> Ty<'tcx> {
27102710
}
27112711

27122712
/// Returns the type of metadata for (potentially fat) pointers to this type,
2713-
/// and a boolean signifying if this is conditional on this type being `Sized`.
2714-
pub fn ptr_metadata_ty(
2713+
/// or the struct tail if the metadata type cannot be determinded.
2714+
pub fn ptr_metadata_ty_or_tail(
27152715
self,
27162716
tcx: TyCtxt<'tcx>,
27172717
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
2718-
) -> (Ty<'tcx>, bool) {
2718+
) -> Result<Ty<'tcx>, Ty<'tcx>> {
27192719
let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
27202720
match tail.kind() {
27212721
// Sized types
@@ -2739,29 +2739,45 @@ impl<'tcx> Ty<'tcx> {
27392739
| ty::Foreign(..)
27402740
// `dyn*` has no metadata
27412741
| ty::Dynamic(_, _, ty::DynStar)
2742-
// If returned by `struct_tail_without_normalization` this is a unit struct
2742+
// If returned by `struct_tail_with_normalize` this is a unit struct
27432743
// without any fields, or not a struct, and therefore is Sized.
27442744
| ty::Adt(..)
2745-
// If returned by `struct_tail_without_normalization` this is the empty tuple,
2745+
// If returned by `struct_tail_with_normalize` this is the empty tuple,
27462746
// a.k.a. unit type, which is Sized
2747-
| ty::Tuple(..) => (tcx.types.unit, false),
2747+
| ty::Tuple(..) => Ok(tcx.types.unit),
2748+
2749+
ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
27482750

2749-
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
27502751
ty::Dynamic(_, _, ty::Dyn) => {
27512752
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
2752-
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
2753-
},
2753+
Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
2754+
}
27542755

2755-
// type parameters only have unit metadata if they're sized, so return true
2756-
// to make sure we double check this during confirmation
2757-
ty::Param(_) | ty::Alias(..) => (tcx.types.unit, true),
2756+
// We don't know the metadata of `self`, but it must be equal to the
2757+
// metadata of `tail`.
2758+
ty::Param(_) | ty::Alias(..) => Err(tail),
27582759

27592760
ty::Infer(ty::TyVar(_))
27602761
| ty::Bound(..)
27612762
| ty::Placeholder(..)
2762-
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2763-
bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
2764-
}
2763+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
2764+
"`ptr_metadata_ty_or_tail` applied to unexpected type: {self:?} (tail = {tail:?})"
2765+
),
2766+
}
2767+
}
2768+
2769+
/// Returns the type of metadata for (potentially fat) pointers to this type.
2770+
/// Causes an ICE if the metadata type cannot be determined.
2771+
pub fn ptr_metadata_ty(
2772+
self,
2773+
tcx: TyCtxt<'tcx>,
2774+
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
2775+
) -> Ty<'tcx> {
2776+
match self.ptr_metadata_ty_or_tail(tcx, normalize) {
2777+
Ok(metadata) => metadata,
2778+
Err(tail) => bug!(
2779+
"`ptr_metadata_ty` failed to get metadata for type: {self:?} (tail = {tail:?})"
2780+
),
27652781
}
27662782
}
27672783

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
19191919
// type parameters, opaques, and unnormalized projections have pointer
19201920
// metadata if they're known (e.g. by the param_env) to be sized
19211921
ty::Param(_) | ty::Alias(..)
1922-
if selcx.infcx.predicate_must_hold_modulo_regions(
1922+
if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions(
19231923
&obligation.with(
19241924
selcx.tcx(),
19251925
ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
@@ -2278,7 +2278,8 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22782278
let args = tcx.mk_args(&[self_ty.into()]);
22792279
let lang_items = tcx.lang_items();
22802280
let item_def_id = obligation.predicate.def_id;
2281-
let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
2281+
let trait_def_id: rustc_span::def_id::DefId = tcx.trait_of_item(item_def_id).unwrap();
2282+
let mut potentially_unnormalized = false;
22822283
let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
22832284
let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
22842285
assert_eq!(discriminant_def_id, item_def_id);
@@ -2289,7 +2290,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22892290
assert_eq!(metadata_def_id, item_def_id);
22902291

22912292
let mut obligations = Vec::new();
2292-
let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
2293+
let normalize = |ty| {
22932294
normalize_with_depth_to(
22942295
selcx,
22952296
obligation.param_env,
@@ -2298,27 +2299,49 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22982299
ty,
22992300
&mut obligations,
23002301
)
2301-
});
2302-
if check_is_sized {
2303-
let sized_predicate = ty::TraitRef::from_lang_item(
2304-
tcx,
2305-
LangItem::Sized,
2306-
obligation.cause.span(),
2307-
[self_ty],
2308-
);
2309-
obligations.push(obligation.with(tcx, sized_predicate));
2310-
}
2311-
(metadata_ty.into(), obligations)
2302+
};
2303+
let metadata = match self_ty.ptr_metadata_ty_or_tail(tcx, normalize) {
2304+
Ok(metadata) => metadata,
2305+
Err(tail) => {
2306+
let sized_predicate = ty::TraitRef::from_lang_item(
2307+
tcx,
2308+
LangItem::Sized,
2309+
obligation.cause.span(),
2310+
[self_ty],
2311+
);
2312+
let sized_obligation = obligation.with(tcx, sized_predicate);
2313+
if self_ty == tail
2314+
|| selcx.infcx.predicate_must_hold_considering_regions(&sized_obligation)
2315+
{
2316+
// If the `self_ty` is `Sized`, then the metadata is `()`.
2317+
// We check this before projecting to the metadata of `tail`,
2318+
// because we may know `self_ty: Sized`, but not `tail: Sized`.
2319+
obligations.push(sized_obligation);
2320+
tcx.types.unit
2321+
} else {
2322+
// We know that `self_ty` has the same metadata as `tail`. This allows
2323+
// us to prove predicates like `Wrapper<T>::Metadata == T::Metadata`.
2324+
potentially_unnormalized = true;
2325+
Ty::new_projection(tcx, metadata_def_id, [tail])
2326+
}
2327+
}
2328+
};
2329+
(metadata.into(), obligations)
23122330
} else {
23132331
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
23142332
};
23152333

23162334
let predicate =
23172335
ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term };
23182336

2319-
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
2320-
.with_addl_obligations(obligations)
2321-
.with_addl_obligations(data)
2337+
confirm_param_env_candidate(
2338+
selcx,
2339+
obligation,
2340+
ty::Binder::dummy(predicate),
2341+
potentially_unnormalized,
2342+
)
2343+
.with_addl_obligations(obligations)
2344+
.with_addl_obligations(data)
23222345
}
23232346

23242347
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// check-pass
2+
3+
#![feature(ptr_metadata)]
4+
5+
use std::ptr::{self, Pointee};
6+
7+
fn cast_same_meta<T: ?Sized, U: ?Sized>(ptr: *const T) -> *const U
8+
where
9+
T: Pointee<Metadata = <U as Pointee>::Metadata>,
10+
{
11+
let (thin, meta) = ptr.to_raw_parts();
12+
ptr::from_raw_parts(thin, meta)
13+
}
14+
15+
struct Wrapper<T: ?Sized>(T);
16+
17+
// if `Wrapper<T>: ?Sized` then normalize `Wrapper<T>::Metadata` -> `T::Metadata`
18+
fn wrapper_to_tail<T: ?Sized>(ptr: *const T) -> *const Wrapper<T> {
19+
cast_same_meta(ptr)
20+
}
21+
22+
// if `Wrapper<T>: Sized` then normalize `Wrapper<T>::Metadata` -> `()`
23+
fn wrapper_to_unit<T: ?Sized>(ptr: *const ()) -> *const Wrapper<T>
24+
where
25+
Wrapper<T>: Sized,
26+
{
27+
cast_same_meta(ptr)
28+
}
29+
30+
trait Project {
31+
type Assoc: ?Sized;
32+
}
33+
34+
struct WrapperProject<T: ?Sized + Project>(T::Assoc);
35+
36+
// normalize `WrapperProject<T>::Metadata` -> `T::Assoc::Metadata`
37+
fn wrapper_project<T: ?Sized + Project>(ptr: *const T::Assoc) -> *const WrapperProject<T> {
38+
cast_same_meta(ptr)
39+
}
40+
41+
// In this example, `WrapperProject<&'a T>` is `Sized` modulo regions,
42+
// but `?Sized` considering regions.
43+
// Normalize `WrapperProject<&'a T>::Metadata` -> `<&'a T as Project>::Assoc::Metadata`
44+
// and don't require `WrapperProject<&'a T>: Sized`.
45+
fn sized_modulo_regions<'a, T: ?Sized + 'static>(
46+
ptr: *const <&'a T as Project>::Assoc,
47+
) -> *const WrapperProject<&'a T>
48+
where
49+
for<'b> &'b T: Project,
50+
WrapperProject<&'static T>: Sized,
51+
{
52+
cast_same_meta(ptr)
53+
}
54+
55+
fn main() {}

0 commit comments

Comments
 (0)