Skip to content
Merged
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
69 changes: 66 additions & 3 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use super::error::*;
use crate::diagnostics::{LongRunning, LongRunningWarn};
use crate::interpret::{
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, RetagMode,
Scalar, compile_time_machine, ensure_monomorphic_enough, err_inval, interp_ok, throw_exhaust,
throw_inval, throw_ub, throw_ub_format, throw_unsup, throw_unsup_format,
GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet,
RetagMode, Scalar, compile_time_machine, ensure_monomorphic_enough, err_inval, interp_ok,
throw_exhaust, throw_inval, throw_ub, throw_ub_format, throw_unsup, throw_unsup_format,
type_implements_dyn_trait,
};

Expand Down Expand Up @@ -712,6 +712,47 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?;
}

sym::field_representing_type_name => {
let frt_ty = ecx.read_type_id(&args[0])?;

let field_name = if let ty::Adt(def, args) = frt_ty.kind()
&& let Some(FieldInfo { name, .. }) =
def.field_representing_type_info(ecx.tcx.tcx, args)
{
name
} else {
span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}")
};
let ptr = ecx.allocate_bytes_dedup(field_name.as_str().as_bytes())?;
ecx.write_immediate(
Immediate::ScalarPair(
Scalar::from_pointer(ptr, ecx),
Scalar::from_target_usize(field_name.as_str().len() as u64, ecx),
),
dest,
)?;
}

sym::field_representing_type_offset => {
let frt_ty = ecx.read_type_id(&args[0])?;

let (ty, variant, field) = if let ty::Adt(def, args) = frt_ty.kind()
&& let Some(FieldInfo { base, variant_idx, field_idx, .. }) =
def.field_representing_type_info(ecx.tcx.tcx, args)
{
(base, variant_idx, field_idx)
} else {
span_bug!(ecx.cur_span(), "expected field representing type, got {frt_ty}")
};
let layout = ecx.layout_of(ty)?;
let cx = ty::layout::LayoutCx::new(ecx.tcx.tcx, ecx.typing_env());

let layout = layout.for_variant(&cx, variant);
let offset = layout.fields.offset(field.index()).bytes();

ecx.write_scalar(Scalar::from_target_usize(offset, ecx), dest)?;
}

sym::field_representing_type_actual_type_id => {
let frt_ty = ecx.read_type_id(&args[0])?;

Expand All @@ -726,6 +767,28 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
ecx.write_type_id(field_ty, dest)?;
}

sym::type_id_generics => {
let ty = ecx.read_type_id(&args[0])?;
ecx.write_type_id_generics(dest, ty)?;
}

sym::non_exhaustive => {
let ty = ecx.read_type_id(&args[0])?;

// FIXME(reflection): need a way to obtain non-exhaustiveness of a variant's fields.
let non_exhaustive = if let ty::Adt(def, _) = ty.kind() {
if def.is_enum() {
def.is_variant_list_non_exhaustive()
} else {
def.non_enum_variant().is_field_list_non_exhaustive()
}
} else {
false
};

ecx.write_scalar(Scalar::from_bool(non_exhaustive), dest)?;
}

