offset_of
This commit is contained in:
parent
b92a41c676
commit
511e457c4b
71 changed files with 841 additions and 38 deletions
|
@ -280,10 +280,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.write_immediate(*val, &dest)?;
|
||||
}
|
||||
|
||||
NullaryOp(null_op, ty) => {
|
||||
NullaryOp(ref null_op, ty) => {
|
||||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
|
||||
let layout = self.layout_of(ty)?;
|
||||
if layout.is_unsized() {
|
||||
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
|
||||
// FIXME: This should be a span_bug (#80742)
|
||||
self.tcx.sess.delay_span_bug(
|
||||
self.frame().current_span(),
|
||||
|
@ -294,6 +294,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let val = match null_op {
|
||||
mir::NullOp::SizeOf => layout.size.bytes(),
|
||||
mir::NullOp::AlignOf => layout.align.abi.bytes(),
|
||||
mir::NullOp::OffsetOf(fields) => {
|
||||
layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes()
|
||||
}
|
||||
};
|
||||
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
|
||||
}
|
||||
|
|
|
@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
Rvalue::Cast(_, _, _) => {}
|
||||
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {}
|
||||
Rvalue::ShallowInitBox(_, _) => {}
|
||||
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
|
|
|
@ -514,6 +514,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
Rvalue::NullaryOp(op, _) => match op {
|
||||
NullOp::SizeOf => {}
|
||||
NullOp::AlignOf => {}
|
||||
NullOp::OffsetOf(_) => {}
|
||||
},
|
||||
|
||||
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
|
||||
|
|
|
@ -8,9 +8,10 @@ use rustc_middle::mir::interpret::Scalar;
|
|||
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{
|
||||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
|
||||
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
||||
TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
|
||||
MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
|
||||
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
|
||||
START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
|
@ -711,10 +712,54 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => {
|
||||
let fail_out_of_bounds = |this: &Self, location, field, ty| {
|
||||
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
|
||||
};
|
||||
|
||||
let mut current_ty = *container;
|
||||
|
||||
for &field in fields {
|
||||
match current_ty.kind() {
|
||||
ty::Tuple(fields) => {
|
||||
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.param_env, f_ty);
|
||||
}
|
||||
ty::Adt(adt_def, substs) => {
|
||||
if adt_def.is_enum() {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot get field offset from enum {current_ty:?}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
|
||||
fail_out_of_bounds(self, location, field, current_ty);
|
||||
return;
|
||||
};
|
||||
|
||||
let f_ty = field.ty(self.tcx, substs);
|
||||
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
|
||||
}
|
||||
_ => {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot get field offset from non-adt type {current_ty:?}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Repeat(_, _)
|
||||
| Rvalue::ThreadLocalRef(_)
|
||||
| Rvalue::AddressOf(_, _)
|
||||
| Rvalue::NullaryOp(_, _)
|
||||
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
|
||||
| Rvalue::Discriminant(_) => {}
|
||||
}
|
||||
self.super_rvalue(rvalue, location);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue