Skip to content

Make TypeId const comparable #142789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ pub(crate) fn codegen_const_value<'tcx>(
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
GlobalAlloc::Type { .. } => {
return CValue::const_val(
fx,
layout,
ScalarInt::try_from_target_usize(offset.bytes(), fx.tcx).unwrap(),
);
}
GlobalAlloc::Static(def_id) => {
assert!(fx.tcx.is_static(def_id));
let data_id = data_id_for_static(
Expand Down Expand Up @@ -360,6 +367,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
GlobalAlloc::Memory(alloc) => alloc,
GlobalAlloc::Function { .. }
| GlobalAlloc::Static(_)
| GlobalAlloc::Type { .. }
| GlobalAlloc::VTable(..) => {
unreachable!()
}
Expand Down Expand Up @@ -471,6 +479,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
.principal()
.map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
),
GlobalAlloc::Type { .. } => {
// Nothing to do, the bytes/offset of this pointer have already been written together with all other bytes,
// so we just need to drop this provenance.
continue;
}
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
{
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_gcc/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use gccjit::{LValue, RValue, ToRValue, Type};
use rustc_abi as abi;
use rustc_abi::HasDataLayout;
use rustc_abi::Primitive::Pointer;
use rustc_abi::{self as abi, HasDataLayout};
use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
};
Expand Down Expand Up @@ -290,6 +289,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
let init = self.const_data_from_alloc(alloc);
self.static_addr_of(init, alloc.inner().align, None)
}
GlobalAlloc::Type { .. } => {
let val = self.const_usize(offset.bytes());
return self.context.new_cast(None, val, ty);
}
GlobalAlloc::Static(def_id) => {
assert!(self.tcx.is_static(def_id));
self.get_static(def_id).get_address(None)
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
use std::borrow::Borrow;

use libc::{c_char, c_uint};
use rustc_abi as abi;
use rustc_abi::HasDataLayout;
use rustc_abi::Primitive::Pointer;
use rustc_abi::{self as abi, HasDataLayout as _};
use rustc_ast::Mutability;
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::traits::*;
Expand Down Expand Up @@ -284,7 +283,8 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
self.const_bitcast(llval, llty)
};
} else {
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
let init =
const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
let alloc = alloc.inner();
let value = match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
Expand Down Expand Up @@ -316,15 +316,19 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
}),
)))
.unwrap_memory();
let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
let value = self.static_addr_of_impl(init, alloc.inner().align, None);
value
let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false);
self.static_addr_of_impl(init, alloc.inner().align, None)
}
GlobalAlloc::Static(def_id) => {
assert!(self.tcx.is_static(def_id));
assert!(!self.tcx.is_thread_local_static(def_id));
self.get_static(def_id)
}
GlobalAlloc::Type { .. } => {
// Drop the provenance, the offset contains the bytes of the hash
let llval = self.const_usize(offset.bytes());
return unsafe { llvm::LLVMConstIntToPtr(llval, llty) };
}
};
let base_addr_space = global_alloc.address_space(self);
let llval = unsafe {
Expand All @@ -346,7 +350,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
}

fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
const_alloc_to_llvm(self, alloc, /*static*/ false)
const_alloc_to_llvm(self, alloc.inner(), /*static*/ false)
}

fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ use crate::{base, debuginfo};

pub(crate) fn const_alloc_to_llvm<'ll>(
cx: &CodegenCx<'ll, '_>,
alloc: ConstAllocation<'_>,
alloc: &Allocation,
is_static: bool,
) -> &'ll Value {
let alloc = alloc.inner();
// We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or
// integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be
// producing empty LLVM allocations as they're just adding noise to binaries and forcing less
Expand Down Expand Up @@ -138,7 +137,7 @@ fn codegen_static_initializer<'ll, 'tcx>(
def_id: DefId,
) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_llvm(cx, alloc, /*static*/ true), alloc))
Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc))
}

fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
offset: Size,
) -> Self {
let alloc_align = alloc.inner().align;
assert!(alloc_align >= layout.align.abi);
assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi);

