mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #103227 - lcnr:bye-bye-unevaluated-const, r=oli-obk
stop using `ty::UnevaluatedConst` directly best reviewed commit by commit. simplifies #99798 because we now don't have to expand `ty::UnevaluatedConst` to `ty::Const`. I also remember some other places where using `ty::UnevaluatedConst` directly was annoying and caused issues, though I don't quite remember what they were rn '^^ r? `@oli-obk` cc `@JulianKnodt`
This commit is contained in:
commit
26c96e3416
@ -192,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
(
|
||||
ty::PredicateKind::ConstEvaluatable(a),
|
||||
ty::PredicateKind::ConstEvaluatable(b),
|
||||
) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
|
||||
) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
|
||||
(
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
|
||||
|
@ -1101,8 +1101,6 @@ fn check_type_defn<'tcx, F>(
|
||||
|
||||
// Explicit `enum` discriminant values must const-evaluate successfully.
|
||||
if let Some(discr_def_id) = variant.explicit_discr {
|
||||
let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
|
||||
|
||||
let cause = traits::ObligationCause::new(
|
||||
tcx.def_span(discr_def_id),
|
||||
wfcx.body_id,
|
||||
@ -1112,10 +1110,7 @@ fn check_type_defn<'tcx, F>(
|
||||
cause,
|
||||
wfcx.param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
|
||||
ty::UnevaluatedConst::new(
|
||||
ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
|
||||
discr_substs,
|
||||
),
|
||||
ty::Const::from_anon_const(tcx, discr_def_id),
|
||||
))
|
||||
.to_predicate(tcx),
|
||||
));
|
||||
|
@ -318,10 +318,10 @@ fn const_evaluatable_predicates_of<'tcx>(
|
||||
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||
let def_id = self.tcx.hir().local_def_id(c.hir_id);
|
||||
let ct = ty::Const::from_anon_const(self.tcx, def_id);
|
||||
if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
|
||||
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
|
||||
let span = self.tcx.hir().span(c.hir_id);
|
||||
self.preds.insert((
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
|
||||
.to_predicate(self.tcx),
|
||||
span,
|
||||
));
|
||||
|
@ -55,6 +55,7 @@
|
||||
#![feature(drain_filter)]
|
||||
#![feature(intra_doc_pointers)]
|
||||
#![feature(yeet_expr)]
|
||||
#![feature(result_option_inspect)]
|
||||
#![feature(const_option)]
|
||||
#![recursion_limit = "512"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
@ -4,7 +4,9 @@ use crate::mir;
|
||||
use crate::ty::subst::InternalSubsts;
|
||||
use crate::ty::visit::TypeVisitable;
|
||||
use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
@ -83,7 +85,29 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
|
||||
Ok(Some(instance)) => {
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
self.const_eval_global_id_for_typeck(param_env, cid, span)
|
||||
self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
|
||||
// We are emitting the lint here instead of in `is_const_evaluatable`
|
||||
// as we normalize obligations before checking them, and normalization
|
||||
// uses this function to evaluate this constant.
|
||||
//
|
||||
// @lcnr believes that successfully evaluating even though there are
|
||||
// used generic parameters is a bug of evaluation, so checking for it
|
||||
// here does feel somewhat sensible.
|
||||
if !self.features().generic_const_exprs && ct.substs.has_non_region_param() {
|
||||
assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst));
|
||||
let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def);
|
||||
if mir_body.is_polymorphic {
|
||||
let Some(local_def_id) = ct.def.did.as_local() else { return };
|
||||
self.struct_span_lint_hir(
|
||||
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
|
||||
self.hir().local_def_id_to_hir_id(local_def_id),
|
||||
self.def_span(ct.def.did),
|
||||
"cannot use constants which depend on generic parameters in types",
|
||||
|err| err,
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
||||
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
|
||||
|
@ -263,6 +263,10 @@ impl<'tcx> Const<'tcx> {
|
||||
self.try_eval_usize(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(self) -> bool {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(_))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
|
||||
|
@ -15,7 +15,7 @@ use super::ScalarInt;
|
||||
|
||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
||||
#[derive(Hash, HashStable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UnevaluatedConst<'tcx> {
|
||||
pub def: ty::WithOptConstParam<DefId>,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
|
@ -34,12 +34,6 @@ impl FlagComputation {
|
||||
result.flags
|
||||
}
|
||||
|
||||
pub fn for_unevaluated_const(uv: ty::UnevaluatedConst<'_>) -> TypeFlags {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_unevaluated_const(uv);
|
||||
result.flags
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
self.flags = self.flags | flags;
|
||||
}
|
||||
@ -256,7 +250,7 @@ impl FlagComputation {
|
||||
self.add_substs(substs);
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
self.add_unevaluated_const(uv);
|
||||
self.add_const(uv);
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(expected, found) => {
|
||||
self.add_const(expected);
|
||||
@ -289,7 +283,10 @@ impl FlagComputation {
|
||||
fn add_const(&mut self, c: ty::Const<'_>) {
|
||||
self.add_ty(c.ty());
|
||||
match c.kind() {
|
||||
ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.add_substs(uv.substs);
|
||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||
}
|
||||
ty::ConstKind::Infer(infer) => {
|
||||
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||
match infer {
|
||||
@ -313,11 +310,6 @@ impl FlagComputation {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_unevaluated_const(&mut self, ct: ty::UnevaluatedConst<'_>) {
|
||||
self.add_substs(ct.substs);
|
||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||
}
|
||||
|
||||
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
|
||||
self.add_substs(projection.substs);
|
||||
match projection.term.unpack() {
|
||||
|
@ -126,13 +126,6 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
|
||||
c.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_ty_unevaluated(
|
||||
&mut self,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> ty::UnevaluatedConst<'tcx> {
|
||||
uv.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
p.super_fold_with(self)
|
||||
}
|
||||
@ -169,13 +162,6 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
|
||||
c.try_super_fold_with(self)
|
||||
}
|
||||
|
||||
fn try_fold_ty_unevaluated(
|
||||
&mut self,
|
||||
c: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Result<ty::UnevaluatedConst<'tcx>, Self::Error> {
|
||||
c.try_super_fold_with(self)
|
||||
}
|
||||
|
||||
fn try_fold_predicate(
|
||||
&mut self,
|
||||
p: ty::Predicate<'tcx>,
|
||||
@ -215,13 +201,6 @@ where
|
||||
Ok(self.fold_const(c))
|
||||
}
|
||||
|
||||
fn try_fold_ty_unevaluated(
|
||||
&mut self,
|
||||
c: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Result<ty::UnevaluatedConst<'tcx>, !> {
|
||||
Ok(self.fold_ty_unevaluated(c))
|
||||
}
|
||||
|
||||
fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
|
||||
Ok(self.fold_predicate(p))
|
||||
}
|
||||
|
@ -683,7 +683,7 @@ pub enum PredicateKind<'tcx> {
|
||||
Coerce(CoercePredicate<'tcx>),
|
||||
|
||||
/// Constant initializer must evaluate successfully.
|
||||
ConstEvaluatable(ty::UnevaluatedConst<'tcx>),
|
||||
ConstEvaluatable(ty::Const<'tcx>),
|
||||
|
||||
/// Constants must be equal. The first component is the const that is expected.
|
||||
ConstEquate(Const<'tcx>, Const<'tcx>),
|
||||
|
@ -2702,8 +2702,8 @@ define_print_and_forward_display! {
|
||||
print_value_path(closure_def_id, &[]),
|
||||
write("` implements the trait `{}`", kind))
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => {
|
||||
p!("the constant `", print(ct), "` can be evaluated")
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => {
|
||||
p!("the constant `", print(c1), "` equals `", print(c2), "`")
|
||||
|
@ -166,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
||||
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => {
|
||||
write!(f, "ConstEvaluatable({ct:?})")
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
|
||||
@ -832,27 +832,6 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||
folder.try_fold_ty_unevaluated(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
visitor.visit_ty_unevaluated(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeSuperFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
|
||||
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(ty::UnevaluatedConst { def: self.def, substs: self.substs.try_fold_with(folder)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||
self.substs.visit_with(visitor)
|
||||
|
@ -188,6 +188,14 @@ impl<'tcx> GenericArg<'tcx> {
|
||||
_ => bug!("expected a const, but found another kind"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_non_region_infer(self) -> bool {
|
||||
match self.unpack() {
|
||||
GenericArgKind::Lifetime(_) => false,
|
||||
GenericArgKind::Type(ty) => ty.is_ty_infer(),
|
||||
GenericArgKind::Const(ct) => ct.is_ct_infer(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
|
||||
|
@ -197,13 +197,6 @@ pub trait TypeVisitor<'tcx>: Sized {
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_ty_unevaluated(
|
||||
&mut self,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
uv.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
p.super_visit_with(self)
|
||||
}
|
||||
@ -592,21 +585,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "trace", ret)]
|
||||
fn visit_ty_unevaluated(
|
||||
&mut self,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
let flags = FlagComputation::for_unevaluated_const(uv);
|
||||
trace!(r.flags=?flags);
|
||||
if flags.intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "trace", ret)]
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
|
@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::Const<'tcx> {
|
||||
/// Iterator that walks `self` and any types reachable from
|
||||
/// `self`, in depth-first order. Note that just walks the types
|
||||
/// that appear in `self`, it does not descend into the fields of
|
||||
/// structs or variants. For example:
|
||||
///
|
||||
/// ```text
|
||||
/// isize => { isize }
|
||||
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
|
||||
/// [isize] => { [isize], isize }
|
||||
/// ```
|
||||
pub fn walk(self) -> TypeWalker<'tcx> {
|
||||
TypeWalker::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// We push `GenericArg`s on the stack in reverse order so as to
|
||||
/// maintain a pre-order traversal. As of the time of this
|
||||
/// writing, the fact that the traversal is pre-order is not
|
||||
|
@ -159,34 +159,12 @@ where
|
||||
ty.visit_with(self)
|
||||
}
|
||||
ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
|
||||
ty::PredicateKind::ConstEvaluatable(uv)
|
||||
if self.def_id_visitor.tcx().features().generic_const_exprs =>
|
||||
{
|
||||
let tcx = self.def_id_visitor.tcx();
|
||||
if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
|
||||
self.visit_abstract_const_expr(tcx, ct)?;
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
|
||||
ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
|
||||
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_abstract_const_expr(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ct: AbstractConst<'tcx>,
|
||||
) -> ControlFlow<V::BreakTy> {
|
||||
walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
|
||||
ACNode::Leaf(leaf) => self.visit_const(leaf),
|
||||
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_predicates(
|
||||
&mut self,
|
||||
predicates: ty::GenericPredicates<'tcx>,
|
||||
@ -309,9 +287,16 @@ where
|
||||
self.visit_ty(c.ty())?;
|
||||
let tcx = self.def_id_visitor.tcx();
|
||||
if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
|
||||
self.visit_abstract_const_expr(tcx, ct)?;
|
||||
walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
|
||||
ACNode::Leaf(leaf) => self.visit_const(leaf),
|
||||
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,12 @@
|
||||
//! `thir_abstract_const` which can then be checked for structural equality with other
|
||||
//! generic constants mentioned in the `caller_bounds` of the current environment.
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::abstract_const::{
|
||||
walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
|
||||
};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::iter;
|
||||
@ -161,11 +159,20 @@ pub fn try_unify_abstract_consts<'tcx>(
|
||||
#[instrument(skip(infcx), level = "debug")]
|
||||
pub fn is_const_evaluatable<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<(), NotConstEvaluatable> {
|
||||
let tcx = infcx.tcx;
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Error(_) => return Ok(()),
|
||||
ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
|
||||
};
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
if let Some(ct) = AbstractConst::new(tcx, uv)? {
|
||||
@ -253,25 +260,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
Err(NotConstEvaluatable::Error(reported))
|
||||
}
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Ok(_) => {
|
||||
if uv.substs.has_non_region_param() {
|
||||
assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
|
||||
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
|
||||
|
||||
if mir_body.is_polymorphic {
|
||||
let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
|
||||
tcx.struct_span_lint_hir(
|
||||
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
|
||||
tcx.hir().local_def_id_to_hir_id(local_def_id),
|
||||
span,
|
||||
"cannot use constants which depend on generic parameters in types",
|
||||
|err| err
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,7 +274,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||
for pred in param_env.caller_bounds() {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
|
||||
if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
|
||||
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
|
||||
|
||||
// Try to unify with each subtree in the AbstractConst to allow for
|
||||
|
@ -1304,7 +1304,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
}
|
||||
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => {
|
||||
let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
|
||||
bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
|
||||
};
|
||||
let mut err =
|
||||
self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
|
||||
let const_span = self.tcx.def_span(uv.def.did);
|
||||
@ -2368,7 +2371,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
if predicate.references_error() || self.is_tainted_by_errors() {
|
||||
return;
|
||||
}
|
||||
let subst = data.substs.iter().find(|g| g.has_non_region_infer());
|
||||
let subst = data.walk().find(|g| g.is_non_region_infer());
|
||||
if let Some(subst) = subst {
|
||||
let err = self.emit_inference_failure_err(
|
||||
body_id,
|
||||
|
@ -476,9 +476,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
Err(NotConstEvaluatable::MentionsInfer) => {
|
||||
pending_obligation.stalled_on.clear();
|
||||
pending_obligation.stalled_on.extend(
|
||||
uv.substs
|
||||
.iter()
|
||||
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
|
||||
uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
|
||||
);
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
|
@ -837,24 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty_unevaluated(
|
||||
&mut self,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> ControlFlow<Self::BreakTy> {
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
// Constants can only influence object safety if they reference `Self`.
|
||||
// This is only possible for unevaluated constants, so we walk these here.
|
||||
//
|
||||
// If `AbstractConst::new` returned an error we already failed compilation
|
||||
// If `AbstractConst::from_const` returned an error we already failed compilation
|
||||
// so we don't have to emit an additional error here.
|
||||
//
|
||||
// We currently recurse into abstract consts here but do not recurse in
|
||||
// `is_const_evaluatable`. This means that the object safety check is more
|
||||
// liberal than the const eval check.
|
||||
//
|
||||
// This shouldn't really matter though as we can't really use any
|
||||
// constants which are not considered const evaluatable.
|
||||
use rustc_middle::ty::abstract_const::Node;
|
||||
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv) {
|
||||
if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
|
||||
walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
|
||||
Node::Leaf(leaf) => self.visit_const(leaf),
|
||||
Node::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
@ -863,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
ct.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,13 +148,8 @@ pub fn predicate_obligations<'tcx>(
|
||||
wf.compute(a.into());
|
||||
wf.compute(b.into());
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
|
||||
wf.out.extend(obligations);
|
||||
|
||||
for arg in uv.substs.iter() {
|
||||
wf.compute(arg);
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(ct) => {
|
||||
wf.compute(ct.into());
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => {
|
||||
wf.compute(c1.into());
|
||||
@ -476,14 +471,14 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||
// obligations are handled by the parent (e.g. `ty::Ref`).
|
||||
GenericArgKind::Lifetime(_) => continue,
|
||||
|
||||
GenericArgKind::Const(constant) => {
|
||||
match constant.kind() {
|
||||
GenericArgKind::Const(ct) => {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let obligations = self.nominal_obligations(uv.def.did, uv.substs);
|
||||
self.out.extend(obligations);
|
||||
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
|
||||
.to_predicate(self.tcx());
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
@ -500,7 +495,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
|
||||
.to_predicate(self.tcx()),
|
||||
));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/dependence_lint.rs:13:32
|
||||
--> $DIR/dependence_lint.rs:14:32
|
||||
|
|
||||
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
| ^ cannot perform const operation using `T`
|
||||
@ -8,7 +8,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/dependence_lint.rs:20:37
|
||||
--> $DIR/dependence_lint.rs:21:37
|
||||
|
|
||||
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
|
||||
| ^ cannot perform const operation using `T`
|
||||
@ -17,7 +17,7 @@ LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable,
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/dependence_lint.rs:9:9
|
||||
--> $DIR/dependence_lint.rs:10:9
|
||||
|
|
||||
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
@ -27,7 +27,7 @@ LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_
|
||||
= note: `#[warn(const_evaluatable_unchecked)]` on by default
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/dependence_lint.rs:16:9
|
||||
--> $DIR/dependence_lint.rs:17:9
|
||||
|
|
||||
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: overly complex generic constant
|
||||
--> $DIR/dependence_lint.rs:16:9
|
||||
--> $DIR/dependence_lint.rs:17:9
|
||||
|
|
||||
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
|
||||
@ -7,7 +7,7 @@ LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error w
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: overly complex generic constant
|
||||
--> $DIR/dependence_lint.rs:20:17
|
||||
--> $DIR/dependence_lint.rs:21:17
|
||||
|
|
||||
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
|
||||
@ -15,7 +15,7 @@ LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable,
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/dependence_lint.rs:13:12
|
||||
--> $DIR/dependence_lint.rs:14:12
|
||||
|
|
||||
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -23,7 +23,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
|
||||
= help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/dependence_lint.rs:9:9
|
||||
--> $DIR/dependence_lint.rs:10:9
|
||||
|
|
||||
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,4 +1,5 @@
|
||||
// revisions: full gce
|
||||
// compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
|
||||
#![cfg_attr(gce, feature(generic_const_exprs))]
|
||||
#![allow(incomplete_features)]
|
||||
|
@ -1,4 +1,5 @@
|
||||
// check-pass
|
||||
// compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
|
||||
const fn foo<T>() -> usize {
|
||||
// We might instead branch on `std::mem::size_of::<*mut T>() < 8` here,
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/function-call.rs:14:17
|
||||
--> $DIR/function-call.rs:15:17
|
||||
|
|
||||
LL | let _ = [0; foo::<T>()];
|
||||
| ^^^^^^^^^^
|
||||
|
@ -1,3 +1,4 @@
|
||||
// compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
use std::mem::size_of;
|
||||
|
||||
fn test<const N: usize>() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:9:38
|
||||
--> $DIR/complex-expression.rs:10:38
|
||||
|
|
||||
LL | struct Break0<const N: usize>([u8; { N + 1 }]);
|
||||
| ^ cannot perform const operation using `N`
|
||||
@ -8,7 +8,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:12:40
|
||||
--> $DIR/complex-expression.rs:13:40
|
||||
|
|
||||
LL | struct Break1<const N: usize>([u8; { { N } }]);
|
||||
| ^ cannot perform const operation using `N`
|
||||
@ -17,7 +17,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:16:17
|
||||
--> $DIR/complex-expression.rs:17:17
|
||||
|
|
||||
LL | let _: [u8; N + 1];
|
||||
| ^ cannot perform const operation using `N`
|
||||
@ -26,7 +26,7 @@ LL | let _: [u8; N + 1];
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:21:17
|
||||
--> $DIR/complex-expression.rs:22:17
|
||||
|
|
||||
LL | let _ = [0; N + 1];
|
||||
| ^ cannot perform const operation using `N`
|
||||
@ -35,7 +35,7 @@ LL | let _ = [0; N + 1];
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:25:45
|
||||
--> $DIR/complex-expression.rs:26:45
|
||||
|
|
||||
LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
|
||||
| ^ cannot perform const operation using `T`
|
||||
@ -44,7 +44,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:28:47
|
||||
--> $DIR/complex-expression.rs:29:47
|
||||
|
|
||||
LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
|
||||
| ^ cannot perform const operation using `T`
|
||||
@ -53,7 +53,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:32:32
|
||||
--> $DIR/complex-expression.rs:33:32
|
||||
|
|
||||
LL | let _: [u8; size_of::<*mut T>() + 1];
|
||||
| ^ cannot perform const operation using `T`
|
||||
@ -62,7 +62,7 @@ LL | let _: [u8; size_of::<*mut T>() + 1];
|
||||
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/complex-expression.rs:37:17
|
||||
--> $DIR/complex-expression.rs:38:17
|
||||
|
|
||||
LL | let _ = [0; size_of::<*mut T>() + 1];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,4 +1,5 @@
|
||||
// check-pass
|
||||
// compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn foo<T>() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/const-evaluatable-unchecked.rs:5:9
|
||||
--> $DIR/const-evaluatable-unchecked.rs:6:9
|
||||
|
|
||||
LL | [0; std::mem::size_of::<*mut T>()];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -9,7 +9,7 @@ LL | [0; std::mem::size_of::<*mut T>()];
|
||||
= note: `#[warn(const_evaluatable_unchecked)]` on by default
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/const-evaluatable-unchecked.rs:16:21
|
||||
--> $DIR/const-evaluatable-unchecked.rs:17:21
|
||||
|
|
||||
LL | let _ = [0; Self::ASSOC];
|
||||
| ^^^^^^^^^^^
|
||||
@ -18,7 +18,7 @@ LL | let _ = [0; Self::ASSOC];
|
||||
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/const-evaluatable-unchecked.rs:28:21
|
||||
--> $DIR/const-evaluatable-unchecked.rs:29:21
|
||||
|
|
||||
LL | let _ = [0; Self::ASSOC];
|
||||
| ^^^^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user