_ => {
// We haven't handled the intrinsic, let's see if we can use a fallback body.
if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
Expand Down
51 changes: 47 additions & 4 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
// A general method to write an array to a static slice place.
fn allocate_fill_and_write_slice_ptr(
&mut self,
slice_place: impl Writeable<'tcx, CtfeProvenance>,
slice_place: &impl Writeable<'tcx, CtfeProvenance>,
len: u64,
writer: impl Fn(&mut Self, /* index */ u64, MPlaceTy<'tcx>) -> InterpResult<'tcx>,
) -> InterpResult<'tcx> {
Expand All @@ -45,7 +45,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
// Write the slice pointing to the array
let array_place = array_place.map_provenance(CtfeProvenance::as_immutable);
let ptr = Immediate::new_slice(array_place.ptr(), len, self);
self.write_immediate(ptr, &slice_place)
self.write_immediate(ptr, slice_place)
}

/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
Expand Down Expand Up @@ -262,7 +262,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
let tuple_layout = self.layout_of(tuple_ty)?;
let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
self.allocate_fill_and_write_slice_ptr(
fields_slice_place,
&fields_slice_place,
fields.len() as u64,
|this, i, place| {
let field_ty = fields[i as usize];
Expand Down Expand Up @@ -383,6 +383,49 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok(())
}

pub(crate) fn write_type_id_generics(
&mut self,
place: &impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
) -> InterpResult<'tcx> {
let generics: ty::Binder<'_, ty::GenericArgsRef<'_>> = match *ty.kind() {
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Foreign(..)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(..)
| ty::Alias(..)
| ty::Param(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
| ty::Error(..)
| ty::Slice(..) => ty::Binder::dummy(ty::GenericArgsRef::default()),
ty::Adt(_, args) => ty::Binder::dummy(args),
ty::FnDef(_, binder) => binder,
ty::UnsafeBinder(binder) => binder.rebind(ty::GenericArgsRef::default()),
ty::Closure(_, args) => ty::Binder::dummy(args),
ty::CoroutineClosure(_, args) => ty::Binder::dummy(args),
ty::Coroutine(_, args) => ty::Binder::dummy(args),
};

// FIXME(type_info): also provide the late bound vars to reflection
let generics = generics.skip_binder();

self.write_generics(place, generics)
}

pub(crate) fn write_fn_ptr_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
Expand Down Expand Up @@ -424,7 +467,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
sym::inputs => {
let inputs = sig.inputs();
self.allocate_fill_and_write_slice_ptr(
field_place,
&field_place,
inputs.len() as _,
|this, i, place| this.write_type_id(inputs[i as usize], &place),
)?;
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(field_place, generics)?,
sym::generics => self.write_generics(&field_place, generics)?,
sym::fields => {
self.write_variant_fields(field_place, struct_def, struct_layout, generics)?
}
Expand Down Expand Up @@ -96,7 +96,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(field_place, generics)?,
sym::generics => self.write_generics(&field_place, generics)?,
sym::fields => {
self.write_variant_fields(field_place, union_def, union_layout, generics)?
}
Expand Down Expand Up @@ -126,10 +126,10 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
let field_place = self.project_field(&place, field_idx)?;

match field.name {
sym::generics => self.write_generics(field_place, generics)?,
sym::generics => self.write_generics(&field_place, generics)?,
sym::variants => {
self.allocate_fill_and_write_slice_ptr(
field_place,
&field_place,
enum_def.variants().len() as u64,
|this, i, place| {
let variant_idx = VariantIdx::from_usize(i as usize);
Expand Down Expand Up @@ -190,7 +190,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
self.allocate_fill_and_write_slice_ptr(
place,
&place,
variant_def.fields.len() as u64,
|this, i, place| {
let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)];
Expand All @@ -200,9 +200,9 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
)
}

fn write_generics(
pub(super) fn write_generics(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
place: &impl Writeable<'tcx, CtfeProvenance>,
generics: &'tcx GenericArgs<'tcx>,
) -> InterpResult<'tcx> {
self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ language_item_table! {
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;

Type, sym::type_info, type_struct, Target::Struct, GenericRequirement::None;
TypeGeneric, sym::type_info_generic, type_generic, Target::Enum, GenericRequirement::None;
TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None;

// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::fdiv_algebraic
| sym::field_offset
| sym::field_representing_type_actual_type_id
| sym::field_representing_type_name
| sym::field_representing_type_offset
| sym::floorf16
| sym::floorf32
| sym::floorf64
Expand Down Expand Up @@ -163,6 +165,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::minimumf128
| sym::mul_with_overflow
| sym::needs_drop
| sym::non_exhaustive
| sym::offload
| sym::offset_of
| sym::overflow_checks
Expand Down Expand Up @@ -216,6 +219,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::type_id_eq
| sym::type_id_field_representing_type
| sym::type_id_fields
| sym::type_id_generics
| sym::type_id_variants
| sym::type_id_vtable
| sym::type_name
Expand Down Expand Up @@ -349,6 +353,22 @@ pub(crate) fn check_intrinsic_type(
tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(),
),
sym::field_representing_type_actual_type_id => (0, 0, vec![type_id_ty()], type_id_ty()),
sym::field_representing_type_name => (0, 0, vec![type_id_ty()], Ty::new_static_str(tcx)),
sym::field_representing_type_offset => (0, 0, vec![type_id_ty()], tcx.types.usize),
sym::non_exhaustive => (0, 0, vec![type_id_ty()], tcx.types.bool),
sym::type_id_generics => (
0,
0,
vec![type_id_ty()],
Ty::new_imm_ref(
tcx,
tcx.lifetimes.re_static,
Ty::new_slice(
tcx,
tcx.type_of(tcx.lang_items().type_generic().unwrap()).no_bound_vars().unwrap(),
),
),
),
sym::offload => (
3,
0,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,8 @@ symbols! {
field_projections,
field_representing_type,
field_representing_type_actual_type_id,
field_representing_type_name,
field_representing_type_offset,
field_representing_type_raw,
field_type,
fields,
Expand Down Expand Up @@ -2171,9 +2173,11 @@ symbols! {
type_id_eq,
type_id_field_representing_type,
type_id_fields,
type_id_generics,
type_id_variants,
type_id_vtable,
type_info,
type_info_generic,
type_ir,
type_ir_infer_ctxt_like,
type_ir_inherent,
Expand Down
33 changes: 33 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3178,6 +3178,39 @@ pub fn field_representing_type_actual_type_id(
_frt_type_id: crate::any::TypeId,
) -> crate::any::TypeId;

/// Gets the name of the field represented by the [`FieldRepresentingType`]'s `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::mem::type_info::FieldId::name`].
///
/// [`FieldRepresentingType`]: crate::field::FieldRepresentingType
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn field_representing_type_name(_frt_type_id: crate::any::TypeId) -> &'static str;

/// Gets the name of the field represented by the [`FieldRepresentingType`]'s `TypeId`.
///
/// The more user-friendly version of this intrinsic is [`core::mem::type_info::FieldId::name`].
///
/// [`FieldRepresentingType`]: crate::field::FieldRepresentingType
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn field_representing_type_offset(_frt_type_id: crate::any::TypeId) -> usize;

/// Checks whether this type is non-exhaustive.
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn non_exhaustive(_id: crate::any::TypeId) -> bool;

/// Returns the list of generic args on this type.
/// Only meaningful for Adts, closures, ... Everything else returns an empty slice.
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_comptime]
pub fn type_id_generics(_id: crate::any::TypeId) -> &'static [crate::mem::type_info::Generic];

/// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`.
///
/// This is used to implement functions like `slice::from_raw_parts_mut` and
Expand Down
Loading
Loading