about summary refs log tree commit diff
diff options
context:
space:
mode:
authorb-naber <bn263@gmx.de>2022-04-02 12:09:22 +0200
committerb-naber <bn263@gmx.de>2022-04-02 12:21:02 +0200
commit9b28d3b494f5507b13b04f383bb4ea2bf23294fc (patch)
treea7438e63c5821c035446625d0c5b7aa81f8f82af
parentd0e05f04266c5725b11677e5c74d33f930e76207 (diff)
downloadrust-9b28d3b494f5507b13b04f383bb4ea2bf23294fc.tar.gz
rust-9b28d3b494f5507b13b04f383bb4ea2bf23294fc.zip
try to evaluate in from_opt_const_arg_anon_const
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs79
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
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 5d09d84e19c..9b39c61719c 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<LocalDefId>,
+        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::<GenericArg<'tcx>>::new().into_iter())
+            }
+        } else {
+            tcx.mk_substs(Vec::<GenericArg<'tcx>>::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 67384242ffa..7ef33011234 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 }