diff --git a/Cargo.lock b/Cargo.lock
index 1a930b64f4581..40349ea4dee34 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5561,7 +5561,6 @@ dependencies = [
"build_helper",
"cargo_metadata 0.21.0",
"clap",
- "fluent-syntax",
"globset",
"ignore",
"miropt-test-tools",
diff --git a/RELEASES.md b/RELEASES.md
index 424e12ceec054..615146eddc92a 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,12 @@
+Version 1.93.1 (2026-02-12)
+===========================
+
+
+
+- [Don't try to recover keyword as non-keyword identifier](https://github.com/rust-lang/rust/pull/150590), fixing an ICE that especially [affected rustfmt](https://github.com/rust-lang/rustfmt/issues/6739).
+- [Fix `clippy::panicking_unwrap` false-positive on field access with implicit deref](https://github.com/rust-lang/rust-clippy/pull/16196).
+- [Revert "Update wasm-related dependencies in CI"](https://github.com/rust-lang/rust/pull/152259), fixing file descriptor leaks on the `wasm32-wasip2` target.
+
Version 1.93.0 (2026-01-22)
==========================
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 061ad8617893c..85f31b75e240a 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,6 +1,6 @@
// tidy-alphabetical-start
+#![cfg_attr(all(feature = "nightly", bootstrap), feature(assert_matches))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
-#![cfg_attr(feature = "nightly", feature(assert_matches))]
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
#![cfg_attr(feature = "nightly", feature(step_trait))]
// tidy-alphabetical-end
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index e01377d247bb6..c055c2936e953 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,4 +1,5 @@
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
+use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
use super::prelude::*;
use super::util::parse_version;
@@ -143,6 +144,8 @@ impl SingleAttributeParser for DeprecationParser {
DeprecatedSince::Future
} else if !is_rustc {
DeprecatedSince::NonStandard(since)
+ } else if since.as_str() == VERSION_PLACEHOLDER {
+ DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
} else if let Some(version) = parse_version(since) {
DeprecatedSince::RustcVersion(version)
} else {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 853ecd3c91f79..96090e85e5622 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -354,14 +354,71 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
{
if snippet.starts_with("&mut ") {
- // We don't have access to the HIR to get accurate spans, but we can
- // give a best effort structured suggestion.
- err.span_suggestion_verbose(
- source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
- "if there is only one mutable reborrow, remove the `&mut`",
- "",
- Applicability::MaybeIncorrect,
- );
+ // In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and
+ // removing the extra `&mut` is the most direct suggestion. But for
+ // pattern-matching expressions (`match`, `if let`, `while let`), that
+ // can easily turn into a move, so prefer suggesting an explicit
+ // reborrow via `&mut *x` instead.
+ let mut in_pat_scrutinee = false;
+ let mut is_deref_coerced = false;
+ if let Some(expr) = self.find_expr(source_info.span) {
+ let tcx = self.infcx.tcx;
+ let span = expr.span.source_callsite();
+ for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
+ if let Node::Expr(parent_expr) = node {
+ match parent_expr.kind {
+ ExprKind::Match(scrutinee, ..)
+ if scrutinee
+ .span
+ .source_callsite()
+ .contains(span) =>
+ {
+ in_pat_scrutinee = true;
+ break;
+ }
+ ExprKind::Let(let_expr)
+ if let_expr
+ .init
+ .span
+ .source_callsite()
+ .contains(span) =>
+ {
+ in_pat_scrutinee = true;
+ break;
+ }
+ _ => {}
+ }
+ }
+ }
+
+ let typeck = tcx.typeck(expr.hir_id.owner.def_id);
+ is_deref_coerced =
+ typeck.expr_adjustments(expr).iter().any(|adj| {
+ matches!(adj.kind, ty::adjustment::Adjust::Deref(_))
+ });
+ }
+
+ if in_pat_scrutinee {
+ // Best-effort structured suggestion: insert `*` after `&mut `.
+ err.span_suggestion_verbose(
+ source_info
+ .span
+ .with_lo(source_info.span.lo() + BytePos(5))
+ .shrink_to_lo(),
+ "to reborrow the mutable reference, add `*`",
+ "*",
+ Applicability::MaybeIncorrect,
+ );
+ } else if is_deref_coerced {
+ // We don't have access to the HIR to get accurate spans, but we
+ // can give a best effort structured suggestion.
+ err.span_suggestion_verbose(
+ source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
+ "if there is only one mutable reborrow, remove the `&mut`",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
} else {
// This can occur with things like `(&mut self).foo()`.
err.span_help(source_info.span, "try removing `&mut` here");
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 38b73a07a6891..1f0fde11b8d87 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,7 +2,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(default_field_values)]
#![feature(file_buffered)]
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 8ac15ceb4bbe1..08da5935bbeab 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -3,7 +3,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index bf3ec1f393302..347d7e1e6f488 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -5,7 +5,7 @@
//! This API is completely unstable and subject to change.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(extern_types)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e3934065b0f7f..cbfa12e21ebac 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,5 +1,5 @@
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs
index f8881f0968bb4..0fd70d784d4fb 100644
--- a/compiler/rustc_const_eval/src/const_eval/type_info.rs
+++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs
@@ -1,4 +1,8 @@
-use rustc_abi::FieldIdx;
+mod adt;
+
+use std::borrow::Cow;
+
+use rustc_abi::{FieldIdx, VariantIdx};
use rustc_ast::Mutability;
use rustc_hir::LangItem;
use rustc_middle::span_bug;
@@ -8,11 +12,58 @@ use rustc_span::{Symbol, sym};
use crate::const_eval::CompileTimeMachine;
use crate::interpret::{
- CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
- interp_ok,
+ CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar,
+ Writeable, interp_ok,
};
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
+ /// Equivalent to `project_downcast`, but identifies the variant by name instead of index.
+ fn downcast<'a>(
+ &self,
+ place: &(impl Writeable<'tcx, CtfeProvenance> + 'a),
+ name: Symbol,
+ ) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> {
+ let variants = place.layout().ty.ty_adt_def().unwrap().variants();
+ let variant_idx = variants
+ .iter_enumerated()
+ .find(|(_idx, var)| var.name == name)
+ .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
+ .0;
+
+ interp_ok((variant_idx, self.project_downcast(place, variant_idx)?))
+ }
+
+ // A general method to write an array to a static slice place.
+ fn allocate_fill_and_write_slice_ptr(
+ &mut self,
+ slice_place: impl Writeable<'tcx, CtfeProvenance>,
+ len: u64,
+ writer: impl Fn(&mut Self, /* index */ u64, MPlaceTy<'tcx>) -> InterpResult<'tcx>,
+ ) -> InterpResult<'tcx> {
+ // Array element type
+ let field_ty = slice_place
+ .layout()
+ .ty
+ .builtin_deref(false)
+ .unwrap()
+ .sequence_element_type(self.tcx.tcx);
+
+ // Allocate an array
+ let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, field_ty, len))?;
+ let array_place = self.allocate(array_layout, MemoryKind::Stack)?;
+
+ // Fill the array fields
+ let mut field_places = self.project_array_fields(&array_place)?;
+ while let Some((i, place)) = field_places.next(self)? {
+ writer(self, i, place)?;
+ }
+
+ // Write the slice pointing to the array
+ let array_place = array_place.map_provenance(CtfeProvenance::as_immutable);
+ let ptr = Immediate::new_slice(array_place.ptr(), len, self);
+ self.write_immediate(ptr, &slice_place)
+ }
+
/// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place.
pub(crate) fn write_type_info(
&mut self,
@@ -26,22 +77,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
// Fill all fields of the `TypeInfo` struct.
for (idx, field) in ty_struct.fields.iter_enumerated() {
let field_dest = self.project_field(dest, idx)?;
- let downcast = |name: Symbol| {
- let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants();
- let variant_id = variants
- .iter_enumerated()
- .find(|(_idx, var)| var.name == name)
- .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}"))
- .0;
-
- interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
- };
let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
match field.name {
sym::kind => {
let variant_index = match ty.kind() {
ty::Tuple(fields) => {
- let (variant, variant_place) = downcast(sym::Tuple)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Tuple)?;
// project to the single tuple variant field of `type_info::Tuple` struct type
let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
assert_eq!(
@@ -55,11 +97,12 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
.fields
.len()
);
- self.write_tuple_fields(tuple_place, fields, ty)?;
+ self.write_tuple_type_info(tuple_place, fields, ty)?;
variant
}
ty::Array(ty, len) => {
- let (variant, variant_place) = downcast(sym::Array)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Array)?;
let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_array_type_info(array_place, *ty, *len)?;
@@ -67,23 +110,29 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Slice(ty) => {
- let (variant, variant_place) = downcast(sym::Slice)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Slice)?;
let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_slice_type_info(slice_place, *ty)?;
variant
}
+ ty::Adt(adt_def, generics) => {
+ self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
+ }
ty::Bool => {
- let (variant, _variant_place) = downcast(sym::Bool)?;
+ let (variant, _variant_place) =
+ self.downcast(&field_dest, sym::Bool)?;
variant
}
ty::Char => {
- let (variant, _variant_place) = downcast(sym::Char)?;
+ let (variant, _variant_place) =
+ self.downcast(&field_dest, sym::Char)?;
variant
}
ty::Int(int_ty) => {
- let (variant, variant_place) = downcast(sym::Int)?;
+ let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_int_type_info(
place,
@@ -93,7 +142,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Uint(uint_ty) => {
- let (variant, variant_place) = downcast(sym::Int)?;
+ let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_int_type_info(
place,
@@ -103,17 +152,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Float(float_ty) => {
- let (variant, variant_place) = downcast(sym::Float)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Float)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_float_type_info(place, float_ty.bit_width())?;
variant
}
ty::Str => {
- let (variant, _variant_place) = downcast(sym::Str)?;
+ let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?;
variant
}
ty::Ref(_, ty, mutability) => {
- let (variant, variant_place) = downcast(sym::Reference)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Reference)?;
let reference_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_reference_type_info(reference_place, *ty, *mutability)?;
@@ -121,7 +172,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::RawPtr(ty, mutability) => {
- let (variant, variant_place) = downcast(sym::Pointer)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::Pointer)?;
let pointer_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
@@ -130,13 +182,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Dynamic(predicates, region) => {
- let (variant, variant_place) = downcast(sym::DynTrait)?;
+ let (variant, variant_place) =
+ self.downcast(&field_dest, sym::DynTrait)?;
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
variant
}
- ty::Adt(_, _)
- | ty::Foreign(_)
+ ty::Foreign(_)
| ty::Pat(_, _)
| ty::FnDef(..)
| ty::FnPtr(..)
@@ -151,14 +203,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(..)
- | ty::Error(_) => downcast(sym::Other)?.0,
+ | ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0,
};
self.write_discriminant(variant_index, &field_dest)?
}
sym::size => {
let layout = self.layout_of(ty)?;
let variant_index = if layout.is_sized() {
- let (variant, variant_place) = downcast(sym::Some)?;
+ let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?;
let size_field_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_scalar(
@@ -168,7 +220,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
)?;
variant
} else {
- downcast(sym::None)?.0
+ self.downcast(&field_dest, sym::None)?.0
};
self.write_discriminant(variant_index, &field_dest)?;
}
@@ -179,46 +231,12 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok(())
}
- pub(crate) fn write_tuple_fields(
- &mut self,
- tuple_place: impl Writeable<'tcx, CtfeProvenance>,
- fields: &[Ty<'tcx>],
- tuple_ty: Ty<'tcx>,
- ) -> InterpResult<'tcx> {
- // project into the `type_info::Tuple::fields` field
- let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
- // get the `type_info::Field` type from `fields: &[Field]`
- let field_type = fields_slice_place
- .layout()
- .ty
- .builtin_deref(false)
- .unwrap()
- .sequence_element_type(self.tcx.tcx);
- // Create an array with as many elements as the number of fields in the inspected tuple
- let fields_layout =
- self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?;
- let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?;
- let mut fields_places = self.project_array_fields(&fields_place)?;
-
- let tuple_layout = self.layout_of(tuple_ty)?;
-
- while let Some((i, place)) = fields_places.next(self)? {
- let field_ty = fields[i as usize];
- self.write_field(field_ty, place, tuple_layout, i)?;
- }
-
- let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable);
-
- let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self);
-
- self.write_immediate(ptr, &fields_slice_place)
- }
-
fn write_field(
&mut self,
field_ty: Ty<'tcx>,
place: MPlaceTy<'tcx>,
layout: TyAndLayout<'tcx>,
+ name: Option,
idx: u64,
) -> InterpResult<'tcx> {
for (field_idx, field_ty_field) in
@@ -226,7 +244,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
{
let field_place = self.project_field(&place, field_idx)?;
match field_ty_field.name {
- sym::ty => self.write_type_id(field_ty, &field_place)?,
+ sym::name => {
+ let name = match name.as_ref() {
+ Some(name) => Cow::Borrowed(name.as_str()),
+ None => Cow::Owned(idx.to_string()), // For tuples
+ };
+ let name_place = self.allocate_str_dedup(&name)?;
+ let ptr = self.mplace_to_ref(&name_place)?;
+ self.write_immediate(*ptr, &field_place)?
+ }
+ sym::ty => {
+ let field_ty = self.tcx.erase_and_anonymize_regions(field_ty);
+ self.write_type_id(field_ty, &field_place)?
+ }
sym::offset => {
let offset = layout.fields.offset(idx as usize);
self.write_scalar(
@@ -242,6 +272,24 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok(())
}
+ pub(crate) fn write_tuple_type_info(
+ &mut self,
+ tuple_place: impl Writeable<'tcx, CtfeProvenance>,
+ fields: &[Ty<'tcx>],
+ tuple_ty: Ty<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let tuple_layout = self.layout_of(tuple_ty)?;
+ let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?;
+ self.allocate_fill_and_write_slice_ptr(
+ fields_slice_place,
+ fields.len() as u64,
+ |this, i, place| {
+ let field_ty = fields[i as usize];
+ this.write_field(field_ty, place, tuple_layout, None, i)
+ },
+ )
+ }
+
pub(crate) fn write_array_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
new file mode 100644
index 0000000000000..60f7b95e799a6
--- /dev/null
+++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs
@@ -0,0 +1,276 @@
+use rustc_abi::{FieldIdx, VariantIdx};
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::{
+ AdtDef, AdtKind, Const, ConstKind, GenericArgKind, GenericArgs, Region, Ty, VariantDef,
+};
+use rustc_middle::{bug, span_bug};
+use rustc_span::sym;
+
+use crate::const_eval::CompileTimeMachine;
+use crate::interpret::{
+ CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Projectable, Scalar, Writeable, interp_ok,
+};
+
+impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
+ // FIXME(type_info): No semver considerations for now
+ pub(crate) fn write_adt_type_info(
+ &mut self,
+ place: &impl Writeable<'tcx, CtfeProvenance>,
+ adt: (Ty<'tcx>, AdtDef<'tcx>),
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx, VariantIdx> {
+ let (adt_ty, adt_def) = adt;
+ let variant_idx = match adt_def.adt_kind() {
+ AdtKind::Struct => {
+ let (variant, variant_place) = self.downcast(place, sym::Struct)?;
+ let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
+ self.write_struct_type_info(
+ place,
+ (adt_ty, adt_def.variant(VariantIdx::ZERO)),
+ generics,
+ )?;
+ variant
+ }
+ AdtKind::Union => {
+ let (variant, variant_place) = self.downcast(place, sym::Union)?;
+ let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
+ self.write_union_type_info(
+ place,
+ (adt_ty, adt_def.variant(VariantIdx::ZERO)),
+ generics,
+ )?;
+ variant
+ }
+ AdtKind::Enum => {
+ let (variant, variant_place) = self.downcast(place, sym::Enum)?;
+ let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
+ self.write_enum_type_info(place, adt, generics)?;
+ variant
+ }
+ };
+ interp_ok(variant_idx)
+ }
+
+ pub(crate) fn write_struct_type_info(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ struct_: (Ty<'tcx>, &'tcx VariantDef),
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let (struct_ty, struct_def) = struct_;
+ let struct_layout = self.layout_of(struct_ty)?;
+
+ for (field_idx, field) in
+ place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
+ {
+ let field_place = self.project_field(&place, field_idx)?;
+
+ match field.name {
+ sym::generics => self.write_generics(field_place, generics)?,
+ sym::fields => {
+ self.write_variant_fields(field_place, struct_def, struct_layout, generics)?
+ }
+ sym::non_exhaustive => {
+ let is_non_exhaustive = struct_def.is_field_list_non_exhaustive();
+ self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
+ }
+ other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
+ }
+ }
+
+ interp_ok(())
+ }
+
+ pub(crate) fn write_union_type_info(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ union_: (Ty<'tcx>, &'tcx VariantDef),
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let (union_ty, union_def) = union_;
+ let union_layout = self.layout_of(union_ty)?;
+
+ for (field_idx, field) in
+ place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
+ {
+ let field_place = self.project_field(&place, field_idx)?;
+
+ match field.name {
+ sym::generics => self.write_generics(field_place, generics)?,
+ sym::fields => {
+ self.write_variant_fields(field_place, union_def, union_layout, generics)?
+ }
+ sym::non_exhaustive => {
+ let is_non_exhaustive = union_def.is_field_list_non_exhaustive();
+ self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
+ }
+ other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
+ }
+ }
+
+ interp_ok(())
+ }
+
+ pub(crate) fn write_enum_type_info(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ enum_: (Ty<'tcx>, AdtDef<'tcx>),
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let (enum_ty, enum_def) = enum_;
+ let enum_layout = self.layout_of(enum_ty)?;
+
+ for (field_idx, field) in
+ place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
+ {
+ let field_place = self.project_field(&place, field_idx)?;
+
+ match field.name {
+ sym::generics => self.write_generics(field_place, generics)?,
+ sym::variants => {
+ self.allocate_fill_and_write_slice_ptr(
+ field_place,
+ enum_def.variants().len() as u64,
+ |this, i, place| {
+ let variant_idx = VariantIdx::from_usize(i as usize);
+ let variant_def = &enum_def.variants()[variant_idx];
+ let variant_layout = enum_layout.for_variant(this, variant_idx);
+ this.write_enum_variant(place, (variant_layout, &variant_def), generics)
+ },
+ )?;
+ }
+ sym::non_exhaustive => {
+ let is_non_exhaustive = enum_def.is_variant_list_non_exhaustive();
+ self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
+ }
+ other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
+ }
+ }
+
+ interp_ok(())
+ }
+
+ fn write_enum_variant(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ variant: (TyAndLayout<'tcx>, &'tcx VariantDef),
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let (variant_layout, variant_def) = variant;
+
+ for (field_idx, field_def) in
+ place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
+ {
+ let field_place = self.project_field(&place, field_idx)?;
+ match field_def.name {
+ sym::name => {
+ let name_place = self.allocate_str_dedup(variant_def.name.as_str())?;
+ let ptr = self.mplace_to_ref(&name_place)?;
+ self.write_immediate(*ptr, &field_place)?
+ }
+ sym::fields => {
+ self.write_variant_fields(field_place, &variant_def, variant_layout, generics)?
+ }
+ sym::non_exhaustive => {
+ let is_non_exhaustive = variant_def.is_field_list_non_exhaustive();
+ self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
+ }
+ other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
+ }
+ }
+ interp_ok(())
+ }
+
+ // Write fields for struct, enum variants
+ fn write_variant_fields(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ variant_def: &'tcx VariantDef,
+ variant_layout: TyAndLayout<'tcx>,
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ self.allocate_fill_and_write_slice_ptr(
+ place,
+ variant_def.fields.len() as u64,
+ |this, i, place| {
+ let field_def = &variant_def.fields[FieldIdx::from_usize(i as usize)];
+ let field_ty = field_def.ty(*this.tcx, generics);
+ this.write_field(field_ty, place, variant_layout, Some(field_def.name), i)
+ },
+ )
+ }
+
+ fn write_generics(
+ &mut self,
+ place: impl Writeable<'tcx, CtfeProvenance>,
+ generics: &'tcx GenericArgs<'tcx>,
+ ) -> InterpResult<'tcx> {
+ self.allocate_fill_and_write_slice_ptr(place, generics.len() as u64, |this, i, place| {
+ match generics[i as usize].kind() {
+ GenericArgKind::Lifetime(region) => this.write_generic_lifetime(region, place),
+ GenericArgKind::Type(ty) => this.write_generic_type(ty, place),
+ GenericArgKind::Const(c) => this.write_generic_const(c, place),
+ }
+ })
+ }
+
+ fn write_generic_lifetime(
+ &mut self,
+ _region: Region<'tcx>,
+ place: MPlaceTy<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?;
+ self.write_discriminant(variant_idx, &place)?;
+ interp_ok(())
+ }
+
+ fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
+ let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?;
+ let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
+
+ for (field_idx, field_def) in generic_type_place
+ .layout()
+ .ty
+ .ty_adt_def()
+ .unwrap()
+ .non_enum_variant()
+ .fields
+ .iter_enumerated()
+ {
+ let field_place = self.project_field(&generic_type_place, field_idx)?;
+ match field_def.name {
+ sym::ty => self.write_type_id(ty, &field_place)?,
+ other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
+ }
+ }
+
+ self.write_discriminant(variant_idx, &place)?;
+ interp_ok(())
+ }
+
+ fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
+ let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") };
+
+ let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?;
+ let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
+
+ for (field_idx, field_def) in const_place
+ .layout()
+ .ty
+ .ty_adt_def()
+ .unwrap()
+ .non_enum_variant()
+ .fields
+ .iter_enumerated()
+ {
+ let field_place = self.project_field(&const_place, field_idx)?;
+ match field_def.name {
+ sym::ty => self.write_type_id(c.ty, &field_place)?,
+ other => span_bug!(self.tcx.def_span(field_def.did), "unimplemented field {other}"),
+ }
+ }
+
+ self.write_discriminant(variant_idx, &place)?;
+ interp_ok(())
+ }
+}
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 2ea5e4a25c116..49038315b546e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -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};
+use rustc_middle::ty::{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};
@@ -73,6 +73,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ty: Ty<'tcx>,
dest: &impl Writeable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()> {
+ debug_assert!(
+ !ty.has_erasable_regions(),
+ "type {ty:?} has regions that need erasing before writing a TypeId",
+ );
+
let tcx = self.tcx;
let type_id_hash = tcx.type_id_hash(ty).as_u128();
let op = self.const_val_to_op(
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index cccebded4b0b8..ead1ee9bf85ec 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,6 +1,6 @@
// tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(array_try_map)]
-#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index bef19d77d1e73..a56b5f5fdc7d3 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -10,12 +10,12 @@
#![allow(internal_features)]
#![allow(rustc::default_hash_types)]
#![allow(rustc::potential_query_instability)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![cfg_attr(bootstrap, feature(cold_path))]
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(allocator_api)]
#![feature(ascii_char)]
#![feature(ascii_char_variants)]
-#![feature(assert_matches)]
#![feature(auto_traits)]
#![feature(cfg_select)]
#![feature(const_default)]
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index c0398b3e8da0b..cfd4ae3795e14 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -5,7 +5,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::direct_use_of_rustc_type_ir)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(default_field_values)]
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 6214106d422b5..70209993a5108 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -56,7 +56,7 @@ This API is completely unstable and subject to change.
*/
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(default_field_values)]
#![feature(gen_blocks)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index ac3db41a4d665..8692720529d50 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -1,5 +1,5 @@
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 2a1733ef63cb9..008b5c94a5eaa 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -14,7 +14,7 @@
// tidy-alphabetical-start
#![allow(rustc::direct_use_of_rustc_type_ir)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(extend_one)]
#![recursion_limit = "512"] // For rustdoc
// tidy-alphabetical-end
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 93b6f1491041d..94dc566d75f18 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -21,7 +21,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(iter_order_by)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 5b32d4551a16f..2095327ea1b59 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -27,8 +27,8 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::direct_use_of_rustc_type_ir)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(allocator_api)]
-#![feature(assert_matches)]
#![feature(associated_type_defaults)]
#![feature(box_as_ptr)]
#![feature(box_patterns)]
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index cc8035e2b0acf..21817dea6cb4c 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -1,7 +1,7 @@
//! Construction of MIR from HIR.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 5f1cf12501522..692591a41a15b 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,5 +1,5 @@
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(exact_size_is_empty)]
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 402e22621426b..bc2c6bd81aca9 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,5 +1,5 @@
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(const_type_name)]
#![feature(cow_is_borrowed)]
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 40cdcfc35c2f8..014ccdc45ef88 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -1,7 +1,7 @@
//! The main parser interface.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(box_patterns)]
#![feature(debug_closure_helpers)]
#![feature(default_field_values)]
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index fc63df3595c41..e8d857cf31786 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,6 +1,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(min_specialization)]
#![feature(trait_alias)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 0912b46f473f4..1399f9933ad4e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -8,9 +8,9 @@
// tidy-alphabetical-start
#![allow(internal_features)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![cfg_attr(bootstrap, feature(ptr_as_ref_unchecked))]
#![feature(arbitrary_self_types)]
-#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(const_default)]
#![feature(const_trait_impl)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0f248925602ff..b9a9d8029d286 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -211,6 +211,7 @@ symbols! {
CoercePointeeValidated,
CoerceUnsized,
Command,
+ Const,
ConstParamTy,
ConstParamTy_,
Context,
@@ -234,6 +235,7 @@ symbols! {
DynTrait,
Encodable,
Encoder,
+ Enum,
Enumerate,
Eq,
Equal,
@@ -292,6 +294,7 @@ symbols! {
IteratorMap,
Layout,
Left,
+ Lifetime,
LinkedList,
LintDiagnostic,
LintPass,
@@ -372,6 +375,7 @@ symbols! {
Stdin,
Str,
String,
+ Struct,
StructuralPartialEq,
Subdiagnostic,
SymbolIntern,
@@ -394,6 +398,8 @@ symbols! {
Ty,
TyCtxt,
TyKind,
+ Type,
+ Union,
Unknown,
Unsize,
UnsizedConstParamTy,
@@ -1085,6 +1091,7 @@ symbols! {
ffi_returns_twice,
field,
field_init_shorthand,
+ fields,
file,
file_options,
flags,
@@ -1173,6 +1180,7 @@ symbols! {
generic_const_parameter_types,
generic_param_attrs,
generic_pattern_types,
+ generics,
get_context,
global_alloc_ty,
global_allocator,
@@ -2473,6 +2481,7 @@ symbols! {
values,
var,
variant_count,
+ variants,
vec,
vec_as_mut_slice,
vec_as_slice,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 7e126cb6a6e95..35a3d0dac8afa 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -88,7 +88,7 @@
//! DefPaths which are much more robust in the face of changes to the code base.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
// tidy-alphabetical-end
use rustc_hir::def::DefKind;
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 645fd17ac7096..708e0b9e84972 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,7 +11,7 @@
//! This API is completely unstable and subject to change.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(default_field_values)]
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 9f8f3b240890b..b7f73fd5570e0 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,7 +5,7 @@
//! This API is completely unstable and subject to change.
// tidy-alphabetical-start
-#![feature(assert_matches)]
+#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index f7167650635d3..0e0c2fcd8b996 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -89,7 +89,6 @@
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(ascii_char)]
-#![feature(assert_matches)]
#![feature(async_fn_traits)]
#![feature(async_iterator)]
#![feature(box_vec_non_null)]
diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs
index fe14480102e32..296f76d7c073d 100644
--- a/library/alloctests/lib.rs
+++ b/library/alloctests/lib.rs
@@ -16,7 +16,6 @@
// tidy-alphabetical-start
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
-#![feature(assert_matches)]
#![feature(box_vec_non_null)]
#![feature(char_internals)]
#![feature(const_alloc_error)]
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs
index e15c86496cf1b..b7b8336ee4294 100644
--- a/library/alloctests/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -3,7 +3,6 @@
#![feature(const_heap)]
#![feature(deque_extend_front)]
#![feature(iter_array_chunks)]
-#![feature(assert_matches)]
#![feature(wtf8_internals)]
#![feature(cow_is_borrowed)]
#![feature(core_intrinsics)]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 17cf6b3714f50..aaa919ece6a58 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -225,7 +225,7 @@ use prelude::rust_2024::*;
#[macro_use]
mod macros;
-#[unstable(feature = "assert_matches", issue = "82775")]
+#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")]
pub use crate::macros::{assert_matches, debug_assert_matches};
#[unstable(feature = "derive_from", issue = "144889")]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 3176f3c067092..79eab552303e3 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -147,8 +147,6 @@ macro_rules! assert_ne {
/// # Examples
///
/// ```
-/// #![feature(assert_matches)]
-///
/// use std::assert_matches;
///
/// let a = Some(345);
@@ -166,7 +164,7 @@ macro_rules! assert_ne {
/// assert_matches!(a, Some(x) if x > 100);
/// // assert_matches!(a, Some(x) if x < 100); // panics
/// ```
-#[unstable(feature = "assert_matches", issue = "82775")]
+#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")]
#[allow_internal_unstable(panic_internals)]
#[rustc_macro_transparency = "semiopaque"]
pub macro assert_matches {
@@ -380,8 +378,6 @@ macro_rules! debug_assert_ne {
/// # Examples
///
/// ```
-/// #![feature(assert_matches)]
-///
/// use std::debug_assert_matches;
///
/// let a = Some(345);
@@ -399,7 +395,7 @@ macro_rules! debug_assert_ne {
/// debug_assert_matches!(a, Some(x) if x > 100);
/// // debug_assert_matches!(a, Some(x) if x < 100); // panics
/// ```
-#[unstable(feature = "assert_matches", issue = "82775")]
+#[stable(feature = "assert_matches", since = "CURRENT_RUSTC_VERSION")]
#[allow_internal_unstable(assert_matches)]
#[rustc_macro_transparency = "semiopaque"]
pub macro debug_assert_matches($($arg:tt)*) {
diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs
index 8b30803c97c98..c2b2cf2f270dd 100644
--- a/library/core/src/mem/type_info.rs
+++ b/library/core/src/mem/type_info.rs
@@ -49,6 +49,12 @@ pub enum TypeKind {
Slice(Slice),
/// Dynamic Traits.
DynTrait(DynTrait),
+ /// Structs.
+ Struct(Struct),
+ /// Enums.
+ Enum(Enum),
+ /// Unions.
+ Union(Union),
/// Primitive boolean type.
Bool(Bool),
/// Primitive character type.
@@ -81,6 +87,8 @@ pub struct Tuple {
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Field {
+ /// The name of the field.
+ pub name: &'static str,
/// The field's type.
pub ty: TypeId,
/// Offset in bytes from the parent type
@@ -137,6 +145,95 @@ pub struct Trait {
pub is_auto: bool,
}
+/// Compile-time type information about arrays.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Struct {
+ /// Instantiated generics of the struct.
+ pub generics: &'static [Generic],
+ /// All fields of the struct.
+ pub fields: &'static [Field],
+ /// Whether the struct field list is non-exhaustive.
+ pub non_exhaustive: bool,
+}
+
+/// Compile-time type information about unions.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Union {
+ /// Instantiated generics of the union.
+ pub generics: &'static [Generic],
+ /// All fields of the union.
+ pub fields: &'static [Field],
+}
+
+/// Compile-time type information about enums.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Enum {
+ /// Instantiated generics of the enum.
+ pub generics: &'static [Generic],
+ /// All variants of the enum.
+ pub variants: &'static [Variant],
+ /// Whether the enum variant list is non-exhaustive.
+ pub non_exhaustive: bool,
+}
+
+/// Compile-time type information about variants of enums.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Variant {
+ /// The name of the variant.
+ pub name: &'static str,
+ /// All fields of the variant.
+ pub fields: &'static [Field],
+ /// Whether the enum variant fields is non-exhaustive.
+ pub non_exhaustive: bool,
+}
+
+/// Compile-time type information about instantiated generics of structs, enum and union variants.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub enum Generic {
+ /// Lifetimes.
+ Lifetime(Lifetime),
+ /// Types.
+ Type(GenericType),
+ /// Const parameters.
+ Const(Const),
+}
+
+/// Compile-time type information about generic lifetimes.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Lifetime {
+ // No additional information to provide for now.
+}
+
+/// Compile-time type information about instantiated generic types.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct GenericType {
+ /// The type itself.
+ pub ty: TypeId,
+}
+
+/// Compile-time type information about generic const parameters.
+#[derive(Debug)]
+#[non_exhaustive]
+#[unstable(feature = "type_info", issue = "146922")]
+pub struct Const {
+ /// The const's type.
+ pub ty: TypeId,
+}
+
/// Compile-time type information about `bool`.
#[derive(Debug)]
#[non_exhaustive]
diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs
index 87f2d5dd8289c..2483b4c2aacd7 100644
--- a/library/coretests/tests/mem/type_info.rs
+++ b/library/coretests/tests/mem/type_info.rs
@@ -1,5 +1,8 @@
+#![allow(dead_code)]
+
use std::any::{Any, TypeId};
-use std::mem::type_info::{Type, TypeKind};
+use std::mem::offset_of;
+use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind};
#[test]
fn test_arrays() {
@@ -66,6 +69,155 @@ fn test_tuples() {
}
}
+#[test]
+fn test_structs() {
+ use TypeKind::*;
+
+ const {
+ struct TestStruct {
+ first: u8,
+ second: u16,
+ reference: &'static u16,
+ }
+
+ let Type { kind: Struct(ty), size, .. } = Type::of::() else { panic!() };
+ assert!(size == Some(size_of::()));
+ assert!(!ty.non_exhaustive);
+ assert!(ty.fields.len() == 3);
+ assert!(ty.fields[0].name == "first");
+ assert!(ty.fields[0].ty == TypeId::of::());
+ assert!(ty.fields[0].offset == offset_of!(TestStruct, first));
+ assert!(ty.fields[1].name == "second");
+ assert!(ty.fields[1].ty == TypeId::of::());
+ assert!(ty.fields[1].offset == offset_of!(TestStruct, second));
+ assert!(ty.fields[2].name == "reference");
+ assert!(ty.fields[2].ty == TypeId::of::<&'static u16>());
+ assert!(ty.fields[2].offset == offset_of!(TestStruct, reference));
+ }
+
+ const {
+ #[non_exhaustive]
+ struct NonExhaustive {
+ a: u8,
+ }
+
+ let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() };
+ assert!(ty.non_exhaustive);
+ }
+
+ const {
+ struct TupleStruct(u8, u16);
+
+ let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() };
+ assert!(ty.fields.len() == 2);
+ assert!(ty.fields[0].name == "0");
+ assert!(ty.fields[0].ty == TypeId::of::());
+ assert!(ty.fields[1].name == "1");
+ assert!(ty.fields[1].ty == TypeId::of::());
+ }
+
+ const {
+ struct Generics<'a, T, const C: u64> {
+ a: &'a T,
+ }
+
+ let Type { kind: Struct(ty), .. } = Type::of::>() else {
+ panic!()
+ };
+ assert!(ty.fields.len() == 1);
+ assert!(ty.generics.len() == 3);
+
+ let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
+ let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
+ assert!(generic_ty == TypeId::of::());
+ let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
+ assert!(const_ty == TypeId::of::());
+ }
+}
+
+#[test]
+fn test_unions() {
+ use TypeKind::*;
+
+ const {
+ union TestUnion {
+ first: i16,
+ second: u16,
+ }
+
+ let Type { kind: Union(ty), size, .. } = Type::of::() else { panic!() };
+ assert!(size == Some(size_of::()));
+ assert!(ty.fields.len() == 2);
+ assert!(ty.fields[0].name == "first");
+ assert!(ty.fields[0].offset == offset_of!(TestUnion, first));
+ assert!(ty.fields[1].name == "second");
+ assert!(ty.fields[1].offset == offset_of!(TestUnion, second));
+ }
+
+ const {
+ union Generics<'a, T: Copy, const C: u64> {
+ a: T,
+ z: &'a (),
+ }
+
+ let Type { kind: Union(ty), .. } = Type::of::>() else {
+ panic!()
+ };
+ assert!(ty.fields.len() == 2);
+ assert!(ty.fields[0].offset == offset_of!(Generics<'static, i32, 1_u64>, a));
+ assert!(ty.fields[1].offset == offset_of!(Generics<'static, i32, 1_u64>, z));
+
+ assert!(ty.generics.len() == 3);
+ let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
+ let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
+ assert!(generic_ty == TypeId::of::());
+ let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
+ assert!(const_ty == TypeId::of::());
+ }
+}
+
+#[test]
+fn test_enums() {
+ use TypeKind::*;
+
+ const {
+ enum E {
+ Some(u32),
+ None,
+ #[non_exhaustive]
+ Foomp {
+ a: (),
+ b: &'static str,
+ },
+ }
+
+ let Type { kind: Enum(ty), size, .. } = Type::of::() else { panic!() };
+ assert!(size == Some(size_of::()));
+ assert!(ty.variants.len() == 3);
+
+ assert!(ty.variants[0].name == "Some");
+ assert!(!ty.variants[0].non_exhaustive);
+ assert!(ty.variants[0].fields.len() == 1);
+
+ assert!(ty.variants[1].name == "None");
+ assert!(!ty.variants[1].non_exhaustive);
+ assert!(ty.variants[1].fields.len() == 0);
+
+ assert!(ty.variants[2].name == "Foomp");
+ assert!(ty.variants[2].non_exhaustive);
+ assert!(ty.variants[2].fields.len() == 2);
+ }
+
+ const {
+ let Type { kind: Enum(ty), size, .. } = Type::of::