Skip to content
Merged
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
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)`
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ tcx_lifetime! {
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,
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1408,12 +1408,6 @@ rustc_queries! {
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>
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_middle/src/ty/consts/valtree.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -189,6 +190,26 @@ impl<'tcx> Value<'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<TyCtxt<'tcx>> for Value<'tcx> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2331,8 +2331,8 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {

/// 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<VariantIdx>,
pub struct DestructuredAdtConst<'tcx> {
pub variant: VariantIdx,
pub fields: &'tcx [ty::Const<'tcx>],
}

Expand Down
89 changes: 44 additions & 45 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1919,66 +1919,65 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
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(());
}
Expand Down
79 changes: 43 additions & 36 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,9 +755,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
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() {
Expand All @@ -776,43 +775,51 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
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);
_ => 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(())
};

self.push("V");
self.print_def_path(variant_def.def_id, args)?;
let variant_idx = contents.variant;
let variant_def = &def.variant(variant_idx);

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");
}
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!(),
}
}
_ => {
Expand Down
60 changes: 3 additions & 57 deletions compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -10,63 +7,12 @@ use rustc_middle::thir::visit;
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::<Vec<_>>();
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::<Vec<_>>();

(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::*;
Expand Down Expand Up @@ -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 };
}
8 changes: 0 additions & 8 deletions tests/crashes/131052.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/131052>
Copy link
Member

Choose a reason for hiding this comment

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

I think what's happened here is that we're now masking an ICE that was originally caused by lit_to_const returning ValTree's with incorrect types 🤔 I can't think of a way to write a test that exposes that underlying brokenness so I think this is fine.

It would be nice to fix the underlying brokenness regardless. Would you be interested in doing that? The short explanation is that we lit_to_const for byte strings doesn't check that the type of the parameter the byte string is an argument to, is &[u8] is only checks if its a reference to a slice.


#![feature(adt_const_params)]

struct ConstBytes<const T: &'static [*mut u8; 3]>;
//~^ ERROR `&'static [*mut u8; 3]` can't be used as a const parameter type

pub fn main() {
let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
}
Loading
Loading