diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 8fa797db24661..ed3ae1e12b925 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -13,6 +13,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -1170,19 +1171,13 @@ fn check_type_defn<'tcx>( // Explicit `enum` discriminant values must const-evaluate successfully. if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr { - let cause = traits::ObligationCause::new( - tcx.def_span(discr_def_id), - wfcx.body_def_id, - ObligationCauseCode::Misc, - ); - wfcx.register_obligation(Obligation::new( - tcx, - cause, - wfcx.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable( - ty::Const::from_anon_const(tcx, discr_def_id.expect_local()), - ))), - )); + match tcx.const_eval_poly(discr_def_id) { + Ok(_) => {} + Err(ErrorHandled::Reported(..)) => {} + Err(ErrorHandled::TooGeneric(sp)) => { + span_bug!(sp, "enum variant discr was too generic to eval") + } + } } } diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 8648a7d1e3220..f1022d9575315 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::intravisit; -use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::sym; @@ -42,7 +42,8 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { } pub(crate) fn def_parents(tcx: TyCtxt<'_>) { - for did in tcx.hir().body_owners() { + for iid in tcx.hir().items() { + let did = iid.owner_id.def_id; if tcx.has_attr(did, sym::rustc_dump_def_parents) { struct AnonConstFinder<'tcx> { tcx: TyCtxt<'tcx>, @@ -50,7 +51,7 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) { } impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> { - type NestedFilter = OnlyBodies; + type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() @@ -62,11 +63,11 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) { } } - // Look for any anon consts inside of this body owner as there is no way to apply + // Look for any anon consts inside of this item as there is no way to apply // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible // to see what its def parent is. let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] }; - intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value); + intravisit::walk_item(&mut anon_ct_finder, tcx.hir().item(iid)); for did in [did].into_iter().chain(anon_ct_finder.anon_consts) { let span = tcx.def_span(did); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index bfee5d33598ad..fc1f8e9438d83 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,12 +1,13 @@ use std::assert_matches::assert_matches; -use hir::{HirId, Node}; +use hir::Node; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_middle::ty::{self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{ + self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, +}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span}; @@ -305,7 +306,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } if tcx.features().generic_const_exprs() { - predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); + predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates)); } let mut predicates: Vec<_> = predicates.into_iter().collect(); @@ -369,32 +370,49 @@ fn compute_bidirectional_outlives_predicates<'tcx>( } } -fn const_evaluatable_predicates_of( - tcx: TyCtxt<'_>, +#[instrument(level = "debug", skip(tcx, predicates), ret)] +fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> FxIndexSet<(ty::Clause<'_>, Span)> { + predicates: &FxIndexSet<(ty::Clause<'tcx>, Span)>, +) -> FxIndexSet<(ty::Clause<'tcx>, Span)> { struct ConstCollector<'tcx> { tcx: TyCtxt<'tcx>, preds: FxIndexSet<(ty::Clause<'tcx>, Span)>, } - impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { - let ct = ty::Const::from_anon_const(self.tcx, c.def_id); - if let ty::ConstKind::Unevaluated(_) = ct.kind() { - let span = self.tcx.def_span(c.def_id); - self.preds.insert((ty::ClauseKind::ConstEvaluatable(ct).upcast(self.tcx), span)); - } - } + fn is_const_param_default(tcx: TyCtxt<'_>, def: LocalDefId) -> bool { + let hir_id = tcx.local_def_id_to_hir_id(def); + let (_, parent_node) = tcx + .hir() + .parent_iter(hir_id) + .skip_while(|(_, n)| matches!(n, Node::ConstArg(..))) + .next() + .unwrap(); + debug!(?parent_node); + matches!( + parent_node, + Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { .. }, .. }) + ) + } - fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) { - // Do not look into const param defaults, - // these get checked when they are actually instantiated. - // - // We do not want the following to error: - // - // struct Foo; - // struct Bar(Foo); + impl<'tcx> TypeVisitor> for ConstCollector<'tcx> { + fn visit_const(&mut self, c: ty::Const<'tcx>) { + if let ty::ConstKind::Unevaluated(uv) = c.kind() { + if is_const_param_default(self.tcx, uv.def.expect_local()) { + // Do not look into const param defaults, + // these get checked when they are actually instantiated. + // + // We do not want the following to error: + // + // struct Foo; + // struct Bar(Foo); + return; + } + + let span = self.tcx.def_span(uv.def); + self.preds.insert((ty::ClauseKind::ConstEvaluatable(c).upcast(self.tcx), span)); + } } } @@ -402,28 +420,31 @@ fn const_evaluatable_predicates_of( let node = tcx.hir_node(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + + for (clause, _sp) in predicates { + clause.visit_with(&mut collector); + } + if let hir::Node::Item(item) = node - && let hir::ItemKind::Impl(impl_) = item.kind + && let hir::ItemKind::Impl(_) = item.kind { - if let Some(of_trait) = &impl_.of_trait { - debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); - collector.visit_trait_ref(of_trait); + if let Some(of_trait) = tcx.impl_trait_ref(def_id) { + debug!("visit impl trait_ref"); + of_trait.instantiate_identity().visit_with(&mut collector); } - debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); - collector.visit_ty(impl_.self_ty); - } - - if let Some(generics) = node.generics() { - debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); - collector.visit_generics(generics); + debug!("visit self_ty"); + let self_ty = tcx.type_of(def_id); + self_ty.instantiate_identity().visit_with(&mut collector); } - if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { - debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); - collector.visit_fn_decl(fn_sig.decl); + if let Some(_) = tcx.hir().fn_sig_by_hir_id(hir_id) { + debug!("visit fn sig"); + let fn_sig = tcx.fn_sig(def_id); + let fn_sig = fn_sig.instantiate_identity(); + debug!(?fn_sig); + fn_sig.visit_with(&mut collector); } - debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); collector.preds } 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 01276abec22b9..025216e572c2d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2088,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qpath.span(), format!("Const::lower_const_arg: invalid qpath {qpath:?}"), ), - hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id), + hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon.def_id), } } @@ -2175,6 +2175,92 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + /// Literals and const generic parameters are eagerly converted to a constant, everything else + /// becomes `Unevaluated`. + #[instrument(skip(self), level = "debug")] + pub fn lower_anon_const(&self, def: LocalDefId) -> Const<'tcx> { + let tcx = self.tcx(); + + let body_id = match tcx.hir_node_by_def_id(def) { + hir::Node::AnonConst(ac) => ac.body, + node => span_bug!( + tcx.def_span(def.to_def_id()), + "from_anon_const can only process anonymous constants, not {node:?}" + ), + }; + + let expr = &tcx.hir().body(body_id).value; + debug!(?expr); + + let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); + + match self.try_lower_anon_const_lit(ty, expr) { + Some(v) => v, + None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { + def: def.to_def_id(), + args: ty::GenericArgs::identity_for_item(tcx, def.to_def_id()), + }), + } + } + + #[instrument(skip(self), level = "debug")] + fn try_lower_anon_const_lit( + &self, + ty: Ty<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ) -> Option> { + let tcx = self.tcx(); + + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + let expr = match &expr.kind { + hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { + block.expr.as_ref().unwrap() + } + _ => expr, + }; + + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, + )) = expr.kind + { + span_bug!( + expr.span, + "try_lower_anon_const_lit: received const param which shouldn't be possible" + ); + }; + + let lit_input = match expr.kind { + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), + _ => None, + }, + _ => None, + }; + + if let Some(lit_input) = lit_input { + // If an error occurred, ignore that it's a literal and leave reporting the error up to + // mir. + match tcx.at(expr.span).lit_to_const(lit_input) { + Ok(c) => return Some(c), + Err(_) if lit_input.ty.has_aliases() => { + // allow the `ty` to be an alias type, though we cannot handle it here + return None; + } + Err(e) => { + tcx.dcx().span_delayed_bug( + expr.span, + format!("try_lower_anon_const_lit: couldn't lit_to_const {e:?}"), + ); + } + } + } + + None + } + fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); match idx { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index d27205e26abbe..310552764224e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -2,15 +2,11 @@ use std::borrow::Cow; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir}; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; -use tracing::{debug, instrument}; -use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::{self, GenericArgs, Ty, TyCtxt, TypeVisitableExt}; +use crate::mir::interpret::Scalar; +use crate::ty::{self, Ty, TyCtxt}; mod int; mod kind; @@ -181,82 +177,6 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { } impl<'tcx> Const<'tcx> { - // FIXME: move this and try_from_lit to hir_ty_lowering like lower_const_arg/from_const_arg - /// Literals and const generic parameters are eagerly converted to a constant, everything else - /// becomes `Unevaluated`. - #[instrument(skip(tcx), level = "debug")] - pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { - let body_id = match tcx.hir_node_by_def_id(def) { - hir::Node::AnonConst(ac) => ac.body, - node => span_bug!( - tcx.def_span(def.to_def_id()), - "from_anon_const can only process anonymous constants, not {node:?}" - ), - }; - - let expr = &tcx.hir().body(body_id).value; - debug!(?expr); - - let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); - - match Self::try_from_lit(tcx, ty, expr) { - Some(v) => v, - None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { - def: def.to_def_id(), - args: GenericArgs::identity_for_item(tcx, def.to_def_id()), - }), - } - } - - #[instrument(skip(tcx), level = "debug")] - fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option { - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. - let expr = match &expr.kind { - hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { - block.expr.as_ref().unwrap() - } - _ => expr, - }; - - if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, - )) = expr.kind - { - span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible"); - }; - - let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), - _ => None, - }, - _ => None, - }; - - if let Some(lit_input) = lit_input { - // If an error occurred, ignore that it's a literal and leave reporting the error up to - // mir. - match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return Some(c), - Err(_) if lit_input.ty.has_aliases() => { - // allow the `ty` to be an alias type, though we cannot handle it here - return None; - } - Err(e) => { - tcx.dcx().span_delayed_bug( - expr.span, - format!("Const::try_from_lit: couldn't lit_to_const {e:?}"), - ); - } - } - } - - None - } - /// Creates a constant with the given integer value and interns it. #[inline] pub fn from_bits( diff --git a/tests/ui/attributes/dump_def_parents.rs b/tests/ui/attributes/dump_def_parents.rs index de0c88bb6c39a..04a725f6c1442 100644 --- a/tests/ui/attributes/dump_def_parents.rs +++ b/tests/ui/attributes/dump_def_parents.rs @@ -3,16 +3,17 @@ fn bar() { fn foo() { + #[rustc_dump_def_parents] fn baz() { - #[rustc_dump_def_parents] + //~^ ERROR: rustc_dump_def_parents: DefId || { - //~^ ERROR: rustc_dump_def_parents: DefId qux::< { //~^ ERROR: rustc_dump_def_parents: DefId fn inhibits_dump() { qux::< { + //~^ ERROR: rustc_dump_def_parents: DefId "hi"; 1 }, diff --git a/tests/ui/attributes/dump_def_parents.stderr b/tests/ui/attributes/dump_def_parents.stderr index b2cc32d09b07e..a928e8e33a4f7 100644 --- a/tests/ui/attributes/dump_def_parents.stderr +++ b/tests/ui/attributes/dump_def_parents.stderr @@ -1,11 +1,50 @@ error: rustc_dump_def_parents: DefId(..) - --> $DIR/dump_def_parents.rs:8:13 + --> $DIR/dump_def_parents.rs:7:9 + | +LL | fn baz() { + | ^^^^^^^^ + | +note: DefId(..) + --> $DIR/dump_def_parents.rs:5:5 + | +LL | fn foo() { + | ^^^^^^^^ +note: DefId(..) + --> $DIR/dump_def_parents.rs:4:1 + | +LL | fn bar() { + | ^^^^^^^^ +note: DefId(..) + --> $DIR/dump_def_parents.rs:2:1 + | +LL | / #![feature(rustc_attrs)] +LL | | +LL | | fn bar() { +LL | | fn foo() { +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: rustc_dump_def_parents: DefId(..) + --> $DIR/dump_def_parents.rs:11:21 + | +LL | / { +LL | | +LL | | fn inhibits_dump() { +LL | | qux::< +... | +LL | | 1 +LL | | }, + | |_____________________^ + | +note: DefId(..) + --> $DIR/dump_def_parents.rs:9:13 | LL | || { | ^^ - | note: DefId(..) - --> $DIR/dump_def_parents.rs:6:9 + --> $DIR/dump_def_parents.rs:7:9 | LL | fn baz() { | ^^^^^^^^ @@ -32,6 +71,21 @@ LL | | fn main() {} | |____________^ error: rustc_dump_def_parents: DefId(..) + --> $DIR/dump_def_parents.rs:15:33 + | +LL | / ... { +LL | | ... +LL | | ... "hi"; +LL | | ... 1 +LL | | ... }, + | |_______________________^ + | +note: DefId(..) + --> $DIR/dump_def_parents.rs:13:25 + | +LL | fn inhibits_dump() { + | ^^^^^^^^^^^^^^^^^^ +note: DefId(..) --> $DIR/dump_def_parents.rs:11:21 | LL | / { @@ -42,14 +96,13 @@ LL | | qux::< LL | | 1 LL | | }, | |_____________________^ - | note: DefId(..) - --> $DIR/dump_def_parents.rs:8:13 + --> $DIR/dump_def_parents.rs:9:13 | LL | || { | ^^ note: DefId(..) - --> $DIR/dump_def_parents.rs:6:9 + --> $DIR/dump_def_parents.rs:7:9 | LL | fn baz() { | ^^^^^^^^ @@ -76,7 +129,7 @@ LL | | fn main() {} | |____________^ error: rustc_dump_def_parents: DefId(..) - --> $DIR/dump_def_parents.rs:22:31 + --> $DIR/dump_def_parents.rs:23:31 | LL | qux::<{ 1 + 1 }>(); | ^^^^^^^^^ @@ -93,12 +146,12 @@ LL | | 1 LL | | }, | |_____________________^ note: DefId(..) - --> $DIR/dump_def_parents.rs:8:13 + --> $DIR/dump_def_parents.rs:9:13 | LL | || { | ^^ note: DefId(..) - --> $DIR/dump_def_parents.rs:6:9 + --> $DIR/dump_def_parents.rs:7:9 | LL | fn baz() { | ^^^^^^^^ @@ -124,5 +177,5 @@ LL | | LL | | fn main() {} | |____________^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/issues/issue-83765.stderr b/tests/ui/const-generics/issues/issue-83765.stderr index c3292314f23b3..52c0ded432bea 100644 --- a/tests/ui/const-generics/issues/issue-83765.stderr +++ b/tests/ui/const-generics/issues/issue-83765.stderr @@ -10,11 +10,11 @@ note: ...which requires computing candidate for `::DIM, DIM> as TensorDimension>::DIM`, completing the cycle -note: cycle used when computing candidate for ` as TensorDimension>` - --> $DIR/issue-83765.rs:4:1 +note: cycle used when checking that `` is well-formed + --> $DIR/issue-83765.rs:50:1 | -LL | trait TensorDimension { - | ^^^^^^^^^^^^^^^^^^^^^ +LL | impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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[E0391]: cycle detected when resolving instance `::DIM, DIM> as TensorDimension>::DIM`