1
Fork 0

Auto merge of #106934 - DrMeepster:offset_of, r=WaffleLapkin

Add offset_of! macro (RFC 3308)

Implements https://github.com/rust-lang/rfcs/pull/3308 (tracking issue #106655) by adding the built in macro `core::mem::offset_of`. Two of the future possibilities are also implemented:

* Nested field accesses (without array indexing)
* DST support (for `Sized` fields)

I wrote this a few months ago, before the RFC merged. Now that it's merged, I decided to rebase and finish it.

cc `@thomcc` (RFC author)
This commit is contained in:
bors 2023-04-22 00:10:44 +00:00
commit 80a2ec49a4
83 changed files with 1355 additions and 42 deletions

View file

@ -2041,7 +2041,11 @@ impl<'tcx> Debug for Rvalue<'tcx> {
}
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
Discriminant(ref place) => write!(fmt, "discriminant({:?})", place),
NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t),
NullaryOp(ref op, ref t) => match op {
NullOp::SizeOf => write!(fmt, "SizeOf({:?})", t),
NullOp::AlignOf => write!(fmt, "AlignOf({:?})", t),
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({:?}, {:?})", t, fields),
},
ThreadLocalRef(did) => ty::tls::with(|tcx| {
let muta = tcx.static_mutability(did).unwrap().prefix_str();
write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))

View file

@ -1115,7 +1115,7 @@ pub enum Rvalue<'tcx> {
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
/// Computes a value as described by the operation.
NullaryOp(NullOp, Ty<'tcx>),
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
/// Exactly like `BinaryOp`, but less operands.
///
@ -1211,12 +1211,14 @@ pub enum AggregateKind<'tcx> {
Generator(DefId, SubstsRef<'tcx>, hir::Movability),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum NullOp {
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum NullOp<'tcx> {
/// Returns the size of a value of that type
SizeOf,
/// Returns the minimum alignment of a type
AlignOf,
/// Returns the offset of a field
OffsetOf(&'tcx List<FieldIdx>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]

View file

@ -188,7 +188,9 @@ impl<'tcx> Rvalue<'tcx> {
}
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
tcx.types.usize
}
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
AggregateKind::Tuple => {

View file

@ -16,7 +16,6 @@ TrivialTypeTraversalAndLiftImpls! {
UserTypeAnnotationIndex,
BorrowKind,
CastKind,
NullOp,
hir::Movability,
BasicBlock,
SwitchTargets,
@ -26,6 +25,7 @@ TrivialTypeTraversalAndLiftImpls! {
TrivialTypeTraversalImpls! {
ConstValue<'tcx>,
NullOp<'tcx>,
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] {

View file

@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts};
use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarSubsts};
use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@ -481,6 +481,11 @@ pub enum ExprKind<'tcx> {
},
/// Inline assembly, i.e. `asm!()`.
InlineAsm(Box<InlineAsmExpr<'tcx>>),
/// Field offset (`offset_of!`)
OffsetOf {
container: Ty<'tcx>,
fields: &'tcx List<FieldIdx>,
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
/// A `yield` expression.

View file

@ -160,6 +160,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
}
}
}
OffsetOf { container: _, fields: _ } => {}
ThreadLocalRef(_) => {}
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
}

View file

@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::Span;
use rustc_target::abi::FieldIdx;
pub use rustc_type_ir::{TyDecoder, TyEncoder};
use std::hash::Hash;
use std::intrinsics;
@ -401,6 +402,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<FieldIdx> {
fn decode(decoder: &mut D) -> &'tcx Self {
let len = decoder.read_usize();
decoder
.interner()
.mk_fields_from_iter((0..len).map::<FieldIdx, _>(|_| Decodable::decode(decoder)))
}
}
impl_decodable_via_ref! {
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
@ -412,6 +422,7 @@ impl_decodable_via_ref! {
&'tcx mir::coverage::CodeRegion,
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Predicate<'tcx>>,
&'tcx ty::List<FieldIdx>,
}
#[macro_export]

View file

@ -155,6 +155,7 @@ pub struct CtxtInterners<'tcx> {
layout: InternedSet<'tcx, LayoutS>,
adt_def: InternedSet<'tcx, AdtDefData>,
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
fields: InternedSet<'tcx, List<FieldIdx>>,
}
impl<'tcx> CtxtInterners<'tcx> {
@ -178,6 +179,7 @@ impl<'tcx> CtxtInterners<'tcx> {
layout: Default::default(),
adt_def: Default::default(),
external_constraints: Default::default(),
fields: Default::default(),
}
}
@ -1571,6 +1573,7 @@ slice_interners!(
projs: pub mk_projs(ProjectionKind),
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
fields: pub mk_fields(FieldIdx),
);
impl<'tcx> TyCtxt<'tcx> {
@ -2239,6 +2242,14 @@ impl<'tcx> TyCtxt<'tcx> {
T::collect_and_apply(iter, |xs| self.mk_place_elems(xs))
}
pub fn mk_fields_from_iter<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<FieldIdx, &'tcx List<FieldIdx>>,
{
T::collect_and_apply(iter, |xs| self.mk_fields(xs))
}
pub fn mk_substs_trait(
self,
self_ty: Ty<'tcx>,

View file

@ -208,6 +208,9 @@ pub struct TypeckResults<'tcx> {
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
/// on closure size.
pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
/// Container types and field indices of `offset_of!` expressions
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
}
/// Whenever a value may be live across a generator yield, the type of that value winds up in the
@ -280,6 +283,7 @@ impl<'tcx> TypeckResults<'tcx> {
generator_interior_predicates: Default::default(),
treat_byte_string_as_slice: Default::default(),
closure_size_eval: Default::default(),
offset_of_data: Default::default(),
}
}
@ -530,6 +534,14 @@ impl<'tcx> TypeckResults<'tcx> {
pub fn coercion_casts(&self) -> &ItemLocalSet {
&self.coercion_casts
}
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data }
}
pub fn offset_of_data_mut(&mut self) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
}
}
/// Validate that the given HirId (respectively its `local_id` part) can be