]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #89561 - nbdd0121:const_typeck, r=nikomatsakis
authorMatthias Krüger <matthias.krueger@famsik.de>
Tue, 9 Nov 2021 18:00:40 +0000 (19:00 +0100)
committerGitHub <noreply@github.com>
Tue, 9 Nov 2021 18:00:40 +0000 (19:00 +0100)
Type inference for inline consts

Fixes #78132
Fixes #78174
Fixes #81857
Fixes #89964

Perform type checking/inference of inline consts in the same context as the outer def, similar to what is currently done to closure.

Doing so would require `closure_base_def_id` of the inline const to return the outer def, and since `closure_base_def_id` can be called on non-local crate (and thus have no HIR available), a new `DefKind` is created for inline consts.

The type of the generated anon const can capture lifetime of outer def, so we couldn't just use the typeck result as the type of the inline const's def. Closure has a similar issue, and it uses extra type params `CK, CS, U` to capture closure kind, input/output signature and upvars. I use a similar approach for inline consts, letting it have an extra type param `R`, and then `typeof(InlineConst<[paremt generics], R>)` would just be `R`. In borrowck region requirements are also propagated to the outer MIR body just like it's currently done for closure.

With this PR, inline consts in expression position are quitely usable now; however the usage in pattern position is still incomplete -- since those does not remain in the MIR borrowck couldn't verify the lifetime there. I have left an ignored test as a FIXME.

Some disucssions can be found on [this Zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/inline.20consts.20typeck).
cc `````@spastorino````` `````@lcnr`````
r? `````@nikomatsakis`````

`````@rustbot````` label A-inference F-inline_const T-compiler

