Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
21 changes: 21 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,27 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
ecx.write_discriminant(variant_index, dest)?;
}

sym::type_id_element_ty => {
let ty = ecx.read_type_id(&args[0])?;
let variant_index = if let ty::Array(ty, _) | ty::Slice(ty) = ty.kind() {
let (variant_idx, variant_place) =
ecx.project_downcast_named(dest, sym::Some)?;
let type_id_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?;
ecx.write_type_id(*ty, &type_id_field_place)?;
variant_idx
} else {
ecx.project_downcast_named(dest, sym::None)?.0
};
ecx.write_discriminant(variant_index, dest)?;
}

sym::type_id_array_len => {
let ty = ecx.read_type_id(&args[0])?;
let len =
if let ty::Array(_, len) = ty.kind() { len.to_leaf().to_u64() } else { 0 };
ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?;
}

sym::type_id_fields => {
let ty = ecx.read_type_id(&args[0])?;
let variant_idx = ecx.read_target_usize(&args[1])? as usize;
Expand Down
63 changes: 5 additions & 58 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_ast::Mutability;
use rustc_hir::attrs::lang_items::LangItem;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Const, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt};
use rustc_middle::ty::{self, FnHeader, FnSigKind, FnSigTys, ScalarInt, Ty, TyCtxt};
use rustc_span::{Symbol, sym};

use crate::const_eval::CompileTimeMachine;
Expand Down Expand Up @@ -83,22 +83,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
self.write_tuple_type_info(tuple_place, fields, ty)?;
variant
}
ty::Array(ty, len) => {
let (variant, variant_place) =
ty::Array(_, _) => {
let (variant, _variant_place) =
self.project_downcast_named(&field_dest, sym::Array)?;
let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?;

self.write_array_type_info(array_place, *ty, *len)?;

variant
}
ty::Slice(ty) => {
let (variant, variant_place) =
ty::Slice(_) => {
let (variant, _variant_place) =
self.project_downcast_named(&field_dest, sym::Slice)?;
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;

self.write_slice_type_info(slice_place, *ty)?;

variant
}
ty::Adt(adt_def, generics) => {
Expand Down Expand Up @@ -256,51 +248,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
)
}

pub(crate) fn write_array_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
len: Const<'tcx>,
) -> InterpResult<'tcx> {
// Iterate over all fields of `type_info::Array`.
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;

match field.name {
// Write the `TypeId` of the array's elements to the `element_ty` field.
sym::element_ty => self.write_type_id(ty, &field_place)?,
// Write the length of the array to the `len` field.
sym::len => self.write_scalar(len.to_leaf(), &field_place)?,
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}

interp_ok(())
}

pub(crate) fn write_slice_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
) -> InterpResult<'tcx> {
// Iterate over all fields of `type_info::Slice`.
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;

match field.name {
// Write the `TypeId` of the slice's elements to the `element_ty` field.
sym::element_ty => self.write_type_id(ty, &field_place)?,
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}

interp_ok(())
}

