Skip to content

Commit 0c1f401

Browse files
author
Lukas Markeffsky
committedFeb 5, 2024
old solver: improve normalization of Pointee::Metadata
1 parent 77fb540 commit 0c1f401

File tree

5 files changed

+113
-39
lines changed

5 files changed

+113
-39
lines changed
 

Diff for: ‎compiler/rustc_codegen_llvm/src/intrinsic.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1985,10 +1985,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
19851985

19861986
match in_elem.kind() {
19871987
ty::RawPtr(p) => {
1988-
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
1988+
let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
19891989
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
19901990
});
1991-
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
19921991
require!(
19931992
metadata.is_unit(),
19941993
InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
@@ -2000,10 +1999,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
20001999
}
20012000
match out_elem.kind() {
20022001
ty::RawPtr(p) => {
2003-
let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
2002+
let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
20042003
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
20052004
});
2006-
assert!(!check_sized); // we are in codegen, so we shouldn't see these types
20072005
require!(
20082006
metadata.is_unit(),
20092007
InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }

Diff for: ‎compiler/rustc_const_eval/src/interpret/terminator.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -377,12 +377,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
377377
// to fields, which can yield non-normalized types. So we need to provide a
378378
// normalization function.
379379
let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
380-
let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, normalize);
381-
assert!(
382-
!only_if_sized,
383-
"there should be no more 'maybe has that metadata' types during interpretation"
384-
);
385-
meta
380+
ty.ptr_metadata_ty(*self.tcx, normalize)
386381
};
387382
return Ok(meta_ty(caller) == meta_ty(callee));
388383
}

Diff for: ‎compiler/rustc_middle/src/ty/sty.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -1957,12 +1957,12 @@ impl<'tcx> Ty<'tcx> {
19571957
}
19581958

19591959
/// Returns the type of metadata for (potentially fat) pointers to this type,
1960-
/// and a boolean signifying if this is conditional on this type being `Sized`.
1961-
pub fn ptr_metadata_ty(
1960+
/// or the struct tail if the metadata type cannot be determined.
1961+
pub fn ptr_metadata_ty_or_tail(
19621962
self,
19631963
tcx: TyCtxt<'tcx>,
19641964
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
1965-
) -> (Ty<'tcx>, bool) {
1965+
) -> Result<Ty<'tcx>, Ty<'tcx>> {
19661966
let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
19671967
match tail.kind() {
19681968
// Sized types
@@ -1984,31 +1984,47 @@ impl<'tcx> Ty<'tcx> {
19841984
| ty::Error(_)
19851985
// Extern types have metadata = ().
19861986
| ty::Foreign(..)
1987-
// `dyn*` has no metadata
1987+
// `dyn*` has metadata = ().
19881988
| ty::Dynamic(_, _, ty::DynStar)
1989-
// If returned by `struct_tail_without_normalization` this is a unit struct
1989+
// If returned by `struct_tail_with_normalize` this is a unit struct
19901990
// without any fields, or not a struct, and therefore is Sized.
19911991
| ty::Adt(..)
1992-
// If returned by `struct_tail_without_normalization` this is the empty tuple,
1992+
// If returned by `struct_tail_with_normalize` this is the empty tuple,
19931993
// a.k.a. unit type, which is Sized
1994-
| ty::Tuple(..) => (tcx.types.unit, false),
1994+
| ty::Tuple(..) => Ok(tcx.types.unit),
1995+
1996+
ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
19951997

1996-
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
19971998
ty::Dynamic(_, _, ty::Dyn) => {
19981999
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
1999-
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
2000-
},
2000+
Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
2001+
}
20012002

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

20062007
ty::Infer(ty::TyVar(_))
20072008
| ty::Bound(..)
20082009
| ty::Placeholder(..)
2009-
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2010-
bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
2011-
}
2010+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
2011+
"`ptr_metadata_ty_or_tail` applied to unexpected type: {self:?} (tail = {tail:?})"
2012+
),
2013+
}
2014+
}
2015+
2016+
/// Returns the type of metadata for (potentially fat) pointers to this type.
2017+
/// Causes an ICE if the metadata type cannot be determined.
2018+
pub fn ptr_metadata_ty(
2019+
self,
2020+
tcx: TyCtxt<'tcx>,
2021+
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
2022+
) -> Ty<'tcx> {
2023+
match self.ptr_metadata_ty_or_tail(tcx, normalize) {
2024+
Ok(metadata) => metadata,
2025+
Err(tail) => bug!(
2026+
"`ptr_metadata_ty` failed to get metadata for type: {self:?} (tail = {tail:?})"
2027+
),
20122028
}
20132029
}
20142030