49 files changed:
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_infer/src/infer/outlives/env.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_passes/src/region.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/regionck.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
src/librustdoc/clean/utils.rs
src/librustdoc/core.rs
src/librustdoc/formats/item_type.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/test/ui/inline-const/const-expr-inference.rs [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime-err.rs [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime-err.stderr [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-inference.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-lifetime-err.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-lifetime.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches.rs

index 439c728798d3a42b1b8c1717fd61a4a873103820..46a3c0fa1015248cfcc806148757693432b26c00 100644 (file)
@@ -408,7 +408,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                     let param = generics.type_param(&param_ty, tcx);
                     if let Some(generics) = tcx
                         .hir()
-                        .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+                        .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
                     {
                         suggest_constraining_type_param(
                             tcx,
index e5924f9d08478ff484bcf5feef030bb7a48419cc..6ffab16577908fcbc747a0a4ff2d5b72620628fb 100644 (file)
@@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     errors_buffer: &mut Vec<Diagnostic>,
 ) {
     let tcx = infcx.tcx;
-    let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+    let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
     if !tcx.has_attr(base_def_id, sym::rustc_regions) {
         return;
     }
index f4a5da1fe36fa8d0f6d2c9465c9f56f65f6b5784..b39a28f79aaddc3f2eda6882bf5bd7b934fb2f9b 100644 (file)
@@ -569,7 +569,7 @@ pub(super) fn solve(
         // to store those. Otherwise, we'll pass in `None` to the
         // functions below, which will trigger them to report errors
         // eagerly.
-        let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+        let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
 
         self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
 
@@ -2229,7 +2229,7 @@ fn apply_requirements(
             tcx,
             closure_substs,
             self.num_external_vids,
-            tcx.closure_base_def_id(closure_def_id),
+            tcx.typeck_root_def_id(closure_def_id),
         );
         debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
 
index 06e34bdce3f8678284b5c5abf55706eef0737ea7..ddd077c22faf86662dfb93c482f2374dc249cd07 100644 (file)
@@ -10,6 +10,7 @@
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
@@ -1343,13 +1344,9 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
                 // though.
                 let category = match place.as_local() {
                     Some(RETURN_PLACE) => {
-                        if let BorrowCheckContext {
-                            universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
-                            ..
-                        } = self.borrowck_context
-                        {
-                            if tcx.is_static(*def_id) {
+                        let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+                        if defining_ty.is_const() {
+                            if tcx.is_static(defining_ty.def_id()) {
                                 ConstraintCategory::UseAsStatic
                             } else {
                                 ConstraintCategory::UseAsConst
@@ -1527,6 +1524,8 @@ fn check_terminator(
                 }
             }
             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+                self.check_operand(discr, term_location);
+
                 let discr_ty = discr.ty(body, tcx);
                 if let Err(terr) = self.sub_types(
                     discr_ty,
@@ -1549,6 +1548,11 @@ fn check_terminator(
                 // FIXME: check the values
             }
             TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+                self.check_operand(func, term_location);
+                for arg in args {
+                    self.check_operand(arg, term_location);
+                }
+
                 let func_ty = func.ty(body, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let sig = match func_ty.kind() {
@@ -1593,6 +1597,8 @@ fn check_terminator(
                 self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
             }
             TerminatorKind::Assert { ref cond, ref msg, .. } => {
+                self.check_operand(cond, term_location);
+
                 let cond_ty = cond.ty(body, tcx);
                 if cond_ty != tcx.types.bool {
                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@@ -1608,6 +1614,8 @@ fn check_terminator(
                 }
             }
             TerminatorKind::Yield { ref value, .. } => {
+                self.check_operand(value, term_location);
+
                 let value_ty = value.ty(body, tcx);
                 match body.yield_ty() {
                     None => span_mirbug!(self, term, "yield in non-generator"),
@@ -1650,7 +1658,12 @@ fn check_call_dest(
                     Some(RETURN_PLACE) => {
                         if let BorrowCheckContext {
                             universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+                                UniversalRegions {
+                                    defining_ty:
+                                        DefiningTy::Const(def_id, _)
+                                        | DefiningTy::InlineConst(def_id, _),
+                                    ..
+                                },
                             ..
                         } = self.borrowck_context
                         {
@@ -1931,15 +1944,51 @@ fn aggregate_field_ty(
         }
     }
 
+    fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+        if let Operand::Constant(constant) = op {
+            let maybe_uneval = match constant.literal {
+                ConstantKind::Ty(ct) => match ct.val {
+                    ty::ConstKind::Unevaluated(uv) => Some(uv),
+                    _ => None,
+                },
+                _ => None,
+            };
+            if let Some(uv) = maybe_uneval {
+                if uv.promoted.is_none() {
+                    let tcx = self.tcx();
+                    let def_id = uv.def.def_id_for_type_of();
+                    if tcx.def_kind(def_id) == DefKind::InlineConst {
+                        let predicates = self.prove_closure_bounds(
+                            tcx,
+                            def_id.expect_local(),
+                            uv.substs(tcx),
+                            location,
+                        );
+                        self.normalize_and_prove_instantiated_predicates(
+                            def_id,
+                            predicates,
+                            location.to_locations(),
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
 
         match rvalue {
             Rvalue::Aggregate(ak, ops) => {
+                for op in ops {
+                    self.check_operand(op, location);
+                }
                 self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
             }
 
             Rvalue::Repeat(operand, len) => {
+                self.check_operand(operand, location);
+
                 // If the length cannot be evaluated we must assume that the length can be larger
                 // than 1.
                 // If the length is larger than 1, the repeat expression will need to copy the
@@ -1990,7 +2039,22 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+            Rvalue::NullaryOp(_, ty) => {
+                let trait_ref = ty::TraitRef {
+                    def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+                    substs: tcx.mk_substs_trait(ty, &[]),
+                };
+
+                self.prove_trait_ref(
+                    trait_ref,
+                    location.to_locations(),
+                    ConstraintCategory::SizedBound,
+                );
+            }
+
+            Rvalue::ShallowInitBox(operand, ty) => {
+                self.check_operand(operand, location);
+
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2004,6 +2068,8 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
             }
 
             Rvalue::Cast(cast_kind, op, ty) => {
+                self.check_operand(op, location);
+
                 match cast_kind {
                     CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@@ -2250,6 +2316,9 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
                 box (left, right),
             ) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+
                 let ty_left = left.ty(body, tcx);
                 match ty_left.kind() {
                     // Types with regions are comparable if they have a common super-type.
@@ -2300,13 +2369,19 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
+            Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+                self.check_operand(operand, location);
+            }
+
+            Rvalue::BinaryOp(_, box (left, right))
+            | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+            }
+
             Rvalue::AddressOf(..)
             | Rvalue::ThreadLocalRef(..)
-            | Rvalue::Use(..)
             | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..) => {}
         }
     }
index 147e2aead648db509356fe9e77b8cd02f6f72c12..b986df403f9f3f2c97789bad02c2b9720708bd71 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
 use std::iter;
 
 use crate::nll::ToRegionVid;
@@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
     /// is that it has no inputs and a single return value, which is
     /// the value of the constant.
     Const(DefId, SubstsRef<'tcx>),
+
+    /// The MIR represents an inline const. The signature has no inputs and a
+    /// single return value found via `InlineConstSubsts::ty`.
+    InlineConst(DefId, SubstsRef<'tcx>),
 }
 
 impl<'tcx> DefiningTy<'tcx> {
@@ -121,7 +125,7 @@ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
             DefiningTy::Generator(_, substs, _) => {
                 Either::Right(Either::Left(substs.as_generator().upvar_tys()))
             }
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
                 Either::Right(Either::Right(iter::empty()))
             }
         }
@@ -133,7 +137,7 @@ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
     pub fn implicit_inputs(self) -> usize {
         match self {
             DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
         }
     }
 
@@ -142,7 +146,7 @@ pub fn is_fn_def(&self) -> bool {
     }
 
     pub fn is_const(&self) -> bool {
-        matches!(*self, DefiningTy::Const(..))
+        matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
     }
 
     pub fn def_id(&self) -> DefId {
@@ -150,7 +154,8 @@ pub fn def_id(&self) -> DefId {
             DefiningTy::Closure(def_id, ..)
             | DefiningTy::Generator(def_id, ..)
             | DefiningTy::FnDef(def_id, ..)
-            | DefiningTy::Const(def_id, ..) => def_id,
+            | DefiningTy::Const(def_id, ..)
+            | DefiningTy::InlineConst(def_id, ..) => def_id,
         }
     }
 }
@@ -242,7 +247,7 @@ pub fn closure_mapping(
         tcx: TyCtxt<'tcx>,
         closure_substs: SubstsRef<'tcx>,
         expected_num_vars: usize,
-        closure_base_def_id: DefId,
+        typeck_root_def_id: DefId,
     ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
         let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
         region_mapping.push(tcx.lifetimes.re_static);
@@ -250,7 +255,7 @@ pub fn closure_mapping(
             region_mapping.push(fr);
         });
 
-        for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+        for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
             region_mapping.push(r);
         });
 
@@ -344,8 +349,8 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                 // tests, and the resulting print-outs include def-ids
                 // and other things that are not stable across tests!
                 // So we just include the region-vid. Annoying.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -359,8 +364,8 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                 // FIXME: As above, we'd like to print out the region
                 // `r` but doing so is not stable across architectures
                 // and so forth.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -376,6 +381,12 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                     tcx.def_path_str_with_substs(def_id, substs),
                 ));
             }
+            DefiningTy::InlineConst(def_id, substs) => {
+                err.note(&format!(
+                    "defining inline constant type: {}",
+                    tcx.def_path_str_with_substs(def_id, substs),
+                ));
+            }
         }
     }
 }
@@ -411,7 +422,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -419,7 +430,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def.did.to_def_id() != closure_base_def_id {
+        if self.mir_def.did.to_def_id() != typeck_root_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
         }
@@ -437,7 +448,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def.did.to_def_id() == closure_base_def_id {
+        if self.mir_def.did.to_def_id() == typeck_root_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
@@ -502,12 +513,12 @@ fn build(self) -> UniversalRegions<'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
-                    tcx.type_of(closure_base_def_id)
+                let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    tcx.type_of(typeck_root_def_id)
                 } else {
                     let tables = tcx.typeck(self.mir_def.did);
                     tables.node_type(self.mir_hir_id)
@@ -534,11 +545,21 @@ fn defining_ty(&self) -> DefiningTy<'tcx> {
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
-                let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
-                let substs =
-                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
-                DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+                if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    let substs =
+                        self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+                    DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                } else {
+                    let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+                    let substs = InlineConstSubsts::new(
+                        tcx,
+                        InlineConstSubstsParts { parent_substs: identity_substs, ty },
+                    )
+                    .substs;
+                    let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+                    DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+                }
             }
         }
     }
@@ -553,17 +574,19 @@ fn compute_indices(
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
-        let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+        let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
         let fr_substs = match defining_ty {
-            DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+            DefiningTy::Closure(_, ref substs)
+            | DefiningTy::Generator(_, ref substs, _)
+            | DefiningTy::InlineConst(_, ref substs) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureSubsts are
-                // inherited from the `closure_base_def_id`.
+                // inherited from the `typeck_root_def_id`.
                 // Therefore, when we zip together (below) with
                 // `identity_substs`, we will get only those regions
                 // that correspond to early-bound regions declared on
-                // the `closure_base_def_id`.
+                // the `typeck_root_def_id`.
                 assert!(substs.len() >= identity_substs.len());
                 assert_eq!(substs.regions().count(), identity_substs.regions().count());
                 substs
@@ -648,6 +671,12 @@ fn compute_inputs_and_output(
                 let ty = indices.fold_to_region_vids(tcx, ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
+
+            DefiningTy::InlineConst(def_id, substs) => {
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
+                let ty = substs.as_inline_const().ty();
+                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+            }
         }
     }
 }
@@ -736,8 +765,8 @@ fn replace_late_bound_regions_with_nll_infer_vars(
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
         debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
-        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
-        for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+        let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+        for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);
index 1f1bd73c7d035d51ae736dae5bfde264980b1d0a..2a6bf7d9b1a4ddac535843a25a4c2e052bd79ac1 100644 (file)
@@ -322,7 +322,7 @@ fn dbg_scope_fn(
         type_names::push_item_name(self.tcx(), def_id, false, &mut name);
 
         // Find the enclosing function, in case this is a closure.
-        let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+        let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
 
         // Get_template_parameters() will append a `<...>` clause to the function
         // name if necessary.
index 57af0ff07143373cacfd7f11d2423e7e0bc8cd7c..6d3a89c0a8a5ba3927510556463c1b55d4397baa 100644 (file)
@@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
                     | DefKind::Static
                     | DefKind::ConstParam
                     | DefKind::AnonConst
+                    | DefKind::InlineConst
                     | DefKind::AssocConst
             ),
         "Unexpected DefKind: {:?}",
index cb668eb35e093da9b2194eef756f4208e436c677..60761a05de8270180810ca2d6995fab17eb59dac 100644 (file)
@@ -104,8 +104,10 @@ pub enum DefKind {
     Use,
     /// An `extern` block.
     ForeignMod,
-    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
     AnonConst,
+    /// An inline constant, e.g. `const { 1 + 2 }`
+    InlineConst,
     /// Opaque type, aka `impl Trait`.
     OpaqueTy,
     Field,
@@ -155,6 +157,7 @@ pub fn descr(self, def_id: DefId) -> &'static str {
             DefKind::Use => "import",
             DefKind::ForeignMod => "foreign module",
             DefKind::AnonConst => "constant expression",
+            DefKind::InlineConst => "inline constant",
             DefKind::Field => "field",
             DefKind::Impl => "implementation",
             DefKind::Closure => "closure",
@@ -174,6 +177,7 @@ pub fn article(&self) -> &'static str {
             | DefKind::OpaqueTy
             | DefKind::Impl
             | DefKind::Use
+            | DefKind::InlineConst
             | DefKind::ExternCrate => "an",
             DefKind::Macro(macro_kind) => macro_kind.article(),
             _ => "a",
@@ -207,6 +211,7 @@ pub fn ns(&self) -> Option<Namespace> {
 
             // Not namespaced.
             DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::Field
             | DefKind::LifetimeParam
             | DefKind::ExternCrate
index 9e04773c5fa2056c9bb4865d9051e938b5a0f86b..3947282aa6217f4dba820c79d75c6596e4294262 100644 (file)
@@ -99,7 +99,7 @@ pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<
     /// function. We can then add implied bounds and the like from the
     /// closure arguments into the environment -- these should only
     /// apply in the closure body, so once we exit, we invoke
-    /// `pop_snapshot_post_closure` to remove them.
+    /// `pop_snapshot_post_typeck_child` to remove them.
     ///
     /// Example:
     ///
@@ -129,12 +129,12 @@ pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<
     /// seems like it'd be readily fixed if we wanted. There are
     /// similar leaks around givens that seem equally suspicious, to
     /// be honest. --nmatsakis
-    pub fn push_snapshot_pre_closure(&self) -> usize {
+    pub fn push_snapshot_pre_typeck_child(&self) -> usize {
         self.region_bound_pairs_accum.len()
     }
 
-    /// See `push_snapshot_pre_closure`.
-    pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+    /// See `push_snapshot_pre_typeck_child`.
+    pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
         self.region_bound_pairs_accum.truncate(len);
     }
 
index 0dbef66ac37d77ff78eeb6fa2fb10a5986f1e1f3..aff5e02d0c655dc5b27909eba4a84b26d7759a51 100644 (file)
@@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::ConstParam
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         DefKind::Use
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
             (true, mir_opt_base)
         }
         // Constants
-        DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
-            (true, false)
-        }
+        DefKind::AnonConst
+        | DefKind::InlineConst
+        | DefKind::AssocConst
+        | DefKind::Static
+        | DefKind::Const => (true, false),
         // Full-fledged functions
         DefKind::AssocFn | DefKind::Fn => {
             let generics = tcx.generics_of(def_id);
@@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Use
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::AssocFn
         | DefKind::AssocConst
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::OpaqueTy
         | DefKind::Impl
         | DefKind::Field
index 8f52e16c2ebe41e7873d6893dc0917be4e1a37a4..d9d0781b37aacefe4afab97366de2b6448907d6e 100644 (file)
@@ -266,7 +266,15 @@ pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
                 };
                 DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
             }
-            Node::AnonConst(_) => DefKind::AnonConst,
+            Node::AnonConst(_) => {
+                let inline = match self.find(self.get_parent_node(hir_id)) {
+                    Some(Node::Expr(&Expr {
+                        kind: ExprKind::ConstBlock(ref anon_const), ..
+                    })) if anon_const.hir_id == hir_id => true,
+                    _ => false,
+                };
+                if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+            }
             Node::Field(_) => DefKind::Field,
             Node::Expr(expr) => match expr.kind {
                 ExprKind::Closure(.., None) => DefKind::Closure,
index 8e363cfbff562d594d9850dfa52c0a6ed2ed553e..8e1b887f87da75695eb5c41a6156250db02171e8 100644 (file)
@@ -958,7 +958,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
             write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
         }
         (_, _) if is_function => write!(w, "fn ")?,
-        (DefKind::AnonConst, _) => {} // things like anon const, not an item
+        (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
         _ => bug!("Unexpected def kind {:?}", kind),
     }
 
index 06041bbb02d355537240c012aefb6835520036d4..a9f94b74c5efb2ade9d3fb13dbefe222f31f8386 100644 (file)
     /// additional requirements that the closure's creator must verify.
     query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
-        cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
+        cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
     }
     query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc {
index 869b2ab9dbcbc5a02495d8b515f6963ad1f10e6c..27e22ccac02a7fb7c771700ada2318eeace3a841 100644 (file)
@@ -1,7 +1,9 @@
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+    self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+    TyCtxt, TypeFoldable,
+};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -54,6 +56,24 @@ pub fn from_opt_const_arg_anon_const(
 
         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 => tcx.mk_const(ty::Const {
+                val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                    def: def.to_global(),
+                    substs_: None,
+                    promoted: None,
+                }),
+                ty,
+            }),
+        }
+    }
+
+    fn try_eval_lit_or_param(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Option<&'tcx Self> {
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
             hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -69,7 +89,7 @@ pub fn from_opt_const_arg_anon_const(
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
             if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return c;
+                return Some(c);
             } else {
                 tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
             }
@@ -85,7 +105,7 @@ pub fn from_opt_const_arg_anon_const(
         };
 
         use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
-        let val = match expr.kind {
+        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`.
@@ -95,16 +115,53 @@ pub fn from_opt_const_arg_anon_const(
                 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);
-                ty::ConstKind::Param(ty::ParamConst::new(index, name))
+                Some(tcx.mk_const(ty::Const {
+                    val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+                    ty,
+                }))
             }
-            _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
-                def: def.to_global(),
-                substs_: None,
-                promoted: None,
-            }),
+            _ => None,
+        }
+    }
+
+    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+        debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def_id.to_def_id()),
+                "from_inline_const can only process anonymous constants"
+            ),
         };
 
-        tcx.mk_const(ty::Const { val, ty })
+        let expr = &tcx.hir().body(body_id).value;
+
+        let ty = tcx.typeck(def_id).node_type(hir_id);
+
+        let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+            Some(v) => v,
+            None => {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+                let parent_substs =
+                    tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+                let substs =
+                    InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+                        .substs;
+                tcx.mk_const(ty::Const {
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                        def: ty::WithOptConstParam::unknown(def_id).to_global(),
+                        substs_: Some(substs),
+                        promoted: None,
+                    }),
+                    ty,
+                })
+            }
+        };
+        debug_assert!(!ret.has_free_regions(tcx));
+        ret
     }
 
     /// Interns the given value as a constant.
index cf47da157d19f7c969eb8e0e9724d06056f052f0..40670f1fdcaefb03ac7b4ec18774be070bfec613 100644 (file)
     Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
     CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
-    GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
-    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
-    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+    GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+    ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+    PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+    UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
 };
 pub use self::trait_def::TraitDef;
 
@@ -1927,7 +1928,8 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
                 | DefKind::Static
                 | DefKind::AssocConst
                 | DefKind::Ctor(..)
-                | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+                | DefKind::AnonConst
+                | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
                 // If the caller wants `mir_for_ctfe` of a function they should not be using
                 // `instance_mir`, so we'll assume const fn also wants the optimized version.
                 _ => {
index 874de3366d79213ee7499075d518f5a41f3eb58d..e57075ed33811d59589d3f340ef2f5c0ae272a1a 100644 (file)
@@ -704,6 +704,66 @@ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
     }
 }
 
+/// An inline const is modeled like
+///
+///     const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+///   inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+    /// Generic parameters from the enclosing item,
+    /// concatenated with the inferred type of the constant.
+    pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+    pub parent_substs: &'tcx [GenericArg<'tcx>],
+    pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+    /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+    ) -> InlineConstSubsts<'tcx> {
+        InlineConstSubsts {
+            substs: tcx.mk_substs(
+                parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+            ),
+        }
+    }
+
+    /// Divides the inline const substs into their respective components.
+    /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+    fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+        match self.substs[..] {
+            [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+            _ => bug!("inline const substs missing synthetics"),
+        }
+    }
+
+    /// Returns the substitutions of the inline const's parent.
+    pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+        self.split().parent_substs
+    }
+
+    /// Returns the type of this inline const.
+    pub fn ty(self) -> Ty<'tcx> {
+        self.split().ty.expect_ty()
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum ExistentialPredicate<'tcx> {
index 2438d1a16021b50aa4f318d5946842e6bc6d4281..73a8e18949de06ad6a4d8d5b3dc0c8329b5c22bf 100644 (file)
@@ -3,7 +3,7 @@
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
@@ -204,6 +204,14 @@ pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
         GeneratorSubsts { substs: self }
     }
 
+    /// Interpret these substitutions as the substitutions of an inline const.
+    /// Inline const substitutions have a particular structure controlled by the
+    /// compiler that encodes information like the inferred type;
+    /// see `ty::InlineConstSubsts` struct for more comments.
+    pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+        InlineConstSubsts { substs: self }
+    }
+
     /// Creates an `InternalSubsts` that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
         Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
index 2c884813d23187eea6f275f54c9cffb979085a36..6b287445ff032dade94803d5ba345326d7d7ac98 100644 (file)
@@ -423,6 +423,15 @@ pub fn is_closure(self, def_id: DefId) -> bool {
         matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
     }
 
+    /// Returns `true` if `def_id` refers to a definition that does not have its own
+    /// type-checking context, i.e. closure, generator or inline const.
+    pub fn is_typeck_child(self, def_id: DefId) -> bool {
+        matches!(
+            self.def_kind(def_id),
+            DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+        )
+    }
+
     /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
     pub fn is_trait(self, def_id: DefId) -> bool {
         self.def_kind(def_id) == DefKind::Trait
@@ -440,16 +449,19 @@ pub fn is_constructor(self, def_id: DefId) -> bool {
         matches!(self.def_kind(def_id), DefKind::Ctor(..))
     }
 
-    /// Given the def-ID of a fn or closure, returns the def-ID of
-    /// the innermost fn item that the closure is contained within.
-    /// This is a significant `DefId` because, when we do
-    /// type-checking, we type-check this fn item and all of its
-    /// (transitive) closures together. Therefore, when we fetch the
+    /// Given the `DefId`, returns the `DefId` of the innermost item that
+    /// has its own type-checking context or "inference enviornment".
+    ///
+    /// For example, a closure has its own `DefId`, but it is type-checked
+    /// with the containing item. Similarly, an inline const block has its
+    /// own `DefId` but it is type-checked together with the containing item.
+    ///
+    /// Therefore, when we fetch the
     /// `typeck` the closure, for example, we really wind up
     /// fetching the `typeck` the enclosing fn item.
-    pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+    pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
-        while self.is_closure(def_id) {
+        while self.is_typeck_child(def_id) {
             def_id = self.parent(def_id).unwrap_or_else(|| {
                 bug!("closure {:?} has no parent", def_id);
             });
index 17296a95bc17e26e2c6560ea91001e977c8841e7..b4005ccd1cc42205db0909d37699f2b802fbf561 100644 (file)
@@ -578,7 +578,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
 
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
 
                 ExprKind::ConstBlock { value }
             }
index cb74ae4df2ef86ac4084583730a0d4343f20307e..ce80214c875fc5e46f329f65fc438f031759bed7 100644 (file)
@@ -544,7 +544,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
             let (lit, neg) = match expr.kind {
                 hir::ExprKind::ConstBlock(ref anon_const) => {
                     let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                    let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                    let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
                     if matches!(value.val, ConstKind::Param(_)) {
                         let span = self.tcx.hir().span(anon_const.hir_id);
                         self.errors.push(PatternError::ConstParamInPattern(span));
index e6e4438b6d41afa63bb448bbc1db8b81cfd51e17..595080619da6faaac8be4cf5b91b93beb4cbf45a 100644 (file)
@@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::OpaqueTy
         | DefKind::Field
         | DefKind::LifetimeParam
@@ -195,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>(
     generics: &'tcx ty::Generics,
     unused_parameters: &FiniteBitSet<u32>,
 ) {
-    let base_def_id = tcx.closure_base_def_id(def_id);
+    let base_def_id = tcx.typeck_root_def_id(def_id);
     if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
         return;
     }
@@ -303,7 +304,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 ControlFlow::CONTINUE
             }
             ty::ConstKind::Unevaluated(uv)
-                if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+                if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
             {
                 self.visit_child_body(uv.def.did, uv.substs(self.tcx));
                 ControlFlow::CONTINUE
index 5fc8e230d72a3eba67aca78d8a258115f9d21e31..6a8feb041da19f5978c4cf6055f79e127bf61ffc 100644 (file)
@@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
     // properly, we can't miss any types.
 
     match expr.kind {
-        // Manually recurse over closures, because they are the only
+        // Manually recurse over closures and inline consts, because they are the only
         // case of nested bodies that share the parent environment.
-        hir::ExprKind::Closure(.., body, _, _) => {
+        hir::ExprKind::Closure(.., body, _, _)
+        | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
         }
@@ -817,9 +818,9 @@ fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
 }
 
 fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
-    let closure_base_def_id = tcx.closure_base_def_id(def_id);
-    if closure_base_def_id != def_id {
-        return tcx.region_scope_tree(closure_base_def_id);
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.region_scope_tree(typeck_root_def_id);
     }
 
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
index fa34b9abc1e6c9314288ae045f6d1e71dde8ec03..a01efc5d85c6e765bd263855f0575656d1daf247 100644 (file)
@@ -618,6 +618,7 @@ fn update_macro_reachable_def(
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::Field
             | DefKind::GlobalAsm
             | DefKind::Impl
index d77a70e5327994dee768eadc67e7ac6dbdc7c440..4173e0fbf5668e546a878ece896cfb026c8b491f 100644 (file)
@@ -967,6 +967,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
                 | DefKind::Use
                 | DefKind::ForeignMod
                 | DefKind::AnonConst
+                | DefKind::InlineConst
                 | DefKind::Field
                 | DefKind::LifetimeParam
                 | DefKind::GlobalAsm
index 5def43c2423443b320f09743a5c1eafd4dca6d91..39e710cb77f3fafd9129d6ad80061aea48ef3837 100644 (file)
@@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>(
     def_id: LocalDefId,
 ) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
     match tcx.def_kind(def_id) {
-        DefKind::AnonConst => {
+        DefKind::AnonConst | DefKind::InlineConst => {
             let mut def_id = tcx
                 .parent(def_id.to_def_id())
                 .unwrap_or_else(|| bug!("anon const or closure without a parent"));
index 543cd0247a53daecd9400c4b4711a6232c54578a..c7f8fe3a88a64b1dc4ea99a8456f852f54083995 100644 (file)
@@ -739,6 +739,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 | HirDefKind::ForeignMod
                 | HirDefKind::LifetimeParam
                 | HirDefKind::AnonConst
+                | HirDefKind::InlineConst
                 | HirDefKind::Use
                 | HirDefKind::Field
                 | HirDefKind::GlobalAsm
index 8edb7069fc45f9a19c55f3c66f75a0bc79b9870f..6b5d37c0f43086516d57425d66807dd3b6ca72b7 100644 (file)
@@ -151,7 +151,7 @@ enum FailureKind {
 
     if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
         match infcx.tcx.def_kind(uv.def.did) {
-            DefKind::AnonConst => {
+            DefKind::AnonConst | DefKind::InlineConst => {
                 let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
 
                 if mir_body.is_polymorphic {
@@ -495,7 +495,7 @@ pub(super) fn thir_abstract_const<'tcx>(
             // we want to look into them or treat them as opaque projections.
             //
             // Right now we do neither of that and simply always fail to unify them.
-            DefKind::AnonConst => (),
+            DefKind::AnonConst | DefKind::InlineConst => (),
             _ => return Ok(None),
         }
 
index 2689e2134fc6b5e0ded2dd2e01f732375f0e4424..b21936a00b04fae8c104dd81668dc4992de6af37 100644 (file)
@@ -1474,7 +1474,7 @@ fn maybe_note_obligation_cause_for_async_await(
         let span = self.tcx.def_span(generator_did);
 
         let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
-        let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+        let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
         debug!(
             "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
              generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
index 410ac24b1f19c84a8659e5186f31f5c264db201d..f7accbb430caae8375fb5a6c318244009f0b15d7 100644 (file)
@@ -92,7 +92,7 @@ fn check_closure(
 
         let parent_substs = InternalSubsts::identity_for_item(
             self.tcx,
-            self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+            self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
         );
 
         let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
index 3cba7991ccaf308f5657233e1b00426d52700c11..93e292394bd28207e18d0f2f8e47a1e8cc224742 100644 (file)
@@ -30,6 +30,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -323,7 +324,9 @@ fn check_expr_kind(
             }
             ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
-            ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+            ExprKind::ConstBlock(ref anon_const) => {
+                self.check_expr_const_block(anon_const, expected, expr)
+            }
             ExprKind::Repeat(element, ref count) => {
                 self.check_expr_repeat(element, count, expected, expr)
             }
@@ -1166,6 +1169,24 @@ fn check_expr_array(
         self.tcx.mk_array(element_ty, args.len() as u64)
     }
 
+    fn check_expr_const_block(
+        &self,
+        anon_const: &'tcx hir::AnonConst,
+        expected: Expectation<'tcx>,
+        _expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        let body = self.tcx.hir().body(anon_const.body);
+
+        // Create a new function context.
+        let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+        crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+        let ty = fcx.check_expr_with_expectation(&body.value, expected);
+        fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+        fcx.write_ty(anon_const.hir_id, ty);
+        ty
+    }
+
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
index 7450b4a4ef1c3f23c0f1554a044f9c6b708df1b4..d19e99606bcd8eec3f0d54d7e921de2ec1e463a9 100644 (file)
@@ -297,9 +297,9 @@ fn primary_body_of(
 fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     // Closures' typeck results come from their outermost function,
     // as they are part of the same "inference environment".
-    let outer_def_id = tcx.closure_base_def_id(def_id);
-    if outer_def_id != def_id {
-        return tcx.has_typeck_results(outer_def_id);
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.has_typeck_results(typeck_root_def_id);
     }
 
     if let Some(def_id) = def_id.as_local() {
@@ -348,9 +348,9 @@ fn typeck_with_fallback<'tcx>(
 ) -> &'tcx ty::TypeckResults<'tcx> {
     // Closures' typeck results come from their outermost function,
     // as they are part of the same "inference environment".
-    let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
-    if outer_def_id != def_id {
-        return tcx.typeck(outer_def_id);
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+    if typeck_root_def_id != def_id {
+        return tcx.typeck(typeck_root_def_id);
     }
 
     let id = tcx.hir().local_def_id_to_hir_id(def_id);
index 5aa11cce25fb6d5247d38f9757f3bea37c5d6487..cbf33cf1b78a147112c2ad55cd868a845a813eb3 100644 (file)
@@ -292,7 +292,9 @@ fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> A
             // String and byte-string literals result in types `&str` and `&[u8]` respectively.
             // All other literals result in non-reference types.
             // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
-            PatKind::Lit(lt) => match self.check_expr(lt).kind() {
+            //
+            // Call `resolve_vars_if_possible` here for inline const blocks.
+            PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
                 ty::Ref(..) => AdjustMode::Pass,
                 _ => AdjustMode::Peel,
             },
index 86d4e4d2b115b5857959bd115066bc850a5a8543..d2d8b14dd9695e917bd27d2dc4a08d7683993991 100644 (file)
@@ -341,6 +341,29 @@ fn visit_fn_body(
         self.visit_region_obligations(body_id.hir_id);
     }
 
+    fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+        debug!("visit_inline_const(id={:?})", id);
+
+        // Save state of current function. We will restore afterwards.
+        let old_body_id = self.body_id;
+        let old_body_owner = self.body_owner;
+        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
+
+        let body_id = body.id();
+        self.body_id = body_id.hir_id;
+        self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+        self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+        self.visit_body(body);
+        self.visit_region_obligations(body_id.hir_id);
+
+        // Restore state from previous function.
+        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+        self.body_id = old_body_id;
+        self.body_owner = old_body_owner;
+    }
+
     fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
         debug!("visit_region_obligations: hir_id={:?}", hir_id);
 
@@ -406,13 +429,13 @@ fn visit_fn(
         // `visit_fn_body`.  We will restore afterwards.
         let old_body_id = self.body_id;
         let old_body_owner = self.body_owner;
-        let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
 
         let body = self.tcx.hir().body(body_id);
         self.visit_fn_body(hir_id, body, span);
 
         // Restore state from previous function.
-        self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
         self.body_id = old_body_id;
         self.body_owner = old_body_owner;
     }
@@ -460,6 +483,11 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 intravisit::walk_expr(self, expr);
             }
 
+            hir::ExprKind::ConstBlock(anon_const) => {
+                let body = self.tcx.hir().body(anon_const.body);
+                self.visit_inline_const(anon_const.hir_id, body);
+            }
+
             _ => intravisit::walk_expr(self, expr),
         }
     }
index 774d8078e52ca31171213b8070848902040aae07..5f5d308a3329bdf5c7f3c3fe2cbd1e0a445c4f8c 100644 (file)
@@ -148,10 +148,17 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
-            let body = self.fcx.tcx.hir().body(body_id);
-            self.visit_body(body);
-            self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+        match expr.kind {
+            hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+                let body = self.fcx.tcx.hir().body(body_id);
+                self.visit_body(body);
+                self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+            }
+            hir::ExprKind::ConstBlock(anon_const) => {
+                let body = self.fcx.tcx.hir().body(anon_const.body);
+                self.visit_body(body);
+            }
+            _ => {}
         }
 
         intravisit::walk_expr(self, expr);
index d951df94dcf50fbb0a2d137feb5ebf182843a782..fdc8b6b5e64519d57642ad6549ec858d880fcc89 100644 (file)
@@ -282,6 +282,12 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
             hir::ExprKind::Field(..) => {
                 self.visit_field_id(e.hir_id);
             }
+            hir::ExprKind::ConstBlock(anon_const) => {
+                self.visit_node_id(e.span, anon_const.hir_id);
+
+                let body = self.tcx().hir().body(anon_const.body);
+                self.visit_body(body);
+            }
             _ => {}
         }
 
index 18e8ed394e81409615a9de263fd05626cb46cac5..2274db76c05fb264be490cb2043398dbf23e575c 100644 (file)
@@ -1494,13 +1494,15 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     {
                         Some(parent_def_id.to_def_id())
                     }
-
+                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+                        Some(tcx.typeck_root_def_id(def_id))
+                    }
                     _ => None,
                 }
             }
         }
         Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
-            Some(tcx.closure_base_def_id(def_id))
+            Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
             ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
@@ -1692,6 +1694,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         }));
     }
 
+    // provide junk type parameter defs for const blocks.
+    if let Node::AnonConst(_) = node {
+        let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+        if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+            params.push(ty::GenericParamDef {
+                index: type_start,
+                name: Symbol::intern("<const_ty>"),
+                def_id,
+                pure_wrt_drop: false,
+                kind: ty::GenericParamDefKind::Type {
+                    has_default: false,
+                    object_lifetime_default: rl::Set1::Empty,
+                    synthetic: None,
+                },
+            });
+        }
+    }
+
     let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
 
     ty::Generics {
index a6ea8abdf3fa6af554918f4a4aeceb51101a1d9d..04a68250ced0cd0a44387b6fa7d3abf868b03351 100644 (file)
@@ -494,7 +494,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
                     if anon_const.hir_id == hir_id =>
                 {
-                    tcx.typeck(def_id).node_type(anon_const.hir_id)
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    substs.as_inline_const().ty()
                 }
 
                 Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
index 2fae3163a1a1a4f19509091f6520929e04bf98f0..2fa7efcc6509b143e69b5192d06cf4bf8d507669 100644 (file)
@@ -430,8 +430,9 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
         | Res::NonMacroAttr(_)
         | Res::Err => return res.def_id(),
         Res::Def(
-            TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
-            | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+            TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
+            | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
+            | Generator,
             id,
         ) => return id,
     };
index ed7c9e7b043ffa75c15750ded66974357b7cc553..92278179a51c96ade994997c336d3e34a811179f 100644 (file)
@@ -265,9 +265,9 @@ impl<'tcx> DocContext<'tcx> {
                 // Closures' tables come from their outermost function,
                 // as they are part of the same "inference environment".
                 // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
-                let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
-                if outer_def_id != def_id {
-                    return tcx.typeck(outer_def_id);
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+                if typeck_root_def_id != def_id {
+                    return tcx.typeck(typeck_root_def_id);
                 }
 
                 let hir = tcx.hir();
index 793db16faf38517dd5954e98b1bfaab9804bf425..3979d29b673fd3bd37a8fc6865b6b0ee3e46bcb0 100644 (file)
@@ -134,6 +134,7 @@ fn from(other: DefKind) -> Self {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::OpaqueTy
             | DefKind::Field
             | DefKind::LifetimeParam
index 8541e6e18816f5c783800fbe23be99e5780cc1fc..4e5812d7f8429e38a5a5f11042f5912b0a5ee0a4 100644 (file)
@@ -1937,7 +1937,8 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             | Use
                             | LifetimeParam
                             | Ctor(_, _)
-                            | AnonConst => {
+                            | AnonConst
+                            | InlineConst => {
                                 let note = assoc_item_not_allowed(res);
                                 if let Some(span) = sp {
                                     diag.span_label(span, &note);
diff --git a/src/test/ui/inline-const/const-expr-inference.rs b/src/test/ui/inline-const/const-expr-inference.rs
new file mode 100644 (file)
index 0000000..6aa2a2f
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+    const { todo!() }
+}
+
+fn main() {
+    let _: usize = const { 0 };
+}
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.rs b/src/test/ui/inline-const/const-expr-lifetime-err.rs
new file mode 100644 (file)
index 0000000..e56cbc9
--- /dev/null
@@ -0,0 +1,30 @@
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn equate<T>(x: T, y: T){}
+
+fn foo<'a>() {
+    let y = ();
+    equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+    //~^ ERROR `y` does not live long enough [E0597]
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.stderr b/src/test/ui/inline-const/const-expr-lifetime-err.stderr
new file mode 100644 (file)
index 0000000..30ecd33
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/const-expr-lifetime-err.rs:24:30
+   |
+LL | fn foo<'a>() {
+   |        -- lifetime `'a` defined here
+LL |     let y = ();
+LL |     equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+   |            ------------------^^-
+   |            |                 |
+   |            |                 borrowed value does not live long enough
+   |            argument requires that `y` is borrowed for `'a`
+LL |
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/inline-const/const-expr-lifetime.rs b/src/test/ui/inline-const/const-expr-lifetime.rs
new file mode 100644 (file)
index 0000000..f622f2c
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+    let foo = const { "foo" };
+    assert_eq!(foo, "foo");
+}
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
+    const { InvariantRef::<'a, ()>::new(&()) }
+}
+
+fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
+    // Try some type inference
+    const { InvariantRef::new(&()) }
+}
+
+fn main() {
+    issue_78174();
+    get_invariant_ref();
+    get_invariant_ref2();
+}
diff --git a/src/test/ui/inline-const/const-match-pat-inference.rs b/src/test/ui/inline-const/const-match-pat-inference.rs
new file mode 100644 (file)
index 0000000..61188ed
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+    match 1u64 {
+        0 => (),
+        const { 0 + 1 } => (),
+        const { 2 - 1 } ..= const { u64::MAX } => (),
+    }
+}
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime-err.rs b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs
new file mode 100644 (file)
index 0000000..bc5aa24
--- /dev/null
@@ -0,0 +1,34 @@
+// ignore-test
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn match_invariant_ref<'a>() {
+    let y = ();
+    match InvariantRef::new(&y) {
+    //~^ ERROR `y` does not live long enough [E0597]
+        // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
+        // const block)
+        const { InvariantRef::<'a>::NEW } => (),
+    }
+}
+
+fn main() {
+    match_invariant_ref();
+}
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime.rs b/src/test/ui/inline-const/const-match-pat-lifetime.rs
new file mode 100644 (file)
index 0000000..3d986f0
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+    match "foo" {
+        const { concat!("fo", "o") } => (),
+        _ => unreachable!(),
+    }
+}
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+fn match_invariant_ref<'a>() {
+    match const { InvariantRef::<'a, _>::new(&()) } {
+        const { InvariantRef::<'a, ()>::new(&()) } => {
+        }
+    }
+}
+
+fn main() {
+    issue_78174();
+    match_invariant_ref();
+}
index eb311983b29276ebf0b21b35ed9e0dcc46750af3..7142df98c3f10fde54afa98e822067dd468532f2 100644 (file)
@@ -1065,7 +1065,10 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 PatKind::Path(path) => {
                     #[allow(clippy::match_same_arms)]
                     let id = match cx.qpath_res(path, pat.hir_id) {
-                        Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
+                        Res::Def(
+                            DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+                            _,
+                        ) => return,
                         Res::Def(_, id) => id,
                         _ => return,
                     };