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:
commit
80a2ec49a4
83 changed files with 1355 additions and 42 deletions
|
@ -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))
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]),
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue