let param = generics.type_param(¶m_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,
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;
}
// 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);
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);
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};
// 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
}
}
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,
// 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() {
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);
}
}
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"),
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
{
}
}
+ 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
}
}
- 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, &[]),
}
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);
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.
}
}
+ 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(..) => {}
}
}
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;
/// 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> {
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()))
}
}
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,
}
}
}
pub fn is_const(&self) -> bool {
- matches!(*self, DefiningTy::Const(..))
+ matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
}
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,
}
}
}
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);
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);
});
// 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),));
});
}
// 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),));
});
}
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),
+ ));
+ }
}
}
}
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
// 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)
}
);
// 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);
}
/// 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)
}
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)
+ }
}
}
}
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
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]))
+ }
}
}
}
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);
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.
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected 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,
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression",
+ DefKind::InlineConst => "inline constant",
DefKind::Field => "field",
DefKind::Impl => "implementation",
DefKind::Closure => "closure",
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Use
+ | DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
// Not namespaced.
DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
/// 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:
///
/// 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);
}
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
(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);
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
};
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,
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),
}
/// 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 {
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};
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 {
// 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");
}
};
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`.
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.
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;
| 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.
_ => {
}
}
+/// 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> {
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;
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))
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
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);
});
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 }
}
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));
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
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;
}
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
// 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);
}
}
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());
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
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"));
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
+ | HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm
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 {
// 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),
}
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={:?}",
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 {
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};
}
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)
}
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>,
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() {
) -> &'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);
// 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,
},
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);
// `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;
}
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),
}
}
}
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);
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);
+ }
_ => {}
}
{
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, .. }) => {
}));
}
+ // 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 {
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), .. })
| 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,
};
// 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();
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
| Use
| LifetimeParam
| Ctor(_, _)
- | AnonConst => {
+ | AnonConst
+ | InlineConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, ¬e);
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+ const { todo!() }
+}
+
+fn main() {
+ let _: usize = const { 0 };
+}
--- /dev/null
+#![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();
+}
--- /dev/null
+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`.
--- /dev/null
+// 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();
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+ match 1u64 {
+ 0 => (),
+ const { 0 + 1 } => (),
+ const { 2 - 1 } ..= const { u64::MAX } => (),
+ }
+}
--- /dev/null
+// 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();
+}
--- /dev/null
+// 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();
+}
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,
};