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
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3470,6 +3470,7 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"serde",
"tracing",
]

Expand Down Expand Up @@ -4334,6 +4335,7 @@ dependencies = [
"rustc_target",
"rustc_thread_pool",
"rustc_type_ir",
"serde",
"smallvec",
"thin-vec",
"tracing",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_serialize = { path = "../rustc_serialize", optional = true }
rustc_span = { path = "../rustc_span", optional = true }
serde = { version = "1.0.125", features = ["derive"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is okay, but I need this in order for FieldId (which contains FieldIdx and VariantIdx) to implement serde::Serialize. This is because FieldId is needed in RigidTy, which derives serde::Serialize.

tracing = "0.1"
# tidy-alphabetical-end

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ rustc_index::newtype_index! {
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
#[derive(HashStable_Generic)]
#[derive(HashStable_Generic, serde::Serialize)]
#[encodable]
#[orderable]
pub struct FieldIdx {}
Expand All @@ -57,7 +57,7 @@ rustc_index::newtype_index! {
///
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
/// with variant index zero, aka [`FIRST_VARIANT`].
#[derive(HashStable_Generic)]
#[derive(HashStable_Generic, serde::Serialize)]
#[encodable]
#[orderable]
pub struct VariantIdx {
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 @@ -2555,6 +2555,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>, Vec<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
17 changes: 17 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Pat(ty, pat) => {
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
}
TyKind::FieldOf(ty, fields) => match fields.len() {
0 => span_bug!(ty.span, "expected at least one field ident parsed in `field_of!`"),
1 => hir::TyKind::FieldOf(
self.lower_ty(ty, itctx),
None,
self.lower_ident(fields[0]),
),
2 => hir::TyKind::FieldOf(
self.lower_ty(ty, itctx),
Some(self.lower_ident(fields[0])),
self.lower_ident(fields[1]),
),
_ => hir::TyKind::Err(self.dcx().span_err(
fields.iter().map(|f| f.span).collect::<Vec<_>>(),
"`field_of!` only supports a single field or a variant with a field",
)),
},
TyKind::MacCall(_) => {
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
}
Expand Down
19 changes: 19 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,25 @@ impl<'a> State<'a> {
self.word(" is ");
self.print_ty_pat(pat);
}
ast::TyKind::FieldOf(ty, fields) => {
self.word("builtin # field_of");
self.popen();
let ib = self.ibox(0);
self.print_type(ty);
self.word(",");
self.space();

if let Some((&first, rest)) = fields.split_first() {
self.print_ident(first);

for &field in rest {
self.word(".");
self.print_ident(field);
}
}
self.end(ib);
self.pclose();
}
}
self.end(ib);
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::FRT(..)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(..)
Expand Down Expand Up @@ -1919,6 +1920,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::FRT(..)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ fn push_debuginfo_type_name<'tcx>(
write!(output, "{:?}", t).unwrap();
}
}
// TODO(FRTs): implement debuginfo for field representing types
ty::FRT(..) => todo!(),
ty::Slice(inner_type) => {
if cpp_like_debuginfo {
output.push_str("slice2$<");
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fn const_to_valtree_inner<'tcx>(
}

match ty.kind() {
ty::FnDef(..) => {
ty::FnDef(..) | ty::FRT(..) => {
*num_nodes += 1;
Ok(ty::ValTree::zst(tcx))
}
Expand Down Expand Up @@ -273,7 +273,7 @@ pub fn valtree_to_const_value<'tcx>(
// create inner `MPlace`s which are filled recursively.
// FIXME: Does this need an example?
match *cv.ty.kind() {
ty::FnDef(..) => {
ty::FnDef(..) | ty::FRT(..) => {
assert!(cv.valtree.is_zst());
mir::ConstValue::ZeroSized
}
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,7 @@ 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, TypeFoldable};
use rustc_middle::ty::{FieldId, FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::{Symbol, sym};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
Expand Down Expand Up @@ -222,6 +222,33 @@ 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, field) = match frt_ty.kind() {
&ty::FRT(ty, field) => (ty, field),
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 FieldId::Resolved { variant, field } = field else {
span_bug!(
self.cur_span(),
"expected resolved field representing type, got `field_of!({ty}, {field:?})`"
)
};
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 Expand Up @@ -305,6 +332,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
| ty::UnsafeBinder(_)
| ty::Never
| ty::Tuple(_)
| ty::FRT(..)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
};
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
| ty::FRT(..)
| ty::Error(_) => true,

ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
| ty::Dynamic(..)
| ty::Closure(..)
| ty::Pat(..)
| ty::FRT(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => interp_ok(false),
// Some types only occur during typechecking, they have no layout.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/util/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
| ty::Float(_)
| ty::Str
| ty::Pat(_, _)
| ty::FRT(..)
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,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)),
/// Controlling the behavior of fmt::Debug
(unstable, fmt_debug, "1.82.0", Some(129709)),
/// Allows using `#[align(...)]` on function items
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3755,6 +3755,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>, Option<Ident>, Ident),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
///
Expand Down Expand Up @@ -5051,8 +5055,8 @@ mod size_asserts {
static_assert_size!(TraitImplHeader<'_>, 48);
static_assert_size!(TraitItem<'_>, 88);
static_assert_size!(TraitItemKind<'_>, 48);
static_assert_size!(Ty<'_>, 48);
static_assert_size!(TyKind<'_>, 32);
static_assert_size!(Ty<'_>, 56);
static_assert_size!(TyKind<'_>, 40);
Comment on lines -5054 to +5059
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is fine, let me know if there is a better solution.

// tidy-alphabetical-end
}

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, 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
6 changes: 6 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,12 @@ 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 projection related lang-items
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 @@ -116,6 +116,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 @@ -292,6 +293,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
11 changes: 11 additions & 0 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,17 @@ pub(super) fn check_item<'tcx>(
.with_span_label(sp, "auto trait")
.emit());
}
if is_auto && let rustc_hir::TyKind::FieldOf(..) = impl_.self_ty.kind {
res = res.and(Err(tcx
.dcx()
.struct_span_err(
item.span,
"impls of auto traits for field representing types not supported",
)
.with_span_label(impl_.self_ty.span, "field representing type")
.with_span_label(of_trait.trait_ref.path.span, "auto trait")
.emit()));
}
Comment on lines +264 to +274
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels pretty hacky, but I copied this from the previous version.

match header.polarity {
ty::ImplPolarity::Positive => {
res = res.and(check_impl(tcx, item, impl_));
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ impl<'tcx> InherentCollect<'tcx> {
while let ty::Pat(base, _) = *self_ty.kind() {
self_ty = base;
}
// TODO(FRTs): make properly recursive with pattern types as well
while let ty::FRT(ty, _) = *self_ty.kind() {
self_ty = ty;
}
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
Expand All @@ -173,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> {
ty::Dynamic(..) => {
Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
}
ty::Pat(_, _) => unreachable!(),
ty::Pat(_, _) | ty::FRT(..) => unreachable!(),
ty::Bool
| ty::Char
| ty::Int(_)
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ pub(crate) fn orphan_check_impl(
);

if tcx.trait_is_auto(trait_def_id) {
let self_ty = trait_ref.self_ty();
let mut self_ty = trait_ref.self_ty();
if let ty::FRT(ty, _) = self_ty.kind() {
self_ty = *ty;
}

// If the impl is in the same crate as the auto-trait, almost anything
// goes.
Expand Down Expand Up @@ -233,6 +236,7 @@ pub(crate) fn orphan_check_impl(
let sp = tcx.def_span(impl_def_id);
span_bug!(sp, "weird self type for autotrait impl")
}
ty::FRT(..) => unreachable!("handled above"),

ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
};
Expand Down
Loading
Loading