pub(crate) fn write_reference_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::truncf64
| sym::truncf128
| sym::type_id
| sym::type_id_array_len
| sym::type_id_element_ty
| sym::type_id_eq
| sym::type_id_field_representing_type
| sym::type_id_fields
Expand Down Expand Up @@ -312,6 +314,8 @@ pub(crate) fn check_intrinsic_type(

sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
sym::type_id => (1, 0, vec![], type_id_ty()),
sym::type_id_array_len => (0, 0, vec![type_id_ty()], tcx.types.usize),
sym::type_id_element_ty => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, type_id_ty())),
sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], tcx.types.bool),
sym::type_id_field_representing_type => {
(0, 0, vec![type_id_ty(), tcx.types.usize, tcx.types.usize], type_id_ty())
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_mir_transform/src/coverage/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_hir::attrs::CoverageAttrKind;
use rustc_hir::find_attr;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, find_attr};
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::{
Expand Down Expand Up @@ -30,11 +31,23 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
// Closures are carved out by their initial `Assign` statement.)
if !tcx.def_kind(def_id).is_fn_like() {
let def_kind = tcx.def_kind(def_id);
if !def_kind.is_fn_like() {
trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
return false;
}

// Comptime functions can't exist at runtime, so instrumenting them is useless.
// This also avoids an ICE when getting the symbol name for an unused-function record
// (due to <https://github.com/rust-lang/rust/pull/159777>).
// We check `def_kind` first to avoid any unexpected panics from merely asking for constness.
if matches!(def_kind, DefKind::Fn | DefKind::AssocFn)
&& matches!(tcx.constness(def_id), hir::Constness::Const { always: true })
{
trace!("InstrumentCoverage skipped for {def_id:?} (comptime)");
return false;
}

if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) {
trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)");
return false;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2167,6 +2167,8 @@ symbols! {
type_ascription,
type_changing_struct_update,
type_id,
type_id_array_len,
type_id_element_ty,
type_id_eq,
type_id_field_representing_type,
type_id_fields,
Expand Down
16 changes: 16 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3009,6 +3009,22 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool {
#[rustc_comptime]
pub fn type_id_is_signed(_id: crate::any::TypeId) -> bool;

/// Gets the length of the array represented by this `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::any::TypeId::array_len`].
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn type_id_array_len(_id: crate::any::TypeId) -> usize;

/// Gets the type of each element of the array or slice represented by this `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::any::TypeId::element_ty`].
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn type_id_element_ty(_id: crate::any::TypeId) -> Option<crate::any::TypeId>;

/// Gets the size of the type represented by this `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::any::TypeId::size`].
Expand Down
62 changes: 40 additions & 22 deletions library/core/src/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ pub enum TypeKind {
/// Tuples.
Tuple,
/// Arrays.
Array(Array),
Array,
/// Slices.
Slice(Slice),
Slice,
/// Dynamic Traits.
DynTrait(DynTrait),
/// Structs.
Expand Down Expand Up @@ -109,26 +109,6 @@ pub enum TypeKind {
Other,
}

/// Compile-time type information about arrays.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Array {
/// The type of each element in the array.
pub element_ty: TypeId,
/// The length of the array.
pub len: usize,
}

/// Compile-time type information about slices.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Slice {
/// The type of each element in the slice.
pub element_ty: TypeId,
}

/// Compile-time type information about dynamic traits.
/// FIXME(#146922): Add super traits and generics
#[derive(Debug)]
Expand Down Expand Up @@ -303,6 +283,44 @@ impl TypeId {
intrinsics::type_id_is_signed(self)
}

/// When called on a `TypeId` representing an array or slice this returns the type of each
/// element otherwise this returns `None`.
///
/// # Examples
///
/// ```
/// #![feature(type_info)]
/// use std::any::TypeId;
///
/// assert_eq!(const { TypeId::of::<[u32; 16]>().element_ty() }, Some(TypeId::of::<u32>()));
/// assert_eq!(const { TypeId::of::<u8>().element_ty() }, None); // not an array or slice
/// ```
#[unstable(feature = "type_info", issue = "146922")]
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
#[rustc_comptime]
pub fn element_ty(self) -> Option<TypeId> {
intrinsics::type_id_element_ty(self)
}

/// When called on a `TypeId` representing an array this returns the length of the array in
/// all other cases this returns zero.
///
/// # Examples
///
/// ```
/// #![feature(type_info)]
/// use std::any::TypeId;
///
/// assert_eq!(const { TypeId::of::<[u32; 16]>().array_len() }, 16);
/// assert_eq!(const { TypeId::of::<u8>().array_len() }, 0); // not an array
/// ```
#[unstable(feature = "type_info", issue = "146922")]
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
#[rustc_comptime]
pub fn array_len(self) -> usize {
intrinsics::type_id_array_len(self)
}

/// Returns the size of the type represented by this `TypeId`. `None` if it is unsized.
///
/// # Examples
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ unsafe impl<T: ?Sized> DerefPure for &mut T {}
/// ```
#[lang = "receiver"]
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
#[rustc_dyn_incompatible_trait]
pub trait Receiver: PointeeSized {
/// The target type on which the method may be called.
#[rustc_diagnostic_item = "receiver_target"]
Expand Down
28 changes: 13 additions & 15 deletions library/coretests/tests/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,27 @@ use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind};
#[test]
fn test_arrays() {
// Normal array.
match const { Type::of::<[u16; 4]>() }.kind {
TypeKind::Array(array) => {
assert_eq!(array.element_ty, TypeId::of::<u16>());
assert_eq!(array.len, 4);
}
_ => unreachable!(),
assert!(matches!(Type::of::<[u16; 4]>().kind, TypeKind::Array));
const {
let ty_id = TypeId::of::<[u16; 4]>();
assert!(ty_id.element_ty() == Some(TypeId::of::<u16>()));
assert!(ty_id.array_len() == 4);
}

// Zero-length array.
match const { Type::of::<[bool; 0]>() }.kind {
TypeKind::Array(array) => {
assert_eq!(array.element_ty, TypeId::of::<bool>());
assert_eq!(array.len, 0);
}
_ => unreachable!(),
assert!(matches!(Type::of::<[bool; 0]>().kind, TypeKind::Array));
const {
let ty_id = TypeId::of::<[bool; 0]>();
assert!(ty_id.element_ty() == Some(TypeId::of::<bool>()));
assert!(ty_id.array_len() == 0);
}
}

#[test]
fn test_slices() {
match const { Type::of::<[usize]>() }.kind {
TypeKind::Slice(slice) => assert_eq!(slice.element_ty, TypeId::of::<usize>()),
_ => unreachable!(),
assert!(matches!(Type::of::<[usize]>().kind, TypeKind::Slice));
const {
assert!(TypeId::of::<[usize]>().element_ty() == Some(TypeId::of::<usize>()));
}
}

Expand Down
10 changes: 10 additions & 0 deletions tests/coverage/comptime.cov-map
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Function name: comptime::main
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 01, 00, 0a, 01, 00, 0c, 00, 0d]
Number of files: 1
- file 0 => $DIR/comptime.rs
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10)
- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13)
Highest counter ID seen: c0

12 changes: 12 additions & 0 deletions tests/coverage/comptime.coverage
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
LL| |#![feature(rustc_attrs)]
LL| |//@ edition: 2024
LL| |
LL| |// Check that instrumenting a crate with a comptime function doesn't ICE.
LL| |// (The function itself doesn't need to be instrumented, and probably shouldn't be.)
LL| |// Regression test for <https://github.com/rust-lang/rust/pull/161808>.
LL| |
LL| |#[rustc_comptime]
LL| |fn comptime_fn() {}
LL| |
LL| 1|fn main() {}

11 changes: 11 additions & 0 deletions tests/coverage/comptime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![feature(rustc_attrs)]
//@ edition: 2024

// Check that instrumenting a crate with a comptime function doesn't ICE.
// (The function itself doesn't need to be instrumented, and probably shouldn't be.)
// Regression test for <https://github.com/rust-lang/rust/pull/161808>.

#[rustc_comptime]
fn comptime_fn() {}

fn main() {}
25 changes: 25 additions & 0 deletions tests/ui/consts/const-eval/do_not_const_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Ensure that we refuse to run a do_not_const_check function, even if the body *would* const-check
//! at the moment.
#![feature(rustc_attrs, intrinsics)]

#[rustc_do_not_const_check]
const fn mostly_harmless() {}

const _: () = {
mostly_harmless(); //~ERROR: calling non-const function
};

// Also ensure the same happens with intrinsics.
// Here we need some intrinsic that the interpreter does *not* have a native implementation for.
// Let's hope nobody adds one...
#[rustc_intrinsic]
#[rustc_do_not_const_check]
pub const fn integer_min<T: Copy>(a: T, b: T) -> T {
a
}

const _: () = {
integer_min(0, 1); //~ERROR: calling non-const function
};

fn main() {}
Loading
Loading