From bfa4e1ebbd61421db8382ca3e5b3cf8a73d806bd Mon Sep 17 00:00:00 2001 From: Yara Date: Wed, 26 Aug 2026 17:44:22 +0200 Subject: [PATCH 1/5] reflection: replace TypeKind::Slice's field with TypeId::element_ty --- .../src/const_eval/machine.rs | 14 +++++++++ .../src/const_eval/type_info.rs | 29 ++---------------- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mod.rs | 8 +++++ library/core/src/mem/type_info.rs | 30 ++++++++++++------- library/coretests/tests/mem/type_info.rs | 6 ++-- 7 files changed, 50 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7c10dd04f39f3..5f24d01b499c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -629,6 +629,20 @@ 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_fields => { let ty = ecx.read_type_id(&args[0])?; let variant_idx = ecx.read_target_usize(&args[1])? as usize; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index f6e0208d98835..eaad28a300678 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -92,13 +92,9 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { 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) => { @@ -280,27 +276,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { 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>, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 0d7ff905300cc..07f863dee91a9 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -218,6 +218,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf64 | sym::truncf128 | sym::type_id + | sym::type_id_element_ty | sym::type_id_eq | sym::type_id_field_representing_type | sym::type_id_fields @@ -331,6 +332,7 @@ 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_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()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6376fe032c64e..a7411c76b44ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2184,6 +2184,7 @@ symbols! { type_ascription, type_changing_struct_update, type_id, + type_id_element_ty, type_id_eq, type_id_field_representing_type, type_id_fields, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 673454abaf04f..4133e67d0eb36 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3136,6 +3136,14 @@ 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 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; + /// Gets the size of the type represented by this `TypeId`. /// /// The more user-friendly version of this intrinsic is [`core::any::TypeId::size`]. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 111664775ca8d..6fab3fbf4da69 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -80,7 +80,7 @@ pub enum TypeKind { /// Arrays. Array(Array), /// Slices. - Slice(Slice), + Slice, /// Dynamic Traits. DynTrait(DynTrait), /// Structs. @@ -120,15 +120,6 @@ pub struct 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)] @@ -303,6 +294,25 @@ 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::())); + /// assert_eq!(const { TypeId::of::().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 { + intrinsics::type_id_element_ty(self) + } + /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized. /// /// # Examples diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index f3a69dd857aba..a3d1ed7e9ebc1 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -27,9 +27,9 @@ fn test_arrays() { #[test] fn test_slices() { - match const { Type::of::<[usize]>() }.kind { - TypeKind::Slice(slice) => assert_eq!(slice.element_ty, TypeId::of::()), - _ => unreachable!(), + assert!(matches!(Type::of::<[usize]>().kind, TypeKind::Slice)); + const { + assert!(TypeId::of::<[usize]>().element_ty() == Some(TypeId::of::())); } } From 75746ce867c431798fffe56c4bb941254498eabc Mon Sep 17 00:00:00 2001 From: Yara Date: Wed, 26 Aug 2026 17:44:22 +0200 Subject: [PATCH 2/5] reflection: replace TypeKind::Array field with methods --- .../src/const_eval/machine.rs | 7 ++++ .../src/const_eval/type_info.rs | 34 ++----------------- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mod.rs | 8 +++++ library/core/src/mem/type_info.rs | 32 ++++++++++------- library/coretests/tests/mem/type_info.rs | 22 ++++++------ 7 files changed, 51 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 5f24d01b499c4..c3dd10e9d6b95 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -643,6 +643,13 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { 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; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index eaad28a300678..2b4c63c10baab 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -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; @@ -83,13 +83,9 @@ 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(_) => { @@ -252,30 +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_reference_type_info( &mut self, place: impl Writeable<'tcx, CtfeProvenance>, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 07f863dee91a9..36bb2ef8ed0e6 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -218,6 +218,7 @@ 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 @@ -332,6 +333,7 @@ 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 => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a7411c76b44ef..bd91b54c56432 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2184,6 +2184,7 @@ 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, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4133e67d0eb36..860b75dce5f0f 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3136,6 +3136,14 @@ 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`]. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 6fab3fbf4da69..e5745b8788858 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -78,7 +78,7 @@ pub enum TypeKind { /// Tuples. Tuple, /// Arrays. - Array(Array), + Array, /// Slices. Slice, /// Dynamic Traits. @@ -109,17 +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 dynamic traits. /// FIXME(#146922): Add super traits and generics #[derive(Debug)] @@ -313,6 +302,25 @@ impl 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::().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 diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index a3d1ed7e9ebc1..9a5b2cf28a4ca 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -7,21 +7,19 @@ 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::()); - 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::())); + 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::()); - 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::())); + assert!(ty_id.array_len() == 0); } } From 714b06b962ffb2a6fbdf01b9622374d505acc96d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2026 19:31:09 +0200 Subject: [PATCH 3/5] add test ensuring we refuse to const-eval the body of a rustc_do_not_const_check function --- .../consts/const-eval/do_not_const_check.rs | 25 +++++++++++++++++++ .../const-eval/do_not_const_check.stderr | 15 +++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/ui/consts/const-eval/do_not_const_check.rs create mode 100644 tests/ui/consts/const-eval/do_not_const_check.stderr diff --git a/tests/ui/consts/const-eval/do_not_const_check.rs b/tests/ui/consts/const-eval/do_not_const_check.rs new file mode 100644 index 0000000000000..ced2557bffd19 --- /dev/null +++ b/tests/ui/consts/const-eval/do_not_const_check.rs @@ -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(a: T, b: T) -> T { + a +} + +const _: () = { + integer_min(0, 1); //~ERROR: calling non-const function +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/do_not_const_check.stderr b/tests/ui/consts/const-eval/do_not_const_check.stderr new file mode 100644 index 0000000000000..507999df218d1 --- /dev/null +++ b/tests/ui/consts/const-eval/do_not_const_check.stderr @@ -0,0 +1,15 @@ +error[E0080]: calling non-const function `mostly_harmless` + --> $DIR/do_not_const_check.rs:9:5 + | +LL | mostly_harmless(); + | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error[E0080]: calling non-const function `integer_min::` + --> $DIR/do_not_const_check.rs:22:5 + | +LL | integer_min(0, 1); + | ^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. From d3cba0b9b57acfc80b5f054b20aeb3f99186d267 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 7 Sep 2026 19:55:35 +1000 Subject: [PATCH 4/5] Temporarily add a crashtest for instrumenting comptime functions This test demonstrates the existing crash, and will be migrated to a successful coverage test in a subsequent commit. Co-Authored-By: Rachel Barker --- tests/crashes/comptime.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/crashes/comptime.rs diff --git a/tests/crashes/comptime.rs b/tests/crashes/comptime.rs new file mode 100644 index 0000000000000..77fec9f509222 --- /dev/null +++ b/tests/crashes/comptime.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] +//@ edition: 2024 +//@ compile-flags: -Cinstrument-coverage +//@ needs-profiler-runtime + +// 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 . + +#[rustc_comptime] +fn comptime_fn() {} + +fn main() {} From 0027ee161223389c9490ffef6d07f1cc00a75385 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 6 Sep 2026 16:47:24 +1000 Subject: [PATCH 5/5] Make comptime functions ineligible for coverage Compile-time-only functions don't generate code, so instrumenting them for coverage is useless. This also avoids an ICE when trying to get the function's symbol name for an unused-function record, which can occur when instrumenting `core`. Co-Authored-By: Rachel Barker --- .../rustc_mir_transform/src/coverage/query.rs | 17 +++++++++++++++-- tests/coverage/comptime.cov-map | 10 ++++++++++ tests/coverage/comptime.coverage | 12 ++++++++++++ tests/{crashes => coverage}/comptime.rs | 2 -- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 tests/coverage/comptime.cov-map create mode 100644 tests/coverage/comptime.coverage rename tests/{crashes => coverage}/comptime.rs (82%) diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 6ffb85d7b90a8..a4d39f09b724d 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -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::{ @@ -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 ). + // 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; diff --git a/tests/coverage/comptime.cov-map b/tests/coverage/comptime.cov-map new file mode 100644 index 0000000000000..30f91da050f6f --- /dev/null +++ b/tests/coverage/comptime.cov-map @@ -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 + diff --git a/tests/coverage/comptime.coverage b/tests/coverage/comptime.coverage new file mode 100644 index 0000000000000..1ff44169babb2 --- /dev/null +++ b/tests/coverage/comptime.coverage @@ -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 . + LL| | + LL| |#[rustc_comptime] + LL| |fn comptime_fn() {} + LL| | + LL| 1|fn main() {} + diff --git a/tests/crashes/comptime.rs b/tests/coverage/comptime.rs similarity index 82% rename from tests/crashes/comptime.rs rename to tests/coverage/comptime.rs index 77fec9f509222..4891051b0076d 100644 --- a/tests/crashes/comptime.rs +++ b/tests/coverage/comptime.rs @@ -1,7 +1,5 @@ #![feature(rustc_attrs)] //@ edition: 2024 -//@ compile-flags: -Cinstrument-coverage -//@ needs-profiler-runtime // 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.)