提交 dbacfbc3 编写于 作者: O Oli Scherer

Add a new normalization query just for mir constants

上级 c7c39ce6
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span}; use super::{FixupError, FixupResult, InferCtxt, Span};
use rustc_middle::mir;
use rustc_middle::ty::fold::{TypeFolder, TypeVisitor}; use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
...@@ -46,6 +47,10 @@ fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { ...@@ -46,6 +47,10 @@ fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
ct.super_fold_with(self) ct.super_fold_with(self)
} }
} }
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
constant.super_fold_with(self)
}
} }
/// The opportunistic region resolver opportunistically resolves regions /// The opportunistic region resolver opportunistically resolves regions
......
...@@ -2410,7 +2410,8 @@ pub struct Constant<'tcx> { ...@@ -2410,7 +2410,8 @@ pub struct Constant<'tcx> {
pub literal: ConstantKind<'tcx>, pub literal: ConstantKind<'tcx>,
} }
#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
#[derive(Lift)]
pub enum ConstantKind<'tcx> { pub enum ConstantKind<'tcx> {
/// This constant came from the type system /// This constant came from the type system
Ty(&'tcx ty::Const<'tcx>), Ty(&'tcx ty::Const<'tcx>),
...@@ -2709,7 +2710,13 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { ...@@ -2709,7 +2710,13 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
ty::FnDef(..) => {} ty::FnDef(..) => {}
_ => write!(fmt, "const ")?, _ => write!(fmt, "const ")?,
} }
match self.literal { Display::fmt(&self.literal, fmt)
}
}
impl<'tcx> Display for ConstantKind<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
} }
......
...@@ -348,6 +348,10 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow ...@@ -348,6 +348,10 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
} }
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
folder.fold_mir_const(self)
}
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
match self { match self {
ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)), ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),
......
...@@ -1482,6 +1482,13 @@ ...@@ -1482,6 +1482,13 @@
desc { "normalizing `{}`", goal.value } desc { "normalizing `{}`", goal.value }
} }
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_mir_const_after_erasing_regions(
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "normalizing `{}`", goal.value }
}
query implied_outlives_bounds( query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx> goal: CanonicalTyGoal<'tcx>
) -> Result< ) -> Result<
......
use crate::mir;
use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::{self, Ty, TyCtxt, TypeFlags}; use crate::ty::{self, Ty, TyCtxt, TypeFlags};
...@@ -65,4 +66,8 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { ...@@ -65,4 +66,8 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
_ => self.tcx.lifetimes.re_erased, _ => self.tcx.lifetimes.re_erased,
} }
} }
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
} }
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
//! //!
//! These methods return true to indicate that the visitor has found what it is //! These methods return true to indicate that the visitor has found what it is
//! looking for, and does not need to visit anything else. //! looking for, and does not need to visit anything else.
use crate::mir;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
...@@ -179,6 +180,10 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { ...@@ -179,6 +180,10 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
c.super_fold_with(self) c.super_fold_with(self)
} }
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
} }
pub trait TypeVisitor<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
//! `normalize_generic_arg_after_erasing_regions` query for each type //! `normalize_generic_arg_after_erasing_regions` query for each type
//! or constant found within. (This underlying query is what is cached.) //! or constant found within. (This underlying query is what is cached.)
use crate::mir;
use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{self, Ty, TyCtxt};
...@@ -101,4 +102,9 @@ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { ...@@ -101,4 +102,9 @@ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let arg = self.param_env.and(c.into()); let arg = self.param_env.and(c.into());
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const() self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
} }
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
let arg = self.param_env.and(c);
self.tcx.normalize_mir_const_after_erasing_regions(arg)
}
} }
// Type substitutions. // Type substitutions.
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
...@@ -503,6 +504,10 @@ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { ...@@ -503,6 +504,10 @@ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
c.super_fold_with(self) c.super_fold_with(self)
} }
} }
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
c.super_fold_with(self)
}
} }
impl<'a, 'tcx> SubstFolder<'a, 'tcx> { impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
......
...@@ -184,7 +184,6 @@ ...@@ -184,7 +184,6 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet; use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{AllocId, ConstValue}; use rustc_middle::mir::interpret::{AllocId, ConstValue};
use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
...@@ -193,6 +192,7 @@ ...@@ -193,6 +192,7 @@
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
use rustc_session::config::EntryFnType; use rustc_session::config::EntryFnType;
use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
use smallvec::SmallVec; use smallvec::SmallVec;
...@@ -638,6 +638,35 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { ...@@ -638,6 +638,35 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location); self.super_rvalue(rvalue, location);
} }
/// This does not walk the constant, as it has been handled entirely here and trying
/// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
/// work, as some constants cannot be represented in the type system.
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
let literal = self.monomorphize(constant.literal);
let val = match literal {
mir::ConstantKind::Val(val, _) => val,
mir::ConstantKind::Ty(ct) => match ct.val {
ty::ConstKind::Value(val) => val,
ty::ConstKind::Unevaluated(ct) => {
let param_env = ty::ParamEnv::reveal_all();
match self.tcx.const_eval_resolve(param_env, ct, None) {
// The `monomorphize` call should have evaluated that constant already.
Ok(val) => val,
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => return,
Err(ErrorHandled::TooGeneric) => span_bug!(
self.body.source_info(location).span,
"collection encountered polymorphic constant: {:?}",
literal
),
}
}
_ => return,
},
};
collect_const_value(self.tcx, val, self.output);
self.visit_ty(literal.ty(), TyContext::Location(location));
}
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
debug!("visiting const {:?} @ {:?}", *constant, location); debug!("visiting const {:?} @ {:?}", *constant, location);
......
...@@ -452,7 +452,11 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { ...@@ -452,7 +452,11 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
match literal { match literal {
ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)), ConstantKind::Ty(literal) => self.push(&format!("+ literal: {:?}", literal)),
ConstantKind::Val(val, ty) => { ConstantKind::Val(val, ty) => {
self.push(&format!("+ literal: {:?}, {}", val, ty)) // To keep the diffs small, we render this almost like we render ty::Const
self.push(&format!(
"+ literal: Const {{ ty: {}, val: Value({:?}) }}",
ty, val
))
} }
} }
} }
......
...@@ -255,6 +255,15 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span { ...@@ -255,6 +255,15 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
} }
} }
impl<'tcx> Key for mir::ConstantKind<'tcx> {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for &'tcx ty::Const<'tcx> { impl<'tcx> Key for &'tcx ty::Const<'tcx> {
fn query_crate(&self) -> CrateNum { fn query_crate(&self) -> CrateNum {
LOCAL_CRATE LOCAL_CRATE
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized; use rustc_infer::traits::Normalized;
use rustc_middle::mir;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
...@@ -214,4 +215,8 @@ fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tc ...@@ -214,4 +215,8 @@ fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tc
let constant = constant.super_fold_with(self); let constant = constant.super_fold_with(self);
constant.eval(self.infcx.tcx, self.param_env) constant.eval(self.infcx.tcx, self.param_env)
} }
fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
constant.super_fold_with(self)
}
} }
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable};
use rustc_trait_selection::traits::query::normalize::AtExt; use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_trait_selection::traits::{Normalized, ObligationCause}; use rustc_trait_selection::traits::{Normalized, ObligationCause};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
crate fn provide(p: &mut Providers) { crate fn provide(p: &mut Providers) {
*p = Providers { normalize_generic_arg_after_erasing_regions, ..*p }; *p = Providers {
normalize_generic_arg_after_erasing_regions: |tcx, goal| {
debug!("normalize_generic_arg_after_erasing_regions(goal={:#?})", goal);
tcx.sess
.perf_stats
.normalize_generic_arg_after_erasing_regions
.fetch_add(1, Ordering::Relaxed);
normalize_after_erasing_regions(tcx, goal)
},
normalize_mir_const_after_erasing_regions: |tcx, goal| {
normalize_after_erasing_regions(tcx, goal)
},
..*p
};
} }
fn normalize_generic_arg_after_erasing_regions<'tcx>( #[instrument(level = "debug", skip(tcx))]
fn normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>, goal: ParamEnvAnd<'tcx, T>,
) -> GenericArg<'tcx> { ) -> T {
debug!("normalize_generic_arg_after_erasing_regions(goal={:#?})", goal);
let ParamEnvAnd { param_env, value } = goal; let ParamEnvAnd { param_env, value } = goal;
tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
tcx.infer_ctxt().enter(|infcx| { tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
match infcx.at(&cause, param_env).normalize(value) { match infcx.at(&cause, param_env).normalize(value) {
......
// build-fail // build-fail
//~^ ERROR cycle detected when normalizing `<() as Tr>::A` //~^ ERROR cycle detected when normalizing
// Cyclic assoc. const defaults don't error unless *used* // Cyclic assoc. const defaults don't error unless *used*
trait Tr { trait Tr {
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
fn main() { fn main() {
println!("{}", FOO); println!("{}", FOO);
//~^ ERROR //~^ ERROR evaluation of constant value failed
//~| WARN erroneous constant used [const_err] //~| WARN erroneous constant used [const_err]
//~| WARN this was previously accepted by the compiler but is being phased out //~| WARN this was previously accepted by the compiler but is being phased out
} }
//~ERROR constructed but no error reported // compile-flags: -Ztreat-err-as-bug=1
// compile-flags: -Ztreat-err-as-bug=2
// build-fail // build-fail
// failure-status: 101 // failure-status: 101
// rustc-env:RUST_BACKTRACE=1 // rustc-env:RUST_BACKTRACE=1
......
warning: any use of this value will cause an error warning: any use of this value will cause an error
--> $DIR/const-eval-query-stack.rs:20:16 --> $DIR/const-eval-query-stack.rs:19:16
| |
LL | const X: i32 = 1 / 0; LL | const X: i32 = 1 / 0;
| ---------------^^^^^- | ---------------^^^^^-
...@@ -7,7 +7,7 @@ LL | const X: i32 = 1 / 0; ...@@ -7,7 +7,7 @@ LL | const X: i32 = 1 / 0;
| attempt to divide `1_i32` by zero | attempt to divide `1_i32` by zero
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/const-eval-query-stack.rs:19:8 --> $DIR/const-eval-query-stack.rs:18:8
| |
LL | #[warn(const_err)] LL | #[warn(const_err)]
| ^^^^^^^^^ | ^^^^^^^^^
...@@ -15,12 +15,16 @@ LL | #[warn(const_err)] ...@@ -15,12 +15,16 @@ LL | #[warn(const_err)]
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/const-eval-query-stack.rs:24:28 --> $DIR/const-eval-query-stack.rs:23:28
| |
LL | let x: &'static i32 = &X; LL | let x: &'static i32 = &X;
| ^ referenced constant has errors | ^ referenced constant has errors
query stack during panic: query stack during panic:
#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` #0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]`
#1 [optimized_mir] optimizing MIR for `main` #1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items #2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
#3 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
#4 [optimized_mir] optimizing MIR for `main`
#5 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack end of query stack
...@@ -25,5 +25,5 @@ impl Foo for u16 { ...@@ -25,5 +25,5 @@ impl Foo for u16 {
fn main() { fn main() {
println!("{}", <Bar<u16, u8> as Foo>::AMT); println!("{}", <Bar<u16, u8> as Foo>::AMT);
//~^ ERROR evaluation of constant value failed [E0080] //~^ ERROR evaluation of constant value failed
} }
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/missing-lifetimes-in-signature.rs:36:11
|
LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
| - ^^ undeclared lifetime
| |
| help: consider introducing lifetime `'a` here: `'a,`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0261`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册