From 34d5e7d74dd78e62bdc91d7326e94bb3f1d2cba6 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Fri, 14 Nov 2025 08:57:41 +0000 Subject: [PATCH 1/5] mgca always resolve params --- .../src/hir_ty_lowering/mod.rs | 8 ++ compiler/rustc_hir_typeck/src/lib.rs | 7 ++ compiler/rustc_middle/src/hir/map.rs | 43 +++++++ compiler/rustc_resolve/src/late.rs | 12 +- .../mgca/explicit_anon_consts.rs | 1 + .../mgca/explicit_anon_consts.stderr | 112 ++++++++---------- .../mgca/type_const-on-generic-expr.rs | 1 + .../mgca/type_const-on-generic-expr.stderr | 41 +++---- 8 files changed, 133 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4db9a4c2bcdd8..9dca0f24f0872 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2378,6 +2378,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let expr = &tcx.hir_body(anon.body).value; debug!(?expr); + // If the rhs is an anon const naming generics it shouldn't have + // access to then we lower to `ConstKind::Error`. + if let ty::AnonConstKind::MCG = tcx.anon_const_kind(anon.def_id) + && let Err(e) = tcx.hir_const_arg_anon_check_invalid_param_uses(anon.def_id) + { + return ty::Const::new_error(tcx, e); + } + // FIXME(generic_const_parameter_types): We should use the proper generic args // here. It's only used as a hint for literals so doesn't matter too much to use the right // generic arguments, just weaker type inference. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9ca5ddd494aeb..b59b886199bca 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -116,6 +116,13 @@ fn typeck_with_inspect<'tcx>( return tcx.typeck(typeck_root_def_id); } + if let DefKind::AnonConst = tcx.def_kind(def_id) + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(def_id) + && let Err(e) = tcx.hir_const_arg_anon_check_invalid_param_uses(def_id) + { + e.raise_fatal(); + } + let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index bf3192d9df173..434cc1c3aa7c4 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -2,6 +2,8 @@ //! eliminated, and all its methods are now on `TyCtxt`. But the module name //! stays as `map` because there isn't an obviously better name for it. +use std::ops::ControlFlow; + use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -1086,6 +1088,47 @@ impl<'tcx> TyCtxt<'tcx> { None } + + pub fn hir_const_arg_anon_check_invalid_param_uses( + self, + anon: LocalDefId, + ) -> Result<(), ErrorGuaranteed> { + struct GenericParamVisitor<'tcx>(TyCtxt<'tcx>); + impl<'tcx> Visitor<'tcx> for GenericParamVisitor<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + type Result = ControlFlow; + + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { + self.0 + } + + fn visit_path( + &mut self, + path: &crate::hir::Path<'tcx>, + _id: HirId, + ) -> ControlFlow { + if let Res::Def( + DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, + _, + ) = path.res + { + let e = self.0.dcx().struct_span_err( + path.span, + "generic parameters may not be used in const operations", + ); + return ControlFlow::Break(e.emit()); + } + + intravisit::walk_path(self, path) + } + } + + let body = self.hir_maybe_body_owned_by(anon).unwrap(); + match GenericParamVisitor(self).visit_expr(&body.value) { + ControlFlow::Break(e) => Err(e), + ControlFlow::Continue(()) => Ok(()), + } + } } impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1c879837d6ed6..9a9a474b2f38e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4842,12 +4842,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { constant, anon_const_kind ); - let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() { - matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct) - } else { - constant.value.is_potential_trivial_const_arg() - }; - + let is_trivial_const_arg = constant.value.is_potential_trivial_const_arg(); self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { this.resolve_expr(&constant.value, None) }) @@ -4877,7 +4872,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { - if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg { + if self.r.tcx.features().generic_const_exprs() + || self.r.tcx.features().min_generic_const_args() + || is_trivial_const_arg + { ConstantHasGenerics::Yes } else { ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index 4592827762660..c573a6bad3bed 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -7,6 +7,7 @@ type Adt1 = Foo; type Adt2 = Foo<{ N }>; type Adt3 = Foo; //~^ ERROR: generic parameters may not be used in const operations +//~^^ ERROR generic parameters may not be used in const operations type Adt4 = Foo<{ 1 + 1 }>; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Adt5 = Foo; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index e4bf49c71efed..9cb75209f2b05 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,92 +1,82 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:8:41 - | -LL | type Adt3 = Foo; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:16:42 - | -LL | type Arr3 = [(); const { N }]; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:25:27 - | -LL | let _3 = [(); const { N }]; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:37:46 - | -LL | const ITEM3: usize = const { N }; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:55:31 - | -LL | T3: Trait, - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:64:58 - | -LL | struct Default3; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:10:33 + --> $DIR/explicit_anon_consts.rs:11:33 | LL | type Adt4 = Foo<{ 1 + 1 }>; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:18:34 + --> $DIR/explicit_anon_consts.rs:19:34 | LL | type Arr4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:27:19 + --> $DIR/explicit_anon_consts.rs:28:19 | LL | let _4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:40:38 + --> $DIR/explicit_anon_consts.rs:41:38 | LL | const ITEM4: usize = { 1 + 1 }; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:57:23 + --> $DIR/explicit_anon_consts.rs:58:23 | LL | T4: Trait, | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:66:50 + --> $DIR/explicit_anon_consts.rs:67:50 | LL | struct Default4; | ^^^^^^^^^ -error: aborting due to 12 previous errors +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:8:41 + | +LL | type Adt3 = Foo; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:17:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:38:46 + | +LL | const ITEM3: usize = const { N }; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:56:31 + | +LL | T3: Trait, + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:65:58 + | +LL | struct Default3; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:26:27 + | +LL | let _3 = [(); const { N }]; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:8:41 + | +LL | type Adt3 = Foo; + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 13 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index 577fee084dbd5..a1008fae9d16d 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -4,6 +4,7 @@ #[type_const] const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations +//~^^ ERROR generic parameters may not be used in const operations #[type_const] const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 8cef77e5b2294..c77be158d0ef7 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -2,46 +2,39 @@ error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic-expr.rs:5:53 | LL | const FREE1: usize = const { std::mem::size_of::() }; - | ^ cannot perform const operation using `T` - | - = note: type parameters may not be used in const expressions - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:8:46 + --> $DIR/type_const-on-generic-expr.rs:9:46 | LL | const FREE2: usize = const { I + 1 }; - | ^ cannot perform const operation using `I` - | - = help: const parameters may only be used as standalone arguments here, i.e. `I` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:24:54 + --> $DIR/type_const-on-generic-expr.rs:25:54 | LL | const N1: usize = const { std::mem::size_of::() }; - | ^ cannot perform const operation using `T` - | - = note: type parameters may not be used in const expressions - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:27:47 + --> $DIR/type_const-on-generic-expr.rs:28:47 | LL | const N2: usize = const { I + 1 }; - | ^ cannot perform const operation using `I` - | - = help: const parameters may only be used as standalone arguments here, i.e. `I` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:30:35 + --> $DIR/type_const-on-generic-expr.rs:31:35 | LL | const N3: usize = const { 2 & X }; - | ^ cannot perform const operation using `X` + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/type_const-on-generic-expr.rs:5:53 + | +LL | const FREE1: usize = const { std::mem::size_of::() }; + | ^ | - = help: const parameters may only be used as standalone arguments here, i.e. `X` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors From 96580b7b0f6da6d75b65f1bb183ffb6afbf07299 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Thu, 20 Nov 2025 02:16:43 +0000 Subject: [PATCH 2/5] Introduce `hir::ConstArgKind::Struct` --- compiler/rustc_ast_lowering/src/index.rs | 7 ++ compiler/rustc_ast_lowering/src/lib.rs | 31 +++++++++ compiler/rustc_hir/src/hir.rs | 13 ++++ compiler/rustc_hir/src/intravisit.rs | 24 +++++++ .../src/hir_ty_lowering/mod.rs | 3 + compiler/rustc_hir_pretty/src/lib.rs | 4 ++ compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_middle/src/hir/map.rs | 2 + compiler/rustc_middle/src/hir/mod.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 68 +++++++++++++++++-- compiler/rustc_resolve/src/lib.rs | 2 + 11 files changed, 149 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 8d7351d3a510c..f6edcaa64dfef 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -281,6 +281,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_const_arg_expr_field(&mut self, field: &'hir ConstArgExprField<'hir>) { + self.insert(field.span, field.hir_id, Node::ConstArgExprField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_const_arg_expr_field(this, field); + }) + } + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 47a8f744820f1..15332ae798643 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2394,6 +2394,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } } + ExprKind::Struct(se) => { + let path = self.lower_qpath( + expr.id, + &se.qself, + &se.path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let fields = self.arena.alloc_from_iter(se.fields.iter().map(|f| { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + + let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind { + self.lower_anon_const_to_const_arg_direct(anon_const) + } else { + self.lower_expr_to_const_arg_direct(&f.expr) + }; + + &*self.arena.alloc(hir::ConstArgExprField { + hir_id, + field: self.lower_ident(f.ident), + expr: self.arena.alloc(expr), + span: self.lower_span(f.span), + }) + })); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) } + } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), kind: hir::ConstArgKind::Infer(expr.span, ()), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f5470adb87e03..bc65a06fd5cd2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -494,6 +494,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { pub fn span(&self) -> Span { match self.kind { + ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), ConstArgKind::Anon(anon) => anon.span, ConstArgKind::Error(span, _) => span, @@ -513,6 +514,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// However, in the future, we'll be using it for all of those. Path(QPath<'hir>), Anon(&'hir AnonConst), + /// Represents construction of struct/struct variants + Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), /// Error const Error(Span, ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes @@ -520,6 +523,14 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Infer(Span, Unambig), } +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub struct ConstArgExprField<'hir> { + pub hir_id: HirId, + pub span: Span, + pub field: Ident, + pub expr: &'hir ConstArg<'hir>, +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct InferArg { #[stable_hasher(ignore)] @@ -4711,6 +4722,7 @@ pub enum Node<'hir> { ConstArg(&'hir ConstArg<'hir>), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), + ConstArgExprField(&'hir ConstArgExprField<'hir>), Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), Ty(&'hir Ty<'hir>), @@ -4770,6 +4782,7 @@ impl<'hir> Node<'hir> { Node::AssocItemConstraint(c) => Some(c.ident), Node::PatField(f) => Some(f.ident), Node::ExprField(f) => Some(f.ident), + Node::ConstArgExprField(f) => Some(f.field), Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), Node::Param(..) | Node::AnonConst(..) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 625766f8bd3da..d003ab53104cd 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -396,6 +396,9 @@ pub trait Visitor<'v>: Sized { fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result { walk_expr_field(self, field) } + fn visit_const_arg_expr_field(&mut self, field: &'v ConstArgExprField<'v>) -> Self::Result { + walk_const_arg_expr_field(self, field) + } fn visit_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result { walk_ty_pat(self, p) } @@ -954,6 +957,17 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField try_visit!(visitor.visit_ident(*ident)); visitor.visit_expr(*expr) } + +pub fn walk_const_arg_expr_field<'v, V: Visitor<'v>>( + visitor: &mut V, + field: &'v ConstArgExprField<'v>, +) -> V::Result { + let ConstArgExprField { hir_id, field, expr, span: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*field)); + visitor.visit_const_arg_unambig(*expr) +} + /// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that /// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited pub enum InferKind<'hir> { @@ -1067,7 +1081,17 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( ) -> V::Result { let ConstArg { hir_id, kind } = const_arg; try_visit!(visitor.visit_id(*hir_id)); + match kind { + ConstArgKind::Struct(qpath, field_exprs) => { + try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); + + for field_expr in *field_exprs { + try_visit!(visitor.visit_const_arg_expr_field(field_expr)); + } + + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 9dca0f24f0872..dc5256b43bfcf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2263,6 +2263,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } + hir::ConstArgKind::Struct(..) => { + span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) + } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3b416955230f..f995339221109 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -180,6 +180,8 @@ impl<'a> State<'a> { Node::ConstArg(a) => self.print_const_arg(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), + // FIXME(mgca): proper printing for struct exprs + Node::ConstArgExprField(_) => self.word("/* STRUCT EXPR */"), Node::Stmt(a) => self.print_stmt(a), Node::PathSegment(a) => self.print_path_segment(a), Node::Ty(a) => self.print_type(a), @@ -1135,6 +1137,8 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { + // FIXME(mgca): proper printing for struct exprs + ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2069c06c3f774..af902a8954f02 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1443,6 +1443,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) + | hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 434cc1c3aa7c4..274cc30d87dad 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -739,6 +739,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::ConstArg(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), + Node::ConstArgExprField(_) => node_str("const arg expr field"), Node::Stmt(_) => node_str("stmt"), Node::PathSegment(_) => node_str("path segment"), Node::Ty(_) => node_str("type"), @@ -1007,6 +1008,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::ConstArg(const_arg) => const_arg.span(), Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, + Node::ConstArgExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, Node::PathSegment(seg) => { let ident_span = seg.ident.span; diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 0ab5a792e040b..21432608f83a7 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -315,6 +315,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::Block(_) | Node::Arm(_) | Node::ExprField(_) + | Node::ConstArgExprField(_) | Node::AnonConst(_) | Node::ConstBlock(_) | Node::ConstArg(_) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ea64a1e6c64dd..2818e2014af4a 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -74,6 +74,12 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.invocation_parent.impl_trait_context = orig_itc; } + fn with_direct_const_arg(&mut self, is_direct: bool, f: F) { + let orig = mem::replace(&mut self.invocation_parent.in_direct_const_arg, is_direct); + f(self); + self.invocation_parent.in_direct_const_arg = orig; + } + fn collect_field(&mut self, field: &'a FieldDef, index: Option) { let index = |this: &Self| { index.unwrap_or_else(|| { @@ -357,25 +363,73 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); - self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); + if let MgcaDisambiguation::Direct = constant.mgca_disambiguation + && self.resolver.tcx.features().min_generic_const_args() + { + self.with_direct_const_arg(true, |this| { + visit::walk_anon_const(this, constant); + }); + } else { + self.with_direct_const_arg(false, |this| { + let parent = + this.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); + this.with_parent(parent, |this| visit::walk_anon_const(this, constant)); + }) + } } fn visit_expr(&mut self, expr: &'a Expr) { + let handle_const_block = |this: &mut Self, constant: &'a AnonConst, def_kind: DefKind| { + for attr in &expr.attrs { + visit::walk_attribute(this, attr); + } + + let def = this.create_def(constant.id, None, def_kind, constant.value.span); + this.with_direct_const_arg(false, |this| { + this.with_parent(def, |this| visit::walk_anon_const(this, constant)); + }); + }; + let parent_def = match expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { self.create_def(expr.id, None, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { - for attr in &expr.attrs { - visit::walk_attribute(self, attr); + handle_const_block(self, constant, DefKind::InlineConst); + return; + } + ExprKind::Struct(ref se) if self.invocation_parent.in_direct_const_arg => { + let StructExpr { qself, path, fields, rest } = &**se; + + for init_expr in fields { + if let ExprKind::ConstBlock(ref constant) = init_expr.expr.kind { + handle_const_block(self, constant, DefKind::AnonConst); + } else { + visit::walk_expr_field(self, init_expr); + } + } + + if let Some(qself) = qself { + self.visit_qself(qself); } - let def = - self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + self.visit_path(path); + + match rest { + StructRest::Base(expr) => self.visit_expr(expr), + _ => (), + } + return; } + ExprKind::Field(ref init_expr, _) if self.invocation_parent.in_direct_const_arg => { + if let ExprKind::ConstBlock(ref constant) = init_expr.kind { + handle_const_block(self, constant, DefKind::AnonConst); + return; + } else { + self.invocation_parent.parent_def + } + } _ => self.invocation_parent.parent_def, }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b3141406e467e..eca2da15b667e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -188,6 +188,7 @@ struct InvocationParent { parent_def: LocalDefId, impl_trait_context: ImplTraitContext, in_attr: bool, + in_direct_const_arg: bool, } impl InvocationParent { @@ -195,6 +196,7 @@ impl InvocationParent { parent_def: CRATE_DEF_ID, impl_trait_context: ImplTraitContext::Existential, in_attr: false, + in_direct_const_arg: false, }; } From c629fbabbff8c8ee6ccefdd97e5ced73374ebdbd Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 19:30:09 +0000 Subject: [PATCH 3/5] Make `ValTree` recurse through `ty::Const` --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 10 ++- .../rustc_codegen_ssa/src/mir/constant.rs | 6 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 4 +- .../src/const_eval/valtrees.rs | 21 +++-- .../src/interpret/intrinsics/simd.rs | 14 ++- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 2 +- compiler/rustc_middle/src/thir.rs | 2 +- .../rustc_middle/src/ty/consts/valtree.rs | 89 ++++++++----------- compiler/rustc_middle/src/ty/context.rs | 5 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/pattern.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 25 +++++- .../src/builder/custom/parse/instruction.rs | 1 + .../src/builder/matches/mod.rs | 7 +- .../src/builder/matches/test.rs | 2 +- compiler/rustc_mir_build/src/builder/scope.rs | 9 +- compiler/rustc_mir_build/src/thir/constant.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 23 +++-- compiler/rustc_pattern_analysis/src/rustc.rs | 3 +- compiler/rustc_symbol_mangling/src/legacy.rs | 1 + compiler/rustc_transmute/src/lib.rs | 3 +- compiler/rustc_ty_utils/src/consts.rs | 13 +-- compiler/rustc_type_ir/src/const_kind.rs | 36 ++++++++ compiler/rustc_type_ir/src/flags.rs | 12 ++- compiler/rustc_type_ir/src/inherent.rs | 5 ++ compiler/rustc_type_ir/src/interner.rs | 3 +- compiler/rustc_type_ir/src/relate.rs | 16 +++- ...transmute_infinitely_recursive_type.stderr | 2 +- 29 files changed, 220 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e43bd8c2feef5..b82b344d7cb96 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -14,7 +14,9 @@ use rustc_hir::{self as hir}; use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::offload_meta::OffloadMetadata; -use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv}; +use rustc_middle::ty::{ + self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv, ValTreeKindExt, +}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol, sym}; @@ -1547,7 +1549,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .iter() .enumerate() .map(|(arg_idx, val)| { - let idx = val.unwrap_leaf().to_i32(); + let idx = val.to_value().valtree.unwrap_leaf().to_i32(); if idx >= i32::try_from(total_len).unwrap() { bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { span, @@ -1944,6 +1946,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // The memory addresses corresponding to the “off” lanes are not accessed. let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(); @@ -2039,6 +2043,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // The memory addresses corresponding to the “off” lanes are not accessed. let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 11b6ab3cdf1ab..44ff252ad51c8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,7 +1,7 @@ use rustc_abi::BackendRepr; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, ValTreeKindExt}; use rustc_middle::{bug, mir, span_bug}; use super::FunctionCx; @@ -79,12 +79,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // A SIMD type has a single field, which is an array. let fields = val.unwrap_branch(); assert_eq!(fields.len(), 1); - let array = fields[0].unwrap_branch(); + let array = fields[0].to_value().valtree.unwrap_branch(); // Iterate over the array elements to obtain the values in the vector. let values: Vec<_> = array .iter() .map(|field| { - if let Some(prim) = field.try_to_scalar() { + if let Some(prim) = field.to_value().valtree.try_to_scalar() { let layout = bx.layout_of(field_ty); let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index aeb7401182347..2e4775e42cba6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,6 +1,6 @@ use rustc_abi::WrappingRange; use rustc_middle::mir::SourceInfo; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, ValTreeKindExt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; @@ -102,7 +102,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let parse_atomic_ordering = |ord: ty::Value<'tcx>| { - let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); + let discr = ord.valtree.unwrap_branch()[0].to_value().valtree.unwrap_leaf(); discr.to_atomic_ordering() }; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 7c41258ebfe5f..a3cb6570ff83d 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -3,7 +3,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::layout::{LayoutCx, TyAndLayout}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, ValTreeKindExt}; use rustc_middle::{bug, mir}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; @@ -36,13 +36,17 @@ fn branches<'tcx>( // For enums, we prepend their variant index before the variant's fields so we can figure out // the variant again when just seeing a valtree. if let Some(variant) = variant { - branches.push(ty::ValTree::from_scalar_int(*ecx.tcx, variant.as_u32().into())); + branches.push(ty::Const::new_value( + *ecx.tcx, + ty::ValTree::from_scalar_int(*ecx.tcx, variant.as_u32().into()), + ecx.tcx.types.u32, + )); } for i in 0..field_count { let field = ecx.project_field(&place, FieldIdx::from_usize(i)).unwrap(); let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; - branches.push(valtree); + branches.push(ty::Const::new_value(*ecx.tcx, valtree, field.layout.ty)); } // Have to account for ZSTs here @@ -65,7 +69,7 @@ fn slice_branches<'tcx>( for i in 0..n { let place_elem = ecx.project_index(place, i).unwrap(); let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; - elems.push(valtree); + elems.push(ty::Const::new_value(*ecx.tcx, valtree, place_elem.layout.ty)); } Ok(ty::ValTree::from_branches(*ecx.tcx, elems)) @@ -201,7 +205,7 @@ fn reconstruct_place_meta<'tcx>( |ty| ty, || { let branches = last_valtree.unwrap_branch(); - last_valtree = *branches.last().unwrap(); + last_valtree = branches.last().unwrap().to_value().valtree; debug!(?branches, ?last_valtree); }, ); @@ -306,7 +310,8 @@ pub fn valtree_to_const_value<'tcx>( for (i, &inner_valtree) in branches.iter().enumerate() { let field = layout.field(&LayoutCx::new(tcx, typing_env), i); if !field.is_zst() { - let cv = ty::Value { valtree: inner_valtree, ty: field.ty }; + let cv = + ty::Value { valtree: inner_valtree.to_value().valtree, ty: field.ty }; return valtree_to_const_value(tcx, typing_env, cv); } } @@ -397,7 +402,7 @@ fn valtree_into_mplace<'tcx>( let (place_adjusted, branches, variant_idx) = match ty.kind() { ty::Adt(def, _) if def.is_enum() => { // First element of valtree corresponds to variant - let scalar_int = branches[0].unwrap_leaf(); + let scalar_int = branches[0].to_value().valtree.unwrap_leaf(); let variant_idx = VariantIdx::from_u32(scalar_int.to_u32()); let variant = def.variant(variant_idx); debug!(?variant); @@ -425,7 +430,7 @@ fn valtree_into_mplace<'tcx>( }; debug!(?place_inner); - valtree_into_mplace(ecx, &place_inner, *inner_valtree); + valtree_into_mplace(ecx, &place_inner, inner_valtree.to_value().valtree); dump_place(ecx, &place_inner); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index 20de476831225..7ea9e04110bcd 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -3,7 +3,7 @@ use rustc_abi::{BackendRepr, Endian}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, Round}; use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo}; -use rustc_middle::ty::{FloatTy, ScalarInt, SimdAlign}; +use rustc_middle::ty::{FloatTy, ScalarInt, SimdAlign, ValTreeKindExt}; use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty}; use rustc_span::{Symbol, sym}; use tracing::trace; @@ -552,8 +552,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(u64::try_from(index_len).unwrap(), dest_len); for i in 0..dest_len { - let src_index: u64 = - index[usize::try_from(i).unwrap()].unwrap_leaf().to_u32().into(); + let src_index: u64 = index[usize::try_from(i).unwrap()] + .to_value() + .valtree + .unwrap_leaf() + .to_u32() + .into(); let dest = self.project_index(&dest, i)?; let val = if src_index < left_len { @@ -658,6 +662,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr, dest_layout, generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(), )?; @@ -690,6 +696,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr, args[2].layout, generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(), )?; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d1d4c32184ee8..4fa39eb83e9e9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,7 +92,7 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, + [] valtree: rustc_middle::ty::ValTreeKind>, [] stable_order_of_exportable_impls: rustc_data_structures::fx::FxIndexMap, diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 6985cc7ddcfa1..b3f852308daf3 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -12,7 +12,7 @@ use super::interpret::ReportedErrorInfo; use crate::mir::interpret::{AllocId, AllocRange, ErrorHandled, GlobalAlloc, Scalar, alloc_range}; use crate::mir::{Promoted, pretty_print_const_value}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; -use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt}; +use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt, ValTreeKindExt}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index edbb736128cf9..c320b3d1ba751 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -33,7 +33,7 @@ use crate::ty::adjustment::PointerCoercion; use crate::ty::layout::IntegerExt; use crate::ty::{ self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, Ty, - TyCtxt, UpvarArgs, + TyCtxt, UpvarArgs, ValTreeKindExt, }; pub mod visit; diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index a14e47d70821d..bd753781733a4 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -3,48 +3,19 @@ use std::ops::Deref; use rustc_data_structures::intern::Interned; use rustc_hir::def::Namespace; -use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{ + HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension, +}; use super::ScalarInt; use crate::mir::interpret::{ErrorHandled, Scalar}; use crate::ty::print::{FmtPrinter, PrettyPrinter}; use crate::ty::{self, Ty, TyCtxt}; -/// This datastructure is used to represent the value of constants used in the type system. -/// -/// We explicitly choose a different datastructure from the way values are processed within -/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have -/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. -/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different -/// `AllocId`s point to equal values. So we may end up with different representations for -/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will -/// have arbitrary values within that padding, even if the values of the struct are the same. -/// -/// `ValTree` does not have this problem with representation, as it only contains integers or -/// lists of (nested) `ValTree`. -#[derive(Clone, Debug, Hash, Eq, PartialEq)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub enum ValTreeKind<'tcx> { - /// integers, `bool`, `char` are represented as scalars. - /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values - /// of these types have the same representation. - Leaf(ScalarInt), - - //SliceOrStr(ValSlice<'tcx>), - // don't use SliceOrStr for now - /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by - /// listing their fields' values in order. - /// - /// Enums are represented by storing their variant index as a u32 field, followed by all - /// the fields of the variant. - /// - /// ZST types are represented as an empty slice. - Branch(Box<[ValTree<'tcx>]>), -} - -impl<'tcx> ValTreeKind<'tcx> { +#[extension(pub trait ValTreeKindExt<'tcx>)] +impl<'tcx> ty::ValTreeKind> { #[inline] - pub fn unwrap_leaf(&self) -> ScalarInt { + fn unwrap_leaf(&self) -> ScalarInt { match self { Self::Leaf(s) => *s, _ => bug!("expected leaf, got {:?}", self), @@ -52,25 +23,25 @@ impl<'tcx> ValTreeKind<'tcx> { } #[inline] - pub fn unwrap_branch(&self) -> &[ValTree<'tcx>] { + fn unwrap_branch(&self) -> &[ty::Const<'tcx>] { match self { Self::Branch(branch) => &**branch, _ => bug!("expected branch, got {:?}", self), } } - pub fn try_to_scalar(&self) -> Option { + fn try_to_scalar(&self) -> Option { self.try_to_scalar_int().map(Scalar::Int) } - pub fn try_to_scalar_int(&self) -> Option { + fn try_to_scalar_int(&self) -> Option { match self { Self::Leaf(s) => Some(*s), Self::Branch(_) => None, } } - pub fn try_to_branch(&self) -> Option<&[ValTree<'tcx>]> { + fn try_to_branch(&self) -> Option<&[ty::Const<'tcx>]> { match self { Self::Branch(branch) => Some(&**branch), Self::Leaf(_) => None, @@ -80,12 +51,18 @@ impl<'tcx> ValTreeKind<'tcx> { /// An interned valtree. Use this rather than `ValTreeKind`, whenever possible. /// -/// See the docs of [`ValTreeKind`] or the [dev guide] for an explanation of this type. +/// See the docs of [`ty::ValTreeKind`] or the [dev guide] for an explanation of this type. /// /// [dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html#valtrees #[derive(Copy, Clone, Hash, Eq, PartialEq)] #[derive(HashStable)] -pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ValTreeKind<'tcx>>); +pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind>>); + +impl<'tcx> rustc_type_ir::inherent::ValTree> for ValTree<'tcx> { + fn kind(&self) -> &ty::ValTreeKind> { + &self + } +} impl<'tcx> ValTree<'tcx> { /// Returns the zero-sized valtree: `Branch([])`. @@ -94,28 +71,33 @@ impl<'tcx> ValTree<'tcx> { } pub fn is_zst(self) -> bool { - matches!(*self, ValTreeKind::Branch(box [])) + matches!(*self, ty::ValTreeKind::Branch(box [])) } pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self { - let branches = bytes.iter().map(|&b| Self::from_scalar_int(tcx, b.into())); + let branches = bytes.iter().map(|&b| { + ty::Const::new_value(tcx, Self::from_scalar_int(tcx, b.into()), tcx.types.u8) + }); Self::from_branches(tcx, branches) } - pub fn from_branches(tcx: TyCtxt<'tcx>, branches: impl IntoIterator) -> Self { - tcx.intern_valtree(ValTreeKind::Branch(branches.into_iter().collect())) + pub fn from_branches( + tcx: TyCtxt<'tcx>, + branches: impl IntoIterator>, + ) -> Self { + tcx.intern_valtree(ty::ValTreeKind::Branch(branches.into_iter().collect())) } pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self { - tcx.intern_valtree(ValTreeKind::Leaf(i)) + tcx.intern_valtree(ty::ValTreeKind::Leaf(i)) } } impl<'tcx> Deref for ValTree<'tcx> { - type Target = &'tcx ValTreeKind<'tcx>; + type Target = &'tcx ty::ValTreeKind>; #[inline] - fn deref(&self) -> &&'tcx ValTreeKind<'tcx> { + fn deref(&self) -> &&'tcx ty::ValTreeKind> { &self.0.0 } } @@ -192,9 +174,14 @@ impl<'tcx> Value<'tcx> { _ => return None, } - Some(tcx.arena.alloc_from_iter( - self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()), - )) + Some( + tcx.arena.alloc_from_iter( + self.valtree + .unwrap_branch() + .into_iter() + .map(|ct| ct.to_value().valtree.unwrap_leaf().to_u8()), + ), + ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 471bd1d937e94..07aaa78b61b16 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -165,6 +165,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; type ValTree = ty::ValTree<'tcx>; + type ScalarInt = ty::ScalarInt; type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; @@ -954,7 +955,7 @@ pub struct CtxtInterners<'tcx> { fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, - valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, + valtree: InternedSet<'tcx, ty::ValTreeKind>>, patterns: InternedSet<'tcx, List>>, outlives: InternedSet<'tcx, List>>, } @@ -2777,7 +2778,7 @@ macro_rules! direct_interners { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, - valtree: pub(crate) intern_valtree(ValTreeKind<'tcx>): ValTree -> ValTree<'tcx>, + valtree: pub(crate) intern_valtree(ValTreeKind>): ValTree -> ValTree<'tcx>, pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutData): Layout -> Layout<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b91176e3d4862..04ddd102d8ea3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -75,7 +75,7 @@ pub use self::closure::{ }; pub use self::consts::{ AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, - ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKind, Value, + ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 335e5c0647435..7be73a438833e 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -8,7 +8,7 @@ use rustc_type_ir::{ }; use super::TyCtxt; -use crate::ty; +use crate::ty::{self, ValTreeKindExt}; pub type PatternKind<'tcx> = ir::PatternKind>; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 4f70830002ce8..b89f788a53026 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -257,8 +257,8 @@ TrivialTypeTraversalImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::BoundRegion, + crate::ty::ScalarInt, crate::ty::UserTypeAnnotationIndex, - crate::ty::ValTree<'tcx>, crate::ty::abstract_const::NotConstEvaluatable, crate::ty::adjustment::AutoBorrowMutability, crate::ty::adjustment::PointerCoercion, @@ -697,6 +697,29 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { } } +impl<'tcx> TypeVisitable> for ty::ValTree<'tcx> { + fn visit_with>>(&self, visitor: &mut V) -> V::Result { + let inner: &ty::ValTreeKind> = &*self; + inner.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable> for ty::ValTree<'tcx> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let inner: &ty::ValTreeKind> = &*self; + let valtree = folder.cx().intern_valtree(inner.clone().try_fold_with(folder)?); + Ok(valtree) + } + + fn fold_with>>(self, folder: &mut F) -> Self { + let inner: &ty::ValTreeKind> = &*self; + folder.cx().intern_valtree(inner.clone().fold_with(folder)) + } +} + impl<'tcx> TypeVisitable> for rustc_span::ErrorGuaranteed { fn visit_with>>(&self, visitor: &mut V) -> V::Result { visitor.visit_error(*self) diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index b221318bf0b10..4708a563e5f98 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -3,6 +3,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; +use rustc_middle::ty::ValTreeKindExt; use rustc_middle::ty::cast::mir_cast_kind; use rustc_span::Span; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 433c3e5aaaeec..def7ce339fe3e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -18,7 +18,9 @@ use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node, Pinned use rustc_middle::middle::region::{self, TempLifetime}; use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind}; +use rustc_middle::ty::{ + self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind, ValTreeKindExt, +}; use rustc_middle::{bug, span_bug}; use rustc_pattern_analysis::constructor::RangeEnd; use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt}; @@ -3014,7 +3016,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { bug!("malformed valtree for an enum") }; - let ValTreeKind::Leaf(actual_variant_idx) = ***actual_variant_idx else { + let ValTreeKind::Leaf(actual_variant_idx) = *actual_variant_idx.to_value().valtree + else { bug!("malformed valtree for an enum") }; diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 1b6d96e49f0c1..4aa204e88cb3a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; use rustc_middle::mir::*; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, ValTreeKindExt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 9665987362202..f765a44156da7 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -897,7 +897,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.tcx, ValTree::from_branches( self.tcx, - [ValTree::from_scalar_int(self.tcx, variant_index.as_u32().into())], + [ty::Const::new_value( + self.tcx, + ValTree::from_scalar_int( + self.tcx, + variant_index.as_u32().into(), + ), + self.tcx.types.u32, + )], ), self.thir[value].ty, ), diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 6e071fb344c44..563212a51f31a 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -63,7 +63,7 @@ pub(crate) fn lit_to_const<'tcx>( // A CStr is a newtype around a byte slice, so we create the inner slice here. // We need a branch for each "level" of the data structure. let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); - ty::ValTree::from_branches(tcx, [bytes]) + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, *inner_ty)]) } (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6316ccf1b8c5b..5688cde06473b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::span_bug; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree, ValTreeKindExt, }; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; @@ -240,13 +240,14 @@ impl<'tcx> ConstToPat<'tcx> { } ty::Adt(adt_def, args) if adt_def.is_enum() => { let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); - let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32()); + let variant_index = + VariantIdx::from_u32(variant_index.to_value().valtree.unwrap_leaf().to_u32()); PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns: self.field_pats( - fields.iter().copied().zip( + fields.iter().map(|ct| ct.to_value().valtree).zip( adt_def.variants()[variant_index] .fields .iter() @@ -258,19 +259,23 @@ impl<'tcx> ConstToPat<'tcx> { ty::Adt(def, args) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { - subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip( - def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)), - )), + subpatterns: self.field_pats( + cv.unwrap_branch().iter().map(|ct| ct.to_value().valtree).zip( + def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)), + ), + ), } } ty::Tuple(fields) => PatKind::Leaf { - subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter())), + subpatterns: self.field_pats( + cv.unwrap_branch().iter().map(|ct| ct.to_value().valtree).zip(fields.iter()), + ), }, ty::Slice(elem_ty) => PatKind::Slice { prefix: cv .unwrap_branch() .iter() - .map(|val| *self.valtree_to_pat(*val, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) .collect(), slice: None, suffix: Box::new([]), @@ -279,7 +284,7 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| *self.valtree_to_pat(*val, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) .collect(), slice: None, suffix: Box::new([]), diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index df86233c2b055..0e356d22a54a1 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -11,7 +11,8 @@ use rustc_middle::middle::stability::EvalResult; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, + self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, ValTreeKindExt, + VariantDef, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index ee2621af84280..1f0650d95a7ec 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -9,6 +9,7 @@ use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt, + ValTreeKindExt, }; use tracing::debug; diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 36281ff16bceb..e8625d9ac20b5 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -4,6 +4,7 @@ // tidy-alphabetical-end pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; +use rustc_middle::ty::ValTreeKindExt; pub mod layout; mod maybe_transmutable; @@ -158,7 +159,7 @@ mod rustc { .enumerate() .find(|(_, field_def)| name == field_def.name) .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); - fields[field_idx].unwrap_leaf() == ScalarInt::TRUE + fields[field_idx].to_value().valtree.unwrap_leaf() == ScalarInt::TRUE }; Some(Self { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 4b19d0f16d78a..0be154458858a 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -9,7 +9,7 @@ use rustc_middle::query::Providers; 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::ty::{self, Expr, TyCtxt, TypeVisitableExt, ValTreeKindExt}; use rustc_middle::{bug, mir, thir}; use rustc_span::Span; use tracing::{debug, instrument}; @@ -33,7 +33,7 @@ fn destructure_const<'tcx>( // construct the consts for the elements of the array/slice let field_consts = branches .iter() - .map(|b| ty::Const::new_value(tcx, *b, *inner_ty)) + .map(|b| ty::Const::new_value(tcx, b.to_value().valtree, *inner_ty)) .collect::>(); debug!(?field_consts); @@ -43,7 +43,7 @@ fn destructure_const<'tcx>( ty::Adt(def, args) => { let (variant_idx, branches) = if def.is_enum() { let (head, rest) = branches.split_first().unwrap(); - (VariantIdx::from_u32(head.unwrap_leaf().to_u32()), rest) + (VariantIdx::from_u32(head.to_value().valtree.unwrap_leaf().to_u32()), rest) } else { (FIRST_VARIANT, branches) }; @@ -52,7 +52,8 @@ fn destructure_const<'tcx>( for (field, field_valtree) in iter::zip(fields, branches) { let field_ty = field.ty(tcx, args); - let field_const = ty::Const::new_value(tcx, *field_valtree, field_ty); + let field_const = + ty::Const::new_value(tcx, field_valtree.to_value().valtree, field_ty); field_consts.push(field_const); } debug!(?field_consts); @@ -61,7 +62,9 @@ fn destructure_const<'tcx>( } ty::Tuple(elem_tys) => { let fields = iter::zip(*elem_tys, branches) - .map(|(elem_ty, elem_valtree)| ty::Const::new_value(tcx, *elem_valtree, elem_ty)) + .map(|(elem_ty, elem_valtree)| { + ty::Const::new_value(tcx, elem_valtree.to_value().valtree, elem_ty) + }) .collect::>(); (fields, None) diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 8393bbe5caf83..7146da6203d5b 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -124,3 +124,39 @@ impl HashStable for InferConst { } } } + +/// This datastructure is used to represent the value of constants used in the type system. +/// +/// We explicitly choose a different datastructure from the way values are processed within +/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have +/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. +/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different +/// `AllocId`s point to equal values. So we may end up with different representations for +/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will +/// have arbitrary values within that padding, even if the values of the struct are the same. +/// +/// `ValTree` does not have this problem with representation, as it only contains integers or +/// lists of (nested) `ValTree`. +#[derive_where(Clone, Debug, Hash, Eq, PartialEq; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] +pub enum ValTreeKind { + /// integers, `bool`, `char` are represented as scalars. + /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values + /// of these types have the same representation. + Leaf(I::ScalarInt), + + //SliceOrStr(ValSlice<'tcx>), + // don't use SliceOrStr for now + /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by + /// listing their fields' values in order. + /// + /// Enums are represented by storing their variant index as a u32 field, followed by all + /// the fields of the variant. + /// + /// ZST types are represented as an empty slice. + Branch(Box<[I::Const]>), +} diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 34b030ee768b6..2c1fc7decc3e7 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -477,7 +477,17 @@ impl FlagComputation { ty::ConstKind::Placeholder(_) => { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); } - ty::ConstKind::Value(cv) => self.add_ty(cv.ty()), + ty::ConstKind::Value(cv) => { + self.add_ty(cv.ty()); + match cv.valtree().kind() { + ty::ValTreeKind::Leaf(_) => (), + ty::ValTreeKind::Branch(cts) => { + for ct in cts { + self.add_const(*ct); + } + } + } + } ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 75ba0231d98cb..b1a722e78f948 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -292,6 +292,11 @@ pub trait ValueConst>: Copy + Debug + Hash + Eq { fn valtree(self) -> I::ValTree; } +pub trait ValTree>: Copy + Debug + Hash + Eq { + // This isnt' `IntoKind` because then we can't return a reference + fn kind(&self) -> &ty::ValTreeKind; +} + pub trait ExprConst>: Copy + Debug + Hash + Eq + Relate { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 3884f29a4fc80..03cf738c05987 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -153,7 +153,8 @@ pub trait Interner: type PlaceholderConst: PlaceholderConst; type ValueConst: ValueConst; type ExprConst: ExprConst; - type ValTree: Copy + Debug + Hash + Eq; + type ValTree: ValTree; + type ScalarInt: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 4f843503d1afe..4954ebc51cfce 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -582,13 +582,27 @@ pub fn structurally_relate_consts>( } (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - a_val.valtree() == b_val.valtree() + match (a_val.valtree().kind(), b_val.valtree().kind()) { + (ty::ValTreeKind::Leaf(scalar_a), ty::ValTreeKind::Leaf(scalar_b)) => { + scalar_a == scalar_b + } + (ty::ValTreeKind::Branch(branches_a), ty::ValTreeKind::Branch(branches_b)) + if branches_a.len() == branches_b.len() => + { + branches_a + .into_iter() + .zip(branches_b) + .all(|(a, b)| relation.relate(*a, *b).is_ok()) + } + _ => false, + } } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can // be stabilized. (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { + // FIXME(mgca): remove this if cfg!(debug_assertions) { let a_ty = cx.type_of(au.def.into()).instantiate(cx, au.args); let b_ty = cx.type_of(bu.def.into()).instantiate(cx, bu.args); diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index 1a0563b469c1e..a96876a2c25a1 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -12,7 +12,7 @@ LL | struct ExplicitlyPadded(Box); error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` | = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` + = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 2 previous errors From d889419dfd0e7e77c8f822922d296319f547d5b1 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 19:31:11 +0000 Subject: [PATCH 4/5] Lower `hir::ConstArgKind::Struct` to a `ValTree` --- .../src/hir_ty_lowering/mod.rs | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index dc5256b43bfcf..2a5770fe147bd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2263,8 +2263,79 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } - hir::ConstArgKind::Struct(..) => { - span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) + hir::ConstArgKind::Struct(qpath, inits) => { + let (ty, variant_did) = match qpath { + hir::QPath::Resolved(maybe_qself, path) => { + debug!(?maybe_qself, ?path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + let ty = self.lower_resolved_ty_path( + opt_self_ty, + path, + hir_id, + PermitVariants::Yes, + ); + let variant_did = match path.res { + Res::Def(DefKind::Variant | DefKind::Struct, did) => did, + _ => todo!(), + }; + + (ty, variant_did) + } + hir::QPath::TypeRelative(hir_self_ty, segment) => { + debug!(?hir_self_ty, ?segment); + let self_ty = self.lower_ty(hir_self_ty); + let opt_res = self.lower_type_relative_ty_path( + self_ty, + hir_self_ty, + segment, + hir_id, + const_arg.span(), + PermitVariants::Yes, + ); + + let (ty, _, res_def_id) = match opt_res { + Ok(r @ (_, DefKind::Variant | DefKind::Struct, _)) => r, + Ok(_) => todo!(), + Err(e) => return ty::Const::new_error(tcx, e), + }; + + (ty, res_def_id) + } + }; + + let (adt_def, adt_args) = match ty.kind() { + ty::Adt(adt_def, args) => (adt_def, args), + _ => todo!(), + }; + + let variant_def = adt_def.variant_with_id(variant_did); + let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32(); + + let fields = variant_def + .fields + .iter() + .map(|field_def| { + let init_expr = inits + .iter() + .find(|init_expr| init_expr.field.name == field_def.name) + .unwrap(); + self.lower_const_arg( + init_expr.expr, + FeedConstTy::Param(field_def.did, adt_args), + ) + }) + .collect::>(); + + let opt_discr_const = if adt_def.is_enum() { + let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into()); + Some(ty::Const::new_value(tcx, valtree, tcx.types.u32)) + } else { + None + }; + + let valtree = + ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields)); + ty::Const::new_value(tcx, valtree, ty) } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), From 11a8f1a4071f33a40dadd56fd5a3064ab15317d1 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 23:28:50 +0000 Subject: [PATCH 5/5] Fix tools --- .../src/intrinsics/simd.rs | 13 ++++++++++-- src/librustdoc/clean/mod.rs | 5 ++++- src/librustdoc/clean/utils.rs | 4 +++- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 21 +++++++++++++++---- src/tools/miri/src/intrinsics/atomic.rs | 4 ++-- 7 files changed, 39 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 0bce31beb8b87..d071188bcc799 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -2,7 +2,7 @@ use cranelift_codegen::ir::immediates::Offset32; use rustc_abi::Endian; -use rustc_middle::ty::SimdAlign; +use rustc_middle::ty::{SimdAlign, ValTreeKindExt}; use super::*; use crate::prelude::*; @@ -143,7 +143,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let total_len = lane_count * 2; - let indexes = idx.iter().map(|idx| idx.unwrap_leaf().to_u32()).collect::>(); + let indexes = idx + .iter() + .map(|idx| idx.to_value().valtree.unwrap_leaf().to_u32()) + .collect::>(); for &idx in &indexes { assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); @@ -962,6 +965,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let ptr_val = ptr.load_scalar(fx); let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(); @@ -1007,6 +1012,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let ret_lane_layout = fx.layout_of(ret_lane_ty); let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(); @@ -1060,6 +1067,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let ptr_val = ptr.load_scalar(fx); let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] + .to_value() + .valtree .unwrap_leaf() .to_simd_alignment(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd5c50d2ba37c..76d88502b7d34 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -319,6 +319,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::Path(qpath) => { ConstantKind::Path { path: qpath_to_string(qpath).into() } } + hir::ConstArgKind::Struct(..) => { + ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1806,7 +1809,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) } - hir::ConstArgKind::Path(..) => { + hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4c3f26701baba..59310649b3653 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -12,7 +12,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_metadata::rendered_const; use rustc_middle::mir; -use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgKind, GenericArgsRef, TyCtxt, TypeVisitableExt, ValTreeKindExt, +}; use rustc_span::symbol::{Symbol, kw, sym}; use tracing::{debug, warn}; use {rustc_ast as ast, rustc_hir as hir}; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 03cbb0311c6ca..685b0a9c0d60f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -319,6 +319,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { chain!(self, "let ConstArgKind::Anon({anon_const}) = {const_arg}.kind"); self.body(field!(anon_const.body)); }, + ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 7e3fa4f9909b3..e43b0b95d9f7f 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1139,7 +1139,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, + ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, }, } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c6d82c0e63fa6..5cadf5fbb869b 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -477,11 +477,18 @@ impl HirEqInterExpr<'_, '_, '_> { (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, + (ConstArgKind::Struct(path_a, inits_a), ConstArgKind::Struct(path_b, inits_b)) => { + self.eq_qpath(path_a, path_b) + && inits_a.iter().zip(*inits_b).all(|(init_a, init_b)| { + self.eq_const_arg(init_a.expr, init_b.expr) + }) + } // Use explicit match for now since ConstArg is undergoing flux. - (ConstArgKind::Path(..), ConstArgKind::Anon(..)) - | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) - | (ConstArgKind::Infer(..) | ConstArgKind::Error(..), _) - | (_, ConstArgKind::Infer(..) | ConstArgKind::Error(..)) => false, + (ConstArgKind::Path(..), _) + | (ConstArgKind::Anon(..), _) + | (ConstArgKind::Infer(..), _) + | (ConstArgKind::Struct(..), _) + | (ConstArgKind::Error(..), _) => false, } } @@ -1332,6 +1339,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { match &const_arg.kind { ConstArgKind::Path(path) => self.hash_qpath(path), ConstArgKind::Anon(anon) => self.hash_body(anon.body), + ConstArgKind::Struct(path, inits) => { + self.hash_qpath(path); + for init in *inits { + self.hash_const_arg(init.expr); + } + } ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 9bb0ab70de236..74901cceb0f8d 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::BinOp; -use rustc_middle::ty::AtomicOrdering; +use rustc_middle::ty::{AtomicOrdering, ValTreeKindExt}; use rustc_middle::{mir, ty}; use super::check_intrinsic_arg_count; @@ -31,7 +31,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let get_ord_at = |i: usize| { let ordering = generic_args.const_at(i).to_value(); - ordering.valtree.unwrap_branch()[0].unwrap_leaf().to_atomic_ordering() + ordering.valtree.unwrap_branch()[0].to_value().valtree.unwrap_leaf().to_atomic_ordering() }; fn read_ord(ord: AtomicOrdering) -> AtomicReadOrd {