Diff for: ‎compiler/rustc_trait_selection/src/traits/project.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -1916,10 +1916,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
19161916
// Integers and floats are always Sized, and so have unit type metadata.
19171917
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
19181918

1919-
// type parameters, opaques, and unnormalized projections have pointer
1920-
// metadata if they're known (e.g. by the param_env) to be sized
1919+
// We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able.
1920+
// Otherwise, type parameters, opaques, and unnormalized projections have
1921+
// unit metadata if they're known (e.g. by the param_env) to be sized.
19211922
ty::Param(_) | ty::Alias(..)
1922-
if selcx.infcx.predicate_must_hold_modulo_regions(
1923+
if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions(
19231924
&obligation.with(
19241925
selcx.tcx(),
19251926
ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
@@ -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,16 +2299,26 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22982299
ty,
22992300
&mut obligations,
23002301
)
2302+
};
2303+
let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| {
2304+
if tail == self_ty {
2305+
// This is the fallback case for type parameters, unnormalizable projections
2306+
// and opaque types.
2307+
// If the `self_ty` is `Sized`, then the metadata is `()`.
2308+
let sized_predicate = ty::TraitRef::from_lang_item(
2309+
tcx,
2310+
LangItem::Sized,
2311+
obligation.cause.span(),
2312+
[self_ty],
2313+
);
2314+
obligations.push(obligation.with(tcx, sized_predicate));
2315+
tcx.types.unit
2316+
} else {
2317+
// We know that `self_ty` has the same metadata as `tail`. This allows us
2318+
// to prove predicates like `Wrapper<Tail>::Metadata == Tail::Metadata`.
2319+
Ty::new_projection(tcx, metadata_def_id, [tail])
2320+
}
23012321
});
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-
}
23112322
(metadata_ty.into(), obligations)
23122323
} else {
23132324
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);

Diff for: ‎tests/ui/traits/pointee-normalize-equate.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
// 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+
// normalize `Wrapper<T>::Metadata` -> `T::Metadata` -> `()`
23+
fn wrapper_to_unit<T>(ptr: *const ()) -> *const Wrapper<T> {
24+
cast_same_meta(ptr)
25+
}
26+
27+
trait Project {
28+
type Assoc: ?Sized;
29+
}
30+
31+
struct WrapperProject<T: ?Sized + Project>(T::Assoc);
32+
33+
// normalize `WrapperProject<T>::Metadata` -> `T::Assoc::Metadata`
34+
fn wrapper_project_tail<T: ?Sized + Project>(ptr: *const T::Assoc) -> *const WrapperProject<T> {
35+
cast_same_meta(ptr)
36+
}
37+
38+
// normalize `WrapperProject<T>::Metadata` -> `T::Assoc::Metadata` -> `()`
39+
fn wrapper_project_unit<T: ?Sized + Project>(ptr: *const ()) -> *const WrapperProject<T>
40+
where
41+
T::Assoc: Sized,
42+
{
43+
cast_same_meta(ptr)
44+
}
45+
46+
// normalize `<[T] as Pointee>::Metadata` -> `usize`, even if `[T]: Sized`
47+
fn sized_slice<T>(ptr: *const [T]) -> *const str
48+
where
49+
[T]: Sized,
50+
{
51+
cast_same_meta(ptr)
52+
}
53+
54+
fn main() {}

0 commit comments

Comments
 (0)