let read_scalar = |start, size, s: abi::Scalar, ty| {
match alloc.0.read_scalar(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ const_eval_dealloc_kind_mismatch =

const_eval_deref_function_pointer =
accessing {$allocation} which contains a function
const_eval_deref_typeid_pointer =
accessing {$allocation} which contains a `TypeId`
const_eval_deref_vtable_pointer =
accessing {$allocation} which contains a vtable
const_eval_division_by_zero =
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow};
use std::fmt;
use std::hash::Hash;

use rustc_abi::{Align, Size};
use rustc_abi::{Align, FieldIdx, Size};
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
use rustc_hir::def_id::{DefId, LocalDefId};
Expand Down Expand Up @@ -403,6 +403,24 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
let cmp = ecx.guaranteed_cmp(a, b)?;
ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
}
sym::type_id_eq => {
let a = ecx.project_field(&args[0], FieldIdx::ZERO)?;
let b = ecx.project_field(&args[1], FieldIdx::ZERO)?;

let a = ecx.project_index(&a, 0)?;
let a = ecx.deref_pointer(&a)?;
let (a, offset_a) = a.ptr().into_parts();
let a = a.unwrap().alloc_id();
let GlobalAlloc::Type { ty: a } = ecx.tcx.global_alloc(a) else { bug!() };

let b = ecx.project_index(&b, 0)?;
let b = ecx.deref_pointer(&b)?;
let (b, offset_b) = b.ptr().into_parts();
let b = b.unwrap().alloc_id();
let GlobalAlloc::Type { ty: b } = ecx.tcx.global_alloc(b) else { bug!() };

ecx.write_scalar(Scalar::from_bool(a == b && offset_a == offset_b), dest)?;
}
sym::const_allocate => {
let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?;
let align = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
WriteToReadOnly(_) => const_eval_write_to_read_only,
DerefFunctionPointer(_) => const_eval_deref_function_pointer,
DerefVTablePointer(_) => const_eval_deref_vtable_pointer,
DerefTypeIdPointer(_) => const_eval_deref_typeid_pointer,
InvalidBool(_) => const_eval_invalid_bool,
InvalidChar(_) => const_eval_invalid_char,
InvalidTag(_) => const_eval_invalid_tag,
Expand Down Expand Up @@ -588,7 +589,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
diag.arg("has", has.bytes());
diag.arg("msg", format!("{msg:?}"));
}
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
WriteToReadOnly(alloc)
| DerefFunctionPointer(alloc)
| DerefVTablePointer(alloc)
| DerefTypeIdPointer(alloc) => {
diag.arg("allocation", alloc);
}
InvalidBool(b) => {
Expand Down
36 changes: 35 additions & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::assert_matches::assert_matches;

use rustc_abi::Size;
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_ast::Mutability;
use rustc_middle::mir::interpret::{AllocId, AllocInit, alloc_range};
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement};
use rustc_middle::ty::{Ty, TyCtxt};
Expand All @@ -29,6 +31,37 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
tcx.mk_const_alloc(alloc)
}

pub(crate) fn alloc_type_id<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> AllocId {
let size = Size::from_bytes(16);
let align = tcx.data_layout.pointer_align;
let mut alloc = Allocation::new(size, *align, AllocInit::Uninit, ());
let ptr_size = tcx.data_layout.pointer_size;
let type_id_hash = tcx.type_id_hash(ty).as_u128();
alloc
.write_scalar(
&tcx,
alloc_range(Size::ZERO, Size::from_bytes(16)),
Scalar::from_u128(type_id_hash),
)
.unwrap();

// Give the first pointer-size bytes provenance that knows about the type id

let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
let offset = alloc
.read_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), false)
.unwrap()
.to_target_usize(&tcx)
.unwrap();
let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset));
let val = Scalar::from_pointer(ptr, &tcx);
alloc.write_scalar(&tcx, alloc_range(Size::ZERO, ptr_size), val).unwrap();

alloc.mutability = Mutability::Not;

tcx.reserve_and_set_memory_alloc(tcx.mk_const_alloc(alloc))
}

impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Returns `true` if emulation happened.
/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
Expand Down Expand Up @@ -63,7 +96,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::type_id => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128());
let alloc_id = alloc_type_id(tcx, tp_ty);
let val = ConstValue::Indirect { alloc_id, offset: Size::ZERO };
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
kind = "vtable",
)
}
Some(GlobalAlloc::Type { .. }) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
alloc_id = alloc_id,
kind = "typeid",
)
}
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
err_ub_custom!(
fluent::const_eval_invalid_dealloc,
Expand Down Expand Up @@ -615,6 +622,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)),
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
Some(GlobalAlloc::Type { .. }) => throw_ub!(DerefTypeIdPointer(id)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)),
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
Expand Down Expand Up @@ -894,7 +902,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
let kind = match global_alloc {
GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
GlobalAlloc::Type { .. }
| GlobalAlloc::Static { .. }
| GlobalAlloc::Memory { .. } => AllocKind::LiveData,
GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
GlobalAlloc::VTable { .. } => AllocKind::VTable,
};
Expand Down Expand Up @@ -1204,6 +1214,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
Some(GlobalAlloc::VTable(ty, dyn_ty)) => {
write!(fmt, " (vtable: impl {dyn_ty} for {ty})")?;
}
Some(GlobalAlloc::Type { ty }) => {
write!(fmt, " (typeid for {ty})")?;
}
Some(GlobalAlloc::Static(did)) => {
write!(fmt, " (static: {})", self.ecx.tcx.def_path_str(did))?;
}
Expand Down
Loading
Loading