Replace OffsetOf by an actual sum.
This commit is contained in:
parent
0df64c5784
commit
72444372ae
71 changed files with 475 additions and 646 deletions
|
|
@ -1559,7 +1559,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
self.consume_operand(location, (operand2, span), state);
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_op, _ty) => {
|
||||
Rvalue::NullaryOp(_op) => {
|
||||
// nullary ops take no dynamic input; no borrowck effect.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.consume_operand(location, operand2);
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_op, _ty) => {}
|
||||
Rvalue::NullaryOp(_op) => {}
|
||||
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
for operand in operands {
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
&Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => {}
|
||||
&Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {}
|
||||
|
||||
Rvalue::ShallowInitBox(_operand, ty) => {
|
||||
let trait_ref =
|
||||
|
|
@ -1633,8 +1633,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
|
||||
| Rvalue::Discriminant(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -853,31 +853,14 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
fx.bcx.ins().nop();
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(ref null_op, ty) => {
|
||||
Rvalue::NullaryOp(ref null_op) => {
|
||||
assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env()));
|
||||
let layout = fx.layout_of(fx.monomorphize(ty));
|
||||
let val = match null_op {
|
||||
NullOp::OffsetOf(fields) => fx
|
||||
.tcx
|
||||
.offset_of_subfield(
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
layout,
|
||||
fields.iter(),
|
||||
)
|
||||
.bytes(),
|
||||
NullOp::RuntimeChecks(kind) => {
|
||||
let val = kind.value(fx.tcx.sess);
|
||||
let val = CValue::by_val(
|
||||
fx.bcx.ins().iconst(types::I8, i64::from(val)),
|
||||
fx.layout_of(fx.tcx.types.bool),
|
||||
);
|
||||
lval.write_cvalue(fx, val);
|
||||
return;
|
||||
}
|
||||
NullOp::RuntimeChecks(kind) => kind.value(fx.tcx.sess),
|
||||
};
|
||||
let val = CValue::by_val(
|
||||
fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()),
|
||||
fx.layout_of(fx.tcx.types.usize),
|
||||
fx.bcx.ins().iconst(types::I8, i64::from(val)),
|
||||
fx.layout_of(fx.tcx.types.bool),
|
||||
);
|
||||
lval.write_cvalue(fx, val);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -613,17 +613,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::NullaryOp(ref null_op, ty) => {
|
||||
let ty = self.monomorphize(ty);
|
||||
let layout = bx.cx().layout_of(ty);
|
||||
mir::Rvalue::NullaryOp(ref null_op) => {
|
||||
let val = match null_op {
|
||||
mir::NullOp::OffsetOf(fields) => {
|
||||
let val = bx
|
||||
.tcx()
|
||||
.offset_of_subfield(bx.typing_env(), layout, fields.iter())
|
||||
.bytes();
|
||||
bx.cx().const_usize(val)
|
||||
}
|
||||
mir::NullOp::RuntimeChecks(kind) => {
|
||||
let val = kind.value(bx.tcx().sess);
|
||||
bx.cx().const_bool(val)
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
Rvalue::Cast(_, _, _) => {}
|
||||
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) => {}
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {}
|
||||
Rvalue::ShallowInitBox(_, _) => {}
|
||||
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
|
|
@ -853,7 +853,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Intrinsics are language primitives, not regular calls, so treat them separately.
|
||||
if let Some(intrinsic) = tcx.intrinsic(callee) {
|
||||
if let Some(intrinsic) = tcx.intrinsic(callee)
|
||||
&& intrinsic.name != sym::offset_of
|
||||
{
|
||||
if !tcx.is_const_fn(callee) {
|
||||
// Non-const intrinsic.
|
||||
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ mod simd;
|
|||
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_abi::{FieldIdx, HasDataLayout, Size};
|
||||
use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
|
||||
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
|
||||
|
|
@ -203,6 +203,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let val = layout.align.bytes();
|
||||
self.write_scalar(Scalar::from_target_usize(val, self), dest)?;
|
||||
}
|
||||
sym::offset_of => {
|
||||
let tp_ty = instance.args.type_at(0);
|
||||
|
||||
let u32_layout = self.layout_of(self.tcx.types.u32)?;
|
||||
let variant = self.read_scalar(&args[0])?.to_bits(u32_layout.size)? as u32;
|
||||
let field = self.read_scalar(&args[1])?.to_bits(u32_layout.size)? as usize;
|
||||
|
||||
let layout = self.layout_of(tp_ty)?;
|
||||
let cx = ty::layout::LayoutCx::new(*self.tcx, self.typing_env);
|
||||
|
||||
let layout = layout.for_variant(&cx, VariantIdx::from_u32(variant));
|
||||
let offset = layout.fields.offset(field).bytes();
|
||||
|
||||
self.write_scalar(Scalar::from_target_usize(offset, self), dest)?;
|
||||
}
|
||||
sym::variant_count => {
|
||||
let tp_ty = instance.args.type_at(0);
|
||||
let ty = match tp_ty.kind() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_apfloat::{Float, FloatConvert};
|
|||
use rustc_middle::mir::NullOp;
|
||||
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
|
||||
use rustc_middle::ty::{self, FloatTy, ScalarInt};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::sym;
|
||||
use tracing::trace;
|
||||
|
|
@ -506,22 +506,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn nullary_op(
|
||||
&self,
|
||||
null_op: NullOp<'tcx>,
|
||||
arg_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
pub fn nullary_op(&self, null_op: NullOp) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
use rustc_middle::mir::NullOp::*;
|
||||
|
||||
let layout = self.layout_of(arg_ty)?;
|
||||
let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
|
||||
|
||||
interp_ok(match null_op {
|
||||
OffsetOf(fields) => {
|
||||
let val =
|
||||
self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes();
|
||||
ImmTy::from_uint(val, usize_layout())
|
||||
}
|
||||
RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,9 +203,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.write_immediate(*result, &dest)?;
|
||||
}
|
||||
|
||||
NullaryOp(null_op, ty) => {
|
||||
let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||
let val = self.nullary_op(null_op, ty)?;
|
||||
NullaryOp(null_op) => {
|
||||
let val = self.nullary_op(null_op)?;
|
||||
self.write_immediate(*val, &dest)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ language_item_table! {
|
|||
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0);
|
||||
SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0);
|
||||
OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1);
|
||||
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
|
||||
StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None;
|
||||
Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
|||
| sym::minnumf128
|
||||
| sym::mul_with_overflow
|
||||
| sym::needs_drop
|
||||
| sym::offset_of
|
||||
| sym::overflow_checks
|
||||
| sym::powf16
|
||||
| sym::powf32
|
||||
|
|
@ -288,6 +289,7 @@ pub(crate) fn check_intrinsic_type(
|
|||
sym::size_of_val | sym::align_of_val => {
|
||||
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
|
||||
}
|
||||
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
|
||||
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
|
||||
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
|
||||
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => {
|
||||
|
|
|
|||
|
|
@ -3884,10 +3884,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fields: &[Ident],
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let container = self.lower_ty(container).normalized;
|
||||
|
||||
let mut current_container = self.lower_ty(container).normalized;
|
||||
let mut field_indices = Vec::with_capacity(fields.len());
|
||||
let mut current_container = container;
|
||||
let mut fields = fields.into_iter();
|
||||
|
||||
while let Some(&field) = fields.next() {
|
||||
|
|
@ -3975,7 +3973,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Save the index of all fields regardless of their visibility in case
|
||||
// of error recovery.
|
||||
field_indices.push((index, subindex));
|
||||
field_indices.push((current_container, index, subindex));
|
||||
current_container = field_ty;
|
||||
|
||||
continue;
|
||||
|
|
@ -4010,7 +4008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Save the index of all fields regardless of their visibility in case
|
||||
// of error recovery.
|
||||
field_indices.push((FIRST_VARIANT, index));
|
||||
field_indices.push((current_container, FIRST_VARIANT, index));
|
||||
current_container = field_ty;
|
||||
|
||||
continue;
|
||||
|
|
@ -4031,7 +4029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
field_indices.push((FIRST_VARIANT, index.into()));
|
||||
field_indices.push((current_container, FIRST_VARIANT, index.into()));
|
||||
current_container = field_ty;
|
||||
|
||||
continue;
|
||||
|
|
@ -4046,10 +4044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
break;
|
||||
}
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.offset_of_data_mut()
|
||||
.insert(expr.hir_id, (container, field_indices));
|
||||
self.typeck_results.borrow_mut().offset_of_data_mut().insert(expr.hir_id, field_indices);
|
||||
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
|
|
|||
|
|
@ -770,12 +770,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
let common_hir_owner = fcx_typeck_results.hir_owner;
|
||||
|
||||
for (local_id, &(container, ref indices)) in
|
||||
fcx_typeck_results.offset_of_data().items_in_stable_order()
|
||||
{
|
||||
for (local_id, indices) in fcx_typeck_results.offset_of_data().items_in_stable_order() {
|
||||
let hir_id = HirId { owner: common_hir_owner, local_id };
|
||||
let container = self.resolve(container, &hir_id);
|
||||
self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone()));
|
||||
let indices = indices
|
||||
.iter()
|
||||
.map(|&(ty, variant, field)| (self.resolve(ty, &hir_id), variant, field))
|
||||
.collect();
|
||||
self.typeck_results.offset_of_data_mut().insert(hir_id, indices);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
hir::ExprKind::AddrOf(..) => Some("borrow"),
|
||||
hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"),
|
||||
hir::ExprKind::Unary(..) => Some("unary operation"),
|
||||
// The `offset_of` macro wraps its contents inside a `const` block.
|
||||
hir::ExprKind::ConstBlock(block) => {
|
||||
let body = cx.tcx.hir_body(block.body);
|
||||
if let hir::ExprKind::Block(block, _) = body.value.kind
|
||||
&& let Some(expr) = block.expr
|
||||
&& let hir::ExprKind::OffsetOf(..) = expr.kind
|
||||
{
|
||||
Some("`offset_of` call")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ impl<'tcx> Body<'tcx> {
|
|||
}
|
||||
|
||||
match rvalue {
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(kind), _) => {
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(kind)) => {
|
||||
Some((kind.value(tcx.sess) as u128, targets))
|
||||
}
|
||||
Rvalue::Use(Operand::Constant(constant)) => {
|
||||
|
|
|
|||
|
|
@ -1097,19 +1097,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
|
||||
UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
|
||||
Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
|
||||
NullaryOp(ref op, ref t) => {
|
||||
let t = with_no_trimmed_paths!(format!("{}", t));
|
||||
match op {
|
||||
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
|
||||
NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"),
|
||||
NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => {
|
||||
write!(fmt, "ContractChecks()")
|
||||
}
|
||||
NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => {
|
||||
write!(fmt, "OverflowChecks()")
|
||||
}
|
||||
NullaryOp(ref op) => match op {
|
||||
NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"),
|
||||
NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => {
|
||||
write!(fmt, "ContractChecks()")
|
||||
}
|
||||
}
|
||||
NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => {
|
||||
write!(fmt, "OverflowChecks()")
|
||||
}
|
||||
},
|
||||
ThreadLocalRef(did) => ty::tls::with(|tcx| {
|
||||
let muta = tcx.static_mutability(did).unwrap().prefix_str();
|
||||
write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
_,
|
||||
)
|
||||
| Rvalue::BinaryOp(_, _)
|
||||
| Rvalue::NullaryOp(_, _)
|
||||
| Rvalue::NullaryOp(_)
|
||||
| Rvalue::UnaryOp(_, _)
|
||||
| Rvalue::Discriminant(_)
|
||||
| Rvalue::Aggregate(_, _)
|
||||
|
|
@ -794,8 +794,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
op.ty(tcx, arg_ty)
|
||||
}
|
||||
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => tcx.types.usize,
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => tcx.types.bool,
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => tcx.types.bool,
|
||||
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
|
||||
AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
|
||||
AggregateKind::Tuple => {
|
||||
|
|
@ -859,10 +858,9 @@ impl BorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> NullOp<'tcx> {
|
||||
pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
impl NullOp {
|
||||
pub fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
match self {
|
||||
NullOp::OffsetOf(_) => tcx.types.usize,
|
||||
NullOp::RuntimeChecks(_) => tcx.types.bool,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1419,7 +1419,7 @@ pub enum Rvalue<'tcx> {
|
|||
BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
|
||||
|
||||
/// Computes a value as described by the operation.
|
||||
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
||||
NullaryOp(NullOp),
|
||||
|
||||
/// Exactly like `BinaryOp`, but less operands.
|
||||
///
|
||||
|
|
@ -1562,9 +1562,7 @@ pub enum AggregateKind<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub enum NullOp<'tcx> {
|
||||
/// Returns the offset of a field
|
||||
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
|
||||
pub enum NullOp {
|
||||
/// Returns whether we should perform some checking at runtime.
|
||||
RuntimeChecks(RuntimeChecks),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -775,9 +775,7 @@ macro_rules! make_mir_visitor {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_op, ty) => {
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
}
|
||||
Rvalue::NullaryOp(_op) => {}
|
||||
|
||||
Rvalue::Aggregate(kind, operands) => {
|
||||
let kind = &$($mutability)? **kind;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use crate::thir::visit::for_each_immediate_subpat;
|
|||
use crate::ty::adjustment::PointerCoercion;
|
||||
use crate::ty::layout::IntegerExt;
|
||||
use crate::ty::{
|
||||
self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty,
|
||||
self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, Ty,
|
||||
TyCtxt, UpvarArgs,
|
||||
};
|
||||
|
||||
|
|
@ -550,11 +550,6 @@ pub enum ExprKind<'tcx> {
|
|||
},
|
||||
/// Inline assembly, i.e. `asm!()`.
|
||||
InlineAsm(Box<InlineAsmExpr<'tcx>>),
|
||||
/// Field offset (`offset_of!`)
|
||||
OffsetOf {
|
||||
container: Ty<'tcx>,
|
||||
fields: &'tcx List<(VariantIdx, FieldIdx)>,
|
||||
},
|
||||
/// An expression taking a reference to a thread local.
|
||||
ThreadLocalRef(DefId),
|
||||
/// A `yield` expression.
|
||||
|
|
|
|||
|
|
@ -188,7 +188,6 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
}
|
||||
}
|
||||
}
|
||||
OffsetOf { container: _, fields: _ } => {}
|
||||
ThreadLocalRef(_) => {}
|
||||
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use std::hash::Hash;
|
|||
use std::intrinsics;
|
||||
use std::marker::{DiscriminantKind, PointeeSized};
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
|
|
@ -489,15 +489,6 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for &'tcx ty::List<LocalDefId> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<(VariantIdx, FieldIdx)> {
|
||||
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||
let len = decoder.read_usize();
|
||||
decoder.interner().mk_offset_of_from_iter(
|
||||
(0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl_decodable_via_ref! {
|
||||
&'tcx ty::TypeckResults<'tcx>,
|
||||
&'tcx ty::List<Ty<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -954,7 +954,6 @@ pub struct CtxtInterners<'tcx> {
|
|||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
||||
captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>,
|
||||
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
|
||||
valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>,
|
||||
patterns: InternedSet<'tcx, List<ty::Pattern<'tcx>>>,
|
||||
outlives: InternedSet<'tcx, List<ty::ArgOutlivesPredicate<'tcx>>>,
|
||||
|
|
@ -992,7 +991,6 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
fields: InternedSet::with_capacity(N * 4),
|
||||
local_def_ids: InternedSet::with_capacity(N),
|
||||
captures: InternedSet::with_capacity(N),
|
||||
offset_of: InternedSet::with_capacity(N),
|
||||
valtree: InternedSet::with_capacity(N),
|
||||
patterns: InternedSet::with_capacity(N),
|
||||
outlives: InternedSet::with_capacity(N),
|
||||
|
|
@ -2831,7 +2829,6 @@ slice_interners!(
|
|||
fields: pub mk_fields(FieldIdx),
|
||||
local_def_ids: intern_local_def_ids(LocalDefId),
|
||||
captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>),
|
||||
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
|
||||
patterns: pub mk_patterns(Pattern<'tcx>),
|
||||
outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>),
|
||||
predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)),
|
||||
|
|
@ -3234,14 +3231,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
T::collect_and_apply(iter, |xs| self.mk_fields(xs))
|
||||
}
|
||||
|
||||
pub fn mk_offset_of_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>,
|
||||
{
|
||||
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
|
||||
}
|
||||
|
||||
pub fn mk_args_trait(
|
||||
self,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1392,37 +1392,3 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn offset_of_subfield<I>(
|
||||
self,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
mut layout: TyAndLayout<'tcx>,
|
||||
indices: I,
|
||||
) -> Size
|
||||
where
|
||||
I: Iterator<Item = (VariantIdx, FieldIdx)>,
|
||||
{
|
||||
let cx = LayoutCx::new(self, typing_env);
|
||||
let mut offset = Size::ZERO;
|
||||
|
||||
for (variant, field) in indices {
|
||||
layout = layout.for_variant(&cx, variant);
|
||||
let index = field.index();
|
||||
offset += layout.fields.offset(index);
|
||||
layout = layout.field(&cx, index);
|
||||
if !layout.is_sized() {
|
||||
// If it is not sized, then the tail must still have at least a known static alignment.
|
||||
let tail = self.struct_tail_for_codegen(layout.ty, typing_env);
|
||||
if !matches!(tail.kind(), ty::Slice(..)) {
|
||||
bug!(
|
||||
"offset of not-statically-aligned field (type {:?}) cannot be computed statically",
|
||||
layout.ty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ TrivialTypeTraversalImpls! {
|
|||
crate::mir::FakeReadCause,
|
||||
crate::mir::Local,
|
||||
crate::mir::MirPhase,
|
||||
crate::mir::NullOp<'tcx>,
|
||||
crate::mir::NullOp,
|
||||
crate::mir::Promoted,
|
||||
crate::mir::RawPtrKind,
|
||||
crate::mir::RetagKind,
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ pub struct TypeckResults<'tcx> {
|
|||
pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>,
|
||||
|
||||
/// Container types and field indices of `offset_of!` expressions
|
||||
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
|
||||
offset_of_data: ItemLocalMap<Vec<(Ty<'tcx>, VariantIdx, FieldIdx)>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeckResults<'tcx> {
|
||||
|
|
@ -553,15 +553,13 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
&self.coercion_casts
|
||||
}
|
||||
|
||||
pub fn offset_of_data(
|
||||
&self,
|
||||
) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
|
||||
pub fn offset_of_data(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, VariantIdx, FieldIdx)>> {
|
||||
LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data }
|
||||
}
|
||||
|
||||
pub fn offset_of_data_mut(
|
||||
&mut self,
|
||||
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
|
||||
) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, VariantIdx, FieldIdx)>> {
|
||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -580,7 +580,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::ConstBlock { .. }
|
||||
| ExprKind::StaticRef { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
| ExprKind::OffsetOf { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::Call { .. }
|
||||
|
|
|
|||
|
|
@ -411,10 +411,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}))))
|
||||
}
|
||||
|
||||
ExprKind::OffsetOf { container, fields } => {
|
||||
block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container))
|
||||
}
|
||||
|
||||
ExprKind::Literal { .. }
|
||||
| ExprKind::NamedConst { .. }
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ impl Category {
|
|||
| ExprKind::Assign { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::OffsetOf { .. }
|
||||
| ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
||||
|
||||
ExprKind::ConstBlock { .. }
|
||||
|
|
|
|||
|
|
@ -784,7 +784,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| ExprKind::ConstParam { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::StaticRef { .. }
|
||||
| ExprKind::OffsetOf { .. }
|
||||
| ExprKind::WrapUnsafeBinder { .. } => {
|
||||
debug_assert!(match Category::of(&expr.kind).unwrap() {
|
||||
// should be handled above
|
||||
|
|
|
|||
|
|
@ -477,7 +477,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
| ExprKind::Box { .. }
|
||||
| ExprKind::If { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
| ExprKind::OffsetOf { .. }
|
||||
| ExprKind::LogicalOp { .. }
|
||||
| ExprKind::Use { .. } => {
|
||||
// We don't need to save the old value and restore it
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use itertools::Itertools;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, Size, VariantIdx};
|
||||
use rustc_ast::UnsafeBinderCastKind;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::find_attr;
|
||||
use rustc_hir::{LangItem, find_attr};
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::hir::place::{
|
||||
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
|
||||
|
|
@ -336,6 +336,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let expr_ty = self.typeck_results.expr_ty(expr);
|
||||
let mk_expr =
|
||||
|kind, ty| Expr { temp_scope_id: expr.hir_id.local_id, span: expr.span, ty, kind };
|
||||
|
||||
let kind = match expr.kind {
|
||||
// Here comes the interesting stuff:
|
||||
|
|
@ -813,11 +815,48 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
})),
|
||||
|
||||
hir::ExprKind::OffsetOf(_, _) => {
|
||||
let data = self.typeck_results.offset_of_data();
|
||||
let &(container, ref indices) = data.get(expr.hir_id).unwrap();
|
||||
let fields = tcx.mk_offset_of_from_iter(indices.iter().copied());
|
||||
let offset_of_intrinsic = tcx.require_lang_item(LangItem::OffsetOf, expr.span);
|
||||
let mk_u32_kind = |val: u32| ExprKind::NonHirLiteral {
|
||||
lit: ScalarInt::try_from_uint(val, Size::from_bits(32)).unwrap(),
|
||||
user_ty: None,
|
||||
};
|
||||
let mk_call =
|
||||
|thir: &mut Thir<'tcx>, ty: Ty<'tcx>, variant: VariantIdx, field: FieldIdx| {
|
||||
let fun_ty =
|
||||
Ty::new_fn_def(tcx, offset_of_intrinsic, [ty::GenericArg::from(ty)]);
|
||||
let fun = thir
|
||||
.exprs
|
||||
.push(mk_expr(ExprKind::ZstLiteral { user_ty: None }, fun_ty));
|
||||
let variant =
|
||||
thir.exprs.push(mk_expr(mk_u32_kind(variant.as_u32()), tcx.types.u32));
|
||||
let field =
|
||||
thir.exprs.push(mk_expr(mk_u32_kind(field.as_u32()), tcx.types.u32));
|
||||
let args = Box::new([variant, field]);
|
||||
ExprKind::Call {
|
||||
ty: fun_ty,
|
||||
fun,
|
||||
args,
|
||||
from_hir_call: false,
|
||||
fn_span: expr.span,
|
||||
}
|
||||
};
|
||||
|
||||
ExprKind::OffsetOf { container, fields }
|
||||
let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap();
|
||||
let mut expr = None::<ExprKind<'tcx>>;
|
||||
|
||||
for &(container, variant, field) in indices.iter() {
|
||||
let next = mk_call(&mut self.thir, container, variant, field);
|
||||
expr = Some(match expr.take() {
|
||||
None => next,
|
||||
Some(last) => {
|
||||
let last = self.thir.exprs.push(mk_expr(last, tcx.types.usize));
|
||||
let next = self.thir.exprs.push(mk_expr(next, tcx.types.usize));
|
||||
ExprKind::Binary { op: BinOp::Add, lhs: last, rhs: next }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
expr.unwrap_or(mk_u32_kind(0))
|
||||
}
|
||||
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
|
|
@ -1081,7 +1120,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"),
|
||||
};
|
||||
|
||||
Expr { temp_scope_id: expr.hir_id.local_id, ty: expr_ty, span: expr.span, kind }
|
||||
mk_expr(kind, expr_ty)
|
||||
}
|
||||
|
||||
fn user_args_applied_to_res(
|
||||
|
|
|
|||
|
|
@ -367,7 +367,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
| Match { .. }
|
||||
| NamedConst { .. }
|
||||
| NonHirLiteral { .. }
|
||||
| OffsetOf { .. }
|
||||
| Repeat { .. }
|
||||
| StaticRef { .. }
|
||||
| ThreadLocalRef { .. }
|
||||
|
|
|
|||
|
|
@ -575,19 +575,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
self.print_inline_asm_expr(&**expr, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl);
|
||||
}
|
||||
OffsetOf { container, fields } => {
|
||||
print_indented!(self, "OffsetOf {", depth_lvl);
|
||||
print_indented!(self, format!("container: {:?}", container), depth_lvl + 1);
|
||||
print_indented!(self, "fields: [", depth_lvl + 1);
|
||||
|
||||
for field in fields.iter() {
|
||||
print_indented!(self, format!("{:?}", field), depth_lvl + 2);
|
||||
print_indented!(self, ",", depth_lvl + 1);
|
||||
}
|
||||
|
||||
print_indented!(self, "]", depth_lvl + 1);
|
||||
print_indented!(self, "}", depth_lvl);
|
||||
}
|
||||
ThreadLocalRef(def_id) => {
|
||||
print_indented!(self, "ThreadLocalRef {", depth_lvl);
|
||||
print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
|||
Rvalue::Ref(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::NullaryOp(NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _) => {}
|
||||
| Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -463,20 +463,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
FlatSet::Top => FlatSet::Top,
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(null_op, ty) => {
|
||||
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
|
||||
return ValueOrPlace::Value(FlatSet::Top);
|
||||
};
|
||||
let val = match null_op {
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.ecx
|
||||
.borrow()
|
||||
.tcx
|
||||
.offset_of_subfield(self.typing_env, layout, fields.iter())
|
||||
.bytes(),
|
||||
_ => return ValueOrPlace::Value(FlatSet::Top),
|
||||
};
|
||||
FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx))
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {
|
||||
return ValueOrPlace::TOP;
|
||||
}
|
||||
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
|
||||
Rvalue::Use(operand) => return self.handle_operand(operand, state),
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ enum Value<'a, 'tcx> {
|
|||
Discriminant(VnIndex),
|
||||
|
||||
// Operations.
|
||||
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
||||
NullaryOp(NullOp),
|
||||
UnaryOp(UnOp, VnIndex),
|
||||
BinaryOp(BinOp, VnIndex, VnIndex),
|
||||
Cast {
|
||||
|
|
@ -668,17 +668,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
|
|||
self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
|
||||
discr_value.into()
|
||||
}
|
||||
NullaryOp(null_op, arg_ty) => {
|
||||
let arg_layout = self.ecx.layout_of(arg_ty).ok()?;
|
||||
let val = match null_op {
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.tcx
|
||||
.offset_of_subfield(self.typing_env(), arg_layout, fields.iter())
|
||||
.bytes(),
|
||||
NullOp::RuntimeChecks(_) => return None,
|
||||
};
|
||||
ImmTy::from_uint(val, ty).into()
|
||||
}
|
||||
NullaryOp(NullOp::RuntimeChecks(_)) => return None,
|
||||
UnaryOp(un_op, operand) => {
|
||||
let operand = self.eval_to_const(operand)?;
|
||||
let operand = self.ecx.read_immediate(operand).discard_err()?;
|
||||
|
|
@ -1031,7 +1021,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
|
|||
let op = self.simplify_operand(op, location)?;
|
||||
Value::Repeat(op, amount)
|
||||
}
|
||||
Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty),
|
||||
Rvalue::NullaryOp(op) => Value::NullaryOp(op),
|
||||
Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location),
|
||||
Rvalue::Ref(_, borrow_kind, ref mut place) => {
|
||||
self.simplify_place_projection(place, location);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
|
|||
|
||||
fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) {
|
||||
// FIXME: Should we do the same for overflow checks?
|
||||
let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), _) = *rvalue else {
|
||||
let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks)) = *rvalue else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -605,17 +605,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
|
||||
Ref(..) | RawPtr(..) => return None,
|
||||
|
||||
NullaryOp(ref null_op, ty) => {
|
||||
let op_layout = self.ecx.layout_of(ty).ok()?;
|
||||
let val = match null_op {
|
||||
NullOp::OffsetOf(fields) => self
|
||||
.tcx
|
||||
.offset_of_subfield(self.typing_env, op_layout, fields.iter())
|
||||
.bytes(),
|
||||
NullOp::RuntimeChecks(_) => return None,
|
||||
};
|
||||
ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
|
||||
}
|
||||
NullaryOp(NullOp::RuntimeChecks(_)) => return None,
|
||||
|
||||
ShallowInitBox(..) => return None,
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
|
|||
terminator.source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
*destination,
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(op), tcx.types.bool),
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(op)),
|
||||
))),
|
||||
));
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
|
|
|
|||
|
|
@ -449,8 +449,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
self.validate_operand(operand)?;
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(op, _) => match op {
|
||||
NullOp::OffsetOf(_) => {}
|
||||
Rvalue::NullaryOp(op) => match op {
|
||||
NullOp::RuntimeChecks(_) => {}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1436,53 +1436,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => {
|
||||
let fail_out_of_bounds = |this: &mut Self, location, field, ty| {
|
||||
this.fail(location, format!("Out of bounds field {field:?} for {ty}"));
|
||||
};
|
||||
|
||||
let mut current_ty = *container;
|
||||
|
||||
for (variant, field) in indices.iter() {
|
||||
match current_ty.kind() {
|
||||
ty::Tuple(fields) => {
|
||||
if variant != FIRST_VARIANT {
|
||||
self.fail(
|
||||
location,
|
||||
format!("tried to get variant {variant:?} of tuple"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
let Some(&f_ty) = fields.get(field.as_usize()) else {
|
||||
fail_out_of_bounds(self, location, field, current_ty);
|
||||
return;
|
||||
};
|
||||
|
||||
current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty);
|
||||
}
|
||||
ty::Adt(adt_def, args) => {
|
||||
let Some(field) = adt_def.variant(variant).fields.get(field) else {
|
||||
fail_out_of_bounds(self, location, field, current_ty);
|
||||
return;
|
||||
};
|
||||
|
||||
let f_ty = field.ty(self.tcx, args);
|
||||
current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty);
|
||||
}
|
||||
_ => {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Repeat(_, _)
|
||||
| Rvalue::ThreadLocalRef(_)
|
||||
| Rvalue::RawPtr(_, _)
|
||||
| Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _)
|
||||
| Rvalue::NullaryOp(NullOp::RuntimeChecks(_))
|
||||
| Rvalue::Discriminant(_) => {}
|
||||
|
||||
Rvalue::WrapUnsafeBinder(op, ty) => {
|
||||
|
|
|
|||
|
|
@ -298,31 +298,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
}
|
||||
|
||||
fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
let data = self.typeck_results().offset_of_data();
|
||||
let &(container, ref indices) =
|
||||
data.get(expr.hir_id).expect("no offset_of_data for offset_of");
|
||||
let indices = self
|
||||
.typeck_results()
|
||||
.offset_of_data()
|
||||
.get(expr.hir_id)
|
||||
.expect("no offset_of_data for offset_of");
|
||||
|
||||
let body_did = self.typeck_results().hir_owner.to_def_id();
|
||||
let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, body_did);
|
||||
|
||||
let mut current_ty = container;
|
||||
|
||||
for &(variant, field) in indices {
|
||||
for &(current_ty, variant, field) in indices {
|
||||
match current_ty.kind() {
|
||||
ty::Adt(def, args) => {
|
||||
ty::Adt(def, _) => {
|
||||
let field = &def.variant(variant).fields[field];
|
||||
|
||||
self.insert_def_id(field.did);
|
||||
let field_ty = field.ty(self.tcx, args);
|
||||
|
||||
current_ty = self.tcx.normalize_erasing_regions(typing_env, field_ty);
|
||||
}
|
||||
// we don't need to mark tuple fields as live,
|
||||
// but we may need to mark subfields
|
||||
ty::Tuple(tys) => {
|
||||
current_ty =
|
||||
self.tcx.normalize_erasing_regions(typing_env, tys[field.as_usize()]);
|
||||
}
|
||||
ty::Tuple(_) => {}
|
||||
_ => span_bug!(expr.span, "named field access on non-ADT"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ pub enum Rvalue {
|
|||
ThreadLocalRef(crate::CrateItem),
|
||||
|
||||
/// Computes a value as described by the operation.
|
||||
NullaryOp(NullOp, Ty),
|
||||
NullaryOp(NullOp),
|
||||
|
||||
/// Exactly like `BinaryOp`, but less operands.
|
||||
///
|
||||
|
|
@ -641,8 +641,7 @@ impl Rvalue {
|
|||
.discriminant_ty()
|
||||
.ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()),
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => Ok(Ty::bool_ty()),
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => Ok(Ty::bool_ty()),
|
||||
Rvalue::Aggregate(ak, ops) => match *ak {
|
||||
AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
|
||||
AggregateKind::Tuple => Ok(Ty::new_tuple(
|
||||
|
|
@ -1021,8 +1020,6 @@ pub enum CastKind {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
|
||||
pub enum NullOp {
|
||||
/// Returns the offset of a field.
|
||||
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
|
||||
/// Codegen conditions for runtime checks.
|
||||
RuntimeChecks(RuntimeChecks),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,8 +386,8 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
|||
Rvalue::ThreadLocalRef(item) => {
|
||||
write!(writer, "thread_local_ref{item:?}")
|
||||
}
|
||||
Rvalue::NullaryOp(nul, ty) => {
|
||||
write!(writer, "{nul:?}::<{ty}>() \" \"")
|
||||
Rvalue::NullaryOp(nul) => {
|
||||
write!(writer, "{nul:?}() \" \"")
|
||||
}
|
||||
Rvalue::UnaryOp(un, op) => {
|
||||
write!(writer, "{:?}({})", un, pretty_operand(op))
|
||||
|
|
|
|||
|
|
@ -282,9 +282,7 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_operand(op, location)
|
||||
}
|
||||
Rvalue::ThreadLocalRef(_) => {}
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
Rvalue::NullaryOp(_) => {}
|
||||
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,9 +232,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
|||
)
|
||||
}
|
||||
}
|
||||
NullaryOp(null_op, ty) => {
|
||||
crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx), ty.stable(tables, cx))
|
||||
}
|
||||
NullaryOp(null_op) => crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx)),
|
||||
UnaryOp(un_op, op) => {
|
||||
crate::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx))
|
||||
}
|
||||
|
|
@ -314,19 +312,16 @@ impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
|
||||
impl<'tcx> Stable<'tcx> for mir::NullOp {
|
||||
type T = crate::mir::NullOp;
|
||||
fn stable<'cx>(
|
||||
&self,
|
||||
tables: &mut Tables<'cx, BridgeTys>,
|
||||
cx: &CompilerCtxt<'cx, BridgeTys>,
|
||||
_: &mut Tables<'cx, BridgeTys>,
|
||||
_: &CompilerCtxt<'cx, BridgeTys>,
|
||||
) -> Self::T {
|
||||
use rustc_middle::mir::NullOp::*;
|
||||
use rustc_middle::mir::RuntimeChecks::*;
|
||||
match self {
|
||||
OffsetOf(indices) => crate::mir::NullOp::OffsetOf(
|
||||
indices.iter().map(|idx| idx.stable(tables, cx)).collect(),
|
||||
),
|
||||
RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op {
|
||||
UbChecks => crate::mir::RuntimeChecks::UbChecks,
|
||||
ContractChecks => crate::mir::RuntimeChecks::ContractChecks,
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ fn recurse_build<'tcx>(
|
|||
ExprKind::VarRef { .. }
|
||||
| ExprKind::UpvarRef { .. }
|
||||
| ExprKind::StaticRef { .. }
|
||||
| ExprKind::OffsetOf { .. }
|
||||
| ExprKind::ThreadLocalRef(_) => {
|
||||
error(GenericConstantTooComplexSub::OperationNotSupported(node.span))?
|
||||
}
|
||||
|
|
@ -364,7 +363,6 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
|
|||
| thir::ExprKind::ZstLiteral { .. }
|
||||
| thir::ExprKind::StaticRef { .. }
|
||||
| thir::ExprKind::InlineAsm(_)
|
||||
| thir::ExprKind::OffsetOf { .. }
|
||||
| thir::ExprKind::ThreadLocalRef(_)
|
||||
| thir::ExprKind::Yield { .. } => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2791,6 +2791,23 @@ pub const fn size_of<T>() -> usize;
|
|||
#[rustc_intrinsic]
|
||||
pub const fn align_of<T>() -> usize;
|
||||
|
||||
/// The offset of a field inside a type.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is [`core::mem::offset_of`].
|
||||
#[rustc_nounwind]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_const_stable_indirect]
|
||||
#[rustc_intrinsic_const_stable_indirect]
|
||||
#[rustc_intrinsic]
|
||||
#[lang = "offset_of"]
|
||||
pub const fn offset_of<T: PointeeSized>(variant: u32, field: u32) -> usize;
|
||||
|
||||
/// Returns the number of variants of the type `T` cast to a `usize`;
|
||||
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1424,10 +1424,10 @@ impl<T> SizedTypeProperties for T {}
|
|||
/// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html
|
||||
/// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html
|
||||
#[stable(feature = "offset_of", since = "1.77.0")]
|
||||
#[allow_internal_unstable(builtin_syntax)]
|
||||
#[allow_internal_unstable(builtin_syntax, core_intrinsics)]
|
||||
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
|
||||
// The `{}` is for better error messages
|
||||
{builtin # offset_of($Container, $($fields)+)}
|
||||
const {builtin # offset_of($Container, $($fields)+)}
|
||||
}
|
||||
|
||||
/// Create a fresh instance of the inhabited ZST type `T`.
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ fn check_rvalue<'tcx>(
|
|||
))
|
||||
}
|
||||
},
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(body, cx.tcx);
|
||||
if ty.is_integral() || ty.is_bool() {
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
//@ known-bug: #123959
|
||||
#![feature(generic_const_exprs)]
|
||||
fn foo<T>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#125680
|
||||
//@ edition:2021
|
||||
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
struct Inline<T>
|
||||
where
|
||||
[(); std::mem::offset_of!((T,), 0)]:,
|
||||
{}
|
||||
|
||||
fn main() {
|
||||
let dst = Inline::<dyn Debug>::new(0); // BANG!
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#129425
|
||||
|
||||
//@compile-flags: --crate-type=lib
|
||||
|
||||
#![feature(generic_const_exprs)]
|
||||
fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
//@ known-bug: #136175
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait {}
|
||||
|
||||
struct A<T>(T)
|
||||
where
|
||||
[(); std::mem::offset_of!((T,), 0)]:;
|
||||
|
||||
fn main() {
|
||||
let x: A<dyn Trait>;
|
||||
}
|
||||
115
tests/mir-opt/building/offset_of.rs
Normal file
115
tests/mir-opt/building/offset_of.rs
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
//@ compile-flags: -Zmir-opt-level=0
|
||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
|
||||
#![feature(offset_of_enum)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::offset_of;
|
||||
|
||||
struct Alpha {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: Beta,
|
||||
}
|
||||
|
||||
struct Beta(u8, u8);
|
||||
|
||||
struct Gamma<T> {
|
||||
x: u8,
|
||||
y: u16,
|
||||
_t: T,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Delta<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
x: u8,
|
||||
y: u16,
|
||||
}
|
||||
|
||||
enum Blah {
|
||||
A,
|
||||
B { x: u8, y: usize },
|
||||
}
|
||||
|
||||
// CHECK-LABEL: fn concrete(
|
||||
fn concrete() {
|
||||
// CHECK: debug x => [[x:_.*]];
|
||||
// CHECK: debug y => [[y:_.*]];
|
||||
// CHECK: debug h => [[h:_.*]];
|
||||
// CHECK: debug z0 => [[z0:_.*]];
|
||||
// CHECK: debug z1 => [[z1:_.*]];
|
||||
|
||||
// CHECK: [[x]] = const concrete::[[const_x:.*]];
|
||||
let x = offset_of!(Alpha, x);
|
||||
|
||||
// CHECK: [[y]] = const concrete::[[const_y:.*]];
|
||||
let y = offset_of!(Alpha, y);
|
||||
|
||||
// CHECK: [[h]] = const concrete::[[const_h:.*]];
|
||||
let h = offset_of!(Blah, B.y);
|
||||
|
||||
// CHECK: [[z0]] = const concrete::[[const_z0:.*]];
|
||||
let z0 = offset_of!(Alpha, z.0);
|
||||
|
||||
// CHECK: [[z1]] = const concrete::[[const_z1:.*]];
|
||||
let z1 = offset_of!(Alpha, z.1);
|
||||
}
|
||||
|
||||
// CHECK: concrete::[[const_x]]: usize
|
||||
// CHECK: _0 = offset_of::<Alpha>(const 0_u32, const 0_u32)
|
||||
|
||||
// CHECK: concrete::[[const_y]]: usize
|
||||
// CHECK: _0 = offset_of::<Alpha>(const 0_u32, const 1_u32)
|
||||
|
||||
// CHECK: concrete::[[const_h]]: usize
|
||||
// CHECK: _0 = offset_of::<Blah>(const 1_u32, const 1_u32)
|
||||
|
||||
// CHECK: concrete::[[const_z0]]: usize
|
||||
// CHECK: [[z:_.*]] = offset_of::<Alpha>(const 0_u32, const 2_u32)
|
||||
// CHECK: [[z0:_.*]] = offset_of::<Beta>(const 0_u32, const 0_u32)
|
||||
// CHECK: [[sum:_.*]] = AddWithOverflow(copy [[z]], copy [[z0]]);
|
||||
// CHECK: _0 = move ([[sum]].0: usize);
|
||||
|
||||
// CHECK: concrete::[[const_z1]]: usize
|
||||
// CHECK: [[z:_.*]] = offset_of::<Alpha>(const 0_u32, const 2_u32)
|
||||
// CHECK: [[z1:_.*]] = offset_of::<Beta>(const 0_u32, const 1_u32)
|
||||
// CHECK: [[sum:_.*]] = AddWithOverflow(copy [[z]], copy [[z1]]);
|
||||
// CHECK: _0 = move ([[sum]].0: usize);
|
||||
|
||||
// CHECK-LABEL: fn generic(
|
||||
fn generic<T>() {
|
||||
// CHECK: debug gx => [[gx:_.*]];
|
||||
// CHECK: debug gy => [[gy:_.*]];
|
||||
// CHECK: debug dx => [[dx:_.*]];
|
||||
// CHECK: debug dy => [[dy:_.*]];
|
||||
|
||||
// CHECK: [[gx]] = const generic::<T>::[[const_gx:.*]];
|
||||
let gx = offset_of!(Gamma<T>, x);
|
||||
|
||||
// CHECK: [[gy]] = const generic::<T>::[[const_gy:.*]];
|
||||
let gy = offset_of!(Gamma<T>, y);
|
||||
|
||||
// CHECK: [[dx]] = const generic::<T>::[[const_dx:.*]];
|
||||
let dx = offset_of!(Delta<T>, x);
|
||||
|
||||
// CHECK: [[dy]] = const generic::<T>::[[const_dy:.*]];
|
||||
let dy = offset_of!(Delta<T>, y);
|
||||
}
|
||||
|
||||
// CHECK: generic::[[const_gx]]: usize
|
||||
// CHECK: _0 = offset_of::<Gamma<T>>(const 0_u32, const 0_u32)
|
||||
|
||||
// CHECK: generic::[[const_gy]]: usize
|
||||
// CHECK: _0 = offset_of::<Gamma<T>>(const 0_u32, const 1_u32)
|
||||
|
||||
// CHECK: generic::[[const_dx]]: usize
|
||||
// CHECK: _0 = offset_of::<Delta<T>>(const 0_u32, const 1_u32)
|
||||
|
||||
// CHECK: generic::[[const_dy]]: usize
|
||||
// CHECK: _0 = offset_of::<Delta<T>>(const 0_u32, const 2_u32)
|
||||
|
||||
fn main() {
|
||||
concrete();
|
||||
generic::<()>();
|
||||
}
|
||||
|
|
@ -34,25 +34,25 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = const concrete::{constant#0};
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _2 = const concrete::{constant#1};
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _3 = const concrete::{constant#2};
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _4 = const concrete::{constant#3};
|
||||
+ _4 = const 3_usize;
|
||||
StorageLive(_5);
|
||||
- _5 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
- _5 = const concrete::{constant#4};
|
||||
+ _5 = const 1_usize;
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
- _6 = const concrete::{constant#5};
|
||||
+ _6 = const 2_usize;
|
||||
StorageLive(_7);
|
||||
- _7 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
- _7 = const concrete::{constant#6};
|
||||
+ _7 = const 4_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
|
|
|
|||
|
|
@ -34,25 +34,25 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = const concrete::{constant#0};
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _2 = const concrete::{constant#1};
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _3 = const concrete::{constant#2};
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _4 = const concrete::{constant#3};
|
||||
+ _4 = const 3_usize;
|
||||
StorageLive(_5);
|
||||
- _5 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
- _5 = const concrete::{constant#4};
|
||||
+ _5 = const 1_usize;
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
- _6 = const concrete::{constant#5};
|
||||
+ _6 = const 2_usize;
|
||||
StorageLive(_7);
|
||||
- _7 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
- _7 = const concrete::{constant#6};
|
||||
+ _7 = const 4_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
|
|
|
|||
|
|
@ -34,21 +34,21 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = const generic::<T>::{constant#0};
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_2 = const generic::<T>::{constant#1};
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _3 = const generic::<T>::{constant#2};
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _4 = const generic::<T>::{constant#3};
|
||||
+ _4 = const 2_usize;
|
||||
StorageLive(_5);
|
||||
_5 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
_5 = const generic::<T>::{constant#4};
|
||||
StorageLive(_6);
|
||||
_6 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
_6 = const generic::<T>::{constant#5};
|
||||
StorageLive(_7);
|
||||
_7 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_7 = const generic::<T>::{constant#6};
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
|
|
|
|||
|
|
@ -34,21 +34,21 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = const generic::<T>::{constant#0};
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_2 = const generic::<T>::{constant#1};
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _3 = const generic::<T>::{constant#2};
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _4 = const generic::<T>::{constant#3};
|
||||
+ _4 = const 2_usize;
|
||||
StorageLive(_5);
|
||||
_5 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
_5 = const generic::<T>::{constant#4};
|
||||
StorageLive(_6);
|
||||
_6 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
_6 = const generic::<T>::{constant#5};
|
||||
StorageLive(_7);
|
||||
_7 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_7 = const generic::<T>::{constant#6};
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
- // MIR for `concrete` before DataflowConstProp
|
||||
+ // MIR for `concrete` after DataflowConstProp
|
||||
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
- // MIR for `concrete` before DataflowConstProp
|
||||
+ // MIR for `concrete` after DataflowConstProp
|
||||
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
- // MIR for `generic` before DataflowConstProp
|
||||
+ // MIR for `generic` after DataflowConstProp
|
||||
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
- // MIR for `generic` before DataflowConstProp
|
||||
+ // MIR for `generic` after DataflowConstProp
|
||||
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
//@ test-mir-pass: DataflowConstProp
|
||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::offset_of;
|
||||
|
||||
struct Alpha {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: Beta,
|
||||
}
|
||||
|
||||
struct Beta(u8, u8);
|
||||
|
||||
struct Gamma<T> {
|
||||
x: u8,
|
||||
y: u16,
|
||||
_t: T,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Delta<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
x: u8,
|
||||
y: u16,
|
||||
}
|
||||
|
||||
// EMIT_MIR offset_of.concrete.DataflowConstProp.diff
|
||||
|
||||
// CHECK-LABEL: fn concrete(
|
||||
fn concrete() {
|
||||
// CHECK: debug x => [[x:_.*]];
|
||||
// CHECK: debug y => [[y:_.*]];
|
||||
// CHECK: debug z0 => [[z0:_.*]];
|
||||
// CHECK: debug z1 => [[z1:_.*]];
|
||||
|
||||
// CHECK: [[x]] = const 4_usize
|
||||
let x = offset_of!(Alpha, x);
|
||||
|
||||
// CHECK: [[y]] = const 0_usize
|
||||
let y = offset_of!(Alpha, y);
|
||||
|
||||
// CHECK: [[z0]] = const 2_usize
|
||||
let z0 = offset_of!(Alpha, z.0);
|
||||
|
||||
// CHECK: [[z1]] = const 3_usize
|
||||
let z1 = offset_of!(Alpha, z.1);
|
||||
}
|
||||
|
||||
// EMIT_MIR offset_of.generic.DataflowConstProp.diff
|
||||
|
||||
// CHECK-LABEL: fn generic(
|
||||
fn generic<T>() {
|
||||
// CHECK: debug gx => [[gx:_.*]];
|
||||
// CHECK: debug gy => [[gy:_.*]];
|
||||
// CHECK: debug dx => [[dx:_.*]];
|
||||
// CHECK: debug dy => [[dy:_.*]];
|
||||
|
||||
// CHECK: [[gx]] = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
let gx = offset_of!(Gamma<T>, x);
|
||||
|
||||
// CHECK: [[gy]] = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
let gy = offset_of!(Gamma<T>, y);
|
||||
|
||||
// CHECK: [[dx]] = const 0_usize
|
||||
let dx = offset_of!(Delta<T>, x);
|
||||
|
||||
// CHECK: [[dy]] = const 2_usize
|
||||
let dy = offset_of!(Delta<T>, y);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
concrete();
|
||||
generic::<()>();
|
||||
}
|
||||
23
tests/ui/offset-of/inside-array-length.rs
Normal file
23
tests/ui/offset-of/inside-array-length.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//! Regression test for ICEs #123959, #125680, #129425 and #136175.
|
||||
//@ edition:2021
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
trait Trait {}
|
||||
|
||||
fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
//~^ ERROR overly complex generic constant
|
||||
//~| ERROR cycle detected when evaluating type-level constant
|
||||
|
||||
struct Inline<T>
|
||||
//~^ ERROR type parameter `T` is never used
|
||||
where
|
||||
[(); std::mem::offset_of!((T,), 0)]:,
|
||||
//~^ ERROR overly complex generic constant
|
||||
{}
|
||||
|
||||
fn main() {
|
||||
let dst: Inline<dyn Trait>;
|
||||
//~^ ERROR the size for values of type `dyn Trait` cannot be known at compilation time
|
||||
}
|
||||
90
tests/ui/offset-of/inside-array-length.stderr
Normal file
90
tests/ui/offset-of/inside-array-length.stderr
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
error: overly complex generic constant
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
= note: this operation may be supported in the future
|
||||
= note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0392]: type parameter `T` is never used
|
||||
--> $DIR/inside-array-length.rs:13:15
|
||||
|
|
||||
LL | struct Inline<T>
|
||||
| ^ unused type parameter
|
||||
|
|
||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/inside-array-length.rs:16:10
|
||||
|
|
||||
LL | [(); std::mem::offset_of!((T,), 0)]:,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
= note: this operation may be supported in the future
|
||||
= note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0391]: cycle detected when evaluating type-level constant
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires const-evaluating + checking `foo::{constant#0}`...
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires caching mir of `foo::{constant#0}` for CTFE...
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires elaborating drops for `foo::{constant#0}`...
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires borrow-checking `foo::{constant#0}`...
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires normalizing `Binder { value: ConstEvaluatable(UnevaluatedConst { def: DefId(0:7 ~ inside_array_length[07d6]::foo::{constant#0}), args: ['^c_1, T/#1] }), bound_vars: [] }`...
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: ...which again requires evaluating type-level constant, completing the cycle
|
||||
note: cycle used when normalizing `inside_array_length::::foo::{constant#0}`
|
||||
--> $DIR/inside-array-length.rs:9:27
|
||||
|
|
||||
LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
= note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
|
||||
--> $DIR/inside-array-length.rs:21:14
|
||||
|
|
||||
LL | let dst: Inline<dyn Trait>;
|
||||
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
note: required by an implicit `Sized` bound in `Inline`
|
||||
--> $DIR/inside-array-length.rs:13:15
|
||||
|
|
||||
LL | struct Inline<T>
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `Inline`
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | struct Inline<T: ?Sized>
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0391, E0392.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
@ -41,9 +41,6 @@ LL | let _: isize = offset_of!(S, v);
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/offset-of-output-type.rs:17:5
|
||||
|
|
||||
LL | fn main() {
|
||||
| - expected `()` because of default return type
|
||||
...
|
||||
LL | offset_of!(S, v)
|
||||
| ^^^^^^^^^^^^^^^^ expected `()`, found `usize`
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,13 +2,52 @@
|
|||
// regression test for #112051, not in `offset-of-dst` as the issue is in codegen,
|
||||
// and isn't triggered in the presence of typeck errors
|
||||
|
||||
#![feature(extern_types)]
|
||||
|
||||
use std::mem::offset_of;
|
||||
|
||||
#[repr(C)]
|
||||
struct Alpha {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: [u8],
|
||||
}
|
||||
|
||||
trait Trait {}
|
||||
|
||||
#[repr(C)]
|
||||
struct Beta {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: dyn Trait,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Gamma {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: Extern,
|
||||
}
|
||||
|
||||
struct S<T: ?Sized> {
|
||||
a: u64,
|
||||
b: T,
|
||||
}
|
||||
trait Tr {}
|
||||
|
||||
fn main() {
|
||||
let _a = core::mem::offset_of!(S<dyn Tr>, a);
|
||||
let _b = core::mem::offset_of!((u64, dyn Tr), 0);
|
||||
let _ = offset_of!(Alpha, x);
|
||||
let _ = offset_of!(Alpha, y);
|
||||
|
||||
let _ = offset_of!(Beta, x);
|
||||
let _ = offset_of!(Beta, y);
|
||||
|
||||
let _ = offset_of!(Gamma, x);
|
||||
let _ = offset_of!(Gamma, y);
|
||||
|
||||
let _ = offset_of!(S<dyn Trait>, a);
|
||||
let _ = offset_of!((u64, dyn Trait), 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ mod expressions {
|
|||
|
||||
|
||||
|
||||
{ builtin # offset_of(T, field) };
|
||||
const { builtin # offset_of(T, field) };
|
||||
}
|
||||
/// ExprKind::MacCall
|
||||
fn expr_mac_call() { "..."; "..."; "..."; }
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ mod expressions {
|
|||
|
||||
|
||||
|
||||
{ offset_of!(T, field) };
|
||||
const { offset_of!(T, field) };
|
||||
}
|
||||
/// ExprKind::MacCall
|
||||
fn expr_mac_call() { "..."; "..."; "..."; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue