Skip to content

Commit 1fd7b66

Browse files
committed
Make TypeId const-comparable
1 parent 03c057d commit 1fd7b66

File tree

12 files changed

+77
-58
lines changed

12 files changed

+77
-58
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,9 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
282282
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
283283
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
284284
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
285-
if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
285+
if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def
286+
&& key.value.promoted.is_none()
287+
{
286288
let ty = key.value.instance.ty(tcx, key.typing_env);
287289
let ty::FnDef(_, args) = ty.kind() else {
288290
bug!("intrinsic with type {:?}", ty);

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow};
22
use std::fmt;
33
use std::hash::Hash;
44

5-
use rustc_abi::{Align, Size};
5+
use rustc_abi::{Align, FieldIdx, Size};
66
use rustc_ast::Mutability;
77
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
88
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -403,6 +403,21 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
403403
let cmp = ecx.guaranteed_cmp(a, b)?;
404404
ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
405405
}
406+
sym::type_id_eq => {
407+
let a = ecx.project_field(&args[0], FieldIdx::ZERO)?;
408+
let a = ecx.deref_pointer(&a)?;
409+
let (a, offset) = a.ptr().into_parts();
410+
assert_eq!(offset, Size::ZERO);
411+
let a = a.unwrap().alloc_id();
412+
let GlobalAlloc::Type(a) = ecx.tcx.global_alloc(a) else { bug!() };
413+
let b = ecx.project_field(&args[1], FieldIdx::ZERO)?;
414+
let b = ecx.deref_pointer(&b)?;
415+
let (b, offset) = b.ptr().into_parts();
416+
assert_eq!(offset, Size::ZERO);
417+
let b = b.unwrap().alloc_id();
418+
let GlobalAlloc::Type(b) = ecx.tcx.global_alloc(b) else { bug!() };
419+
ecx.write_scalar(Scalar::from_bool(a == b), dest)?;
420+
}
406421
sym::const_allocate => {
407422
let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?;
408423
let align = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?;

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
9393
| sym::three_way_compare
9494
| sym::discriminant_value
9595
| sym::type_id
96+
| sym::type_id_eq
9697
| sym::select_unpredictable
9798
| sym::cold_path
9899
| sym::ptr_guaranteed_cmp
@@ -223,6 +224,10 @@ pub(crate) fn check_intrinsic_type(
223224
sym::type_id => {
224225
(1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity())
225226
}
227+
sym::type_id_eq => {
228+
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity();
229+
(0, 0, vec![type_id, type_id], tcx.types.bool)
230+
}
226231
sym::offset => (2, 0, vec![param(0), param(1)], param(0)),
227232
sym::arith_offset => (
228233
1,

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,7 @@ symbols! {
21832183
type_changing_struct_update,
21842184
type_const,
21852185
type_id,
2186+
type_id_eq,
21862187
type_ir,
21872188
type_ir_infer_ctxt_like,
21882189
type_ir_inherent,

library/core/src/any.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -727,24 +727,42 @@ unsafe impl Send for TypeId {}
727727
unsafe impl Sync for TypeId {}
728728

729729
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
730-
struct TypeIdData {
730+
pub(crate) struct TypeIdData {
731731
full_hash: [u8; 16],
732732
}
733733

734734
#[stable(feature = "rust1", since = "1.0.0")]
735-
impl PartialEq for TypeId {
735+
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
736+
impl const PartialEq for TypeId {
736737
#[inline]
737738
fn eq(&self, other: &Self) -> bool {
738-
self.data as *const TypeIdData == other.data as *const TypeIdData
739-
|| (self.partial_hash == other.partial_hash
740-
&& self.data.full_hash == other.data.full_hash)
739+
const fn ct(a: &TypeId, b: &TypeId) -> bool {
740+
crate::intrinsics::type_id_eq(*a, *b)
741+
}
742+
743+
#[inline]
744+
fn rt(a: &TypeId, b: &TypeId) -> bool {
745+
a.data as *const TypeIdData == b.data as *const TypeIdData
746+
|| (a.partial_hash == b.partial_hash && a.data.full_hash == b.data.full_hash)
747+
}
748+
749+
core::intrinsics::const_eval_select((self, other), ct, rt)
741750
}
742751

743752
#[inline]
744753
fn ne(&self, other: &Self) -> bool {
745-
self.partial_hash != other.partial_hash
746-
|| (self.data as *const TypeIdData != other.data as *const TypeIdData
747-
&& self.data.full_hash != other.data.full_hash)
754+
const fn ct(a: &TypeId, b: &TypeId) -> bool {
755+
!crate::intrinsics::type_id_eq(*a, *b)
756+
}
757+
758+
#[inline]
759+
fn rt(a: &TypeId, b: &TypeId) -> bool {
760+
a.partial_hash != b.partial_hash
761+
|| (a.data as *const TypeIdData != b.data as *const TypeIdData
762+
&& a.data.full_hash != b.data.full_hash)
763+
}
764+
765+
core::intrinsics::const_eval_select((self, other), ct, rt)
748766
}
749767
}
750768

library/core/src/intrinsics/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,6 +2720,18 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
27202720
#[rustc_intrinsic]
27212721
pub const fn type_id<T: ?Sized + 'static>() -> crate::any::TypeId;
27222722

2723+
/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the
2724+
/// same type. This is necessary because at const-eval time the actual discriminating
2725+
/// data is opaque and cannot be inspected directly.
2726+
///
2727+
/// The stabilized version of this intrinsic is the [PartialEq] impl for [`core::any::TypeId`].
2728+
#[rustc_nounwind]
2729+
#[unstable(feature = "core_intrinsics", issue = "none")]
2730+
#[rustc_intrinsic]
2731+
pub const fn type_id_eq(_a: crate::any::TypeId, _b: crate::any::TypeId) -> bool {
2732+
panic!("type_id_eq should only be used from const eval")
2733+
}
2734+
27232735
/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`.
27242736
///
27252737
/// This is used to implement functions like `slice::from_raw_parts_mut` and

tests/ui/const-generics/issues/issue-90318.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(const_type_id)]
22
#![feature(generic_const_exprs)]
3+
#![feature(const_trait_impl)]
34
#![feature(core_intrinsics)]
45
#![allow(incomplete_features)]
56

@@ -13,15 +14,13 @@ fn consume<T: 'static>(_val: T)
1314
where
1415
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
1516
//~^ ERROR overly complex generic constant
16-
//~| ERROR: cannot call
1717
{
1818
}
1919

2020
fn test<T: 'static>()
2121
where
2222
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
2323
//~^ ERROR overly complex generic constant
24-
//~| ERROR: cannot call
2524
{
2625
}
2726

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: overly complex generic constant
2-
--> $DIR/issue-90318.rs:14:8
2+
--> $DIR/issue-90318.rs:15:8
33
|
44
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
55
| ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,26 +20,5 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
2020
= help: consider moving this anonymous constant into a `const` function
2121
= note: this operation may be supported in the future
2222

23-
error[E0015]: cannot call non-const operator in constants
24-
--> $DIR/issue-90318.rs:14:10
25-
|
26-
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
27-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28-
|
29-
note: impl defined here, but it is not `const`
30-
--> $SRC_DIR/core/src/any.rs:LL:COL
31-
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
32-
33-
error[E0015]: cannot call non-const operator in constants
34-
--> $DIR/issue-90318.rs:22:10
35-
|
36-
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
37-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38-
|
39-
note: impl defined here, but it is not `const`
40-
--> $SRC_DIR/core/src/any.rs:LL:COL
41-
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
42-
43-
error: aborting due to 4 previous errors
23+
error: aborting due to 2 previous errors
4424

45-
For more information about this error, try `rustc --explain E0015`.

tests/ui/consts/const_cmp_type_id.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ use std::any::TypeId;
66
fn main() {
77
const {
88
assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
9-
//~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied
109
assert!(TypeId::of::<()>() != TypeId::of::<u8>());
11-
//~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied
1210
let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
11+
//~^ ERROR: cannot call non-const operator in constants
1312
// can't assert `_a` because it is not deterministic
1413
// FIXME(const_trait_impl) make it pass
1514
}
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied
2-
--> $DIR/const_cmp_type_id.rs:8:17
1+
error[E0015]: cannot call non-const operator in constants
2+
--> $DIR/const_cmp_type_id.rs:10:18
33
|
4-
LL | assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
7-
error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied
8-
--> $DIR/const_cmp_type_id.rs:10:17
4+
LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
96
|
10-
LL | assert!(TypeId::of::<()>() != TypeId::of::<u8>());
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
note: impl defined here, but it is not `const`
8+
--> $SRC_DIR/core/src/any.rs:LL:COL
9+
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
1210

13-
error: aborting due to 2 previous errors
11+
error: aborting due to 1 previous error
1412

15-
For more information about this error, try `rustc --explain E0277`.
13+
For more information about this error, try `rustc --explain E0015`.

tests/ui/consts/issue-73976-monomorphic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ known-bug: #110395
1+
//@ check-pass
22
//
33
// This test is complement to the test in issue-73976-polymorphic.rs.
44
// In that test we ensure that polymorphic use of type_id and type_name in patterns

tests/ui/consts/issue-73976-monomorphic.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)