From 9b28d3b494f5507b13b04f383bb4ea2bf23294fc Mon Sep 17 00:00:00 2001 From: b-naber Date: Sat, 2 Apr 2022 12:09:22 +0200 Subject: [PATCH] try to evaluate in from_opt_const_arg_anon_const --- compiler/rustc_middle/src/mir/mod.rs | 79 ++++++++++++++++++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 7 +- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5d09d84e19c4..9b39c61719c8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -9,7 +9,7 @@ use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; @@ -2901,14 +2901,19 @@ impl<'tcx> ConstantKind<'tcx> { /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly /// converted to a constant, everything else becomes `Unevaluated`. - pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id)) + pub fn from_anon_const( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) } #[instrument(skip(tcx), level = "debug")] fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, + param_env: ty::ParamEnv<'tcx>, ) -> Self { let body_id = match tcx.hir().get_by_def_id(def.did) { hir::Node::AnonConst(ac) => ac.body, @@ -2921,11 +2926,72 @@ impl<'tcx> ConstantKind<'tcx> { let expr = &tcx.hir().body(body_id).value; debug!(?expr); + // 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, + }; + let ty = tcx.type_of(def.def_id_for_type_of()); - match Self::try_eval_lit_or_param(tcx, ty, expr) { - Some(v) => v, - None => { + // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` + // does not provide the parents generics to anonymous constants. We still allow generic const + // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to + // ever try to substitute the generic parameters in their bodies. + // + // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does + // cause issues if we were to remove that special-case and try to evaluate the constant instead. + use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; + match expr.kind { + ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { + // Find the name and index of the const parameter by indexing the generics of + // the parent item and construct a `ParamConst`. + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().get_parent_node(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id.to_def_id()); + let index = generics.param_def_id_to_index[&def_id]; + let name = tcx.hir().name(hir_id); + let ty_const = tcx.mk_const(ty::ConstS { + val: ty::ConstKind::Param(ty::ParamConst::new(index, name)), + ty, + }); + + return Self::Ty(ty_const); + } + _ => {} + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) { + if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) { + InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) + } else { + tcx.mk_substs(Vec::>::new().into_iter()) + } + } else { + tcx.mk_substs(Vec::>::new().into_iter()) + }; + debug!(?parent_substs); + + let did = def.did.to_def_id(); + let child_substs = InternalSubsts::identity_for_item(tcx, did); + let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter())); + debug!(?substs); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let span = tcx.hir().span(hir_id); + let uneval = ty::Unevaluated::new(def.to_global(), substs); + debug!(?span, ?param_env); + + match tcx.const_eval_resolve(param_env, uneval, Some(span)) { + Ok(val) => Self::Val(val, ty), + Err(_) => { + // Error was handled in `const_eval_resolve`. Here we just create a + // new unevaluated const and error hard later in codegen let ty_const = tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), @@ -2934,6 +3000,7 @@ impl<'tcx> ConstantKind<'tcx> { }), ty, }); + Self::Ty(ty_const) } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 67384242ffa8..7ef33011234f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -491,8 +491,11 @@ impl<'tcx> Cx<'tcx> { hir::InlineAsmOperand::Const { ref anon_const } => { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = - mir::ConstantKind::from_anon_const(self.tcx, anon_const_def_id); + let value = mir::ConstantKind::from_anon_const( + self.tcx, + anon_const_def_id, + self.param_env, + ); let span = self.tcx.hir().span(anon_const.hir_id); InlineAsmOperand::Const { value, span }