Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4749,6 +4749,7 @@ dependencies = [
"ena",
"indexmap",
"rustc-hash 2.1.1",
"rustc_abi",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_error_messages",
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2553,6 +2553,11 @@ pub enum TyKind {
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`,
/// just as part of the type system.
Pat(Box<Ty>, Box<TyPat>),
/// A `field_of` expression (e.g., `builtin # field_of(Struct, field)`).
///
/// Usually not written directly in user code but indirectly via the macro
/// `core::field::field_of!(...)`.
FieldOf(Box<Ty>, Option<Ident>, Ident),
/// Sometimes we need a dummy value when no error has occurred.
Dummy,
/// Placeholder for a kind that has failed to be defined.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
| ast::TyKind::ImplicitSelf
| ast::TyKind::CVarArgs
| ast::TyKind::Pat(..)
| ast::TyKind::FieldOf(..)
| ast::TyKind::Dummy
| ast::TyKind::Err(..) => break None,
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Pat(ty, pat) => {
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
}
TyKind::FieldOf(ty, variant, field) => hir::TyKind::FieldOf(
self.lower_ty_alloc(ty, itctx),
self.arena.alloc(hir::TyFieldPath {
variant: variant.map(|variant| self.lower_ident(variant)),
field: self.lower_ident(*field),
}),
),
TyKind::MacCall(_) => {
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
}
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,23 @@ impl<'a> State<'a> {
self.word(" is ");
self.print_ty_pat(pat);
}
ast::TyKind::FieldOf(ty, variant, field) => {
self.word("builtin # field_of");
self.popen();
let ib = self.ibox(0);
self.print_type(ty);
self.word(",");
self.space();

if let Some(variant) = variant {
self.print_ident(*variant);
self.word(".");
}
self.print_ident(*field);

self.end(ib);
self.pclose();
}
}
self.end(ib);
}
Expand Down
30 changes: 29 additions & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{
FieldInfo, FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt,
};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::{Symbol, sym};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
Expand Down Expand Up @@ -227,6 +229,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

self.write_scalar(Scalar::from_target_usize(offset, self), dest)?;
}
sym::field_offset => {
let frt_ty = instance.args.type_at(0);

let (ty, variant, field) = match frt_ty.kind() {
ty::Adt(def, args)
if let Some(FieldInfo { base, variant_idx, field_idx, .. }) =
def.field_representing_type_info(tcx, args) =>
{
(base, variant_idx, field_idx)
}
ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) | ty::Infer(..) => {
// This can happen in code which is generic over the field type.
throw_inval!(TooGeneric)
}
_ => {
span_bug!(self.cur_span(), "expected field representing type, got {frt_ty}")
}
};
let layout = self.layout_of(ty)?;
let cx = ty::layout::LayoutCx::new(*self.tcx, self.typing_env);

let layout = layout.for_variant(&cx, variant);
let offset = layout.fields.offset(field.index()).bytes();

self.write_scalar(Scalar::from_target_usize(offset, self), dest)?;
}
sym::vtable_for => {
let tp_ty = instance.args.type_at(0);
let result_ty = instance.args.type_at(1);
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ declare_features! (
(internal, custom_mir, "1.65.0", None),
/// Implementation details of externally implementable items
(internal, eii_internals, "1.94.0", None),
/// Implementation details of field representing types.
(internal, field_representing_type_raw, "CURRENT_RUSTC_VERSION", None),
/// Outputs useful `assert!` messages
(unstable, generic_assert, "1.63.0", None),
/// Allows using the #[rustc_intrinsic] attribute.
Expand Down Expand Up @@ -492,6 +494,8 @@ declare_features! (
(unstable, ffi_const, "1.45.0", Some(58328)),
/// Allows the use of `#[ffi_pure]` on foreign functions.
(unstable, ffi_pure, "1.45.0", Some(58329)),
/// Experimental field projections.
(incomplete, field_projections, "CURRENT_RUSTC_VERSION", Some(145383)),
/// Allows marking trait functions as `final` to prevent overriding impls
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
/// Controlling the behavior of fmt::Debug
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,12 @@ impl<'hir> Block<'hir> {
}
}

#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TyFieldPath {
pub variant: Option<Ident>,
pub field: Ident,
}

#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TyPat<'hir> {
#[stable_hasher(ignore)]
Expand Down Expand Up @@ -3800,6 +3806,10 @@ pub enum TyKind<'hir, Unambig = ()> {
Err(rustc_span::ErrorGuaranteed),
/// Pattern types (`pattern_type!(u32 is 1..)`)
Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>),
/// Field representing type (`field_of!(Struct, field)`).
///
/// The optional ident is the variant when an enum is passed `field_of!(Enum, Variant.field)`.
FieldOf(&'hir Ty<'hir>, &'hir TyFieldPath),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,13 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -
try_visit!(visitor.visit_ty_unambig(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
TyKind::FieldOf(ty, TyFieldPath { variant, field }) => {
try_visit!(visitor.visit_ty_unambig(ty));
if let Some(variant) = *variant {
try_visit!(visitor.visit_ident(variant));
}
try_visit!(visitor.visit_ident(*field));
}
}
V::Result::output()
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,13 @@ language_item_table! {
// Reborrowing related lang-items
Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0);
CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0);

// Field representing types.
FieldRepresentingType, sym::field_representing_type, field_representing_type, Target::Struct, GenericRequirement::Exact(3);
Field, sym::field, field, Target::Trait, GenericRequirement::Exact(0);
FieldBase, sym::field_base, field_base, Target::AssocTy, GenericRequirement::Exact(0);
FieldType, sym::field_type, field_type, Target::AssocTy, GenericRequirement::Exact(0);
FieldOffset, sym::field_offset, field_offset, Target::AssocConst, GenericRequirement::Exact(0);
}

/// The requirement imposed on the generics of a lang item
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::fabsf128
| sym::fadd_algebraic
| sym::fdiv_algebraic
| sym::field_offset
| sym::floorf16
| sym::floorf32
| sym::floorf64
Expand Down Expand Up @@ -297,6 +298,7 @@ pub(crate) fn check_intrinsic_type(
(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::field_offset => (1, 0, vec![], 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 => {
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,15 @@ pub struct NoVariantNamed<'tcx> {
pub ty: Ty<'tcx>,
}

#[derive(Diagnostic)]
#[diag("no field `{$field}` on type `{$ty}`", code = E0609)]
pub struct NoFieldOnType<'tcx> {
#[primary_span]
pub span: Span,
pub ty: Ty<'tcx>,
pub field: Ident,
}

// FIXME(fmease): Deduplicate:

#[derive(Diagnostic)]
Expand Down
Loading
Loading