From b29cc9860b27d310f51ebc76eed154cf1fedccdc Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 25 Dec 2025 19:18:32 +0000 Subject: [PATCH] refactor destructure_const --- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 -- .../rustc_middle/src/ty/consts/valtree.rs | 21 +++++ compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 89 +++++++++---------- compiler/rustc_symbol_mangling/src/v0.rs | 85 ++++++++++-------- compiler/rustc_ty_utils/src/consts.rs | 60 +------------ tests/crashes/131052.rs | 8 -- .../mismatch-raw-ptr-in-adt.rs | 13 +++ .../mismatch-raw-ptr-in-adt.stderr | 42 +++++++++ 11 files changed, 174 insertions(+), 159 deletions(-) delete mode 100644 tests/crashes/131052.rs create mode 100644 tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs create mode 100644 tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 2d84e919359e..a31f03362a3d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1896,7 +1896,8 @@ fn pretty_print_const_value_tcx<'tcx>( // Aggregates, printed as array/tuple/struct/variant construction syntax. // // NB: the `has_non_region_param` check ensures that we can use - // the `destructure_const` query with an empty `ty::ParamEnv` without + // the `try_destructure_mir_constant_for_user_output ` query with + // an empty `TypingEnv::fully_monomorphized` without // introducing ICEs (e.g. via `layout_of`) from missing bounds. // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // to be able to destructure the tuple into `(0u8, *mut T)` diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 774dd88997f2..711a597d4603 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -402,7 +402,7 @@ impl<'tcx> EraseType for $($fake_path)::+<'tcx> { rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, - rustc_middle::ty::DestructuredConst, + rustc_middle::ty::DestructuredAdtConst, rustc_middle::ty::ExistentialTraitRef, rustc_middle::ty::FnSig, rustc_middle::ty::GenericArg, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 676f0d82e4fb..b2473052b442 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1408,12 +1408,6 @@ desc { "converting type-level constant value to MIR constant value"} } - /// Destructures array, ADT or tuple constants into the constants - /// of their fields. - query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> { - desc { "destructuring type level constant"} - } - // FIXME get rid of this with valtrees query lit_to_const( key: LitToConstInput<'tcx> diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 8afee2dfe3bc..6501ddeed6fa 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,6 +1,7 @@ use std::fmt; use std::ops::Deref; +use rustc_abi::{FIRST_VARIANT, VariantIdx}; use rustc_data_structures::intern::Interned; use rustc_hir::def::Namespace; use rustc_macros::{ @@ -189,6 +190,26 @@ pub fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> { ValTreeKind::Leaf(_) => None, } } + + /// Destructures array, ADT or tuple constants into the constants + /// of their fields. + pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> { + let fields = self.to_branch(); + + let (variant, fields) = match self.ty.kind() { + ty::Adt(def, _) if def.variants().is_empty() => { + bug!("unreachable") + } + ty::Adt(def, _) if def.is_enum() => { + let (head, rest) = fields.split_first().unwrap(); + (VariantIdx::from_u32(head.to_leaf().to_u32()), rest) + } + ty::Adt(_, _) => (FIRST_VARIANT, fields), + _ => bug!("destructure_adt_const called on non-ADT type: {:?}", self.ty), + }; + + ty::DestructuredAdtConst { variant, fields } + } } impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cb47869a1351..e2a94b607de1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2331,8 +2331,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { /// The constituent parts of a type level constant of kind ADT or array. #[derive(Copy, Clone, Debug, HashStable)] -pub struct DestructuredConst<'tcx> { - pub variant: Option, +pub struct DestructuredAdtConst<'tcx> { + pub variant: VariantIdx, pub fields: &'tcx [ty::Const<'tcx>], } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0d5ce492a39..2a65517de403 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1919,66 +1919,65 @@ fn pretty_print_const_valtree( self.pretty_print_byte_str(bytes)?; return Ok(()); } - // Aggregates, printed as array/tuple/struct/variant construction syntax. - (ty::ValTreeKind::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let contents = self.tcx().destructure_const(ty::Const::new_value( - self.tcx(), - cv.valtree, - cv.ty, - )); - let fields = contents.fields.iter().copied(); + (ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => { + let fields_iter = fields.iter().copied(); + match *cv.ty.kind() { ty::Array(..) => { write!(self, "[")?; - self.comma_sep(fields)?; + self.comma_sep(fields_iter)?; write!(self, "]")?; } ty::Tuple(..) => { write!(self, "(")?; - self.comma_sep(fields)?; - if contents.fields.len() == 1 { + self.comma_sep(fields_iter)?; + if fields.len() == 1 { write!(self, ",")?; } write!(self, ")")?; } - ty::Adt(def, _) if def.variants().is_empty() => { - self.typed_value( - |this| { - write!(this, "unreachable()")?; - Ok(()) - }, - |this| this.print_type(cv.ty), - ": ", - )?; - } - ty::Adt(def, args) => { - let variant_idx = - contents.variant.expect("destructed const of adt without variant idx"); - let variant_def = &def.variant(variant_idx); - self.pretty_print_value_path(variant_def.def_id, args)?; - match variant_def.ctor_kind() { - Some(CtorKind::Const) => {} - Some(CtorKind::Fn) => { - write!(self, "(")?; - self.comma_sep(fields)?; - write!(self, ")")?; - } - None => { - write!(self, " {{ ")?; - let mut first = true; - for (field_def, field) in iter::zip(&variant_def.fields, fields) { - if !first { - write!(self, ", ")?; - } - write!(self, "{}: ", field_def.name)?; - field.print(self)?; - first = false; + _ => unreachable!(), + } + return Ok(()); + } + (ty::ValTreeKind::Branch(_), ty::Adt(def, args)) => { + let contents = cv.destructure_adt_const(); + let fields = contents.fields.iter().copied(); + + if def.variants().is_empty() { + self.typed_value( + |this| { + write!(this, "unreachable()")?; + Ok(()) + }, + |this| this.print_type(cv.ty), + ": ", + )?; + } else { + let variant_idx = contents.variant; + let variant_def = &def.variant(variant_idx); + self.pretty_print_value_path(variant_def.def_id, args)?; + match variant_def.ctor_kind() { + Some(CtorKind::Const) => {} + Some(CtorKind::Fn) => { + write!(self, "(")?; + self.comma_sep(fields)?; + write!(self, ")")?; + } + None => { + write!(self, " {{ ")?; + let mut first = true; + for (field_def, field) in iter::zip(&variant_def.fields, fields) { + if !first { + write!(self, ", ")?; } - write!(self, " }}")?; + write!(self, "{}: ", field_def.name)?; + field.print(self)?; + first = false; } + write!(self, " }}")?; } } - _ => unreachable!(), } return Ok(()); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4880a79ea9cf..755b4923e9cd 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -755,9 +755,8 @@ fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { dereferenced_const.print(self)?; } - ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => { - let contents = self.tcx.destructure_const(ct); - let fields = contents.fields.iter().copied(); + ty::Array(..) | ty::Tuple(..) | ty::Slice(_) => { + let fields = cv.to_branch().iter().copied(); let print_field_list = |this: &mut Self| { for field in fields.clone() { @@ -776,45 +775,53 @@ fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { self.push("T"); print_field_list(self)?; } - ty::Adt(def, args) => { - let variant_idx = - contents.variant.expect("destructed const of adt without variant idx"); - let variant_def = &def.variant(variant_idx); - - self.push("V"); - self.print_def_path(variant_def.def_id, args)?; - - match variant_def.ctor_kind() { - Some(CtorKind::Const) => { - self.push("U"); - } - Some(CtorKind::Fn) => { - self.push("T"); - print_field_list(self)?; - } - None => { - self.push("S"); - for (field_def, field) in iter::zip(&variant_def.fields, fields) { - // HACK(eddyb) this mimics `print_path_with_simple`, - // instead of simply using `field_def.ident`, - // just to be able to handle disambiguators. - let disambiguated_field = - self.tcx.def_key(field_def.did).disambiguated_data; - let field_name = disambiguated_field.data.get_opt_name(); - self.push_disambiguator( - disambiguated_field.disambiguator as u64, - ); - self.push_ident(field_name.unwrap().as_str()); - - field.print(self)?; - } - self.push("E"); - } - } - } _ => unreachable!(), } } + ty::Adt(def, args) => { + let contents = cv.destructure_adt_const(); + let fields = contents.fields.iter().copied(); + + let print_field_list = |this: &mut Self| { + for field in fields.clone() { + field.print(this)?; + } + this.push("E"); + Ok(()) + }; + + let variant_idx = contents.variant; + let variant_def = &def.variant(variant_idx); + + self.push("V"); + self.print_def_path(variant_def.def_id, args)?; + + match variant_def.ctor_kind() { + Some(CtorKind::Const) => { + self.push("U"); + } + Some(CtorKind::Fn) => { + self.push("T"); + print_field_list(self)?; + } + None => { + self.push("S"); + for (field_def, field) in iter::zip(&variant_def.fields, fields) { + // HACK(eddyb) this mimics `print_path_with_simple`, + // instead of simply using `field_def.ident`, + // just to be able to handle disambiguators. + let disambiguated_field = + self.tcx.def_key(field_def.did).disambiguated_data; + let field_name = disambiguated_field.data.get_opt_name(); + self.push_disambiguator(disambiguated_field.disambiguator as u64); + self.push_ident(field_name.unwrap().as_str()); + + field.print(self)?; + } + self.push("E"); + } + } + } _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct); } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 9be8a48c740a..f6d08bd458bd 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -1,6 +1,3 @@ -use std::iter; - -use rustc_abi::{FIRST_VARIANT, VariantIdx}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -10,63 +7,12 @@ use rustc_middle::thir::visit::Visitor; use rustc_middle::ty::abstract_const::CastKind; use rustc_middle::ty::{self, Expr, TyCtxt, TypeVisitableExt}; -use rustc_middle::{bug, mir, thir}; +use rustc_middle::{mir, thir}; use rustc_span::Span; -use tracing::{debug, instrument}; +use tracing::instrument; use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub}; -/// Destructures array, ADT or tuple constants into the constants -/// of their fields. -fn destructure_const<'tcx>( - tcx: TyCtxt<'tcx>, - const_: ty::Const<'tcx>, -) -> ty::DestructuredConst<'tcx> { - let ty::ConstKind::Value(cv) = const_.kind() else { - bug!("cannot destructure constant {:?}", const_) - }; - let branches = cv.to_branch(); - - let (fields, variant) = match cv.ty.kind() { - ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { - // construct the consts for the elements of the array/slice - let field_consts = branches - .iter() - .map(|b| ty::Const::new_value(tcx, b.to_value().valtree, *inner_ty)) - .collect::>(); - debug!(?field_consts); - - (field_consts, None) - } - ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"), - ty::Adt(def, _) => { - let (variant_idx, field_consts) = if def.is_enum() { - let (head, rest) = branches.split_first().unwrap(); - (VariantIdx::from_u32(head.to_leaf().to_u32()), rest) - } else { - (FIRST_VARIANT, branches) - }; - debug!(?field_consts); - - (field_consts.to_vec(), Some(variant_idx)) - } - ty::Tuple(elem_tys) => { - let fields = iter::zip(*elem_tys, branches) - .map(|(elem_ty, elem_valtree)| { - ty::Const::new_value(tcx, elem_valtree.to_value().valtree, elem_ty) - }) - .collect::>(); - - (fields, None) - } - _ => bug!("cannot destructure constant {:?}", const_), - }; - - let fields = tcx.arena.alloc_from_iter(fields); - - ty::DestructuredConst { variant, fields } -} - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -432,5 +378,5 @@ fn thir_abstract_const<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { destructure_const, thir_abstract_const, ..*providers }; + *providers = Providers { thir_abstract_const, ..*providers }; } diff --git a/tests/crashes/131052.rs b/tests/crashes/131052.rs deleted file mode 100644 index 7ae3ec08f3ed..000000000000 --- a/tests/crashes/131052.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #131052 -#![feature(adt_const_params)] - -struct ConstBytes; - -pub fn main() { - let _: ConstBytes = ConstBytes::; -} diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs new file mode 100644 index 000000000000..7a31cd40207d --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs @@ -0,0 +1,13 @@ +//! Regression test for + +#![feature(adt_const_params)] + +struct ConstBytes; +//~^ ERROR `&'static [*mut u8; 3]` can't be used as a const parameter type + +pub fn main() { + let _: ConstBytes = ConstBytes::; + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr new file mode 100644 index 000000000000..3384a8b385cb --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -0,0 +1,42 @@ +error[E0741]: `&'static [*mut u8; 3]` can't be used as a const parameter type + --> $DIR/mismatch-raw-ptr-in-adt.rs:5:28 + | +LL | struct ConstBytes; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `*mut u8` must implement `ConstParamTy_`, but it does not + = note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not + +error[E0308]: mismatched types + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:33 + | +LL | let _: ConstBytes = ConstBytes::; + | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `&[65, 65, 65]`, found `&[66, 66, 66]` + | | + | expected due to this + | + = note: expected struct `ConstBytes<&[65, 65, 65]>` + found struct `ConstBytes<&[66, 66, 66]>` + +error[E0308]: mismatched types + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&'static [*mut u8; 3]` + found reference `&'static [u8; 3]` + +error[E0308]: mismatched types + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:23 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&'static [*mut u8; 3]` + found reference `&'static [u8; 3]` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0741. +For more information about an error, try `rustc --explain E0308`.