From 3c78e9e3f6939befd3382c79fbe383bbe0ec894a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 24 Jan 2021 15:48:27 +0100 Subject: [PATCH 01/12] add new Reveal for const eval during selection --- .../rustc_codegen_cranelift/src/constant.rs | 6 + compiler/rustc_codegen_ssa/src/mir/mod.rs | 5 +- .../rustc_middle/src/mir/interpret/error.rs | 5 +- compiler/rustc_middle/src/traits/mod.rs | 6 + compiler/rustc_middle/src/ty/consts/kind.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 19 +- .../rustc_mir/src/const_eval/eval_queries.rs | 453 ++++++ .../rustc_mir/src/monomorphize/collector.rs | 1265 +++++++++++++++++ .../src/traits/const_evaluatable.rs | 3 +- .../src/traits/error_reporting/mod.rs | 3 +- .../src/traits/fulfill.rs | 5 + .../src/traits/project.rs | 3 +- .../src/traits/query/normalize.rs | 3 +- .../src/traits/select/mod.rs | 14 +- .../silent-selection-err.rs | 43 + 15 files changed, 1819 insertions(+), 16 deletions(-) create mode 100644 compiler/rustc_mir/src/const_eval/eval_queries.rs create mode 100644 compiler/rustc_mir/src/monomorphize/collector.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 9a6c45ae98d5f..66679f6fe4696 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -64,6 +64,12 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { err ); } + ErrorHandled::Silent => { + span_bug!( + constant.span, + "codgen encountered silent error", + ); + } } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 1ef863e84af7f..dbb5069d57d54 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -189,7 +189,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // errored or at least linted ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {} ErrorHandled::TooGeneric => { - span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err) + span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) + } + ErrorHandled::Silent => { + span_bug!(const_.span, "silent error during codegen") } } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e9a857d09124f..714e7ba8ca9df 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -18,6 +18,9 @@ pub enum ErrorHandled { Reported(ErrorReported), /// Already emitted a lint for this evaluation. Linted, + /// Encountered an error without emitting anything. Only returned + /// with `Reveal::Selection`. + Silent, /// Don't emit an error, the evaluation failed because the MIR was generic /// and the substs didn't fully monomorphize it. TooGeneric, @@ -88,7 +91,7 @@ fn print_backtrace(backtrace: &Backtrace) { impl From for InterpErrorInfo<'_> { fn from(err: ErrorHandled) -> Self { match err { - ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => { + ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted | ErrorHandled::Silent => { err_inval!(ReferencedConstant) } ErrorHandled::TooGeneric => err_inval!(TooGeneric), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index de5beffb5c541..c5a883d876818 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -37,6 +37,12 @@ pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] pub enum Reveal { + // Similar to `Reveal::UserFacing`, except that we also do not emit errors + // when failing const evaluation. + // + // Used by `feature(const_evaluatable_checked)` to allow for `ConstEvaluatable` + // predicates to not hold without emitting an error. + Selection, /// At type-checking time, we refuse to project any associated /// type that is marked `default`. Non-`default` ("final") types /// are always projected. This is necessary in general for diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 7188eed544551..d6204a8efb783 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -191,7 +191,7 @@ impl<'tcx> ConstKind<'tcx> { // (which may be identity substs, see above), // can leak through `val` into the const we return. Ok(val) => Some(Ok(val)), - Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted | ErrorHandled::Silent) => None, Err(ErrorHandled::Reported(e)) => Some(Err(e)), } } else { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 37d99766da9d2..72514e4456105 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -150,7 +150,11 @@ pub struct MainDefinition { impl MainDefinition { pub fn opt_fn_def_id(self) -> Option { - if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } + if let Res::Def(DefKind::Fn, def_id) = self.res { + Some(def_id) + } else { + None + } } } @@ -1180,7 +1184,11 @@ impl WithOptConstParam { } pub fn def_id_for_type_of(self) -> DefId { - if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() } + if let Some(did) = self.const_param_did { + did + } else { + self.did.to_def_id() + } } } @@ -1343,6 +1351,11 @@ impl<'tcx> ParamEnv<'tcx> { ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) } } + pub fn with_reveal_selection(mut self) -> Self { + self.packed.set_tag(Reveal::Selection); + self + } + pub fn with_user_facing(mut self) -> Self { self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() }); self @@ -1412,7 +1425,7 @@ impl<'tcx> ParamEnv<'tcx> { /// although the surrounding function is never reachable. pub fn and>(self, value: T) -> ParamEnvAnd<'tcx, T> { match self.reveal() { - Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, + Reveal::Selection | Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, Reveal::All => { if value.is_known_global() { diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs new file mode 100644 index 0000000000000..303ebc829dc9f --- /dev/null +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -0,0 +1,453 @@ +use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; +use crate::interpret::eval_nullary_intrinsic; +use crate::interpret::{ + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, + Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, + ScalarMaybeUninit, StackPopCleanup, +}; + +use rustc_errors::ErrorReported; +use rustc_hir::def::DefKind; +use rustc_middle::mir; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::traits::Reveal; +use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, subst::Subst, TyCtxt}; +use rustc_span::source_map::Span; +use rustc_target::abi::{Abi, LayoutOf}; +use std::convert::TryInto; + +pub fn note_on_undefined_behavior_error() -> &'static str { + "The rules on what exactly is undefined behavior aren't clear, \ + so this check might be overzealous. Please open an issue on the rustc \ + repository if you believe it should not be considered undefined behavior." +} + +// Returns a pointer to where the result lives +fn eval_body_using_ecx<'mir, 'tcx>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + cid: GlobalId<'tcx>, + body: &'mir mir::Body<'tcx>, +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); + let tcx = *ecx.tcx; + assert!( + cid.promoted.is_some() + || matches!( + ecx.tcx.def_kind(cid.instance.def_id()), + DefKind::Const + | DefKind::Static + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::AssocConst + ), + "Unexpected DefKind: {:?}", + ecx.tcx.def_kind(cid.instance.def_id()) + ); + let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; + assert!(!layout.is_unsized()); + let ret = ecx.allocate(layout, MemoryKind::Stack); + + let name = + with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); + + ecx.push_stack_frame( + cid.instance, + body, + Some(ret.into()), + StackPopCleanup::None { cleanup: false }, + )?; + + // The main interpreter loop. + ecx.run()?; + + // Intern the result + let intern_kind = if cid.promoted.is_some() { + InternKind::Promoted + } else { + match tcx.static_mutability(cid.instance.def_id()) { + Some(m) => InternKind::Static(m), + None => InternKind::Constant, + } + }; + intern_const_alloc_recursive(ecx, intern_kind, ret)?; + + debug!("eval_body_using_ecx done: {:?}", *ret); + Ok(ret) +} + +/// The `InterpCx` is only meant to be used to do field and index projections into constants for +/// `simd_shuffle` and const patterns in match arms. +/// +/// The function containing the `match` that is currently being analyzed may have generic bounds +/// that inform us about the generic bounds of the constant. E.g., using an associated constant +/// of a function's generic parameter will require knowledge about the bounds on the generic +/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. +pub(super) fn mk_eval_cx<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, + root_span: Span, + param_env: ty::ParamEnv<'tcx>, + can_access_statics: bool, +) -> CompileTimeEvalContext<'mir, 'tcx> { + debug!("mk_eval_cx: {:?}", param_env); + InterpCx::new( + tcx, + root_span, + param_env, + CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), + MemoryExtra { can_access_statics }, + ) +} + +/// This function converts an interpreter value into a constant that is meant for use in the +/// type system. +pub(super) fn op_to_const<'tcx>( + ecx: &CompileTimeEvalContext<'_, 'tcx>, + op: OpTy<'tcx>, +) -> ConstValue<'tcx> { + // We do not have value optimizations for everything. + // Only scalars and slices, since they are very common. + // Note that further down we turn scalars of uninitialized bits back to `ByRef`. These can result + // from scalar unions that are initialized with one of their zero sized variants. We could + // instead allow `ConstValue::Scalar` to store `ScalarMaybeUninit`, but that would affect all + // the usual cases of extracting e.g. a `usize`, without there being a real use case for the + // `Undef` situation. + let try_as_immediate = match op.layout.abi { + Abi::Scalar(..) => true, + Abi::ScalarPair(..) => match op.layout.ty.kind() { + ty::Ref(_, inner, _) => match *inner.kind() { + ty::Slice(elem) => elem == ecx.tcx.types.u8, + ty::Str => true, + _ => false, + }, + _ => false, + }, + _ => false, + }; + let immediate = if try_as_immediate { + Err(ecx.read_immediate(op).expect("normalization works on validated constants")) + } else { + // It is guaranteed that any non-slice scalar pair is actually ByRef here. + // When we come back from raw const eval, we are always by-ref. The only way our op here is + // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we + // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or + // structs containing such. + op.try_as_mplace(ecx) + }; + + let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr { + Scalar::Ptr(ptr) => { + let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + Scalar::Int(int) => { + assert!(mplace.layout.is_zst()); + assert_eq!( + int.assert_bits(ecx.tcx.data_layout.pointer_size) + % u128::from(mplace.layout.align.abi.bytes()), + 0, + "this MPlaceTy must come from a validated constant, thus we can assume the \ + alignment is correct", + ); + ConstValue::Scalar(Scalar::ZST) + } + }; + match immediate { + Ok(mplace) => to_const_value(mplace), + // see comment on `let try_as_immediate` above + Err(imm) => match *imm { + Immediate::Scalar(x) => match x { + ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), + ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)), + }, + Immediate::ScalarPair(a, b) => { + let (data, start) = match a.check_init().unwrap() { + Scalar::Ptr(ptr) => { + (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes()) + } + Scalar::Int { .. } => ( + ecx.tcx + .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), + 0, + ), + }; + let len = b.to_machine_usize(ecx).unwrap(); + let start = start.try_into().unwrap(); + let len: usize = len.try_into().unwrap(); + ConstValue::Slice { data, start, end: start + len } + } + }, + } +} + +fn turn_into_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + constant: ConstAlloc<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ConstValue<'tcx> { + let cid = key.value; + let def_id = cid.instance.def.def_id(); + let is_static = tcx.is_static(def_id); + let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); + + let mplace = ecx.raw_const_to_mplace(constant).expect( + "can only fail if layout computation failed, \ + which should have given a good error before ever invoking this function", + ); + assert!( + !is_static || cid.promoted.is_some(), + "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" + ); + // Turn this into a proper constant. + op_to_const(&ecx, mplace.into()) +} + +pub fn eval_to_const_value_raw_provider<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { + // see comment in const_eval_raw_provider for what we're doing here + match key.param_env.reveal() { + Reveal::Selection => {} + Reveal::UserFacing => { + let mut key = key; + key.param_env = key.param_env.with_reveal_selection(); + match tcx.eval_to_const_value_raw(key) { + // try again with reveal all as requested + Err(ErrorHandled::Silent) => {} + // deduplicate calls + other => return other, + } + } + Reveal::All => { + let mut key = key; + key.param_env = key.param_env.with_user_facing(); + match tcx.eval_to_const_value_raw(key) { + // try again with reveal all as requested + Err(ErrorHandled::Silent) => bug!("unexpected error for {:?}", key), + Err(ErrorHandled::TooGeneric) => {} + // deduplicate calls + other => return other, + } + } + } + + // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. + // Catch such calls and evaluate them instead of trying to load a constant's MIR. + if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { + let ty = key.value.instance.ty(tcx, key.param_env); + let substs = match ty.kind() { + ty::FnDef(_, substs) => substs, + _ => bug!("intrinsic with type {:?}", ty), + }; + return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { + let span = tcx.def_span(def_id); + let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; + error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") + }); + } + + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) +} + +pub fn eval_to_allocation_raw_provider<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, +) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // Because the constant is computed twice (once per value of `Reveal`), we are at risk of + // reporting the same error twice here. To resolve this, we check whether we can evaluate the + // constant in the more restrictive `Reveal::UserFacing`, which most likely already was + // computed. For a large percentage of constants that will already have succeeded. Only + // associated constants of generic functions will fail due to not enough monomorphization + // information being available. + match key.param_env.reveal() { + Reveal::Selection => {} + Reveal::UserFacing => { + let mut key = key; + key.param_env = key.param_env.with_reveal_selection(); + match tcx.eval_to_allocation_raw(key) { + Err(ErrorHandled::Silent) => {} + // deduplicate calls + other => return other, + } + } + Reveal::All => { + let mut key = key; + key.param_env = key.param_env.with_user_facing(); + match tcx.eval_to_allocation_raw(key) { + Err(ErrorHandled::Silent) => bug!("unexpected error for {:?}", key), + Err(ErrorHandled::TooGeneric) => {} + // deduplicate calls + other => return other, + } + } + } + + if cfg!(debug_assertions) { + // Make sure we format the instance even if we do not print it. + // This serves as a regression test against an ICE on printing. + // The next two lines concatenated contain some discussion: + // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ + // subject/anon_const_instance_printing/near/135980032 + let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); + trace!("const eval: {:?} ({})", key, instance); + } + + let cid = key.value; + let def = cid.instance.def.with_opt_param(); + + if let Some(def) = def.as_local() { + if tcx.has_typeck_results(def.did) { + if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors { + return Err(ErrorHandled::Reported(error_reported)); + } + } + if !tcx.is_mir_available(def.did) { + tcx.sess.delay_span_bug( + tcx.def_span(def.did), + &format!("no MIR body is available for {:?}", def.did), + ); + return Err(ErrorHandled::Reported(ErrorReported {})); + } + if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { + return Err(ErrorHandled::Reported(error_reported)); + } + } + + let is_static = tcx.is_static(def.did); + + let mut ecx = InterpCx::new( + tcx, + tcx.def_span(def.did), + key.param_env, + CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), + MemoryExtra { can_access_statics: is_static }, + ); + + let res = ecx.load_mir(cid.instance.def, cid.promoted); + match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { + Err(error) => { + if key.param_env.reveal() == Reveal::Selection { + match error.kind { + err_inval!(Layout(LayoutError::Unknown(_))) + | err_inval!(TooGeneric) + | err_inval!(AlreadyReported(_)) => {} + _ => return Err(ErrorHandled::Silent), + } + } + + let err = ConstEvalErr::new(&ecx, error, None); + // errors in statics are always emitted as fatal errors + if is_static { + // Ensure that if the above error was either `TooGeneric` or `Reported` + // an error must be reported. + let v = err.report_as_error( + ecx.tcx.at(ecx.cur_span()), + "could not evaluate static initializer", + ); + + // If this is `Reveal:All`, then we need to make sure an error is reported but if + // this is `Reveal::UserFacing`, then it's expected that we could get a + // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either + // succeed or we'll report this error then. + if key.param_env.reveal() == Reveal::All { + tcx.sess.delay_span_bug( + err.span, + &format!("static eval failure did not emit an error: {:#?}", v), + ); + } + + Err(v) + } else if let Some(def) = def.as_local() { + // constant defined in this crate, we can figure out a lint level! + match tcx.def_kind(def.did.to_def_id()) { + // constants never produce a hard error at the definition site. Anything else is + // a backwards compatibility hazard (and will break old versions of winapi for + // sure) + // + // note that validation may still cause a hard error on this very same constant, + // because any code that existed before validation could not have failed + // validation thus preventing such a hard error from being a backwards + // compatibility hazard + DefKind::Const | DefKind::AssocConst => { + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + Err(err.report_as_lint( + tcx.at(tcx.def_span(def.did)), + "any use of this value will cause an error", + hir_id, + Some(err.span), + )) + } + // promoting runtime code is only allowed to error if it references broken + // constants any other kind of error will be reported to the user as a + // deny-by-default lint + _ => { + if let Some(p) = cid.promoted { + let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span; + if let err_inval!(ReferencedConstant) = err.error { + Err(err.report_as_error( + tcx.at(span), + "evaluation of constant expression failed", + )) + } else { + Err(err.report_as_lint( + tcx.at(span), + "reaching this expression at runtime will panic or abort", + tcx.hir().local_def_id_to_hir_id(def.did), + Some(err.span), + )) + } + // anything else (array lengths, enum initializers, constant patterns) are + // reported as hard errors + } else { + Err(err.report_as_error( + ecx.tcx.at(ecx.cur_span()), + "evaluation of constant value failed", + )) + } + } + } + } else { + // use of broken constant from other crate + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")) + } + } + Ok(mplace) => { + // Since evaluation had no errors, valiate the resulting constant: + let validation = try { + let mut ref_tracking = RefTracking::new(mplace); + let mut inner = false; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + let mode = match tcx.static_mutability(cid.instance.def_id()) { + Some(_) if cid.promoted.is_some() => { + // Promoteds in statics are allowed to point to statics. + CtfeValidationMode::Const { inner, allow_static_ptrs: true } + } + Some(_) => CtfeValidationMode::Regular, // a `static` + None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, + }; + ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; + inner = true; + } + }; + if let Err(error) = validation { + // Validation failed, report an error + let err = ConstEvalErr::new(&ecx, error, None); + Err(err.struct_error( + ecx.tcx, + "it is undefined behavior to use this value", + |mut diag| { + diag.note(note_on_undefined_behavior_error()); + diag.emit(); + }, + )) + } else { + // Convert to raw constant + Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) + } + } + } +} diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs new file mode 100644 index 0000000000000..a2a58207f279f --- /dev/null +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -0,0 +1,1265 @@ +//! Mono Item Collection +//! ==================== +//! +//! This module is responsible for discovering all items that will contribute +//! to code generation of the crate. The important part here is that it not only +//! needs to find syntax-level items (functions, structs, etc) but also all +//! their monomorphized instantiations. Every non-generic, non-const function +//! maps to one LLVM artifact. Every generic function can produce +//! from zero to N artifacts, depending on the sets of type arguments it +//! is instantiated with. +//! This also applies to generic items from other crates: A generic definition +//! in crate X might produce monomorphizations that are compiled into crate Y. +//! We also have to collect these here. +//! +//! The following kinds of "mono items" are handled here: +//! +//! - Functions +//! - Methods +//! - Closures +//! - Statics +//! - Drop glue +//! +//! The following things also result in LLVM artifacts, but are not collected +//! here, since we instantiate them locally on demand when needed in a given +//! codegen unit: +//! +//! - Constants +//! - Vtables +//! - Object Shims +//! +//! +//! General Algorithm +//! ----------------- +//! Let's define some terms first: +//! +//! - A "mono item" is something that results in a function or global in +//! the LLVM IR of a codegen unit. Mono items do not stand on their +//! own, they can reference other mono items. For example, if function +//! `foo()` calls function `bar()` then the mono item for `foo()` +//! references the mono item for function `bar()`. In general, the +//! definition for mono item A referencing a mono item B is that +//! the LLVM artifact produced for A references the LLVM artifact produced +//! for B. +//! +//! - Mono items and the references between them form a directed graph, +//! where the mono items are the nodes and references form the edges. +//! Let's call this graph the "mono item graph". +//! +//! - The mono item graph for a program contains all mono items +//! that are needed in order to produce the complete LLVM IR of the program. +//! +//! The purpose of the algorithm implemented in this module is to build the +//! mono item graph for the current crate. It runs in two phases: +//! +//! 1. Discover the roots of the graph by traversing the HIR of the crate. +//! 2. Starting from the roots, find neighboring nodes by inspecting the MIR +//! representation of the item corresponding to a given node, until no more +//! new nodes are found. +//! +//! ### Discovering roots +//! +//! The roots of the mono item graph correspond to the non-generic +//! syntactic items in the source code. We find them by walking the HIR of the +//! crate, and whenever we hit upon a function, method, or static item, we +//! create a mono item consisting of the items DefId and, since we only +//! consider non-generic items, an empty type-substitution set. +//! +//! ### Finding neighbor nodes +//! Given a mono item node, we can discover neighbors by inspecting its +//! MIR. We walk the MIR and any time we hit upon something that signifies a +//! reference to another mono item, we have found a neighbor. Since the +//! mono item we are currently at is always monomorphic, we also know the +//! concrete type arguments of its neighbors, and so all neighbors again will be +//! monomorphic. The specific forms a reference to a neighboring node can take +//! in MIR are quite diverse. Here is an overview: +//! +//! #### Calling Functions/Methods +//! The most obvious form of one mono item referencing another is a +//! function or method call (represented by a CALL terminator in MIR). But +//! calls are not the only thing that might introduce a reference between two +//! function mono items, and as we will see below, they are just a +//! specialization of the form described next, and consequently will not get any +//! special treatment in the algorithm. +//! +//! #### Taking a reference to a function or method +//! A function does not need to actually be called in order to be a neighbor of +//! another function. It suffices to just take a reference in order to introduce +//! an edge. Consider the following example: +//! +//! ```rust +//! fn print_val(x: T) { +//! println!("{}", x); +//! } +//! +//! fn call_fn(f: &Fn(i32), x: i32) { +//! f(x); +//! } +//! +//! fn main() { +//! let print_i32 = print_val::; +//! call_fn(&print_i32, 0); +//! } +//! ``` +//! The MIR of none of these functions will contain an explicit call to +//! `print_val::`. Nonetheless, in order to mono this program, we need +//! an instance of this function. Thus, whenever we encounter a function or +//! method in operand position, we treat it as a neighbor of the current +//! mono item. Calls are just a special case of that. +//! +//! #### Closures +//! In a way, closures are a simple case. Since every closure object needs to be +//! constructed somewhere, we can reliably discover them by observing +//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also +//! true for closures inlined from other crates. +//! +//! #### Drop glue +//! Drop glue mono items are introduced by MIR drop-statements. The +//! generated mono item will again have drop-glue item neighbors if the +//! type to be dropped contains nested values that also need to be dropped. It +//! might also have a function item neighbor for the explicit `Drop::drop` +//! implementation of its type. +//! +//! #### Unsizing Casts +//! A subtle way of introducing neighbor edges is by casting to a trait object. +//! Since the resulting fat-pointer contains a reference to a vtable, we need to +//! instantiate all object-save methods of the trait, as we need to store +//! pointers to these functions even if they never get called anywhere. This can +//! be seen as a special case of taking a function reference. +//! +//! #### Boxes +//! Since `Box` expression have special compiler support, no explicit calls to +//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the +//! compiler will generate them. We have to observe `Rvalue::Box` expressions +//! and Box-typed drop-statements for that purpose. +//! +//! +//! Interaction with Cross-Crate Inlining +//! ------------------------------------- +//! The binary of a crate will not only contain machine code for the items +//! defined in the source code of that crate. It will also contain monomorphic +//! instantiations of any extern generic functions and of functions marked with +//! `#[inline]`. +//! The collection algorithm handles this more or less mono. If it is +//! about to create a mono item for something with an external `DefId`, +//! it will take a look if the MIR for that item is available, and if so just +//! proceed normally. If the MIR is not available, it assumes that the item is +//! just linked to and no node is created; which is exactly what we want, since +//! no machine code should be generated in the current crate for such an item. +//! +//! Eager and Lazy Collection Mode +//! ------------------------------ +//! Mono item collection can be performed in one of two modes: +//! +//! - Lazy mode means that items will only be instantiated when actually +//! referenced. The goal is to produce the least amount of machine code +//! possible. +//! +//! - Eager mode is meant to be used in conjunction with incremental compilation +//! where a stable set of mono items is more important than a minimal +//! one. Thus, eager mode will instantiate drop-glue for every drop-able type +//! in the crate, even if no drop call for that type exists (yet). It will +//! also instantiate default implementations of trait methods, something that +//! otherwise is only done on demand. +//! +//! +//! Open Issues +//! ----------- +//! Some things are not yet fully implemented in the current version of this +//! module. +//! +//! ### Const Fns +//! Ideally, no mono item should be generated for const fns unless there +//! is a call to them that cannot be evaluated at compile time. At the moment +//! this is not implemented however: a mono item will be produced +//! regardless of whether it is actually needed or not. + +use crate::monomorphize; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; +use rustc_errors::{ErrorReported, FatalError}; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::lang_items::LangItem; +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::{ErrorHandled, GlobalAlloc, Scalar}; +use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::visit::Visitor as MirVisitor; +use rustc_middle::mir::{self, Local, Location}; +use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_session::config::EntryFnType; +use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; +use smallvec::SmallVec; +use std::iter; +use std::ops::Range; +use std::path::PathBuf; + +#[derive(PartialEq)] +pub enum MonoItemCollectionMode { + Eager, + Lazy, +} + +/// Maps every mono item to all mono items it references in its +/// body. +pub struct InliningMap<'tcx> { + // Maps a source mono item to the range of mono items + // accessed by it. + // The range selects elements within the `targets` vecs. + index: FxHashMap, Range>, + targets: Vec>, + + // Contains one bit per mono item in the `targets` field. That bit + // is true if that mono item needs to be inlined into every CGU. + inlines: GrowableBitSet, +} + +impl<'tcx> InliningMap<'tcx> { + fn new() -> InliningMap<'tcx> { + InliningMap { + index: FxHashMap::default(), + targets: Vec::new(), + inlines: GrowableBitSet::with_capacity(1024), + } + } + + fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { + let start_index = self.targets.len(); + let new_items_count = new_targets.len(); + let new_items_count_total = new_items_count + self.targets.len(); + + self.targets.reserve(new_items_count); + self.inlines.ensure(new_items_count_total); + + for (i, (target, inline)) in new_targets.iter().enumerate() { + self.targets.push(*target); + if *inline { + self.inlines.insert(i + start_index); + } + } + + let end_index = self.targets.len(); + assert!(self.index.insert(source, start_index..end_index).is_none()); + } + + // Internally iterate over all items referenced by `source` which will be + // made available for inlining. + pub fn with_inlining_candidates(&self, source: MonoItem<'tcx>, mut f: F) + where + F: FnMut(MonoItem<'tcx>), + { + if let Some(range) = self.index.get(&source) { + for (i, candidate) in self.targets[range.clone()].iter().enumerate() { + if self.inlines.contains(range.start + i) { + f(*candidate); + } + } + } + } + + // Internally iterate over all items and the things each accesses. + pub fn iter_accesses(&self, mut f: F) + where + F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), + { + for (&accessor, range) in &self.index { + f(accessor, &self.targets[range.clone()]) + } + } +} + +pub fn collect_crate_mono_items( + tcx: TyCtxt<'_>, + mode: MonoItemCollectionMode, +) -> (FxHashSet>, InliningMap<'_>) { + let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); + + let roots = + tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode)); + + debug!("building mono item graph, beginning at roots"); + + let mut visited = MTLock::new(FxHashSet::default()); + let mut inlining_map = MTLock::new(InliningMap::new()); + + { + let visited: MTRef<'_, _> = &mut visited; + let inlining_map: MTRef<'_, _> = &mut inlining_map; + + tcx.sess.time("monomorphization_collector_graph_walk", || { + par_iter(roots).for_each(|root| { + let mut recursion_depths = DefIdMap::default(); + collect_items_rec( + tcx, + dummy_spanned(root), + visited, + &mut recursion_depths, + inlining_map, + ); + }); + }); + } + + (visited.into_inner(), inlining_map.into_inner()) +} + +// Find all non-generic items by walking the HIR. These items serve as roots to +// start monomorphizing from. +fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { + debug!("collecting roots"); + let mut roots = Vec::new(); + + { + let entry_fn = tcx.entry_fn(LOCAL_CRATE); + + debug!("collect_roots: entry_fn = {:?}", entry_fn); + + let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots }; + + tcx.hir().krate().visit_all_item_likes(&mut visitor); + + visitor.push_extra_entry_roots(); + } + + // We can only codegen items that are instantiable - items all of + // whose predicates hold. Luckily, items that aren't instantiable + // can't actually be used, so we can just skip codegenning them. + roots + .into_iter() + .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node)) + .collect() +} + +// Collect all monomorphized items reachable from `starting_point` +fn collect_items_rec<'tcx>( + tcx: TyCtxt<'tcx>, + starting_point: Spanned>, + visited: MTRef<'_, MTLock>>>, + recursion_depths: &mut DefIdMap, + inlining_map: MTRef<'_, MTLock>>, +) { + if !visited.lock_mut().insert(starting_point.node) { + // We've been here already, no need to search again. + return; + } + debug!("BEGIN collect_items_rec({})", starting_point.node); + + let mut neighbors = Vec::new(); + let recursion_depth_reset; + + match starting_point.node { + MonoItem::Static(def_id) => { + let instance = Instance::mono(tcx, def_id); + + // Sanity check whether this ended up being collected accidentally + debug_assert!(should_codegen_locally(tcx, &instance)); + + let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors); + + recursion_depth_reset = None; + + if let Ok(alloc) = tcx.eval_static_initializer(def_id) { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, &mut neighbors); + } + } + } + MonoItem::Fn(instance) => { + // Sanity check whether this ended up being collected accidentally + debug_assert!(should_codegen_locally(tcx, &instance)); + + // Keep track of the monomorphization recursion depth + recursion_depth_reset = + Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths)); + check_type_length_limit(tcx, instance); + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_neighbours(tcx, instance, &mut neighbors); + }); + } + MonoItem::GlobalAsm(..) => { + recursion_depth_reset = None; + } + } + + record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); + + for neighbour in neighbors { + collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map); + } + + if let Some((def_id, depth)) = recursion_depth_reset { + recursion_depths.insert(def_id, depth); + } + + debug!("END collect_items_rec({})", starting_point.node); +} + +fn record_accesses<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, + caller: MonoItem<'tcx>, + callees: impl Iterator>, + inlining_map: MTRef<'_, MTLock>>, +) { + let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { + mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy + }; + + // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. + // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` + // instead to avoid creating this `SmallVec`. + let accesses: SmallVec<[_; 128]> = + callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); + + inlining_map.lock_mut().record_accesses(caller, &accesses); +} + +/// Format instance name that is already known to be too long for rustc. +/// Show only the first and last 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +fn shrunk_instance_name( + tcx: TyCtxt<'tcx>, + instance: &Instance<'tcx>, + before: usize, + after: usize, +) -> (String, Option) { + let s = instance.to_string(); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if s.chars().nth(before + after + 1).is_some() { + // An iterator of all byte positions including the end of the string. + let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); + + let shrunk = format!( + "{before}...{after}", + before = &s[..positions().nth(before).unwrap_or(s.len())], + after = &s[positions().rev().nth(after).unwrap_or(0)..], + ); + + let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); + + (shrunk, written_to_path) + } else { + (s, None) + } +} + +fn check_recursion_limit<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + span: Span, + recursion_depths: &mut DefIdMap, +) -> (DefId, usize) { + let def_id = instance.def_id(); + let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); + debug!(" => recursion depth={}", recursion_depth); + + let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + // HACK: drop_in_place creates tight monomorphization loops. Give + // it more margin. + recursion_depth / 4 + } else { + recursion_depth + }; + + // Code that needs to instantiate the same function recursively + // more than the recursion limit is assumed to be causing an + // infinite expansion. + if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let error = format!("reached the recursion limit while instantiating `{}`", shrunk); + let mut err = tcx.sess.struct_span_fatal(span, &error); + err.span_note( + tcx.def_span(def_id), + &format!("`{}` defined here", tcx.def_path_str(def_id)), + ); + if let Some(path) = written_to_path { + err.note(&format!("the full type name has been written to '{}'", path.display())); + } + err.emit(); + FatalError.raise(); + } + + recursion_depths.insert(def_id, recursion_depth + 1); + + (def_id, recursion_depth) +} + +fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let type_length = instance + .substs + .iter() + .flat_map(|arg| arg.walk()) + .filter(|arg| match arg.unpack() { + GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, + GenericArgKind::Lifetime(_) => false, + }) + .count(); + debug!(" => type length={}", type_length); + + // Rust code can easily create exponentially-long types using only a + // polynomial recursion depth. Even with the default recursion + // depth, you can easily get cases that take >2^60 steps to run, + // which means that rustc basically hangs. + // + // Bail out in these cases to avoid that bad user experience. + if !tcx.sess.type_length_limit().value_within_limit(type_length) { + let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); + let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); + let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); + if let Some(path) = written_to_path { + diag.note(&format!("the full type name has been written to '{}'", path.display())); + } + diag.help(&format!( + "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", + type_length + )); + diag.emit(); + tcx.sess.abort_if_errors(); + } +} + +struct MirNeighborCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + output: &'a mut Vec>>, + instance: Instance<'tcx>, +} + +impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { + pub fn monomorphize(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + debug!("monomorphize: self.instance={:?}", self.instance); + self.instance.subst_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + value, + ) + } +} + +impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { + debug!("visiting rvalue {:?}", *rvalue); + + let span = self.body.source_info(location).span; + + match *rvalue { + // When doing an cast from a regular pointer to a fat pointer, we + // have to instantiate all methods of the trait being cast to, so we + // can build the appropriate vtable. + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::Unsize), + ref operand, + target_ty, + ) => { + let target_ty = self.monomorphize(target_ty); + let source_ty = operand.ty(self.body, self.tcx); + let source_ty = self.monomorphize(source_ty); + let (source_ty, target_ty) = + find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); + // This could also be a different Unsize instruction, like + // from a fixed sized array to a slice. But we are only + // interested in things that produce a vtable. + if target_ty.is_trait() && !source_ty.is_trait() { + create_mono_items_for_vtable_methods( + self.tcx, + target_ty, + source_ty, + span, + self.output, + ); + } + } + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ReifyFnPointer), + ref operand, + _, + ) => { + let fn_ty = operand.ty(self.body, self.tcx); + let fn_ty = self.monomorphize(fn_ty); + visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); + } + mir::Rvalue::Cast( + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), + ref operand, + _, + ) => { + let source_ty = operand.ty(self.body, self.tcx); + let source_ty = self.monomorphize(source_ty); + match *source_ty.kind() { + ty::Closure(def_id, substs) => { + let instance = Instance::resolve_closure( + self.tcx, + def_id, + substs, + ty::ClosureKind::FnOnce, + ); + if should_codegen_locally(self.tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); + } + } + _ => bug!(), + } + } + mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { + let tcx = self.tcx; + let exchange_malloc_fn_def_id = + tcx.require_lang_item(LangItem::ExchangeMalloc, None); + let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); + if should_codegen_locally(tcx, &instance) { + self.output.push(create_fn_mono_item(self.tcx, instance, span)); + } + } + mir::Rvalue::ThreadLocalRef(def_id) => { + assert!(self.tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(self.tcx, def_id); + if should_codegen_locally(self.tcx, &instance) { + trace!("collecting thread-local static {:?}", def_id); + self.output.push(respan(span, MonoItem::Static(def_id))); + } + } + _ => { /* not interesting */ } + } + + self.super_rvalue(rvalue, location); + } + + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { + debug!("visiting const {:?} @ {:?}", *constant, location); + + let substituted_constant = self.monomorphize(*constant); + let param_env = ty::ParamEnv::reveal_all(); + + match substituted_constant.val { + ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), + ty::ConstKind::Unevaluated(def, substs, promoted) => { + match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) { + Ok(val) => collect_const_value(self.tcx, val, self.output), + Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} + Err(ErrorHandled::TooGeneric) => span_bug!( + self.body.source_info(location).span, + "collection encountered polymorphic constant: {}", + substituted_constant + ), + Err(ErrorHandled::Silent) => span_bug!( + self.body.source_info(location).span, + "silent error emitted during collection", + ), + } + } + _ => {} + } + + self.super_const(constant); + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + debug!("visiting terminator {:?} @ {:?}", terminator, location); + let source = self.body.source_info(location).span; + + let tcx = self.tcx; + match terminator.kind { + mir::TerminatorKind::Call { ref func, .. } => { + let callee_ty = func.ty(self.body, tcx); + let callee_ty = self.monomorphize(callee_ty); + visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); + } + mir::TerminatorKind::Drop { ref place, .. } + | mir::TerminatorKind::DropAndReplace { ref place, .. } => { + let ty = place.ty(self.body, self.tcx).ty; + let ty = self.monomorphize(ty); + visit_drop_use(self.tcx, ty, true, source, self.output); + } + mir::TerminatorKind::InlineAsm { ref operands, .. } => { + for op in operands { + match *op { + mir::InlineAsmOperand::SymFn { ref value } => { + let fn_ty = self.monomorphize(value.literal.ty); + visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); + } + mir::InlineAsmOperand::SymStatic { def_id } => { + let instance = Instance::mono(self.tcx, def_id); + if should_codegen_locally(self.tcx, &instance) { + trace!("collecting asm sym static {:?}", def_id); + self.output.push(respan(source, MonoItem::Static(def_id))); + } + } + _ => {} + } + } + } + mir::TerminatorKind::Goto { .. } + | mir::TerminatorKind::SwitchInt { .. } + | mir::TerminatorKind::Resume + | mir::TerminatorKind::Abort + | mir::TerminatorKind::Return + | mir::TerminatorKind::Unreachable + | mir::TerminatorKind::Assert { .. } => {} + mir::TerminatorKind::GeneratorDrop + | mir::TerminatorKind::Yield { .. } + | mir::TerminatorKind::FalseEdge { .. } + | mir::TerminatorKind::FalseUnwind { .. } => bug!(), + } + + self.super_terminator(terminator, location); + } + + fn visit_local( + &mut self, + _place_local: &Local, + _context: mir::visit::PlaceContext, + _location: Location, + ) { + } +} + +fn visit_drop_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + let instance = Instance::resolve_drop_in_place(tcx, ty); + visit_instance_use(tcx, instance, is_direct_call, source, output); +} + +fn visit_fn_use<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + if let ty::FnDef(def_id, substs) = *ty.kind() { + let instance = if is_direct_call { + ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() + } else { + ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs) + .unwrap() + }; + visit_instance_use(tcx, instance, is_direct_call, source, output); + } +} + +fn visit_instance_use<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + is_direct_call: bool, + source: Span, + output: &mut Vec>>, +) { + debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); + if !should_codegen_locally(tcx, &instance) { + return; + } + + match instance.def { + ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { + if !is_direct_call { + bug!("{:?} being reified", instance); + } + } + ty::InstanceDef::DropGlue(_, None) => { + // Don't need to emit noop drop glue if we are calling directly. + if !is_direct_call { + output.push(create_fn_mono_item(tcx, instance, source)); + } + } + ty::InstanceDef::DropGlue(_, Some(_)) + | ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Item(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::CloneShim(..) => { + output.push(create_fn_mono_item(tcx, instance, source)); + } + } +} + +// Returns `true` if we should codegen an instance in the local crate. +// Returns `false` if we can just link to the upstream crate and therefore don't +// need a mono item. +fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { + let def_id = match instance.def { + ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, + ty::InstanceDef::VtableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::Virtual(..) + | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::Intrinsic(_) + | ty::InstanceDef::CloneShim(..) => return true, + }; + + if tcx.is_foreign_item(def_id) { + // Foreign items are always linked against, there's no way of instantiating them. + return false; + } + + if def_id.is_local() { + // Local items cannot be referred to locally without monomorphizing them locally. + return true; + } + + if tcx.is_reachable_non_generic(def_id) + || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + { + // We can link to the item in question, no instance needed in this crate. + return false; + } + + if !tcx.is_mir_available(def_id) { + bug!("no MIR available for {:?}", def_id); + } + + true +} + +/// For a given pair of source and target type that occur in an unsizing coercion, +/// this function finds the pair of types that determines the vtable linking +/// them. +/// +/// For example, the source type might be `&SomeStruct` and the target type\ +/// might be `&SomeTrait` in a cast like: +/// +/// let src: &SomeStruct = ...; +/// let target = src as &SomeTrait; +/// +/// Then the output of this function would be (SomeStruct, SomeTrait) since for +/// constructing the `target` fat-pointer we need the vtable for that pair. +/// +/// Things can get more complicated though because there's also the case where +/// the unsized type occurs as a field: +/// +/// ```rust +/// struct ComplexStruct { +/// a: u32, +/// b: f64, +/// c: T +/// } +/// ``` +/// +/// In this case, if `T` is sized, `&ComplexStruct` is a thin pointer. If `T` +/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is +/// for the pair of `T` (which is a trait) and the concrete type that `T` was +/// originally coerced from: +/// +/// let src: &ComplexStruct = ...; +/// let target = src as &ComplexStruct; +/// +/// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair +/// `(SomeStruct, SomeTrait)`. +/// +/// Finally, there is also the case of custom unsizing coercions, e.g., for +/// smart pointers such as `Rc` and `Arc`. +fn find_vtable_types_for_unsizing<'tcx>( + tcx: TyCtxt<'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, +) -> (Ty<'tcx>, Ty<'tcx>) { + let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { + let param_env = ty::ParamEnv::reveal_all(); + let type_has_metadata = |ty: Ty<'tcx>| -> bool { + if ty.is_sized(tcx.at(DUMMY_SP), param_env) { + return false; + } + let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); + match tail.kind() { + ty::Foreign(..) => false, + ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail), + } + }; + if type_has_metadata(inner_source) { + (inner_source, inner_target) + } else { + tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env) + } + }; + + match (&source_ty.kind(), &target_ty.kind()) { + (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) + | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { + ptr_vtable(a, b) + } + (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) + } + + (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { + assert_eq!(source_adt_def, target_adt_def); + + let CustomCoerceUnsized::Struct(coerce_index) = + monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); + + let source_fields = &source_adt_def.non_enum_variant().fields; + let target_fields = &target_adt_def.non_enum_variant().fields; + + assert!( + coerce_index < source_fields.len() && source_fields.len() == target_fields.len() + ); + + find_vtable_types_for_unsizing( + tcx, + source_fields[coerce_index].ty(tcx, source_substs), + target_fields[coerce_index].ty(tcx, target_substs), + ) + } + _ => bug!( + "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", + source_ty, + target_ty + ), + } +} + +fn create_fn_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + source: Span, +) -> Spanned> { + debug!("create_fn_mono_item(instance={})", instance); + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) +} + +/// Creates a `MonoItem` for each method that is referenced by the vtable for +/// the given trait/impl pair. +fn create_mono_items_for_vtable_methods<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: Ty<'tcx>, + impl_ty: Ty<'tcx>, + source: Span, + output: &mut Vec>>, +) { + assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); + + if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind() { + if let Some(principal) = trait_ty.principal() { + let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); + assert!(!poly_trait_ref.has_escaping_bound_vars()); + + // Walk all methods of the trait, including those of its supertraits + let methods = tcx.vtable_methods(poly_trait_ref); + let methods = methods + .iter() + .cloned() + .filter_map(|method| method) + .map(|(def_id, substs)| { + ty::Instance::resolve_for_vtable( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .unwrap() + }) + .filter(|&instance| should_codegen_locally(tcx, &instance)) + .map(|item| create_fn_mono_item(tcx, item, source)); + output.extend(methods); + } + + // Also add the destructor. + visit_drop_use(tcx, impl_ty, false, source, output); + } +} + +//=----------------------------------------------------------------------------- +// Root Collection +//=----------------------------------------------------------------------------- + +struct RootCollector<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + mode: MonoItemCollectionMode, + output: &'a mut Vec>>, + entry_fn: Option<(LocalDefId, EntryFnType)>, +} + +impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { + fn visit_item(&mut self, item: &'v hir::Item<'v>) { + match item.kind { + hir::ItemKind::ExternCrate(..) + | hir::ItemKind::Use(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::TyAlias(..) + | hir::ItemKind::Trait(..) + | hir::ItemKind::TraitAlias(..) + | hir::ItemKind::OpaqueTy(..) + | hir::ItemKind::Mod(..) => { + // Nothing to do, just keep recursing. + } + + hir::ItemKind::Impl { .. } => { + if self.mode == MonoItemCollectionMode::Eager { + create_mono_items_for_default_impls(self.tcx, item, self.output); + } + } + + hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) => { + if generics.params.is_empty() { + if self.mode == MonoItemCollectionMode::Eager { + let def_id = self.tcx.hir().local_def_id(item.hir_id); + debug!( + "RootCollector: ADT drop-glue for {}", + self.tcx.def_path_str(def_id.to_def_id()) + ); + + let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty()) + .ty(self.tcx, ty::ParamEnv::reveal_all()); + visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); + } + } + } + hir::ItemKind::GlobalAsm(..) => { + debug!( + "RootCollector: ItemKind::GlobalAsm({})", + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id()) + ); + self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id))); + } + hir::ItemKind::Static(..) => { + let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); + debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id)); + self.output.push(dummy_spanned(MonoItem::Static(def_id))); + } + hir::ItemKind::Const(..) => { + // const items only generate mono items if they are + // actually used somewhere. Just declaring them is insufficient. + + // but even just declaring them must collect the items they refer to + let def_id = self.tcx.hir().local_def_id(item.hir_id); + + if let Ok(val) = self.tcx.const_eval_poly(def_id.to_def_id()) { + collect_const_value(self.tcx, val, &mut self.output); + } + } + hir::ItemKind::Fn(..) => { + let def_id = self.tcx.hir().local_def_id(item.hir_id); + self.push_if_root(def_id); + } + } + } + + fn visit_trait_item(&mut self, _: &'v hir::TraitItem<'v>) { + // Even if there's a default body with no explicit generics, + // it's still generic over some `Self: Trait`, so not a root. + } + + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { + if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind { + let def_id = self.tcx.hir().local_def_id(ii.hir_id); + self.push_if_root(def_id); + } + } + + fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} +} + +impl RootCollector<'_, 'v> { + fn is_root(&self, def_id: LocalDefId) -> bool { + !item_requires_monomorphization(self.tcx, def_id) + && match self.mode { + MonoItemCollectionMode::Eager => true, + MonoItemCollectionMode::Lazy => { + self.entry_fn.map(|(id, _)| id) == Some(def_id) + || self.tcx.is_reachable_non_generic(def_id) + || self + .tcx + .codegen_fn_attrs(def_id) + .flags + .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + } + } + } + + /// If `def_id` represents a root, pushes it onto the list of + /// outputs. (Note that all roots must be monomorphic.) + fn push_if_root(&mut self, def_id: LocalDefId) { + if self.is_root(def_id) { + debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); + + let instance = Instance::mono(self.tcx, def_id.to_def_id()); + self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); + } + } + + /// As a special case, when/if we encounter the + /// `main()` function, we also have to generate a + /// monomorphized copy of the start lang item based on + /// the return type of `main`. This is not needed when + /// the user writes their own `start` manually. + fn push_extra_entry_roots(&mut self) { + let main_def_id = match self.entry_fn { + Some((def_id, EntryFnType::Main)) => def_id, + _ => return, + }; + + let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { + Ok(s) => s, + Err(err) => self.tcx.sess.fatal(&err), + }; + let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); + + // Given that `main()` has no arguments, + // then its return type cannot have + // late-bound regions, since late-bound + // regions must appear in the argument + // listing. + let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + + let start_instance = Instance::resolve( + self.tcx, + ty::ParamEnv::reveal_all(), + start_def_id, + self.tcx.intern_substs(&[main_ret_ty.into()]), + ) + .unwrap() + .unwrap(); + + self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); + } +} + +fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let generics = tcx.generics_of(def_id); + generics.requires_monomorphization(tcx) +} + +fn create_mono_items_for_default_impls<'tcx>( + tcx: TyCtxt<'tcx>, + item: &'tcx hir::Item<'tcx>, + output: &mut Vec>>, +) { + match item.kind { + hir::ItemKind::Impl(ref impl_) => { + for param in impl_.generics.params { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => {} + hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { + return; + } + } + } + + let impl_def_id = tcx.hir().local_def_id(item.hir_id); + + debug!( + "create_mono_items_for_default_impls(item={})", + tcx.def_path_str(impl_def_id.to_def_id()) + ); + + if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { + let param_env = ty::ParamEnv::reveal_all(); + let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); + let overridden_methods: FxHashSet<_> = + impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); + for method in tcx.provided_trait_methods(trait_ref.def_id) { + if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { + continue; + } + + if tcx.generics_of(method.def_id).own_requires_monomorphization() { + continue; + } + + let substs = + InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + trait_ref.substs[param.index as usize] + } + }); + let instance = ty::Instance::resolve(tcx, param_env, method.def_id, substs) + .unwrap() + .unwrap(); + + let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); + if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) + { + output.push(mono_item); + } + } + } + } + _ => bug!(), + } +} + +/// Scans the miri alloc in order to find function calls, closures, and drop-glue. +fn collect_miri<'tcx>( + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, + output: &mut Vec>>, +) { + match tcx.global_alloc(alloc_id) { + GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(tcx, def_id); + if should_codegen_locally(tcx, &instance) { + trace!("collecting static {:?}", def_id); + output.push(dummy_spanned(MonoItem::Static(def_id))); + } + } + GlobalAlloc::Memory(alloc) => { + trace!("collecting {:?} with {:#?}", alloc_id, alloc); + for &((), inner) in alloc.relocations().values() { + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_miri(tcx, inner, output); + }); + } + } + GlobalAlloc::Function(fn_instance) => { + if should_codegen_locally(tcx, &fn_instance) { + trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); + output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); + } + } + } +} + +/// Scans the MIR in order to find function calls, closures, and drop-glue. +fn collect_neighbours<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + output: &mut Vec>>, +) { + debug!("collect_neighbours: {:?}", instance.def_id()); + let body = tcx.instance_mir(instance.def); + + MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); +} + +fn collect_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + value: ConstValue<'tcx>, + output: &mut Vec>>, +) { + match value { + ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), + ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, output); + } + } + _ => {} + } +} diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 0ea3a18ca34fa..710803fead242 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -147,7 +147,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // and hopefully soon change this to an error. // // See #74595 for more details about this. - let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); + let concrete = + infcx.const_eval_resolve(param_env.with_reveal_selection(), uv.expand(), Some(span)); if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) { match infcx.tcx.def_kind(uv.def.did) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index b5c5724f56edc..19ce6c3a44085 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -795,11 +795,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } - SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { bug!( "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`" ) + ConstEvalFailure(ErrorHandled::Silent) => { + tcx.sess.struct_span_err(span, "failed to evaluate the given constant") } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { if !self.tcx.features().generic_const_exprs { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 42e3f0db15e53..cb5798b188c64 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -625,6 +625,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { "ConstEquate: const_eval_resolve returned an unexpected error" ) } + (Err(ErrorHandled::Silent), _) | (_, Err(ErrorHandled::Silent)) => { + ProcessResult::Error(CodeSelectionError(ConstEvalFailure( + ErrorHandled::Silent, + ))) + } (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { ProcessResult::Unchanged diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 23f615a96185d..96d5a85f8dbe2 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -394,8 +394,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { - Reveal::UserFacing => ty.super_fold_with(self), - + Reveal::UserFacing | Reveal::Selection => ty.super_fold_with(self), Reveal::All => { let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 26bacf787e2eb..d91a7c00acfe9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -210,8 +210,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { - Reveal::UserFacing => ty.try_super_fold_with(self), - + Reveal::UserFacing | Reveal::Selection => ty.try_super_fold_with(self), Reveal::All => { let substs = substs.try_super_fold_with(self)?; let recursion_limit = self.tcx().recursion_limit(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index fa88c8ee37015..b7c116fa89b97 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -654,7 +654,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ty::ConstKind::Unevaluated(unevaluated) = c.val { self.infcx .const_eval_resolve( - obligation.param_env, + obligation.param_env.with_reveal_selection(), unevaluated, Some(obligation.cause.span), ) @@ -675,8 +675,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => Ok(EvaluatedToErr), } } - (Err(ErrorHandled::Reported(ErrorReported)), _) - | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent), _) + | (_, Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent)) => { + Ok(EvaluatedToErr) + } (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { span_bug!( obligation.cause.span(self.tcx()), @@ -2657,7 +2659,11 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { } fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } + if let Some(head) = self.head { + head.depth + } else { + 0 + } } } diff --git a/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs b/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs new file mode 100644 index 0000000000000..c292361e1cdfd --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs @@ -0,0 +1,43 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Array; + +trait Matrix { + fn do_it(&self) -> usize; +} + +impl Matrix for Array<0> { + fn do_it(&self) -> usize { + 0 + } +} + +impl Matrix for Array<1> { + fn do_it(&self) -> usize { + 1 + } +} + +impl Matrix for Array<2> { + fn do_it(&self) -> usize { + 2 + } +} + +impl Matrix for Array +where + [u8; N - 3]: Sized, +{ + fn do_it(&self) -> usize { + N + 1 + } +} + +fn main() { + assert_eq!(Array::<0>.do_it(), 0); + assert_eq!(Array::<1>.do_it(), 1); + assert_eq!(Array::<2>.do_it(), 2); + assert_eq!(Array::<3>.do_it(), 4); +} From 10e5f1a2dbb664895eee21564eb651852d9ec32d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 24 Jan 2021 15:48:37 +0100 Subject: [PATCH 02/12] update tests --- .../defaults-cyclic-fail.stderr | 10 + ...9-assoc-const-static-recursion-impl.stderr | 10 + ...onst-static-recursion-trait-default.stderr | 10 + ...-assoc-const-static-recursion-trait.stderr | 10 + .../from-sig-fail.rs | 12 + .../from-sig-fail.stderr | 20 ++ .../simple_fail.full.stderr | 17 ++ .../const_evaluatable_checked/simple_fail.rs | 17 ++ .../const-eval/const-eval-overflow-3.rs | 1 + .../const-eval/const-eval-overflow-3.stderr | 8 +- ...nst-pointer-values-in-various-types.stderr | 237 ++++++++++++++++++ .../ui/consts/const-eval/infinite_loop.rs | 2 +- .../ui/consts/const-eval/infinite_loop.stderr | 15 +- .../ui/consts/const-eval/issue-49296.stderr | 8 + src/test/ui/consts/const-eval/issue-52475.rs | 2 +- .../ui/consts/const-eval/issue-52475.stderr | 15 +- src/test/ui/consts/const-size_of-cycle.stderr | 5 + src/test/ui/consts/issue-36163.stderr | 10 + src/test/ui/consts/issue-44415.stderr | 5 + src/test/ui/consts/issue-52432.rs | 10 + src/test/ui/consts/issue-52432.stderr | 28 +++ .../recursive-zst-static.default.stderr | 5 + .../recursive-zst-static.unleash.stderr | 5 + .../write-to-static-mut-in-static.stderr | 5 + src/test/ui/issues/issue-17252.stderr | 5 + src/test/ui/issues/issue-23302-1.stderr | 5 + src/test/ui/issues/issue-23302-2.stderr | 5 + src/test/ui/issues/issue-23302-3.stderr | 10 + src/test/ui/mir/issue-80742.rs | 35 +++ src/test/ui/mir/issue-80742.stderr | 54 ++++ .../recursive-static-definition.stderr | 5 + .../self-in-enum-definition.stderr | 5 + 32 files changed, 586 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs create mode 100644 src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr create mode 100644 src/test/ui/consts/issue-52432.rs create mode 100644 src/test/ui/consts/issue-52432.stderr create mode 100644 src/test/ui/mir/issue-80742.rs create mode 100644 src/test/ui/mir/issue-80742.stderr diff --git a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr index 3fb4ab72fe6d6..9ae202bf5368b 100644 --- a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr @@ -10,6 +10,11 @@ note: ...which requires simplifying constant for the type system `Tr::A`... | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Tr::A`... + --> $DIR/defaults-cyclic-fail.rs:6:5 + | +LL | const A: u8 = Self::B; + | ^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | @@ -26,6 +31,11 @@ note: ...which requires simplifying constant for the type system `Tr::B`... | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Tr::B`... + --> $DIR/defaults-cyclic-fail.rs:8:5 + | +LL | const B: u8 = Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 61b16cb9d5811..aaa9b63c8f5fd 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`. | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 + | +LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 + | +LL | const BAR: u32 = IMPL_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index 494dc0c0ed447..a65832b096fbc 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `DEFAULT_REF_BA | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 + | +LL | const DEFAULT_REF_BAR: u32 = ::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `FooDefault::BA | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 + | +LL | const BAR: u32 = DEFAULT_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 4ff253bffcb32..1fea9c0dabaf4 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR` | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 + | +LL | const TRAIT_REF_BAR: u32 = ::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 + | +LL | const BAR: u32 = TRAIT_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs new file mode 100644 index 0000000000000..87fdc63f6393e --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -0,0 +1,12 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] { + todo!() +} + +fn main() { + test::<0>(); + //~^ ERROR failed to evaluate the given constant + //~| ERROR failed to evaluate the given constant +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr new file mode 100644 index 0000000000000..e94545235d115 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -0,0 +1,20 @@ +error: failed to evaluate the given constant + --> $DIR/from-sig-fail.rs:9:5 + | +LL | fn test() -> [u8; N - 1] { + | ----- required by this bound in `test` +... +LL | test::<0>(); + | ^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/from-sig-fail.rs:9:5 + | +LL | fn test() -> [u8; N - 1] { + | ----- required by this bound in `test` +... +LL | test::<0>(); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr new file mode 100644 index 0000000000000..c38c58897f305 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -0,0 +1,17 @@ +error: failed to evaluate the given constant + --> $DIR/simple_fail.rs:14:5 + | +LL | fn test() -> Arr where Arr: Sized { + | ------ required by this bound in `test` +... +LL | test::<0>(); + | ^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/simple_fail.rs:14:5 + | +LL | test::<0>(); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs new file mode 100644 index 0000000000000..f673b918fbcdd --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -0,0 +1,17 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters may not be used in const operations + +fn test() -> Arr where Arr: Sized { + todo!() +} + +fn main() { + test::<0>(); + //[full]~^ ERROR failed to evaluate the given constant + //[full]~| ERROR failed to evaluate the given constant +} diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs index bcc966dc9621c..89e0011b7d10c 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.rs @@ -17,6 +17,7 @@ const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1) as usize]; //~^ ERROR evaluation of constant value failed +//~| ERROR failed to evaluate the given constant fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr index 73f421b5b1465..2d1cd5459125b 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -4,6 +4,12 @@ error[E0080]: evaluation of constant value failed LL | = [0; (i8::MAX + 1) as usize]; | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/const-eval-overflow-3.rs:18:11 + | +LL | = [0; (i8::MAX + 1) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr new file mode 100644 index 0000000000000..72e54f8ec21da --- /dev/null +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -0,0 +1,237 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:25:5 + | +LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc2, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:28:43 + | +LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:31:45 + | +LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:34:45 + | +LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:37:5 + | +LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc24, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:40:5 + | +LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:43:43 + | +LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:46:45 + | +LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:49:45 + | +LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:52:5 + | +LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc50, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:55:5 + | +LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:58:45 + | +LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; + | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:61:5 + | +LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc64, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:64:47 + | +LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; + | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:67:47 + | +LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; + | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:70:39 + | +LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:73:41 + | +LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:76:41 + | +LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:79:5 + | +LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc98, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:82:43 + | +LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:85:39 + | +LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; + | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:88:41 + | +LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:91:41 + | +LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:94:5 + | +LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc125, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:97:43 + | +LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:100:41 + | +LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; + | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const-pointer-values-in-various-types.rs:103:5 + | +LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc140, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:106:43 + | +LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:109:43 + | +LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; + | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | unable to turn pointer into raw bytes + +error: aborting due to 29 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/infinite_loop.rs b/src/test/ui/consts/const-eval/infinite_loop.rs index 14a573ccf5ac6..3c40c337cd005 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.rs +++ b/src/test/ui/consts/const-eval/infinite_loop.rs @@ -1,7 +1,7 @@ fn main() { // Tests the Collatz conjecture with an incorrect base case (0 instead of 1). // The value of `n` will loop indefinitely (4 - 2 - 1 - 4). - let _ = [(); { + let _ = [(); { //~ ERROR failed to evaluate the given constant let mut n = 113383; // #20 in https://oeis.org/A006884 while n != 0 { n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index 3b5a0f22f28be..b30a53619b574 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -1,9 +1,22 @@ +error: failed to evaluate the given constant + --> $DIR/infinite_loop.rs:4:18 + | +LL | let _ = [(); { + | __________________^ +LL | | let mut n = 113383; // #20 in https://oeis.org/A006884 +LL | | while n != 0 { +LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; +... | +LL | | n +LL | | }]; + | |_____^ + error[E0080]: evaluation of constant value failed --> $DIR/infinite_loop.rs:7:20 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; | ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index bc3074b10bee6..5fc869d4ce137 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -2,7 +2,15 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-49296.rs:11:16 | LL | const X: u64 = *wat(42); +<<<<<<< HEAD | ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed +======= + | ---------------^^^^^^^^- + | | + | pointer to alloc4 was dereferenced after this allocation got freed + | + = note: `#[deny(const_err)]` on by default +>>>>>>> 9ee0d801b76 (update tests) error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs index ce65407bbab0b..6b8b42d417b35 100644 --- a/src/test/ui/consts/const-eval/issue-52475.rs +++ b/src/test/ui/consts/const-eval/issue-52475.rs @@ -1,5 +1,5 @@ fn main() { - let _ = [(); { + let _ = [(); { //~ ERROR failed to evaluate the given constant let mut x = &0; let mut n = 0; while n < 5 { diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index 8536ff02c6dae..5679f51c9ea54 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -1,9 +1,22 @@ +error: failed to evaluate the given constant + --> $DIR/issue-52475.rs:2:18 + | +LL | let _ = [(); { + | __________________^ +LL | | let mut x = &0; +LL | | let mut n = 0; +LL | | while n < 5 { +... | +LL | | 0 +LL | | }]; + | |_____^ + error[E0080]: evaluation of constant value failed --> $DIR/issue-52475.rs:6:17 | LL | n = (n + 1) % 5; | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 1067eb003f7c7..0b1b6f0caf192 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `Foo::bytes::{c | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... + --> $DIR/const-size_of-cycle.rs:4:17 + | +LL | bytes: [u8; std::mem::size_of::()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | diff --git a/src/test/ui/consts/issue-36163.stderr b/src/test/ui/consts/issue-36163.stderr index 113f86cf0f99f..96ab7033e2501 100644 --- a/src/test/ui/consts/issue-36163.stderr +++ b/src/test/ui/consts/issue-36163.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `Foo::B::{const | LL | B = A, | ^ +note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... + --> $DIR/issue-36163.rs:4:9 + | +LL | B = A, + | ^ note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `A`... + --> $DIR/issue-36163.rs:1:1 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/consts/issue-44415.stderr b/src/test/ui/consts/issue-44415.stderr index 9e3db5ce9a402..6a8e09cfcb971 100644 --- a/src/test/ui/consts/issue-44415.stderr +++ b/src/test/ui/consts/issue-44415.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `Foo::bytes::{c | LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^ +note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::() }], + | ^^^^^^ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/issue-44415.rs:6:17 | diff --git a/src/test/ui/consts/issue-52432.rs b/src/test/ui/consts/issue-52432.rs new file mode 100644 index 0000000000000..6be782f95ad37 --- /dev/null +++ b/src/test/ui/consts/issue-52432.rs @@ -0,0 +1,10 @@ +#![feature(const_raw_ptr_to_usize_cast)] + +fn main() { + [(); &(static |x| {}) as *const _ as usize]; + //~^ ERROR: closures cannot be static + //~| ERROR: type annotations needed + [(); &(static || {}) as *const _ as usize]; + //~^ ERROR: closures cannot be static + //~| ERROR: failed to evaluate the given constant +} diff --git a/src/test/ui/consts/issue-52432.stderr b/src/test/ui/consts/issue-52432.stderr new file mode 100644 index 0000000000000..2710a72f3a105 --- /dev/null +++ b/src/test/ui/consts/issue-52432.stderr @@ -0,0 +1,28 @@ +error[E0697]: closures cannot be static + --> $DIR/issue-52432.rs:4:12 + | +LL | [(); &(static |x| {}) as *const _ as usize]; + | ^^^^^^^^^^ + +error[E0697]: closures cannot be static + --> $DIR/issue-52432.rs:7:12 + | +LL | [(); &(static || {}) as *const _ as usize]; + | ^^^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/issue-52432.rs:4:20 + | +LL | [(); &(static |x| {}) as *const _ as usize]; + | ^ consider giving this closure parameter a type + +error: failed to evaluate the given constant + --> $DIR/issue-52432.rs:7:10 + | +LL | [(); &(static || {}) as *const _ as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0697. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 03f8f5c5a0e5d..8ddc9fe4f5ff9 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -7,6 +7,11 @@ LL | static FOO: () = FOO; note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/recursive-zst-static.rs:10:1 + | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 03f8f5c5a0e5d..8ddc9fe4f5ff9 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -7,6 +7,11 @@ LL | static FOO: () = FOO; note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/recursive-zst-static.rs:10:1 + | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle diff --git a/src/test/ui/consts/write-to-static-mut-in-static.stderr b/src/test/ui/consts/write-to-static-mut-in-static.stderr index 789919bd1668d..6493ddabc4ea0 100644 --- a/src/test/ui/consts/write-to-static-mut-in-static.stderr +++ b/src/test/ui/consts/write-to-static-mut-in-static.stderr @@ -13,6 +13,11 @@ LL | pub static mut C: u32 = unsafe { C = 1; 0 }; note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:1 | +LL | pub static mut C: u32 = unsafe { C = 1; 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `C`... + --> $DIR/write-to-static-mut-in-static.rs:5:1 + | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `C`, completing the cycle diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 1148577016ab4..2372bbb5ca3d7 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -10,6 +10,11 @@ note: ...which requires simplifying constant for the type system `FOO`... | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `FOO`... + --> $DIR/issue-17252.rs:1:1 + | +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `FOO`... --> $DIR/issue-17252.rs:1:1 | diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index d3a1993536a00..4b5a33057f50d 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `X::A::{constan | LL | A = X::A as isize, | ^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... + --> $DIR/issue-23302-1.rs:4:9 + | +LL | A = X::A as isize, + | ^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index d3b78ea1af5f5..e2a0d977cc655 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `Y::A::{constan | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... + --> $DIR/issue-23302-2.rs:4:9 + | +LL | A = Y::B as isize, + | ^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index 5233b832ecc79..66ba9c2f68e7c 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `A`... | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `A`... + --> $DIR/issue-23302-3.rs:1:1 + | +LL | const A: i32 = B; + | ^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-23302-3.rs:1:1 | @@ -25,6 +30,11 @@ note: ...which requires simplifying constant for the type system `B`... | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `B`... + --> $DIR/issue-23302-3.rs:3:1 + | +LL | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | diff --git a/src/test/ui/mir/issue-80742.rs b/src/test/ui/mir/issue-80742.rs new file mode 100644 index 0000000000000..d82f73fc2a189 --- /dev/null +++ b/src/test/ui/mir/issue-80742.rs @@ -0,0 +1,35 @@ +// check-fail + +// This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place + +#![allow(incomplete_features)] +#![feature(const_evaluatable_checked)] +#![feature(const_generics)] + +use std::fmt::Debug; +use std::marker::PhantomData; +use std::mem::size_of; + +struct Inline +where + [u8; size_of::() + 1]: , +{ + _phantom: PhantomData, + buf: [u8; size_of::() + 1], +} + +impl Inline +where + [u8; size_of::() + 1]: , +{ + pub fn new(val: T) -> Inline { + todo!() + } +} + +fn main() { + let dst = Inline::::new(0); + //~^ ERROR failed to evaluate the given constant + //~| ERROR the size for values of type + //~| ERROR no function or associated item +} diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr new file mode 100644 index 0000000000000..61992f3b9c407 --- /dev/null +++ b/src/test/ui/mir/issue-80742.stderr @@ -0,0 +1,54 @@ +error[E0599]: no function or associated item named `new` found for struct `Inline` in the current scope + --> $DIR/issue-80742.rs:31:36 + | +LL | / struct Inline +LL | | where +LL | | [u8; size_of::() + 1]: , +LL | | { +LL | | _phantom: PhantomData, +LL | | buf: [u8; size_of::() + 1], +LL | | } + | |_- function or associated item `new` not found for this +... +LL | let dst = Inline::::new(0); + | ^^^ function or associated item not found in `Inline` + | + ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL + | +LL | pub trait Debug { + | --------------- doesn't satisfy `dyn Debug: Sized` + | + = note: the method `new` exists but the following trait bounds were not satisfied: + `dyn Debug: Sized` + +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/issue-80742.rs:31:15 + | +LL | struct Inline + | - required by this bound in `Inline` +... +LL | let dst = Inline::::new(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Debug` +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Inline + | ^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/issue-80742.rs:31:15 + | +LL | struct Inline + | ------ required by a bound in this +LL | where +LL | [u8; size_of::() + 1]: , + | ------------------ required by this bound in `Inline` +... +LL | let dst = Inline::::new(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index ee73b026a0b75..42bfa76000b1e 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -7,6 +7,11 @@ LL | pub static FOO: u32 = FOO; note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:1 | +LL | pub static FOO: u32 = FOO; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/recursive-static-definition.rs:1:1 + | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index 277f4e8424030..211086e5ec528 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -9,6 +9,11 @@ note: ...which requires simplifying constant for the type system `Alpha::V3::{co | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ +note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... + --> $DIR/self-in-enum-definition.rs:5:10 + | +LL | V3 = Self::V1 {} as u8 + 2, + | ^^^^^^^^ note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | From bbd8ef9de7794a1a9ca7aee2afc5d752d656df43 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sun, 24 Jan 2021 16:22:07 +0100 Subject: [PATCH 03/12] typo Co-authored-by: bjorn3 --- compiler/rustc_codegen_cranelift/src/constant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 66679f6fe4696..8b19cbf74a054 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -67,7 +67,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { ErrorHandled::Silent => { span_bug!( constant.span, - "codgen encountered silent error", + "codegen encountered silent error", ); } } From c4c55094765dd5dcb80084ced33d501d046c519e Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:13:47 +0100 Subject: [PATCH 04/12] rebase, introduce Silent error and move ConstEvalErr to middle --- .../rustc_const_eval/src/const_eval/error.rs | 138 +- .../rustc_middle/src/mir/interpret/error.rs | 179 ++- compiler/rustc_middle/src/ty/adt.rs | 1 + .../rustc_mir/src/const_eval/eval_queries.rs | 453 ------ .../rustc_mir/src/monomorphize/collector.rs | 1265 ----------------- .../rustc_mir_transform/src/const_prop.rs | 11 +- compiler/rustc_monomorphize/src/collector.rs | 8 + 7 files changed, 192 insertions(+), 1863 deletions(-) delete mode 100644 compiler/rustc_mir/src/const_eval/eval_queries.rs delete mode 100644 compiler/rustc_mir/src/monomorphize/collector.rs diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 87298023980ed..4b04d27b21cba 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,16 +1,13 @@ use std::error::Error; use std::fmt; -use rustc_errors::{DiagnosticBuilder, ErrorReported}; -use rustc_hir as hir; +use rustc_middle::mir::interpret::ConstEvalErr; use rustc_middle::mir::AssertKind; -use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; +use rustc_middle::ty::ConstInt; use rustc_span::{Span, Symbol}; use super::InterpCx; -use crate::interpret::{ - struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, -}; +use crate::interpret::{InterpErrorInfo, Machine, MachineStopType}; /// The CTFE machine has some custom error kinds. #[derive(Clone, Debug)] @@ -63,13 +60,11 @@ impl Error for ConstEvalErrKind {} /// When const-evaluation errors, this type is constructed with the resulting information, /// and then used to emit the error as a lint or hard error. #[derive(Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub error: InterpError<'tcx>, - pub stacktrace: Vec>, +pub struct ConstEvalError<'tcx> { + inner: ConstEvalErr<'tcx>, } -impl<'tcx> ConstEvalErr<'tcx> { +impl<'tcx> ConstEvalError<'tcx> { /// Turn an interpreter error into something to report to the user. /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. /// Should be called only if the error is actually going to to be reported! @@ -77,131 +72,22 @@ impl<'tcx> ConstEvalErr<'tcx> { ecx: &InterpCx<'mir, 'tcx, M>, error: InterpErrorInfo<'tcx>, span: Option, - ) -> ConstEvalErr<'tcx> + ) -> ConstEvalError<'tcx> where 'tcx: 'mir, { error.print_backtrace(); let stacktrace = ecx.generate_stacktrace(); - ConstEvalErr { + let inner = ConstEvalErr { error: error.into_kind(), stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()), - } - } - - pub fn struct_error( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - ) -> ErrorHandled { - self.struct_generic(tcx, message, emit, None) - } - - pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { - self.struct_error(tcx, message, |mut e| e.emit()) - } - - pub fn report_as_lint( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - lint_root: hir::HirId, - span: Option, - ) -> ErrorHandled { - self.struct_generic( - tcx, - message, - |mut lint: DiagnosticBuilder<'_>| { - // Apply the span. - if let Some(span) = span { - let primary_spans = lint.span.primary_spans().to_vec(); - // point at the actual error as the primary span - lint.replace_span_with(span); - // point to the `const` statement as a secondary span - // they don't have any label - for sp in primary_spans { - if sp != span { - lint.span_label(sp, ""); - } - } - } - lint.emit(); - }, - Some(lint_root), - ) - } - - /// Create a diagnostic for this const eval error. - /// - /// Sets the message passed in via `message` and adds span labels with detailed error - /// information before handing control back to `emit` to do any final processing. - /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` - /// function to dispose of the diagnostic properly. - /// - /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. - /// (Except that for some errors, we ignore all that -- see `must_error` below.) - fn struct_generic( - &self, - tcx: TyCtxtAt<'tcx>, - message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), - lint_root: Option, - ) -> ErrorHandled { - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option| { - trace!("reporting const eval failure at {:?}", self.span); - if let Some(span_msg) = span_msg { - err.span_label(self.span, span_msg); - } - // Add spans for the stacktrace. Don't print a single-line backtrace though. - if self.stacktrace.len() > 1 { - for frame_info in &self.stacktrace { - err.span_label(frame_info.span, frame_info.to_string()); - } - } - // Let the caller finish the job. - emit(err) }; - // Special handling for certain errors - match &self.error { - // Don't emit a new diagnostic for these errors - err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - return ErrorHandled::TooGeneric; - } - err_inval!(AlreadyReported(error_reported)) => { - return ErrorHandled::Reported(*error_reported); - } - err_inval!(Layout(LayoutError::SizeOverflow(_))) => { - // We must *always* hard error on these, even if the caller wants just a lint. - // The `message` makes little sense here, this is a more serious error than the - // caller thinks anyway. - // See . - finish(struct_error(tcx, &self.error.to_string()), None); - return ErrorHandled::Reported(ErrorReported); - } - _ => {} - }; - - let err_msg = self.error.to_string(); + ConstEvalError { inner } + } - // Regular case - emit a lint. - if let Some(lint_root) = lint_root { - // Report as lint. - let hir_id = - self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root); - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::CONST_ERR, - hir_id, - tcx.span, - |lint| finish(lint.build(message), Some(err_msg)), - ); - ErrorHandled::Linted - } else { - // Report as hard error. - finish(struct_error(tcx, message), Some(err_msg)); - ErrorHandled::Reported(ErrorReported) - } + pub fn into_inner(self) -> ConstEvalErr<'tcx> { + self.inner } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 714e7ba8ca9df..fdf16b337fb97 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,18 +1,20 @@ -use super::{AllocId, ConstAlloc, Pointer, Scalar}; +use super::{AllocId, ConstAlloc, ConstValue, FrameInfo, GlobalId, Pointer, Scalar}; -use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; +use crate::ty::layout::LayoutError; +use crate::ty::{query::TyCtxtAt, tls, FnSig, Ty}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::def_id::DefId; +use rustc_span::Span; use rustc_target::abi::{call, Align, Size}; use std::{any::Any, backtrace::Backtrace, fmt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum ErrorHandled { +pub enum ErrorHandled<'tcx> { /// Already reported an error for this evaluation, and the compilation is /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. Reported(ErrorReported), @@ -20,24 +22,24 @@ pub enum ErrorHandled { Linted, /// Encountered an error without emitting anything. Only returned /// with `Reveal::Selection`. - Silent, + Silent(GlobalId<'tcx>), /// Don't emit an error, the evaluation failed because the MIR was generic /// and the substs didn't fully monomorphize it. TooGeneric, } -impl From for ErrorHandled { - fn from(err: ErrorReported) -> ErrorHandled { +impl<'tcx> From for ErrorHandled<'tcx> { + fn from(err: ErrorReported) -> ErrorHandled<'tcx> { ErrorHandled::Reported(err) } } TrivialTypeFoldableAndLiftImpls! { - ErrorHandled, + ErrorHandled<'tcx>, } -pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; -pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; +pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled<'tcx>>; +pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled<'tcx>>; pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) @@ -88,10 +90,12 @@ fn print_backtrace(backtrace: &Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{}", backtrace); } -impl From for InterpErrorInfo<'_> { - fn from(err: ErrorHandled) -> Self { +impl<'tcx> From> for InterpErrorInfo<'tcx> { + fn from(err: ErrorHandled<'tcx>) -> Self { match err { - ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted | ErrorHandled::Silent => { + ErrorHandled::Reported(ErrorReported) + | ErrorHandled::Linted + | ErrorHandled::Silent(_) => { err_inval!(ReferencedConstant) } ErrorHandled::TooGeneric => err_inval!(TooGeneric), @@ -143,7 +147,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Abort in case errors are already reported. AlreadyReported(ErrorReported), /// An error occurred during layout computation. - Layout(layout::LayoutError<'tcx>), + Layout(LayoutError<'tcx>), /// An error occurred during FnAbi computation: the passed --target lacks FFI support /// (which unfortunately typeck does not reject). /// Not using `FnAbiError` as that contains a nested `LayoutError`. @@ -563,3 +567,150 @@ impl InterpError<'_> { } } } + +#[derive(Debug, Copy, Clone)] +pub enum ConstErrorEmitted<'tcx> { + Emitted(ErrorHandled<'tcx>), + NotEmitted(ErrorHandled<'tcx>), +} + +impl<'tcx> ConstErrorEmitted<'tcx> { + pub fn get_error(self) -> ErrorHandled<'tcx> { + match self { + ConstErrorEmitted::Emitted(e) => e, + ConstErrorEmitted::NotEmitted(e) => e, + } + } +} + +/// When const-evaluation errors, this type is constructed with the resulting information, +/// and then used to emit the error as a lint or hard error. +#[derive(Debug)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub error: InterpError<'tcx>, + pub stacktrace: Vec>, +} + +impl<'tcx> ConstEvalErr<'tcx> { + pub fn struct_error( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + emit: impl FnOnce(DiagnosticBuilder<'_>), + ) -> ConstErrorEmitted<'tcx> { + self.struct_generic(tcx, message, emit, None) + } + + pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ConstErrorEmitted<'tcx> { + self.struct_error(tcx, message, |mut e| e.emit()) + } + + pub fn report_as_lint( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + lint_root: hir::HirId, + span: Option, + ) -> ConstErrorEmitted<'tcx> { + self.struct_generic( + tcx, + message, + |mut lint: DiagnosticBuilder<'_>| { + // Apply the span. + if let Some(span) = span { + let primary_spans = lint.span.primary_spans().to_vec(); + // point at the actual error as the primary span + lint.replace_span_with(span); + // point to the `const` statement as a secondary span + // they don't have any label + for sp in primary_spans { + if sp != span { + lint.span_label(sp, ""); + } + } + } + lint.emit(); + }, + Some(lint_root), + ) + } + + /// Create a diagnostic for this const eval error. + /// + /// Sets the message passed in via `message` and adds span labels with detailed error + /// information before handing control back to `emit` to do any final processing. + /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` + /// function to dispose of the diagnostic properly. + /// + /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. + /// (Except that for some errors, we ignore all that -- see `must_error` below.) + #[instrument(skip(tcx, emit, lint_root), level = "debug")] + fn struct_generic( + &self, + tcx: TyCtxtAt<'tcx>, + message: &str, + emit: impl FnOnce(DiagnosticBuilder<'_>), + lint_root: Option, + ) -> ConstErrorEmitted<'tcx> { + debug!("self.error: {:?}", self.error); + + let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option| { + trace!("reporting const eval failure at {:?}", self.span); + if let Some(span_msg) = span_msg { + err.span_label(self.span, span_msg); + } + // Add spans for the stacktrace. Don't print a single-line backtrace though. + if self.stacktrace.len() > 1 { + for frame_info in &self.stacktrace { + err.span_label(frame_info.span, frame_info.to_string()); + } + } + // Let the caller finish the job. + emit(err) + }; + + // Special handling for certain errors + match &self.error { + // Don't emit a new diagnostic for these errors + err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { + debug!("returning TooGeneric"); + return ConstErrorEmitted::NotEmitted(ErrorHandled::TooGeneric); + } + err_inval!(AlreadyReported(error_reported)) => { + debug!("Already Reported"); + return ConstErrorEmitted::NotEmitted(ErrorHandled::Reported(*error_reported)); + } + err_inval!(Layout(LayoutError::SizeOverflow(_))) => { + // We must *always* hard error on these, even if the caller wants just a lint. + // The `message` makes little sense here, this is a more serious error than the + // caller thinks anyway. + // See . + finish(struct_error(tcx, &self.error.to_string()), None); + return ConstErrorEmitted::Emitted(ErrorHandled::Reported(ErrorReported)); + } + _ => {} + }; + + let err_msg = self.error.to_string(); + debug!(?err_msg); + + // Regular case - emit a lint. + if let Some(lint_root) = lint_root { + // Report as lint. + let hir_id = + self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root); + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::CONST_ERR, + hir_id, + tcx.span, + |lint| finish(lint.build(message), Some(err_msg)), + ); + ConstErrorEmitted::Emitted(ErrorHandled::Linted) + } else { + // Report as hard error. + finish(struct_error(tcx, message), Some(err_msg)); + ConstErrorEmitted::Emitted(ErrorHandled::Reported(ErrorReported)) + } + } +} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 5cde54c9328d1..0387ac66a0dd7 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -426,6 +426,7 @@ impl<'tcx> AdtDef { "enum discriminant evaluation failed" } ErrorHandled::TooGeneric => "enum discriminant depends on generics", + ErrorHandled::Silent(_) => return None, }; tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg); None diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs deleted file mode 100644 index 303ebc829dc9f..0000000000000 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ /dev/null @@ -1,453 +0,0 @@ -use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; -use crate::interpret::eval_nullary_intrinsic; -use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, - Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, - ScalarMaybeUninit, StackPopCleanup, -}; - -use rustc_errors::ErrorReported; -use rustc_hir::def::DefKind; -use rustc_middle::mir; -use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::traits::Reveal; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, subst::Subst, TyCtxt}; -use rustc_span::source_map::Span; -use rustc_target::abi::{Abi, LayoutOf}; -use std::convert::TryInto; - -pub fn note_on_undefined_behavior_error() -> &'static str { - "The rules on what exactly is undefined behavior aren't clear, \ - so this check might be overzealous. Please open an issue on the rustc \ - repository if you believe it should not be considered undefined behavior." -} - -// Returns a pointer to where the result lives -fn eval_body_using_ecx<'mir, 'tcx>( - ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, - cid: GlobalId<'tcx>, - body: &'mir mir::Body<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); - let tcx = *ecx.tcx; - assert!( - cid.promoted.is_some() - || matches!( - ecx.tcx.def_kind(cid.instance.def_id()), - DefKind::Const - | DefKind::Static - | DefKind::ConstParam - | DefKind::AnonConst - | DefKind::AssocConst - ), - "Unexpected DefKind: {:?}", - ecx.tcx.def_kind(cid.instance.def_id()) - ); - let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ret = ecx.allocate(layout, MemoryKind::Stack); - - let name = - with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - - ecx.push_stack_frame( - cid.instance, - body, - Some(ret.into()), - StackPopCleanup::None { cleanup: false }, - )?; - - // The main interpreter loop. - ecx.run()?; - - // Intern the result - let intern_kind = if cid.promoted.is_some() { - InternKind::Promoted - } else { - match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None => InternKind::Constant, - } - }; - intern_const_alloc_recursive(ecx, intern_kind, ret)?; - - debug!("eval_body_using_ecx done: {:?}", *ret); - Ok(ret) -} - -/// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. -/// -/// The function containing the `match` that is currently being analyzed may have generic bounds -/// that inform us about the generic bounds of the constant. E.g., using an associated constant -/// of a function's generic parameter will require knowledge about the bounds on the generic -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(super) fn mk_eval_cx<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - root_span: Span, - param_env: ty::ParamEnv<'tcx>, - can_access_statics: bool, -) -> CompileTimeEvalContext<'mir, 'tcx> { - debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx, - root_span, - param_env, - CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), - MemoryExtra { can_access_statics }, - ) -} - -/// This function converts an interpreter value into a constant that is meant for use in the -/// type system. -pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, 'tcx>, - op: OpTy<'tcx>, -) -> ConstValue<'tcx> { - // We do not have value optimizations for everything. - // Only scalars and slices, since they are very common. - // Note that further down we turn scalars of uninitialized bits back to `ByRef`. These can result - // from scalar unions that are initialized with one of their zero sized variants. We could - // instead allow `ConstValue::Scalar` to store `ScalarMaybeUninit`, but that would affect all - // the usual cases of extracting e.g. a `usize`, without there being a real use case for the - // `Undef` situation. - let try_as_immediate = match op.layout.abi { - Abi::Scalar(..) => true, - Abi::ScalarPair(..) => match op.layout.ty.kind() { - ty::Ref(_, inner, _) => match *inner.kind() { - ty::Slice(elem) => elem == ecx.tcx.types.u8, - ty::Str => true, - _ => false, - }, - _ => false, - }, - _ => false, - }; - let immediate = if try_as_immediate { - Err(ecx.read_immediate(op).expect("normalization works on validated constants")) - } else { - // It is guaranteed that any non-slice scalar pair is actually ByRef here. - // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we - // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or - // structs containing such. - op.try_as_mplace(ecx) - }; - - let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr { - Scalar::Ptr(ptr) => { - let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(); - ConstValue::ByRef { alloc, offset: ptr.offset } - } - Scalar::Int(int) => { - assert!(mplace.layout.is_zst()); - assert_eq!( - int.assert_bits(ecx.tcx.data_layout.pointer_size) - % u128::from(mplace.layout.align.abi.bytes()), - 0, - "this MPlaceTy must come from a validated constant, thus we can assume the \ - alignment is correct", - ); - ConstValue::Scalar(Scalar::ZST) - } - }; - match immediate { - Ok(mplace) => to_const_value(mplace), - // see comment on `let try_as_immediate` above - Err(imm) => match *imm { - Immediate::Scalar(x) => match x { - ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)), - }, - Immediate::ScalarPair(a, b) => { - let (data, start) = match a.check_init().unwrap() { - Scalar::Ptr(ptr) => { - (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes()) - } - Scalar::Int { .. } => ( - ecx.tcx - .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), - 0, - ), - }; - let len = b.to_machine_usize(ecx).unwrap(); - let start = start.try_into().unwrap(); - let len: usize = len.try_into().unwrap(); - ConstValue::Slice { data, start, end: start + len } - } - }, - } -} - -fn turn_into_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - constant: ConstAlloc<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ConstValue<'tcx> { - let cid = key.value; - let def_id = cid.instance.def.def_id(); - let is_static = tcx.is_static(def_id); - let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); - - let mplace = ecx.raw_const_to_mplace(constant).expect( - "can only fail if layout computation failed, \ - which should have given a good error before ever invoking this function", - ); - assert!( - !is_static || cid.promoted.is_some(), - "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead" - ); - // Turn this into a proper constant. - op_to_const(&ecx, mplace.into()) -} - -pub fn eval_to_const_value_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // see comment in const_eval_raw_provider for what we're doing here - match key.param_env.reveal() { - Reveal::Selection => {} - Reveal::UserFacing => { - let mut key = key; - key.param_env = key.param_env.with_reveal_selection(); - match tcx.eval_to_const_value_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::Silent) => {} - // deduplicate calls - other => return other, - } - } - Reveal::All => { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_const_value_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::Silent) => bug!("unexpected error for {:?}", key), - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } - } - - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. - // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.param_env); - let substs = match ty.kind() { - ty::FnDef(_, substs) => substs, - _ => bug!("intrinsic with type {:?}", ty), - }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { - let span = tcx.def_span(def_id); - let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; - error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") - }); - } - - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) -} - -pub fn eval_to_allocation_raw_provider<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - // Because the constant is computed twice (once per value of `Reveal`), we are at risk of - // reporting the same error twice here. To resolve this, we check whether we can evaluate the - // constant in the more restrictive `Reveal::UserFacing`, which most likely already was - // computed. For a large percentage of constants that will already have succeeded. Only - // associated constants of generic functions will fail due to not enough monomorphization - // information being available. - match key.param_env.reveal() { - Reveal::Selection => {} - Reveal::UserFacing => { - let mut key = key; - key.param_env = key.param_env.with_reveal_selection(); - match tcx.eval_to_allocation_raw(key) { - Err(ErrorHandled::Silent) => {} - // deduplicate calls - other => return other, - } - } - Reveal::All => { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_allocation_raw(key) { - Err(ErrorHandled::Silent) => bug!("unexpected error for {:?}", key), - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } - } - - if cfg!(debug_assertions) { - // Make sure we format the instance even if we do not print it. - // This serves as a regression test against an ICE on printing. - // The next two lines concatenated contain some discussion: - // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ - // subject/anon_const_instance_printing/near/135980032 - let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); - trace!("const eval: {:?} ({})", key, instance); - } - - let cid = key.value; - let def = cid.instance.def.with_opt_param(); - - if let Some(def) = def.as_local() { - if tcx.has_typeck_results(def.did) { - if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors { - return Err(ErrorHandled::Reported(error_reported)); - } - } - if !tcx.is_mir_available(def.did) { - tcx.sess.delay_span_bug( - tcx.def_span(def.did), - &format!("no MIR body is available for {:?}", def.did), - ); - return Err(ErrorHandled::Reported(ErrorReported {})); - } - if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { - return Err(ErrorHandled::Reported(error_reported)); - } - } - - let is_static = tcx.is_static(def.did); - - let mut ecx = InterpCx::new( - tcx, - tcx.def_span(def.did), - key.param_env, - CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), - MemoryExtra { can_access_statics: is_static }, - ); - - let res = ecx.load_mir(cid.instance.def, cid.promoted); - match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { - Err(error) => { - if key.param_env.reveal() == Reveal::Selection { - match error.kind { - err_inval!(Layout(LayoutError::Unknown(_))) - | err_inval!(TooGeneric) - | err_inval!(AlreadyReported(_)) => {} - _ => return Err(ErrorHandled::Silent), - } - } - - let err = ConstEvalErr::new(&ecx, error, None); - // errors in statics are always emitted as fatal errors - if is_static { - // Ensure that if the above error was either `TooGeneric` or `Reported` - // an error must be reported. - let v = err.report_as_error( - ecx.tcx.at(ecx.cur_span()), - "could not evaluate static initializer", - ); - - // If this is `Reveal:All`, then we need to make sure an error is reported but if - // this is `Reveal::UserFacing`, then it's expected that we could get a - // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either - // succeed or we'll report this error then. - if key.param_env.reveal() == Reveal::All { - tcx.sess.delay_span_bug( - err.span, - &format!("static eval failure did not emit an error: {:#?}", v), - ); - } - - Err(v) - } else if let Some(def) = def.as_local() { - // constant defined in this crate, we can figure out a lint level! - match tcx.def_kind(def.did.to_def_id()) { - // constants never produce a hard error at the definition site. Anything else is - // a backwards compatibility hazard (and will break old versions of winapi for - // sure) - // - // note that validation may still cause a hard error on this very same constant, - // because any code that existed before validation could not have failed - // validation thus preventing such a hard error from being a backwards - // compatibility hazard - DefKind::Const | DefKind::AssocConst => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - Err(err.report_as_lint( - tcx.at(tcx.def_span(def.did)), - "any use of this value will cause an error", - hir_id, - Some(err.span), - )) - } - // promoting runtime code is only allowed to error if it references broken - // constants any other kind of error will be reported to the user as a - // deny-by-default lint - _ => { - if let Some(p) = cid.promoted { - let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span; - if let err_inval!(ReferencedConstant) = err.error { - Err(err.report_as_error( - tcx.at(span), - "evaluation of constant expression failed", - )) - } else { - Err(err.report_as_lint( - tcx.at(span), - "reaching this expression at runtime will panic or abort", - tcx.hir().local_def_id_to_hir_id(def.did), - Some(err.span), - )) - } - // anything else (array lengths, enum initializers, constant patterns) are - // reported as hard errors - } else { - Err(err.report_as_error( - ecx.tcx.at(ecx.cur_span()), - "evaluation of constant value failed", - )) - } - } - } - } else { - // use of broken constant from other crate - Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")) - } - } - Ok(mplace) => { - // Since evaluation had no errors, valiate the resulting constant: - let validation = try { - let mut ref_tracking = RefTracking::new(mplace); - let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { - let mode = match tcx.static_mutability(cid.instance.def_id()) { - Some(_) if cid.promoted.is_some() => { - // Promoteds in statics are allowed to point to statics. - CtfeValidationMode::Const { inner, allow_static_ptrs: true } - } - Some(_) => CtfeValidationMode::Regular, // a `static` - None => CtfeValidationMode::Const { inner, allow_static_ptrs: false }, - }; - ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; - inner = true; - } - }; - if let Err(error) = validation { - // Validation failed, report an error - let err = ConstEvalErr::new(&ecx, error, None); - Err(err.struct_error( - ecx.tcx, - "it is undefined behavior to use this value", - |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.emit(); - }, - )) - } else { - // Convert to raw constant - Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) - } - } - } -} diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs deleted file mode 100644 index a2a58207f279f..0000000000000 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ /dev/null @@ -1,1265 +0,0 @@ -//! Mono Item Collection -//! ==================== -//! -//! This module is responsible for discovering all items that will contribute -//! to code generation of the crate. The important part here is that it not only -//! needs to find syntax-level items (functions, structs, etc) but also all -//! their monomorphized instantiations. Every non-generic, non-const function -//! maps to one LLVM artifact. Every generic function can produce -//! from zero to N artifacts, depending on the sets of type arguments it -//! is instantiated with. -//! This also applies to generic items from other crates: A generic definition -//! in crate X might produce monomorphizations that are compiled into crate Y. -//! We also have to collect these here. -//! -//! The following kinds of "mono items" are handled here: -//! -//! - Functions -//! - Methods -//! - Closures -//! - Statics -//! - Drop glue -//! -//! The following things also result in LLVM artifacts, but are not collected -//! here, since we instantiate them locally on demand when needed in a given -//! codegen unit: -//! -//! - Constants -//! - Vtables -//! - Object Shims -//! -//! -//! General Algorithm -//! ----------------- -//! Let's define some terms first: -//! -//! - A "mono item" is something that results in a function or global in -//! the LLVM IR of a codegen unit. Mono items do not stand on their -//! own, they can reference other mono items. For example, if function -//! `foo()` calls function `bar()` then the mono item for `foo()` -//! references the mono item for function `bar()`. In general, the -//! definition for mono item A referencing a mono item B is that -//! the LLVM artifact produced for A references the LLVM artifact produced -//! for B. -//! -//! - Mono items and the references between them form a directed graph, -//! where the mono items are the nodes and references form the edges. -//! Let's call this graph the "mono item graph". -//! -//! - The mono item graph for a program contains all mono items -//! that are needed in order to produce the complete LLVM IR of the program. -//! -//! The purpose of the algorithm implemented in this module is to build the -//! mono item graph for the current crate. It runs in two phases: -//! -//! 1. Discover the roots of the graph by traversing the HIR of the crate. -//! 2. Starting from the roots, find neighboring nodes by inspecting the MIR -//! representation of the item corresponding to a given node, until no more -//! new nodes are found. -//! -//! ### Discovering roots -//! -//! The roots of the mono item graph correspond to the non-generic -//! syntactic items in the source code. We find them by walking the HIR of the -//! crate, and whenever we hit upon a function, method, or static item, we -//! create a mono item consisting of the items DefId and, since we only -//! consider non-generic items, an empty type-substitution set. -//! -//! ### Finding neighbor nodes -//! Given a mono item node, we can discover neighbors by inspecting its -//! MIR. We walk the MIR and any time we hit upon something that signifies a -//! reference to another mono item, we have found a neighbor. Since the -//! mono item we are currently at is always monomorphic, we also know the -//! concrete type arguments of its neighbors, and so all neighbors again will be -//! monomorphic. The specific forms a reference to a neighboring node can take -//! in MIR are quite diverse. Here is an overview: -//! -//! #### Calling Functions/Methods -//! The most obvious form of one mono item referencing another is a -//! function or method call (represented by a CALL terminator in MIR). But -//! calls are not the only thing that might introduce a reference between two -//! function mono items, and as we will see below, they are just a -//! specialization of the form described next, and consequently will not get any -//! special treatment in the algorithm. -//! -//! #### Taking a reference to a function or method -//! A function does not need to actually be called in order to be a neighbor of -//! another function. It suffices to just take a reference in order to introduce -//! an edge. Consider the following example: -//! -//! ```rust -//! fn print_val(x: T) { -//! println!("{}", x); -//! } -//! -//! fn call_fn(f: &Fn(i32), x: i32) { -//! f(x); -//! } -//! -//! fn main() { -//! let print_i32 = print_val::; -//! call_fn(&print_i32, 0); -//! } -//! ``` -//! The MIR of none of these functions will contain an explicit call to -//! `print_val::`. Nonetheless, in order to mono this program, we need -//! an instance of this function. Thus, whenever we encounter a function or -//! method in operand position, we treat it as a neighbor of the current -//! mono item. Calls are just a special case of that. -//! -//! #### Closures -//! In a way, closures are a simple case. Since every closure object needs to be -//! constructed somewhere, we can reliably discover them by observing -//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also -//! true for closures inlined from other crates. -//! -//! #### Drop glue -//! Drop glue mono items are introduced by MIR drop-statements. The -//! generated mono item will again have drop-glue item neighbors if the -//! type to be dropped contains nested values that also need to be dropped. It -//! might also have a function item neighbor for the explicit `Drop::drop` -//! implementation of its type. -//! -//! #### Unsizing Casts -//! A subtle way of introducing neighbor edges is by casting to a trait object. -//! Since the resulting fat-pointer contains a reference to a vtable, we need to -//! instantiate all object-save methods of the trait, as we need to store -//! pointers to these functions even if they never get called anywhere. This can -//! be seen as a special case of taking a function reference. -//! -//! #### Boxes -//! Since `Box` expression have special compiler support, no explicit calls to -//! `exchange_malloc()` and `box_free()` may show up in MIR, even if the -//! compiler will generate them. We have to observe `Rvalue::Box` expressions -//! and Box-typed drop-statements for that purpose. -//! -//! -//! Interaction with Cross-Crate Inlining -//! ------------------------------------- -//! The binary of a crate will not only contain machine code for the items -//! defined in the source code of that crate. It will also contain monomorphic -//! instantiations of any extern generic functions and of functions marked with -//! `#[inline]`. -//! The collection algorithm handles this more or less mono. If it is -//! about to create a mono item for something with an external `DefId`, -//! it will take a look if the MIR for that item is available, and if so just -//! proceed normally. If the MIR is not available, it assumes that the item is -//! just linked to and no node is created; which is exactly what we want, since -//! no machine code should be generated in the current crate for such an item. -//! -//! Eager and Lazy Collection Mode -//! ------------------------------ -//! Mono item collection can be performed in one of two modes: -//! -//! - Lazy mode means that items will only be instantiated when actually -//! referenced. The goal is to produce the least amount of machine code -//! possible. -//! -//! - Eager mode is meant to be used in conjunction with incremental compilation -//! where a stable set of mono items is more important than a minimal -//! one. Thus, eager mode will instantiate drop-glue for every drop-able type -//! in the crate, even if no drop call for that type exists (yet). It will -//! also instantiate default implementations of trait methods, something that -//! otherwise is only done on demand. -//! -//! -//! Open Issues -//! ----------- -//! Some things are not yet fully implemented in the current version of this -//! module. -//! -//! ### Const Fns -//! Ideally, no mono item should be generated for const fns unless there -//! is a call to them that cannot be evaluated at compile time. At the moment -//! this is not implemented however: a mono item will be produced -//! regardless of whether it is actually needed or not. - -use crate::monomorphize; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; -use rustc_errors::{ErrorReported, FatalError}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::lang_items::LangItem; -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::{ErrorHandled, GlobalAlloc, Scalar}; -use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::mir::visit::Visitor as MirVisitor; -use rustc_middle::mir::{self, Local, Location}; -use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; -use rustc_session::config::EntryFnType; -use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; -use smallvec::SmallVec; -use std::iter; -use std::ops::Range; -use std::path::PathBuf; - -#[derive(PartialEq)] -pub enum MonoItemCollectionMode { - Eager, - Lazy, -} - -/// Maps every mono item to all mono items it references in its -/// body. -pub struct InliningMap<'tcx> { - // Maps a source mono item to the range of mono items - // accessed by it. - // The range selects elements within the `targets` vecs. - index: FxHashMap, Range>, - targets: Vec>, - - // Contains one bit per mono item in the `targets` field. That bit - // is true if that mono item needs to be inlined into every CGU. - inlines: GrowableBitSet, -} - -impl<'tcx> InliningMap<'tcx> { - fn new() -> InliningMap<'tcx> { - InliningMap { - index: FxHashMap::default(), - targets: Vec::new(), - inlines: GrowableBitSet::with_capacity(1024), - } - } - - fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { - let start_index = self.targets.len(); - let new_items_count = new_targets.len(); - let new_items_count_total = new_items_count + self.targets.len(); - - self.targets.reserve(new_items_count); - self.inlines.ensure(new_items_count_total); - - for (i, (target, inline)) in new_targets.iter().enumerate() { - self.targets.push(*target); - if *inline { - self.inlines.insert(i + start_index); - } - } - - let end_index = self.targets.len(); - assert!(self.index.insert(source, start_index..end_index).is_none()); - } - - // Internally iterate over all items referenced by `source` which will be - // made available for inlining. - pub fn with_inlining_candidates(&self, source: MonoItem<'tcx>, mut f: F) - where - F: FnMut(MonoItem<'tcx>), - { - if let Some(range) = self.index.get(&source) { - for (i, candidate) in self.targets[range.clone()].iter().enumerate() { - if self.inlines.contains(range.start + i) { - f(*candidate); - } - } - } - } - - // Internally iterate over all items and the things each accesses. - pub fn iter_accesses(&self, mut f: F) - where - F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), - { - for (&accessor, range) in &self.index { - f(accessor, &self.targets[range.clone()]) - } - } -} - -pub fn collect_crate_mono_items( - tcx: TyCtxt<'_>, - mode: MonoItemCollectionMode, -) -> (FxHashSet>, InliningMap<'_>) { - let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); - - let roots = - tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode)); - - debug!("building mono item graph, beginning at roots"); - - let mut visited = MTLock::new(FxHashSet::default()); - let mut inlining_map = MTLock::new(InliningMap::new()); - - { - let visited: MTRef<'_, _> = &mut visited; - let inlining_map: MTRef<'_, _> = &mut inlining_map; - - tcx.sess.time("monomorphization_collector_graph_walk", || { - par_iter(roots).for_each(|root| { - let mut recursion_depths = DefIdMap::default(); - collect_items_rec( - tcx, - dummy_spanned(root), - visited, - &mut recursion_depths, - inlining_map, - ); - }); - }); - } - - (visited.into_inner(), inlining_map.into_inner()) -} - -// Find all non-generic items by walking the HIR. These items serve as roots to -// start monomorphizing from. -fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { - debug!("collecting roots"); - let mut roots = Vec::new(); - - { - let entry_fn = tcx.entry_fn(LOCAL_CRATE); - - debug!("collect_roots: entry_fn = {:?}", entry_fn); - - let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots }; - - tcx.hir().krate().visit_all_item_likes(&mut visitor); - - visitor.push_extra_entry_roots(); - } - - // We can only codegen items that are instantiable - items all of - // whose predicates hold. Luckily, items that aren't instantiable - // can't actually be used, so we can just skip codegenning them. - roots - .into_iter() - .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node)) - .collect() -} - -// Collect all monomorphized items reachable from `starting_point` -fn collect_items_rec<'tcx>( - tcx: TyCtxt<'tcx>, - starting_point: Spanned>, - visited: MTRef<'_, MTLock>>>, - recursion_depths: &mut DefIdMap, - inlining_map: MTRef<'_, MTLock>>, -) { - if !visited.lock_mut().insert(starting_point.node) { - // We've been here already, no need to search again. - return; - } - debug!("BEGIN collect_items_rec({})", starting_point.node); - - let mut neighbors = Vec::new(); - let recursion_depth_reset; - - match starting_point.node { - MonoItem::Static(def_id) => { - let instance = Instance::mono(tcx, def_id); - - // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); - - let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors); - - recursion_depth_reset = None; - - if let Ok(alloc) = tcx.eval_static_initializer(def_id) { - for &((), id) in alloc.relocations().values() { - collect_miri(tcx, id, &mut neighbors); - } - } - } - MonoItem::Fn(instance) => { - // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); - - // Keep track of the monomorphization recursion depth - recursion_depth_reset = - Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths)); - check_type_length_limit(tcx, instance); - - rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_neighbours(tcx, instance, &mut neighbors); - }); - } - MonoItem::GlobalAsm(..) => { - recursion_depth_reset = None; - } - } - - record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); - - for neighbour in neighbors { - collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map); - } - - if let Some((def_id, depth)) = recursion_depth_reset { - recursion_depths.insert(def_id, depth); - } - - debug!("END collect_items_rec({})", starting_point.node); -} - -fn record_accesses<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - caller: MonoItem<'tcx>, - callees: impl Iterator>, - inlining_map: MTRef<'_, MTLock>>, -) { - let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { - mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy - }; - - // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. - // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` - // instead to avoid creating this `SmallVec`. - let accesses: SmallVec<[_; 128]> = - callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); - - inlining_map.lock_mut().record_accesses(caller, &accesses); -} - -/// Format instance name that is already known to be too long for rustc. -/// Show only the first and last 32 characters to avoid blasting -/// the user's terminal with thousands of lines of type-name. -/// -/// If the type name is longer than before+after, it will be written to a file. -fn shrunk_instance_name( - tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, - before: usize, - after: usize, -) -> (String, Option) { - let s = instance.to_string(); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if s.chars().nth(before + after + 1).is_some() { - // An iterator of all byte positions including the end of the string. - let positions = || s.char_indices().map(|(i, _)| i).chain(iter::once(s.len())); - - let shrunk = format!( - "{before}...{after}", - before = &s[..positions().nth(before).unwrap_or(s.len())], - after = &s[positions().rev().nth(after).unwrap_or(0)..], - ); - - let path = tcx.output_filenames(LOCAL_CRATE).temp_path_ext("long-type.txt", None); - let written_to_path = std::fs::write(&path, s).ok().map(|_| path); - - (shrunk, written_to_path) - } else { - (s, None) - } -} - -fn check_recursion_limit<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - span: Span, - recursion_depths: &mut DefIdMap, -) -> (DefId, usize) { - let def_id = instance.def_id(); - let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); - debug!(" => recursion depth={}", recursion_depth); - - let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - // HACK: drop_in_place creates tight monomorphization loops. Give - // it more margin. - recursion_depth / 4 - } else { - recursion_depth - }; - - // Code that needs to instantiate the same function recursively - // more than the recursion limit is assumed to be causing an - // infinite expansion. - if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let error = format!("reached the recursion limit while instantiating `{}`", shrunk); - let mut err = tcx.sess.struct_span_fatal(span, &error); - err.span_note( - tcx.def_span(def_id), - &format!("`{}` defined here", tcx.def_path_str(def_id)), - ); - if let Some(path) = written_to_path { - err.note(&format!("the full type name has been written to '{}'", path.display())); - } - err.emit(); - FatalError.raise(); - } - - recursion_depths.insert(def_id, recursion_depth + 1); - - (def_id, recursion_depth) -} - -fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance - .substs - .iter() - .flat_map(|arg| arg.walk()) - .filter(|arg| match arg.unpack() { - GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, - GenericArgKind::Lifetime(_) => false, - }) - .count(); - debug!(" => type length={}", type_length); - - // Rust code can easily create exponentially-long types using only a - // polynomial recursion depth. Even with the default recursion - // depth, you can easily get cases that take >2^60 steps to run, - // which means that rustc basically hangs. - // - // Bail out in these cases to avoid that bad user experience. - if !tcx.sess.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32); - let msg = format!("reached the type-length limit while instantiating `{}`", shrunk); - let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg); - if let Some(path) = written_to_path { - diag.note(&format!("the full type name has been written to '{}'", path.display())); - } - diag.help(&format!( - "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate", - type_length - )); - diag.emit(); - tcx.sess.abort_if_errors(); - } -} - -struct MirNeighborCollector<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - output: &'a mut Vec>>, - instance: Instance<'tcx>, -} - -impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { - pub fn monomorphize(&self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("monomorphize: self.instance={:?}", self.instance); - self.instance.subst_mir_and_normalize_erasing_regions( - self.tcx, - ty::ParamEnv::reveal_all(), - value, - ) - } -} - -impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - debug!("visiting rvalue {:?}", *rvalue); - - let span = self.body.source_info(location).span; - - match *rvalue { - // When doing an cast from a regular pointer to a fat pointer, we - // have to instantiate all methods of the trait being cast to, so we - // can build the appropriate vtable. - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::Unsize), - ref operand, - target_ty, - ) => { - let target_ty = self.monomorphize(target_ty); - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - let (source_ty, target_ty) = - find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); - // This could also be a different Unsize instruction, like - // from a fixed sized array to a slice. But we are only - // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { - create_mono_items_for_vtable_methods( - self.tcx, - target_ty, - source_ty, - span, - self.output, - ); - } - } - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ReifyFnPointer), - ref operand, - _, - ) => { - let fn_ty = operand.ty(self.body, self.tcx); - let fn_ty = self.monomorphize(fn_ty); - visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); - } - mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), - ref operand, - _, - ) => { - let source_ty = operand.ty(self.body, self.tcx); - let source_ty = self.monomorphize(source_ty); - match *source_ty.kind() { - ty::Closure(def_id, substs) => { - let instance = Instance::resolve_closure( - self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - if should_codegen_locally(self.tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } - _ => bug!(), - } - } - mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } - mir::Rvalue::ThreadLocalRef(def_id) => { - assert!(self.tcx.is_thread_local_static(def_id)); - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting thread-local static {:?}", def_id); - self.output.push(respan(span, MonoItem::Static(def_id))); - } - } - _ => { /* not interesting */ } - } - - self.super_rvalue(rvalue, location); - } - - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { - debug!("visiting const {:?} @ {:?}", *constant, location); - - let substituted_constant = self.monomorphize(*constant); - let param_env = ty::ParamEnv::reveal_all(); - - match substituted_constant.val { - ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), - ty::ConstKind::Unevaluated(def, substs, promoted) => { - match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) { - Ok(val) => collect_const_value(self.tcx, val, self.output), - Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} - Err(ErrorHandled::TooGeneric) => span_bug!( - self.body.source_info(location).span, - "collection encountered polymorphic constant: {}", - substituted_constant - ), - Err(ErrorHandled::Silent) => span_bug!( - self.body.source_info(location).span, - "silent error emitted during collection", - ), - } - } - _ => {} - } - - self.super_const(constant); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - debug!("visiting terminator {:?} @ {:?}", terminator, location); - let source = self.body.source_info(location).span; - - let tcx = self.tcx; - match terminator.kind { - mir::TerminatorKind::Call { ref func, .. } => { - let callee_ty = func.ty(self.body, tcx); - let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); - } - mir::TerminatorKind::Drop { ref place, .. } - | mir::TerminatorKind::DropAndReplace { ref place, .. } => { - let ty = place.ty(self.body, self.tcx).ty; - let ty = self.monomorphize(ty); - visit_drop_use(self.tcx, ty, true, source, self.output); - } - mir::TerminatorKind::InlineAsm { ref operands, .. } => { - for op in operands { - match *op { - mir::InlineAsmOperand::SymFn { ref value } => { - let fn_ty = self.monomorphize(value.literal.ty); - visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output); - } - mir::InlineAsmOperand::SymStatic { def_id } => { - let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { - trace!("collecting asm sym static {:?}", def_id); - self.output.push(respan(source, MonoItem::Static(def_id))); - } - } - _ => {} - } - } - } - mir::TerminatorKind::Goto { .. } - | mir::TerminatorKind::SwitchInt { .. } - | mir::TerminatorKind::Resume - | mir::TerminatorKind::Abort - | mir::TerminatorKind::Return - | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Assert { .. } => {} - mir::TerminatorKind::GeneratorDrop - | mir::TerminatorKind::Yield { .. } - | mir::TerminatorKind::FalseEdge { .. } - | mir::TerminatorKind::FalseUnwind { .. } => bug!(), - } - - self.super_terminator(terminator, location); - } - - fn visit_local( - &mut self, - _place_local: &Local, - _context: mir::visit::PlaceContext, - _location: Location, - ) { - } -} - -fn visit_drop_use<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - let instance = Instance::resolve_drop_in_place(tcx, ty); - visit_instance_use(tcx, instance, is_direct_call, source, output); -} - -fn visit_fn_use<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - if let ty::FnDef(def_id, substs) = *ty.kind() { - let instance = if is_direct_call { - ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap() - } else { - ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs) - .unwrap() - }; - visit_instance_use(tcx, instance, is_direct_call, source, output); - } -} - -fn visit_instance_use<'tcx>( - tcx: TyCtxt<'tcx>, - instance: ty::Instance<'tcx>, - is_direct_call: bool, - source: Span, - output: &mut Vec>>, -) { - debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_codegen_locally(tcx, &instance) { - return; - } - - match instance.def { - ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { - if !is_direct_call { - bug!("{:?} being reified", instance); - } - } - ty::InstanceDef::DropGlue(_, None) => { - // Don't need to emit noop drop glue if we are calling directly. - if !is_direct_call { - output.push(create_fn_mono_item(tcx, instance, source)); - } - } - ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Item(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::CloneShim(..) => { - output.push(create_fn_mono_item(tcx, instance, source)); - } - } -} - -// Returns `true` if we should codegen an instance in the local crate. -// Returns `false` if we can just link to the upstream crate and therefore don't -// need a mono item. -fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Intrinsic(_) - | ty::InstanceDef::CloneShim(..) => return true, - }; - - if tcx.is_foreign_item(def_id) { - // Foreign items are always linked against, there's no way of instantiating them. - return false; - } - - if def_id.is_local() { - // Local items cannot be referred to locally without monomorphizing them locally. - return true; - } - - if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() - { - // We can link to the item in question, no instance needed in this crate. - return false; - } - - if !tcx.is_mir_available(def_id) { - bug!("no MIR available for {:?}", def_id); - } - - true -} - -/// For a given pair of source and target type that occur in an unsizing coercion, -/// this function finds the pair of types that determines the vtable linking -/// them. -/// -/// For example, the source type might be `&SomeStruct` and the target type\ -/// might be `&SomeTrait` in a cast like: -/// -/// let src: &SomeStruct = ...; -/// let target = src as &SomeTrait; -/// -/// Then the output of this function would be (SomeStruct, SomeTrait) since for -/// constructing the `target` fat-pointer we need the vtable for that pair. -/// -/// Things can get more complicated though because there's also the case where -/// the unsized type occurs as a field: -/// -/// ```rust -/// struct ComplexStruct { -/// a: u32, -/// b: f64, -/// c: T -/// } -/// ``` -/// -/// In this case, if `T` is sized, `&ComplexStruct` is a thin pointer. If `T` -/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is -/// for the pair of `T` (which is a trait) and the concrete type that `T` was -/// originally coerced from: -/// -/// let src: &ComplexStruct = ...; -/// let target = src as &ComplexStruct; -/// -/// Again, we want this `find_vtable_types_for_unsizing()` to provide the pair -/// `(SomeStruct, SomeTrait)`. -/// -/// Finally, there is also the case of custom unsizing coercions, e.g., for -/// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'tcx>( - tcx: TyCtxt<'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>, -) -> (Ty<'tcx>, Ty<'tcx>) { - let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - let param_env = ty::ParamEnv::reveal_all(); - let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.at(DUMMY_SP), param_env) { - return false; - } - let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } - }; - if type_has_metadata(inner_source) { - (inner_source, inner_target) - } else { - tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env) - } - }; - - match (&source_ty.kind(), &target_ty.kind()) { - (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) - | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { - ptr_vtable(a, b) - } - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) - } - - (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { - assert_eq!(source_adt_def, target_adt_def); - - let CustomCoerceUnsized::Struct(coerce_index) = - monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); - - let source_fields = &source_adt_def.non_enum_variant().fields; - let target_fields = &target_adt_def.non_enum_variant().fields; - - assert!( - coerce_index < source_fields.len() && source_fields.len() == target_fields.len() - ); - - find_vtable_types_for_unsizing( - tcx, - source_fields[coerce_index].ty(tcx, source_substs), - target_fields[coerce_index].ty(tcx, target_substs), - ) - } - _ => bug!( - "find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", - source_ty, - target_ty - ), - } -} - -fn create_fn_mono_item<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - source: Span, -) -> Spanned> { - debug!("create_fn_mono_item(instance={})", instance); - respan(source, MonoItem::Fn(instance.polymorphize(tcx))) -} - -/// Creates a `MonoItem` for each method that is referenced by the vtable for -/// the given trait/impl pair. -fn create_mono_items_for_vtable_methods<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ty: Ty<'tcx>, - impl_ty: Ty<'tcx>, - source: Span, - output: &mut Vec>>, -) { - assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); - - if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind() { - if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); - assert!(!poly_trait_ref.has_escaping_bound_vars()); - - // Walk all methods of the trait, including those of its supertraits - let methods = tcx.vtable_methods(poly_trait_ref); - let methods = methods - .iter() - .cloned() - .filter_map(|method| method) - .map(|(def_id, substs)| { - ty::Instance::resolve_for_vtable( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap() - }) - .filter(|&instance| should_codegen_locally(tcx, &instance)) - .map(|item| create_fn_mono_item(tcx, item, source)); - output.extend(methods); - } - - // Also add the destructor. - visit_drop_use(tcx, impl_ty, false, source, output); - } -} - -//=----------------------------------------------------------------------------- -// Root Collection -//=----------------------------------------------------------------------------- - -struct RootCollector<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mode: MonoItemCollectionMode, - output: &'a mut Vec>>, - entry_fn: Option<(LocalDefId, EntryFnType)>, -} - -impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { - fn visit_item(&mut self, item: &'v hir::Item<'v>) { - match item.kind { - hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Mod(..) => { - // Nothing to do, just keep recursing. - } - - hir::ItemKind::Impl { .. } => { - if self.mode == MonoItemCollectionMode::Eager { - create_mono_items_for_default_impls(self.tcx, item, self.output); - } - } - - hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) => { - if generics.params.is_empty() { - if self.mode == MonoItemCollectionMode::Eager { - let def_id = self.tcx.hir().local_def_id(item.hir_id); - debug!( - "RootCollector: ADT drop-glue for {}", - self.tcx.def_path_str(def_id.to_def_id()) - ); - - let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty()) - .ty(self.tcx, ty::ParamEnv::reveal_all()); - visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); - } - } - } - hir::ItemKind::GlobalAsm(..) => { - debug!( - "RootCollector: ItemKind::GlobalAsm({})", - self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id()) - ); - self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id))); - } - hir::ItemKind::Static(..) => { - let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); - debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id)); - self.output.push(dummy_spanned(MonoItem::Static(def_id))); - } - hir::ItemKind::Const(..) => { - // const items only generate mono items if they are - // actually used somewhere. Just declaring them is insufficient. - - // but even just declaring them must collect the items they refer to - let def_id = self.tcx.hir().local_def_id(item.hir_id); - - if let Ok(val) = self.tcx.const_eval_poly(def_id.to_def_id()) { - collect_const_value(self.tcx, val, &mut self.output); - } - } - hir::ItemKind::Fn(..) => { - let def_id = self.tcx.hir().local_def_id(item.hir_id); - self.push_if_root(def_id); - } - } - } - - fn visit_trait_item(&mut self, _: &'v hir::TraitItem<'v>) { - // Even if there's a default body with no explicit generics, - // it's still generic over some `Self: Trait`, so not a root. - } - - fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { - if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind { - let def_id = self.tcx.hir().local_def_id(ii.hir_id); - self.push_if_root(def_id); - } - } - - fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {} -} - -impl RootCollector<'_, 'v> { - fn is_root(&self, def_id: LocalDefId) -> bool { - !item_requires_monomorphization(self.tcx, def_id) - && match self.mode { - MonoItemCollectionMode::Eager => true, - MonoItemCollectionMode::Lazy => { - self.entry_fn.map(|(id, _)| id) == Some(def_id) - || self.tcx.is_reachable_non_generic(def_id) - || self - .tcx - .codegen_fn_attrs(def_id) - .flags - .contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - } - } - } - - /// If `def_id` represents a root, pushes it onto the list of - /// outputs. (Note that all roots must be monomorphic.) - fn push_if_root(&mut self, def_id: LocalDefId) { - if self.is_root(def_id) { - debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); - - let instance = Instance::mono(self.tcx, def_id.to_def_id()); - self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); - } - } - - /// As a special case, when/if we encounter the - /// `main()` function, we also have to generate a - /// monomorphized copy of the start lang item based on - /// the return type of `main`. This is not needed when - /// the user writes their own `start` manually. - fn push_extra_entry_roots(&mut self) { - let main_def_id = match self.entry_fn { - Some((def_id, EntryFnType::Main)) => def_id, - _ => return, - }; - - let start_def_id = match self.tcx.lang_items().require(LangItem::Start) { - Ok(s) => s, - Err(err) => self.tcx.sess.fatal(&err), - }; - let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); - - // Given that `main()` has no arguments, - // then its return type cannot have - // late-bound regions, since late-bound - // regions must appear in the argument - // listing. - let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); - - let start_instance = Instance::resolve( - self.tcx, - ty::ParamEnv::reveal_all(), - start_def_id, - self.tcx.intern_substs(&[main_ret_ty.into()]), - ) - .unwrap() - .unwrap(); - - self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); - } -} - -fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let generics = tcx.generics_of(def_id); - generics.requires_monomorphization(tcx) -} - -fn create_mono_items_for_default_impls<'tcx>( - tcx: TyCtxt<'tcx>, - item: &'tcx hir::Item<'tcx>, - output: &mut Vec>>, -) { - match item.kind { - hir::ItemKind::Impl(ref impl_) => { - for param in impl_.generics.params { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => {} - hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => { - return; - } - } - } - - let impl_def_id = tcx.hir().local_def_id(item.hir_id); - - debug!( - "create_mono_items_for_default_impls(item={})", - tcx.def_path_str(impl_def_id.to_def_id()) - ); - - if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { - let param_env = ty::ParamEnv::reveal_all(); - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - let overridden_methods: FxHashSet<_> = - impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); - for method in tcx.provided_trait_methods(trait_ref.def_id) { - if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { - continue; - } - - if tcx.generics_of(method.def_id).own_requires_monomorphization() { - continue; - } - - let substs = - InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize] - } - }); - let instance = ty::Instance::resolve(tcx, param_env, method.def_id, substs) - .unwrap() - .unwrap(); - - let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) - { - output.push(mono_item); - } - } - } - } - _ => bug!(), - } -} - -/// Scans the miri alloc in order to find function calls, closures, and drop-glue. -fn collect_miri<'tcx>( - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, - output: &mut Vec>>, -) { - match tcx.global_alloc(alloc_id) { - GlobalAlloc::Static(def_id) => { - assert!(!tcx.is_thread_local_static(def_id)); - let instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, &instance) { - trace!("collecting static {:?}", def_id); - output.push(dummy_spanned(MonoItem::Static(def_id))); - } - } - GlobalAlloc::Memory(alloc) => { - trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &((), inner) in alloc.relocations().values() { - rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_miri(tcx, inner, output); - }); - } - } - GlobalAlloc::Function(fn_instance) => { - if should_codegen_locally(tcx, &fn_instance) { - trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); - output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); - } - } - } -} - -/// Scans the MIR in order to find function calls, closures, and drop-glue. -fn collect_neighbours<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - output: &mut Vec>>, -) { - debug!("collect_neighbours: {:?}", instance.def_id()); - let body = tcx.instance_mir(instance.def); - - MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); -} - -fn collect_const_value<'tcx>( - tcx: TyCtxt<'tcx>, - value: ConstValue<'tcx>, - output: &mut Vec>>, -) { - match value { - ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), - ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { - for &((), id) in alloc.relocations().values() { - collect_miri(tcx, id, output); - } - } - _ => {} - } -} diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 7e56e062fc989..8ec72c2effaca 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -29,7 +29,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use crate::MirPass; -use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::const_eval::ConstEvalError; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy, @@ -490,7 +490,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ok(op) => Some(op), Err(error) => { let tcx = self.ecx.tcx.at(c.span); - let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); + let err = ConstEvalError::new(&self.ecx, error, Some(c.span)).into_inner(); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal { ConstantKind::Ty(ct) => match ct.val { @@ -509,12 +509,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if lint_only { // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. - err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span)); + err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span)) + .get_error(); } else { - err.report_as_error(tcx, "erroneous constant used"); + err.report_as_error(tcx, "erroneous constant used").get_error(); } } else { - err.report_as_error(tcx, "erroneous constant used"); + err.report_as_error(tcx, "erroneous constant used").get_error(); } None } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b1fa9041342a6..248a0aa45354e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -731,6 +731,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { "collection encountered polymorphic constant: {:?}", literal ), + Err(ErrorHandled::Silent(_)) => span_bug!( + self.body.source_info(location).span, + "silent error emitted during collection", + ), } } _ => return, @@ -763,6 +767,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { "collection encountered polymorphic constant: {}", substituted_constant ), + Err(ErrorHandled::Silent(_)) => span_bug!( + self.body.source_info(location).span, + "silent error emitted during collection", + ), } } _ => {} From 910c09bff88d8c88d2675700c914bcd0aa04157d Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:16:52 +0100 Subject: [PATCH 05/12] introduce Reveal::Selection and deduplication for eval const queries --- .../rustc_middle/src/mir/interpret/mod.rs | 726 +++++++++++++++++- compiler/rustc_middle/src/ty/consts/kind.rs | 18 +- compiler/rustc_middle/src/ty/context.rs | 5 + compiler/rustc_middle/src/ty/mod.rs | 37 +- 4 files changed, 756 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b762a10da847a..c48d99c71479f 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -95,6 +95,7 @@ mod pointer; mod queries; mod value; +use std::cell::RefCell; use std::convert::TryFrom; use std::fmt; use std::io; @@ -106,21 +107,29 @@ use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_data_structures::tiny_list::TinyList; +use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_macros::HashStable; +use rustc_hir::definitions::DefPathData; +use rustc_middle::traits::Reveal; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; +use rustc_span::{Pos, Span, DUMMY_SP}; use rustc_target::abi::Endian; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; +use crate::ty::layout::LayoutError; use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Instance, Ty, TyCtxt}; +use crate::ty::{self, Instance, Ty, TyCtxt, WithOptConstParam}; + +use std::borrow::Cow; pub use self::error::{ - struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, - InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, - ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + struct_error, CheckInAllocMsg, ConstErrorEmitted, ConstEvalErr, ErrorHandled, + EvalToAllocationRawResult, EvalToConstValueResult, InterpError, InterpErrorInfo, InterpResult, + InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo, UndefinedBehaviorInfo, + UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; @@ -446,6 +455,206 @@ impl<'tcx> AllocMap<'tcx> { } } +/// What we store about a frame in an interpreter backtrace. +#[derive(Debug)] +pub struct FrameInfo<'tcx> { + pub instance: ty::Instance<'tcx>, + pub span: Span, + pub lint_root: Option, +} + +impl<'tcx> fmt::Display for FrameInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(|tcx| { + if tcx.def_key(self.instance.def_id()).disambiguated_data.data + == DefPathData::ClosureExpr + { + write!(f, "inside closure")?; + } else { + write!(f, "inside `{}`", self.instance)?; + } + if !self.span.is_dummy() { + let sm = tcx.sess.source_map(); + let lo = sm.lookup_char_pos(self.span.lo()); + write!( + f, + " at {}:{}:{}", + sm.filename_for_diagnostics(&lo.file.name), + lo.line, + lo.col.to_usize() + 1 + )?; + } + Ok(()) + }) + } +} + +/// Errors that were returned from calls to `eval_to_allocation_raw` or +/// `eval_to_const_value_raw` with `Reveal::Selection`. Since we want to +/// deduplicate from `Reveal::Selection` results, we store the returned +/// `ConstEvalErr` in order to allow us to report those errors on calls +/// with `Reveal::UserFacing` or `Reveal::All`. +#[derive(Debug)] +pub enum SilentError<'tcx> { + ConstErr(ConstEvalErr<'tcx>), + Handled(ErrorHandled<'tcx>), +} + +#[derive(Debug)] +pub enum ConstDedupError<'tcx> { + /// used for errors found in `eval_to_allocation_raw` with `Reveal::Selection` + /// in order to allow deduplication. + Silent(SilentError<'tcx>), + + /// error that was reported in call of `eval_to_allocation_raw`. + Handled(ErrorHandled<'tcx>), +} + +impl<'tcx> ConstDedupError<'tcx> { + pub fn new_handled(e: ErrorHandled<'tcx>, reveal: Reveal) -> Self { + match reveal { + Reveal::Selection => ConstDedupError::Silent(SilentError::Handled(e)), + _ => ConstDedupError::Handled(e), + } + } + + pub fn new_silent(e: SilentError<'tcx>, reveal: Reveal) -> Self { + match reveal { + Reveal::Selection => ConstDedupError::Silent(e), + _ => bug!("can only create a `ConstDedupError::Silent` with `Reveal::Selection`"), + } + } + + pub fn get_const_err(self) -> ConstEvalErr<'tcx> { + match self { + ConstDedupError::Silent(e) => match e { + SilentError::ConstErr(e) => e, + _ => bug!( + "cannot call `get_const_err` on `ConstDedupError::Silent(SilentError::Handled)`" + ), + }, + ConstDedupError::Handled(_) => { + bug!("get_const_err called on ConstDedupError::Handled") + } + } + } + + pub fn get_handled_err(&self) -> ErrorHandled<'tcx> { + match self { + ConstDedupError::Handled(e) => *e, + ConstDedupError::Silent(e) => match e { + SilentError::Handled(e) => *e, + SilentError::ConstErr(_) => { + bug!("get_handled_err called on ConstDedupError::Silent(SilentError::ConstErr)") + } + }, + } + } +} + +#[derive(Debug)] +pub enum ConstDedupResult<'tcx, T: 'tcx> { + // include a Span so that we can report errors when we try to deduplicate calls + // with Reveal::UserFacing from calls with Reveal::Selection, for which we have + // to report the error during the dedup call + Selection((Result>, Span)), + UserFacing(Result>), + All(Result>), +} + +impl<'tcx, T: 'tcx> ConstDedupResult<'tcx, T> { + pub fn new( + reveal: Reveal, + val: Result>, + opt_span: Option, + ) -> Self { + match reveal { + Reveal::Selection => ConstDedupResult::Selection(( + val.map_err(|e| match e { + ConstDedupError::Silent(err) => err, + ConstDedupError::Handled(_) => bug!("expected ConstDedupError::Silent"), + }), + opt_span.unwrap_or(DUMMY_SP), + )), + Reveal::UserFacing => { + ConstDedupResult::UserFacing(val.or_else(|e| Err(e.get_handled_err()))) + } + Reveal::All => ConstDedupResult::All(val.or_else(|e| Err(e.get_handled_err()))), + } + } +} + +#[derive(Copy, Clone, Debug)] +pub enum ConstOrigin { + ConstValue, + Alloc, +} + +/// Used to store results of calls to `eval_to_allocation_raw` and +/// `eval_to_const_value_raw`. +/// +/// Depending on the value of `Reveal` of the `ParamEnv` with which the queries +/// are executed we handle errors differently. We suppress errors with `Reveal::Selection`, +/// and report errors otherwise. +/// Since a large portion of the calls with different `Reveal` arguments leads to +/// duplicate results, we try to only store the result of a call with one specific `Reveal` +/// and use that result for queries with other `Reveal` arguments. +#[derive(Debug)] +pub struct ConstDedupMap<'tcx> { + // interning for deduplication of `eval_to_allocation_raw` + pub alloc_map: RefCell, ConstDedupResult<'tcx, ConstAlloc<'tcx>>>>, + + // interning for deduplication of `eval_to_const_value_raw` + pub const_val_map: RefCell, ConstDedupResult<'tcx, ConstValue<'tcx>>>>, + + // Used to tell whether an error needs to be reported when trying to deduplicate a + // call to `eval_to_allocation_raw` or `eval_to_const_value_raw` with + // `Reveal::UserFacing` or `Reveal::All` from a call with `Reveal::Selection` + pub error_reported_map: RefCell, ErrorHandled<'tcx>>>, +} + +impl<'tcx> ConstDedupMap<'tcx> { + pub fn new() -> Self { + ConstDedupMap { + alloc_map: Default::default(), + const_val_map: Default::default(), + error_reported_map: Default::default(), + } + } + + #[instrument(skip(self), level = "debug")] + fn add_error_reported( + &self, + id: GlobalId<'tcx>, + err: ConstErrorEmitted<'tcx>, + ) -> ConstErrorEmitted<'tcx> { + match err { + ConstErrorEmitted::Emitted(err_handled) => { + let mut error_reported_map = self.error_reported_map.borrow_mut(); + error_reported_map.insert(id, err_handled); + debug!("error_reported_map after update: {:#?}", self.error_reported_map); + + err + } + ConstErrorEmitted::NotEmitted(_) => err, + } + } + + #[instrument(skip(self), level = "debug")] + fn insert_alloc(&self, id: GlobalId<'tcx>, val: ConstDedupResult<'tcx, ConstAlloc<'tcx>>) { + let mut alloc_map = self.alloc_map.borrow_mut(); + alloc_map.insert(id, val); + debug!("alloc_map after update: {:#?}", alloc_map); + } + + #[instrument(skip(self), level = "debug")] + fn insert_const_val(&self, id: GlobalId<'tcx>, val: ConstDedupResult<'tcx, ConstValue<'tcx>>) { + let mut const_val_map = self.const_val_map.borrow_mut(); + const_val_map.insert(id, val); + debug!("const_val_map after update: {:#?}", const_val_map); + } +} + impl<'tcx> TyCtxt<'tcx> { /// Obtains a new allocation ID that can be referenced but does not /// yet have an allocation backing it. @@ -554,6 +763,513 @@ impl<'tcx> TyCtxt<'tcx> { fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } + + /// Called after an error has been returned from `eval_to_allocation_raw` + /// or `eval_to_const_value_raw`. We handle this differently based on + /// the `Reveal` argument. With `Reveal::Selection` we don't report the + /// error, otherwise we do. In all cases we cache the error. + #[instrument(skip(self, report_fn), level = "debug")] + pub fn handle_err_for_dedup( + self, + id: GlobalId<'tcx>, + origin: ConstOrigin, + error: ConstEvalErr<'tcx>, + reveal: Reveal, + span: Span, + report_fn: F, + ) -> ErrorHandled<'tcx> + where + F: Fn(&ConstEvalErr<'tcx>) -> ErrorHandled<'tcx>, + { + match reveal { + Reveal::Selection => { + match origin { + ConstOrigin::ConstValue => { + let res = ConstDedupResult::new( + reveal, + Err(ConstDedupError::new_silent(SilentError::ConstErr(error), reveal)), + Some(span), + ); + + self.save_const_value_for_dedup(id, res); + } + ConstOrigin::Alloc => { + let res = ConstDedupResult::new( + reveal, + Err(ConstDedupError::new_silent(SilentError::ConstErr(error), reveal)), + Some(span), + ); + self.save_alloc_for_dedup(id, res); + } + } + + return ErrorHandled::Silent(id); + } + _ => { + let error_handled = report_fn(&error); + debug!(?error_handled); + + match origin { + ConstOrigin::ConstValue => { + let res = ConstDedupResult::new( + reveal, + Err(ConstDedupError::new_handled(error_handled, reveal)), + None, + ); + + self.save_const_value_for_dedup(id, res); + } + ConstOrigin::Alloc => { + let res = ConstDedupResult::new( + reveal, + Err(ConstDedupError::new_handled(error_handled, reveal)), + None, + ); + + self.save_alloc_for_dedup(id, res); + } + } + + error_handled + } + } + } + + /// Stores returned errors from `eval_to_allocation_raw` or `eval_to_const_value_raw` + /// calls that were already reported. + #[instrument(skip(self), level = "debug")] + pub fn handle_reported_error_for_dedup( + self, + id: GlobalId<'tcx>, + origin: ConstOrigin, + err: ConstErrorEmitted<'tcx>, + reveal: Reveal, + ) -> ErrorHandled<'tcx> { + match err { + ConstErrorEmitted::Emitted(error_handled) => { + let dedup_err = ConstDedupError::new_handled(error_handled, reveal); + + match origin { + ConstOrigin::ConstValue => { + let val = ConstDedupResult::new(reveal, Err(dedup_err), None); + self.save_const_value_for_dedup(id, val); + } + ConstOrigin::Alloc => { + let val = ConstDedupResult::new(reveal, Err(dedup_err), None); + self.save_alloc_for_dedup(id, val); + } + } + + let error_handled = self.add_error_reported(id, err).get_error(); + + error_handled + } + ConstErrorEmitted::NotEmitted(_) => bug!( + "`handle_reported_error_for_dedup` should only be called on emitted `ConstErr`s" + ), + } + } + + fn add_error_reported( + self, + id: GlobalId<'tcx>, + err: ConstErrorEmitted<'tcx>, + ) -> ConstErrorEmitted<'tcx> { + let const_dedup_map = self.dedup_const_map.lock(); + const_dedup_map.add_error_reported(id, err) + } + + #[instrument(skip(self), level = "debug")] + pub fn report_and_add_error( + self, + id: GlobalId<'tcx>, + err: &ConstEvalErr<'tcx>, + span: Span, + msg: &str, + ) -> ErrorHandled<'tcx> { + let error_emitted = err.report_as_error(self.at(span), msg); + debug!(?error_emitted); + + let const_dedup_map = self.dedup_const_map.lock(); + let error_handled = const_dedup_map.add_error_reported(id, error_emitted).get_error(); + debug!(?error_handled); + + error_handled + } + + /// Store the result of a call to `eval_to_allocation_raw` in order to + /// allow deduplication. + #[instrument(skip(self), level = "debug")] + pub fn save_alloc_for_dedup( + self, + id: GlobalId<'tcx>, + val: ConstDedupResult<'tcx, ConstAlloc<'tcx>>, + ) { + let dedup_const_map = self.dedup_const_map.lock(); + dedup_const_map.insert_alloc(id, val); + debug!("dedup_const_map after insert: {:#?}", dedup_const_map); + } + + /// Store the result of a call to `eval_to_const_value_raw` in order to deduplicate it. + #[instrument(skip(self), level = "debug")] + pub fn save_const_value_for_dedup( + self, + id: GlobalId<'tcx>, + val: ConstDedupResult<'tcx, ConstValue<'tcx>>, + ) { + let dedup_const_map = self.dedup_const_map.lock(); + dedup_const_map.insert_const_val(id, val); + debug!("dedup_const_map after insert: {:#?}", dedup_const_map); + } + + /// This function reports errors that were returned from calls of + /// `eval_to_allocation_raw` and stores them in order to allow + /// errors to be retrieved in deduplication. + #[instrument(skip(self, dedup_const_map), level = "debug")] + pub fn report_const_alloc_error( + self, + dedup_const_map: &ConstDedupMap<'tcx>, + id: GlobalId<'tcx>, + param_env: ty::ParamEnv<'tcx>, + err: &ConstEvalErr<'tcx>, + is_static: bool, + def: WithOptConstParam, + span: Span, + ) -> ConstErrorEmitted<'tcx> { + // Some CTFE errors raise just a lint, not a hard error; see + // . + let is_hard_err = if let Some(def) = def.as_local() { + // (Associated) consts only emit a lint, since they might be unused. + !matches!(self.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst) + // check if the inner InterpError is hard + || err.error.is_hard_err() + } else { + // use of broken constant from other crate: always an error + true + }; + + if is_hard_err { + let msg = if is_static { + Cow::from("could not evaluate static initializer") + } else { + // If the current item has generics, we'd like to enrich the message with the + // instance and its substs: to show the actual compile-time values, in addition to + // the expression, leading to the const eval error. + let instance = &id.instance; + if !instance.substs.is_empty() { + let instance = with_no_trimmed_paths(|| instance.to_string()); + let msg = format!("evaluation of `{}` failed", instance); + Cow::from(msg) + } else { + Cow::from("evaluation of constant value failed") + } + }; + + let e = err.report_as_error(self.at(span), &msg); + dedup_const_map.add_error_reported(id, e).get_error(); + + e + } else { + let hir_id = self.hir().local_def_id_to_hir_id(def.as_local().unwrap().did); + let e = err.report_as_lint( + self.at(self.def_span(def.did)), + "any use of this value will cause an error", + hir_id, + Some(err.span), + ); + + dedup_const_map.add_error_reported(id, e).get_error(); + + e + } + } + + /// This function reports errors that were returned from calls of + /// `eval_to_const_value_raw` and stores them in order to allow + /// errors to be retrieved in deduplication. + #[instrument(skip(self), level = "debug")] + fn report_const_val_error_if_not_already_reported( + self, + dedup_const_map: &ConstDedupMap<'tcx>, + id: GlobalId<'tcx>, + error: &ConstEvalErr<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + ) -> ErrorHandled<'tcx> { + // FIXME: This is really problematic in that it is tightly coupled to the + // implementation of `eval_to_const_value_raw`. Introducing new errors + // in that function would have to be considered here. Need to find an + // abstraction that makes this coupling explicit. + if let ty::InstanceDef::Intrinsic(_) = id.instance.def { + let contained = dedup_const_map.error_reported_map.borrow().contains_key(&id); + + if !contained { + let error_emitted = + error.report_as_error(self.at(span), "could not evaluate nullary intrinsic"); + let error_handled = + dedup_const_map.add_error_reported(id, error_emitted).get_error(); + + error_handled + } else { + let error_handled = *dedup_const_map.error_reported_map.borrow().get(&id).unwrap(); + error_handled + } + } else { + let def = id.instance.def.with_opt_param(); + + self.report_alloc_error_if_not_already_reported( + dedup_const_map, + id, + error, + def, + param_env, + span, + ) + } + } + + /// Tries to deduplicate a call to `eval_to_allocation_raw`. If deduplication isn't + /// successful `eval_to_allocation_raw` query is executed. + #[instrument(skip(self, opt_span), level = "debug")] + pub fn dedup_eval_alloc_raw( + self, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + opt_span: Option, + ) -> EvalToAllocationRawResult<'tcx> { + use ConstDedupResult::*; + + let (param_env, id) = key.into_parts(); + let def = id.instance.def.with_opt_param(); + + let dedup_const_map = self.dedup_const_map.lock(); + debug!("dedup_const_map: {:#?}", dedup_const_map); + let alloc_map = dedup_const_map.alloc_map.borrow(); + debug!("alloc_map: {:#?}", alloc_map); + + let dedup_result = alloc_map.get(&id); + debug!(?dedup_result); + + match param_env.reveal() { + Reveal::Selection => match dedup_result { + Some(Selection((Ok(alloc), _))) | Some(UserFacing(Ok(alloc))) => { + return Ok(*alloc); + } + Some(Selection((Err(err), span))) => { + match err { + SilentError::ConstErr(const_eval_err) => { + match const_eval_err.error { + err_inval!(Layout(LayoutError::Unknown(_))) + | err_inval!(TooGeneric) + | err_inval!(AlreadyReported(_)) => { + // We do want to report these errors even with `Reveal::Selection` + + let is_static = self.is_static(def.did); + let err_handled = self + .report_const_alloc_error( + &dedup_const_map, + id, + param_env, + const_eval_err, + is_static, + def, + *span, + ) + .get_error(); + + debug!(?err_handled); + + return Err(err_handled); + } + _ => return Err(ErrorHandled::Silent(id)), + } + } + SilentError::Handled(err) => { + return Err(*err); + } + } + } + Some(UserFacing(Err(_)) | All(Err(_))) => { + // these errors were previously reported, so we stay silent here + // and later access the reported errors using `id`. + return Err(ErrorHandled::Silent(id)); + } + _ => {} + }, + Reveal::UserFacing => match dedup_result { + Some(Selection((Ok(alloc), _))) | Some(UserFacing(Ok(alloc))) => { + return Ok(*alloc); + } + Some(UserFacing(Err(e)) | All(Err(e))) => { + return Err(*e); + } + Some(Selection((Err(e), span))) => match e { + SilentError::ConstErr(const_err) => { + let error_handled = self.report_alloc_error_if_not_already_reported( + &dedup_const_map, + id, + const_err, + def, + param_env, + *span, + ); + + return Err(error_handled); + } + SilentError::Handled(error_handled) => return Err(*error_handled), + }, + _ => {} + }, + Reveal::All => match dedup_result { + Some(Selection((Ok(alloc), _)) | UserFacing(Ok(alloc)) | All(Ok(alloc))) => { + return Ok(*alloc); + } + Some(All(Err(e))) => return Err(*e), + Some(UserFacing(Err(e))) => match e { + ErrorHandled::TooGeneric => {} // run query again with Reveal::All + _ => return Err(*e), + }, + _ => {} + }, + } + + // Important to drop the lock here + drop(alloc_map); + drop(dedup_const_map); + + debug!("unable to deduplicate"); + + // We weren't able to deduplicate + match opt_span { + Some(span) => self.at(span).eval_to_allocation_raw(key), + None => self.eval_to_allocation_raw(key), + } + } + + /// Tries to deduplicate a call to `eval_to_const_value_raw`. If deduplication isn't + /// successful, `eval_to_const_value_raw` query is executed. + #[instrument(skip(self), level = "debug")] + pub fn dedup_eval_const_value_raw( + self, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + ) -> EvalToConstValueResult<'tcx> { + use ConstDedupResult::*; + + let (param_env, id) = key.into_parts(); + let dedup_const_map = self.dedup_const_map.lock(); + debug!("dedup_const_map: {:#?}", dedup_const_map); + let const_val_map = dedup_const_map.const_val_map.borrow(); + debug!("const_val_map: {:#?}", const_val_map); + + let dedup_result = const_val_map.get(&id); + debug!(?dedup_result); + + match param_env.reveal() { + Reveal::Selection => match dedup_result { + Some(Selection((Ok(val), _))) | Some(UserFacing(Ok(val))) => { + return Ok(*val); + } + Some(Selection((Err(_), _)) | UserFacing(Err(_)) | All(Err(_))) => { + return Err(ErrorHandled::Silent(id)); + } + _ => {} + }, + Reveal::UserFacing => match dedup_result { + Some(Selection((Ok(val), _))) | Some(UserFacing(Ok(val))) => { + return Ok(*val); + } + Some(UserFacing(Err(e)) | All(Err(e))) => { + return Err(*e); + } + Some(Selection((Err(e), span))) => match e { + SilentError::ConstErr(const_err) => { + let error_handled = self.report_const_val_error_if_not_already_reported( + &dedup_const_map, + id, + const_err, + param_env, + *span, + ); + + return Err(error_handled); + } + SilentError::Handled(error_handled) => return Err(*error_handled), + }, + _ => {} + }, + Reveal::All => match dedup_result { + Some(Selection((Ok(val), _)) | UserFacing(Ok(val)) | All(Ok(val))) => { + return Ok(*val); + } + Some(All(Err(e))) => return Err(*e), + Some(UserFacing(Err(e))) => match e { + ErrorHandled::TooGeneric => {} // run query again with Reveal::All + _ => return Err(*e), + }, + _ => {} + }, + } + + // Important to drop the lock here + drop(const_val_map); + drop(dedup_const_map); + + debug!("unable to deduplicate"); + + // We weren't able to deduplicate + self.eval_to_const_value_raw(key) + } + + #[instrument(skip(self), level = "debug")] + pub fn report_alloc_error( + self, + id: GlobalId<'tcx>, + param_env: ty::ParamEnv<'tcx>, + err: &ConstEvalErr<'tcx>, + is_static: bool, + def: WithOptConstParam, + span: Span, + ) -> ErrorHandled<'tcx> { + let dedup_const_map = self.dedup_const_map.lock(); + let error_handled = self + .report_const_alloc_error(&dedup_const_map, id, param_env, err, is_static, def, span) + .get_error(); + + error_handled + } + + #[instrument(skip(self, dedup_const_map), level = "debug")] + fn report_alloc_error_if_not_already_reported( + self, + dedup_const_map: &ConstDedupMap<'tcx>, + id: GlobalId<'tcx>, + e: &ConstEvalErr<'tcx>, + def: WithOptConstParam, + param_env: ty::ParamEnv<'tcx>, + span: Span, + ) -> ErrorHandled<'tcx> { + let stored_error = dedup_const_map.error_reported_map.borrow().get(&id).cloned(); + match stored_error { + Some(err) => err, + None => { + let is_static = self.is_static(def.did); + let def = id.instance.def.with_opt_param(); + + let error_handled = self + .report_const_alloc_error( + dedup_const_map, + id, + param_env, + e, + is_static, + def, + span, + ) + .get_error(); + + error_handled + } + } + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index d6204a8efb783..206473e8c333a 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -3,6 +3,7 @@ use std::fmt; use crate::mir::interpret::{AllocId, ConstValue, Scalar}; use crate::mir::Promoted; +use crate::traits::Reveal; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::ParamEnv; use crate::ty::{self, TyCtxt, TypeFoldable}; @@ -160,10 +161,15 @@ impl<'tcx> ConstKind<'tcx> { // Note that we erase regions *before* calling `with_reveal_all_normalized`, // so that we don't try to invoke this query with // any region variables. - let param_env_and = tcx - .erase_regions(param_env) - .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(unevaluated)); + let param_env_and = match param_env.reveal() { + Reveal::Selection => { + tcx.erase_regions(param_env).and(tcx.erase_regions(unevaluated)) + } + _ => tcx + .erase_regions(param_env) + .with_reveal_all_normalized(tcx) + .and(tcx.erase_regions(unevaluated)), + }; // HACK(eddyb) when the query key would contain inference variables, // attempt using identity substs and `ParamEnv` instead, that will succeed @@ -191,7 +197,9 @@ impl<'tcx> ConstKind<'tcx> { // (which may be identity substs, see above), // can leak through `val` into the const we return. Ok(val) => Some(Ok(val)), - Err(ErrorHandled::TooGeneric | ErrorHandled::Linted | ErrorHandled::Silent) => None, + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted | ErrorHandled::Silent(_)) => { + None + } Err(ErrorHandled::Reported(e)) => Some(Err(e)), } } else { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index caa7008f1085e..6086117b8111f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1043,6 +1043,10 @@ pub struct GlobalCtxt<'tcx> { /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock>, + /// Used to deduplicate calls to `eval_to_allocation_raw` and + /// `eval_to_const_value_raw`. + pub dedup_const_map: Lock>, + output_filenames: Arc, } @@ -1187,6 +1191,7 @@ impl<'tcx> TyCtxt<'tcx> { stability_interner: Default::default(), const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), + dedup_const_map: Lock::new(interpret::ConstDedupMap::new()), output_filenames: Arc::new(output_filenames), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 72514e4456105..a6558e2af2a48 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -150,11 +150,7 @@ pub struct MainDefinition { impl MainDefinition { pub fn opt_fn_def_id(self) -> Option { - if let Res::Def(DefKind::Fn, def_id) = self.res { - Some(def_id) - } else { - None - } + if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } } } @@ -1184,11 +1180,7 @@ impl WithOptConstParam { } pub fn def_id_for_type_of(self) -> DefId { - if let Some(did) = self.const_param_did { - did - } else { - self.did.to_def_id() - } + if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() } } } @@ -1245,23 +1237,28 @@ struct ParamTag { } unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { - const BITS: usize = 2; + const BITS: usize = 3; #[inline] fn into_usize(self) -> usize { match self { - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0, - Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1, - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2, - Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3, + Self { reveal: traits::Reveal::Selection, constness: hir::Constness::NotConst } => 0, + Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 1, + Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 2, + Self { reveal: traits::Reveal::Selection, constness: hir::Constness::Const } => 3, + Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 4, + Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 5, } } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { match ptr { - 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, - 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, - 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, - 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const }, + 0 => Self { reveal: traits::Reveal::Selection, constness: hir::Constness::NotConst }, + 1 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, + 2 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, + 3 => Self { reveal: traits::Reveal::Selection, constness: hir::Constness::Const }, + 4 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, + 5 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const }, _ => std::hint::unreachable_unchecked(), } } @@ -1352,7 +1349,7 @@ impl<'tcx> ParamEnv<'tcx> { } pub fn with_reveal_selection(mut self) -> Self { - self.packed.set_tag(Reveal::Selection); + self.packed.set_tag(ParamTag { reveal: Reveal::Selection, ..self.packed.tag() }); self } From deaebac6dd864409a9efb171c3807b360b27a739 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:17:54 +0100 Subject: [PATCH 06/12] update queries for deduplication --- .../src/const_eval/eval_queries.rs | 245 +++++++++++------- .../src/interpret/eval_context.rs | 48 +--- .../rustc_const_eval/src/interpret/mod.rs | 2 +- .../rustc_middle/src/mir/interpret/queries.rs | 22 +- 4 files changed, 169 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c5412affafe23..175685fcfa2ee 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,4 +1,4 @@ -use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; +use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalError, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, @@ -10,15 +10,16 @@ use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::mir; -use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::interpret::{ + ConstDedupError, ConstDedupResult, ConstErrorEmitted, ConstEvalErr, ConstOrigin, ErrorHandled, +}; use rustc_middle::mir::pretty::display_allocation; use rustc_middle::traits::Reveal; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{LayoutError, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::Abi; -use std::borrow::Cow; use std::convert::TryInto; pub fn note_on_undefined_behavior_error() -> &'static str { @@ -28,6 +29,7 @@ pub fn note_on_undefined_behavior_error() -> &'static str { } // Returns a pointer to where the result lives +#[instrument(skip(ecx, body), level = "debug")] fn eval_body_using_ecx<'mir, 'tcx>( ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, cid: GlobalId<'tcx>, @@ -66,6 +68,8 @@ fn eval_body_using_ecx<'mir, 'tcx>( StackPopCleanup::None { cleanup: false }, )?; + debug!("returned from push_stack_frame"); + // The main interpreter loop. ecx.run()?; @@ -160,6 +164,7 @@ pub(super) fn op_to_const<'tcx>( ConstValue::Scalar(Scalar::ZST) } }; + match immediate { Ok(ref mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above @@ -212,81 +217,99 @@ fn turn_into_const_value<'tcx>( op_to_const(&ecx, &mplace.into()) } +#[instrument(skip(tcx), level = "debug")] pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { assert!(key.param_env.constness() == hir::Constness::Const); - // see comment in eval_to_allocation_raw_provider for what we're doing here - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_const_value_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } + let (param_env, id) = key.into_parts(); + let reveal = param_env.reveal(); // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.param_env); + let ty = key.value.instance.ty(tcx, param_env); let substs = match ty.kind() { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { - let span = tcx.def_span(def_id); - let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span }; - error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") - }); + match eval_nullary_intrinsic(tcx, param_env, def_id, substs) { + Ok(val) => { + // store result for deduplication + let res = ConstDedupResult::new(reveal, Ok(val), None); + tcx.save_const_value_for_dedup(id, res); + + return Ok(val); + } + Err(e) => { + let span = tcx.def_span(def_id); + let error = ConstEvalErr { error: e.into_kind(), stacktrace: vec![], span }; + + let error_handled = tcx.handle_err_for_dedup( + id, + ConstOrigin::ConstValue, + error, + reveal, + span, + |e| { + tcx.report_and_add_error( + id, + e, + span, + "could not evaluate nullary intrinsic", + ) + }, + ); + + return Err(error_handled); + } + } } - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) + let result = + tcx.dedup_eval_alloc_raw(key, None).map(|val| turn_into_const_value(tcx, val, key)); + + // store result for deduplication + let val = ConstDedupResult::new( + reveal, + result.map_err(|e| ConstDedupError::new_handled(e, reveal)), + None, + ); + tcx.save_const_value_for_dedup(id, val); + + result } +#[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { assert!(key.param_env.constness() == hir::Constness::Const); - // Because the constant is computed twice (once per value of `Reveal`), we are at risk of - // reporting the same error twice here. To resolve this, we check whether we can evaluate the - // constant in the more restrictive `Reveal::UserFacing`, which most likely already was - // computed. For a large percentage of constants that will already have succeeded. Only - // associated constants of generic functions will fail due to not enough monomorphization - // information being available. - - // In case we fail in the `UserFacing` variant, we just do the real computation. - if key.param_env.reveal() == Reveal::All { - let mut key = key; - key.param_env = key.param_env.with_user_facing(); - match tcx.eval_to_allocation_raw(key) { - // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} - // deduplicate calls - other => return other, - } - } + let (param_env, cid) = key.into_parts(); + let reveal = param_env.reveal(); + if cfg!(debug_assertions) { // Make sure we format the instance even if we do not print it. // This serves as a regression test against an ICE on printing. // The next two lines concatenated contain some discussion: // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ // subject/anon_const_instance_printing/near/135980032 - let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); + let instance = with_no_trimmed_paths(|| cid.instance.to_string()); trace!("const eval: {:?} ({})", key, instance); } - let cid = key.value; let def = cid.instance.def.with_opt_param(); if let Some(def) = def.as_local() { if tcx.has_typeck_results(def.did) { if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors { - return Err(ErrorHandled::Reported(error_reported)); + let err = ConstErrorEmitted::Emitted(ErrorHandled::Reported(error_reported)); + let err_handled = + tcx.handle_reported_error_for_dedup(cid, ConstOrigin::Alloc, err, reveal); + + return Err(err_handled); } } if !tcx.is_mir_available(def.did) { @@ -294,10 +317,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx.def_span(def.did), &format!("no MIR body is available for {:?}", def.did), ); - return Err(ErrorHandled::Reported(ErrorReported {})); + + let err = ConstErrorEmitted::Emitted(ErrorHandled::Reported(ErrorReported {})); + let err_handled = + tcx.handle_reported_error_for_dedup(cid, ConstOrigin::Alloc, err, reveal); + + return Err(err_handled); } if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured { - return Err(ErrorHandled::Reported(error_reported)); + let err = ConstErrorEmitted::Emitted(ErrorHandled::Reported(error_reported)); + let err_handled = + tcx.handle_reported_error_for_dedup(cid, ConstOrigin::Alloc, err, reveal); + + return Err(err_handled); } } @@ -316,46 +348,41 @@ pub fn eval_to_allocation_raw_provider<'tcx>( let res = ecx.load_mir(cid.instance.def, cid.promoted); match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { Err(error) => { - let err = ConstEvalErr::new(&ecx, error, None); - // Some CTFE errors raise just a lint, not a hard error; see - // . - let is_hard_err = if let Some(def) = def.as_local() { - // (Associated) consts only emit a lint, since they might be unused. - !matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst) - // check if the inner InterpError is hard - || err.error.is_hard_err() - } else { - // use of broken constant from other crate: always an error - true - }; - - if is_hard_err { - let msg = if is_static { - Cow::from("could not evaluate static initializer") - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its substs: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &key.value.instance; - if !instance.substs.is_empty() { - let instance = with_no_trimmed_paths(|| instance.to_string()); - let msg = format!("evaluation of `{}` failed", instance); - Cow::from(msg) - } else { - Cow::from("evaluation of constant value failed") + debug!("error from eval_body_using_ecx: {:?}", error); + if reveal == Reveal::Selection { + match error.kind() { + err_inval!(Layout(LayoutError::Unknown(_))) + | err_inval!(TooGeneric) + | err_inval!(AlreadyReported(_)) => { + // We do want to report these errors } - }; + _ => { + let err = ConstEvalError::new(&ecx, error, None); + let error_handled = tcx.handle_err_for_dedup( + cid, + ConstOrigin::Alloc, + err.into_inner(), + reveal, + ecx.cur_span(), + |_e| ErrorHandled::Silent(cid), + ); - Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg)) - } else { - let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did); - Err(err.report_as_lint( - tcx.at(tcx.def_span(def.did)), - "any use of this value will cause an error", - hir_id, - Some(err.span), - )) + return Err(error_handled); + } + } } + + let err = ConstEvalError::new(&ecx, error, None); + let err_handled = tcx.handle_err_for_dedup( + cid, + ConstOrigin::Alloc, + err.into_inner(), + reveal, + ecx.cur_span(), + |e| tcx.report_alloc_error(cid, param_env, e, is_static, def, ecx.cur_span()), + ); + + Err(err_handled) } Ok(mplace) => { // Since evaluation had no errors, validate the resulting constant. @@ -377,27 +404,49 @@ pub fn eval_to_allocation_raw_provider<'tcx>( } }; let alloc_id = mplace.ptr.provenance.unwrap(); + if let Err(error) = validation { // Validation failed, report an error. This is always a hard error. - let err = ConstEvalErr::new(&ecx, error, None); - Err(err.struct_error( - ecx.tcx, - "it is undefined behavior to use this value", - |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.note(&format!( - "the raw bytes of the constant ({}", - display_allocation( - *ecx.tcx, - ecx.tcx.global_alloc(alloc_id).unwrap_memory() - ) - )); - diag.emit(); + let err = ConstEvalError::new(&ecx, error, None).into_inner(); + + // FIXME: Do we also want to keep these silent with Reveal::Selection? + let error_handled = tcx.handle_err_for_dedup( + cid, + ConstOrigin::Alloc, + err, + reveal, + ecx.cur_span(), + |e| { + e.struct_error( + ecx.tcx, + "it is undefined behavior to use this value", + |mut diag| { + diag.note(note_on_undefined_behavior_error()); + diag.note(&format!( + "the raw bytes of the constant ({}", + display_allocation( + *ecx.tcx, + ecx.tcx.global_alloc(alloc_id).unwrap_memory() + ) + )); + diag.emit(); + }, + ) + .get_error() }, - )) + ); + + Err(error_handled) } else { // Convert to raw constant - Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty }) + let const_alloc = ConstAlloc { alloc_id, ty: mplace.layout.ty }; + let result = Ok(const_alloc); + let val = ConstDedupResult::new(reveal, result, None); + + // store result in order to deduplicate later + tcx.save_alloc_for_dedup(cid, val); + + Ok(const_alloc) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 246807a112a40..b063abf768ddf 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,13 +1,12 @@ use std::cell::Cell; -use std::fmt; use std::mem; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; +use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::mir; -use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo}; +use rustc_middle::mir::interpret::{FrameInfo, InterpError, InvalidProgramInfo}; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, @@ -18,7 +17,7 @@ use rustc_middle::ty::{ use rustc_mir_dataflow::storage::AlwaysLiveLocals; use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; -use rustc_span::{Pos, Span}; +use rustc_span::Span; use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout}; use super::{ @@ -129,14 +128,6 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { pub(super) loc: Result, } -/// What we store about a frame in an interpreter backtrace. -#[derive(Debug)] -pub struct FrameInfo<'tcx> { - pub instance: ty::Instance<'tcx>, - pub span: Span, - pub lint_root: Option, -} - /// Unwind information. #[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] pub enum StackPopUnwind { @@ -265,32 +256,6 @@ impl<'mir, 'tcx, Tag: Provenance, Extra> Frame<'mir, 'tcx, Tag, Extra> { } } -impl<'tcx> fmt::Display for FrameInfo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - if tcx.def_key(self.instance.def_id()).disambiguated_data.data - == DefPathData::ClosureExpr - { - write!(f, "inside closure")?; - } else { - write!(f, "inside `{}`", self.instance)?; - } - if !self.span.is_dummy() { - let sm = tcx.sess.source_map(); - let lo = sm.lookup_char_pos(self.span.lo()); - write!( - f, - " at {}:{}:{}", - sm.filename_for_diagnostics(&lo.file.name), - lo.line, - lo.col.to_usize() + 1 - )?; - } - Ok(()) - }) - } -} - impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &TargetDataLayout { @@ -926,6 +891,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + #[instrument(skip(self), level = "debug")] pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, @@ -941,8 +907,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env }; let param_env = param_env.with_const(); - let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; - self.raw_const_to_mplace(val) + let val = self.tcx.dedup_eval_alloc_raw(param_env.and(gid), None); + debug!(?val); + + self.raw_const_to_mplace(val?) } #[must_use] diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2b9fe56599715..22b2e89091002 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -19,7 +19,7 @@ mod visitor; pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::eval_context::{ - Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, + Frame, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, }; pub use self::intern::{intern_const_alloc_recursive, InternKind}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index f983185563315..53f253f4cc49a 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -58,6 +58,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Evaluate a constant. + #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id( self, param_env: ty::ParamEnv<'tcx>, @@ -68,18 +69,18 @@ impl<'tcx> TyCtxt<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(param_env.and(cid)); - if let Some(span) = span { - self.at(span).eval_to_const_value_raw(inputs) - } else { - self.eval_to_const_value_raw(inputs) - } + + let raw_const = self.dedup_eval_const_value_raw(inputs); + debug!(?raw_const); + + raw_const } /// Evaluate a static's initializer, returning the allocation of the initializer's memory. pub fn eval_static_initializer( self, def_id: DefId, - ) -> Result<&'tcx mir::Allocation, ErrorHandled> { + ) -> Result<&'tcx mir::Allocation, ErrorHandled<'tcx>> { trace!("eval_static_initializer: Need to compute {:?}", def_id); assert!(self.is_static(def_id)); let instance = ty::Instance::mono(self, def_id); @@ -88,14 +89,17 @@ impl<'tcx> TyCtxt<'tcx> { } /// Evaluate anything constant-like, returning the allocation of the final memory. + #[instrument(skip(self), level = "debug")] fn eval_to_allocation( self, gid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Result<&'tcx mir::Allocation, ErrorHandled> { + ) -> Result<&'tcx mir::Allocation, ErrorHandled<'tcx>> { let param_env = param_env.with_const(); trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; - Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) + let raw_const = self.dedup_eval_alloc_raw(param_env.and(gid), None); + debug!(?raw_const); + + Ok(self.global_alloc(raw_const?.alloc_id).unwrap_memory()) } } From 49799f2ba16bc6555df8193b1f36f3343e6ba783 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:22:22 +0100 Subject: [PATCH 07/12] update NotConstEvaluatable --- compiler/rustc_middle/src/thir/abstract_const.rs | 10 ++++++---- compiler/rustc_middle/src/traits/mod.rs | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index f80beadd6e551..80ac17e006aef 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -1,5 +1,6 @@ //! A subset of a mir body used for const evaluatability checking. use crate::mir; +use crate::mir::interpret::GlobalId; use crate::ty::{self, Ty, TyCtxt}; use rustc_errors::ErrorReported; @@ -30,20 +31,21 @@ pub enum Node<'tcx> { } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum NotConstEvaluatable { +pub enum NotConstEvaluatable<'tcx> { Error(ErrorReported), MentionsInfer, MentionsParam, + Silent(GlobalId<'tcx>), } -impl From for NotConstEvaluatable { - fn from(e: ErrorReported) -> NotConstEvaluatable { +impl<'tcx> From for NotConstEvaluatable<'tcx> { + fn from(e: ErrorReported) -> NotConstEvaluatable<'tcx> { NotConstEvaluatable::Error(e) } } TrivialTypeFoldableAndLiftImpls! { - NotConstEvaluatable, + NotConstEvaluatable<'tcx>, } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index c5a883d876818..a44441d491e23 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -456,7 +456,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_code: Lrc>, } -#[derive(Clone, Debug, TypeFoldable, Lift)] +#[derive(Clone, Debug, TypeFoldable)] pub enum SelectionError<'tcx> { /// The trait is not implemented. Unimplemented, @@ -471,7 +471,7 @@ pub enum SelectionError<'tcx> { /// The trait pointed by `DefId` is not object safe. TraitNotObjectSafe(DefId), /// A given constant couldn't be evaluated. - NotConstEvaluatable(NotConstEvaluatable), + NotConstEvaluatable(NotConstEvaluatable<'tcx>), /// Exceeded the recursion depth during type projection. Overflow, /// Signaling that an error has already been emitted, to avoid From 9728930e8234eb4bb1fcc727ca5e40d763aa1607 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:23:44 +0100 Subject: [PATCH 08/12] deduplication logic in trait selection --- .../src/traits/const_evaluatable.rs | 3 ++- .../src/traits/fulfill.rs | 21 ++++++++++++------- .../rustc_trait_selection/src/traits/mod.rs | 1 + .../src/traits/project.rs | 3 ++- .../src/traits/select/mod.rs | 18 ++++++++-------- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 710803fead242..192f99438be65 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -32,7 +32,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( uv: ty::Unevaluated<'tcx, ()>, param_env: ty::ParamEnv<'tcx>, span: Span, -) -> Result<(), NotConstEvaluatable> { +) -> Result<(), NotConstEvaluatable<'tcx>> { debug!("is_const_evaluatable({:?})", uv); if infcx.tcx.features().generic_const_exprs { let tcx = infcx.tcx; @@ -174,6 +174,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Err(NotConstEvaluatable::Error(ErrorReported)) } Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Err(ErrorHandled::Silent(id)) => Err(NotConstEvaluatable::Silent(id)), Ok(_) => Ok(()), } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index cb5798b188c64..0716228ded8a3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -528,12 +528,14 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateKind::ConstEvaluatable(uv) => { - match const_evaluatable::is_const_evaluatable( + let res = const_evaluatable::is_const_evaluatable( self.selcx.infcx(), uv, - obligation.param_env, + obligation.param_env.with_reveal_selection(), obligation.cause.span, - ) { + ); + + match res { Ok(()) => ProcessResult::Changed(vec![]), Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); @@ -546,7 +548,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } Err( e @ NotConstEvaluatable::MentionsParam - | e @ NotConstEvaluatable::Error(_), + | e @ NotConstEvaluatable::Error(_) + | e @ NotConstEvaluatable::Silent(_), ) => ProcessResult::Error(CodeSelectionError( SelectionError::NotConstEvaluatable(e), )), @@ -625,10 +628,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { "ConstEquate: const_eval_resolve returned an unexpected error" ) } - (Err(ErrorHandled::Silent), _) | (_, Err(ErrorHandled::Silent)) => { - ProcessResult::Error(CodeSelectionError(ConstEvalFailure( - ErrorHandled::Silent, - ))) + (Err(ErrorHandled::Silent(id)), _) | (_, Err(ErrorHandled::Silent(id))) => { + ProcessResult::Error(CodeSelectionError( + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Silent( + id, + )), + )) } (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a8f26982d2e42..b7660dddc8ce0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -273,6 +273,7 @@ fn do_normalize_predicates<'tcx>( // FIXME: this is gonna need to be removed ... /// Normalizes the parameter environment, reporting errors if they occur. +#[instrument(skip(tcx), level = "debug")] pub fn normalize_param_env_or_error<'tcx>( tcx: TyCtxt<'tcx>, region_context: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 96d5a85f8dbe2..dbd6cf1bd06d4 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -26,6 +26,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; + use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -296,7 +297,7 @@ where pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool { match reveal { - Reveal::UserFacing => value + Reveal::Selection | Reveal::UserFacing => value .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), Reveal::All => value.has_type_flags( ty::TypeFlags::HAS_TY_PROJECTION diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b7c116fa89b97..fb638d020414b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -675,10 +675,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => Ok(EvaluatedToErr), } } - (Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent), _) - | (_, Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent)) => { - Ok(EvaluatedToErr) - } + ( + Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent(_)), + _, + ) + | ( + _, + Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Silent(_)), + ) => Ok(EvaluatedToErr), (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { span_bug!( obligation.cause.span(self.tcx()), @@ -2659,11 +2663,7 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { } fn depth(&self) -> usize { - if let Some(head) = self.head { - head.depth - } else { - 0 - } + if let Some(head) = self.head { head.depth } else { 0 } } } From ffeec17b22bd81932532bbd2753bfd72d2db2cee Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:24:23 +0100 Subject: [PATCH 09/12] update error reporting in trait selection for deduplication --- .../src/traits/error_reporting/mod.rs | 93 ++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 19ce6c3a44085..87205eaf8214f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -19,6 +19,9 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; +use rustc_middle::mir::interpret::{ + ConstDedupResult, ConstErrorEmitted, ErrorHandled, SilentError, +}; use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; @@ -238,6 +241,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { error: &SelectionError<'tcx>, fallback_has_occurred: bool, ) { + debug!("report_selection_error(error: {:?})", error); let tcx = self.tcx; let mut span = obligation.cause.span; @@ -799,7 +803,94 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { bug!( "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`" ) - ConstEvalFailure(ErrorHandled::Silent) => { + } + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Silent(id)) => { + // try to report a ConstEvalErr which gives better diagnostics by providing + // information about why the constant couldn't be evaluated. + let const_dedup_map = tcx.dedup_const_map.lock(); + debug!("const_dedup_map: {:#?}", &const_dedup_map); + debug!(?id); + + // FIXME This only reports errors stored as `ConstDedupResult::Selection` + // but we should also report cached errors with other Reveal variants + // here. See e.g. test `ui/const-generics/generic_const_exprs/issue-62504.rs` + // which fails to report the `TooGeneric` error because it was stored + // with `Reveal::All`. + if !const_dedup_map.error_reported_map.borrow().contains_key(&id) { + if let Some(ConstDedupResult::Selection(( + Err(SilentError::ConstErr(err)), + sp, + ))) = const_dedup_map.alloc_map.borrow().get(&id) + { + let def = id.instance.def.with_opt_param(); + let is_static = tcx.is_static(def.did); + + let err_emitted = tcx.report_const_alloc_error( + &const_dedup_map, + id, + obligation.param_env, + err, + is_static, + def, + *sp, + ); + + match err_emitted { + ConstErrorEmitted::NotEmitted(err) => { + if let ErrorHandled::TooGeneric = err { + let selection_err = SelectionError::NotConstEvaluatable( + NotConstEvaluatable::MentionsParam, + ); + + self.report_selection_error( + obligation.clone(), + root_obligation, + &selection_err, + fallback_has_occurred, + ); + } + } + _ => {} + } + } else { + if let Some(ConstDedupResult::Selection(( + Err(SilentError::ConstErr(err)), + sp, + ))) = const_dedup_map.const_val_map.borrow().get(&id) + { + let def = id.instance.def.with_opt_param(); + let is_static = tcx.is_static(def.did); + + let err_emitted = tcx.report_const_alloc_error( + &const_dedup_map, + id, + obligation.param_env, + err, + is_static, + def, + *sp, + ); + + match err_emitted { + ConstErrorEmitted::NotEmitted(err) => { + if let ErrorHandled::TooGeneric = err { + let selection_err = SelectionError::NotConstEvaluatable( + NotConstEvaluatable::MentionsParam, + ); + + self.report_selection_error( + obligation.clone(), + root_obligation, + &selection_err, + fallback_has_occurred, + ); + } + } + _ => {} + } + } + } + } tcx.sess.struct_span_err(span, "failed to evaluate the given constant") } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { From 135a98f7b3a247f536fe18788de7d667dc1a8e42 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:25:04 +0100 Subject: [PATCH 10/12] update code generation --- compiler/rustc_codegen_cranelift/src/constant.rs | 2 +- compiler/rustc_codegen_gcc/src/consts.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/constant.rs | 6 +++--- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 8b19cbf74a054..8ffb59a6dd642 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -64,7 +64,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { err ); } - ErrorHandled::Silent => { + ErrorHandled::Silent(_) => { span_bug!( constant.span, "codegen encountered silent error", diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 205498acc3187..5e374b7db2776 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -334,7 +334,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Alloca cx.const_struct(&llvals, true) } -pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> { +pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled<'tcx>> { let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_gcc(cx, alloc), alloc)) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index d43c7c6065179..168b983a95817 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -130,7 +130,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> pub fn codegen_static_initializer<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, -) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { +) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled<'tcx>> { let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 93b39dc8e9ee1..faca33a736dd3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -14,7 +14,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, bx: &mut Bx, constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { + ) -> Result, ErrorHandled<'tcx>> { let val = self.eval_mir_constant(constant)?; let ty = self.monomorphize(constant.ty()); Ok(OperandRef::from_const(bx, val, ty)) @@ -23,7 +23,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant( &self, constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { + ) -> Result, ErrorHandled<'tcx>> { let ct = self.monomorphize(constant.literal); let ct = match ct { mir::ConstantKind::Ty(ct) => ct, @@ -53,7 +53,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result, ErrorHandled>, + constant: Result, ErrorHandled<'tcx>>, ) -> (Bx::Value, Ty<'tcx>) { constant .map(|val| { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index dbb5069d57d54..7dae4482183eb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -191,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ErrorHandled::TooGeneric => { span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) } - ErrorHandled::Silent => { + ErrorHandled::Silent(_) => { span_bug!(const_.span, "silent error during codegen") } } From 614301aa25bb38ab392278db224958d73ad32058 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 20:25:34 +0100 Subject: [PATCH 11/12] update tests --- ...ssociated-const-type-parameter-arrays-2.rs | 1 + ...iated-const-type-parameter-arrays-2.stderr | 8 +- .../defaults-cyclic-fail.stderr | 20 ----- ...9-assoc-const-static-recursion-impl.stderr | 20 ----- ...onst-static-recursion-trait-default.stderr | 20 ----- ...-assoc-const-static-recursion-trait.stderr | 20 ----- .../from-sig-fail.rs | 12 --- .../from-sig-fail.stderr | 20 ----- .../simple_fail.full.stderr | 17 ---- .../const_evaluatable_checked/simple_fail.rs | 17 ---- .../defaults/default-param-wf-concrete.rs | 1 + .../defaults/default-param-wf-concrete.stderr | 8 +- src/test/ui/const-generics/defaults/wfness.rs | 1 + .../ui/const-generics/defaults/wfness.stderr | 14 +++- .../generic_const_exprs/from-sig-fail.rs | 2 + .../generic_const_exprs/from-sig-fail.stderr | 26 +++++- .../issue-62504.min.stderr | 4 +- .../generic_const_exprs/issue-62504.rs | 2 +- .../generic_const_exprs/issue-80742.rs | 1 + .../generic_const_exprs/issue-80742.stderr | 47 +++++------ .../silent-selection-err.rs | 43 ---------- .../generic_const_exprs/simple_fail.rs | 2 + .../generic_const_exprs/simple_fail.stderr | 20 ++++- .../issues/issue-62878.full.stderr | 14 +++- .../ui/const-generics/issues/issue-62878.rs | 2 + .../issues/issue-67739.min.stderr | 8 +- .../ui/const-generics/issues/issue-67739.rs | 5 +- .../issues/issue-71169.full.stderr | 14 +++- .../ui/const-generics/issues/issue-71169.rs | 2 + .../ui/const-generics/issues/issue-86530.rs | 1 + .../const-generics/issues/issue-86530.stderr | 17 +++- .../legacy-const-generics-bad.rs | 2 + .../legacy-const-generics-bad.stderr | 16 +++- ...const-expression-suggest-missing-braces.rs | 9 ++ ...t-expression-suggest-missing-braces.stderr | 82 +++++++++++++++---- .../invalid-patterns.64bit.stderr | 64 +++++++++++++-- .../min_const_generics/invalid-patterns.rs | 8 ++ ...ms-in-ct-in-ty-param-lazy-norm.full.stderr | 4 +- ...ams-in-ct-in-ty-param-lazy-norm.min.stderr | 18 +++- .../params-in-ct-in-ty-param-lazy-norm.rs | 2 + .../sneaky-array-repeat-expr.rs | 2 + .../sneaky-array-repeat-expr.stderr | 16 +++- .../const-eval/const-eval-overflow-3b.rs | 1 + .../const-eval/const-eval-overflow-3b.stderr | 8 +- .../ui/consts/const-eval/infinite_loop.rs | 1 + .../ui/consts/const-eval/infinite_loop.stderr | 8 +- .../ui/consts/const-eval/issue-49296.stderr | 8 -- src/test/ui/consts/const-eval/issue-52475.rs | 4 +- .../ui/consts/const-eval/issue-52475.stderr | 8 +- .../consts/const-eval/match-test-ptr-null.rs | 1 + .../const-eval/match-test-ptr-null.stderr | 17 +++- .../ui/consts/const-eval/ub-enum.64bit.stderr | 20 ++--- src/test/ui/consts/const-size_of-cycle.stderr | 10 --- src/test/ui/consts/issue-3521.fixed | 1 + src/test/ui/consts/issue-3521.rs | 1 + src/test/ui/consts/issue-3521.stderr | 8 +- src/test/ui/consts/issue-36163.stderr | 20 ----- src/test/ui/consts/issue-44415.stderr | 10 --- src/test/ui/consts/issue-52060.rs | 1 + src/test/ui/consts/issue-52060.stderr | 8 +- src/test/ui/consts/issue-52432.rs | 10 --- src/test/ui/consts/issue-52432.stderr | 28 ------- .../consts/issue-66693-panic-in-array-len.rs | 2 + .../issue-66693-panic-in-array-len.stderr | 18 +++- src/test/ui/consts/issue-91434.rs | 1 + src/test/ui/consts/issue-91434.stderr | 8 +- .../recursive-zst-static.default.stderr | 12 +-- .../recursive-zst-static.unleash.stderr | 12 +-- src/test/ui/consts/too_generic_eval_ice.rs | 3 +- .../ui/consts/too_generic_eval_ice.stderr | 12 ++- .../write-to-static-mut-in-static.stderr | 12 +-- .../issue-70453-generics-in-discr-ice-2.rs | 1 + ...issue-70453-generics-in-discr-ice-2.stderr | 8 +- .../issue-70453-generics-in-discr-ice.rs | 1 + .../issue-70453-generics-in-discr-ice.stderr | 8 +- .../issue-70453-polymorphic-ctfe.rs | 1 + .../issue-70453-polymorphic-ctfe.stderr | 8 +- src/test/ui/enum/issue-67945-1.rs | 4 +- src/test/ui/enum/issue-67945-1.stderr | 16 +++- src/test/ui/enum/issue-67945-2.rs | 1 + src/test/ui/enum/issue-67945-2.stderr | 8 +- .../param-in-ct-in-ty-param-default.rs | 1 + .../param-in-ct-in-ty-param-default.stderr | 8 +- src/test/ui/issues/issue-17252.stderr | 10 --- src/test/ui/issues/issue-23302-1.stderr | 10 --- src/test/ui/issues/issue-23302-2.stderr | 10 --- src/test/ui/issues/issue-23302-3.stderr | 20 ----- src/test/ui/issues/issue-39211.rs | 1 + src/test/ui/issues/issue-39211.stderr | 8 +- ...issue-69602-type-err-during-codegen-ice.rs | 2 + ...e-69602-type-err-during-codegen-ice.stderr | 16 +++- src/test/ui/issues/issue-77919.rs | 1 + src/test/ui/issues/issue-77919.stderr | 14 +++- src/test/ui/mir/issue-80742.rs | 7 +- src/test/ui/mir/issue-80742.stderr | 57 ++++++++----- .../recursive-static-definition.stderr | 12 +-- src/test/ui/resolve/issue-50599.rs | 1 + src/test/ui/resolve/issue-50599.stderr | 8 +- .../issue-86188-return-not-in-fn-body.rs | 1 + .../issue-86188-return-not-in-fn-body.stderr | 20 ++++- src/test/ui/treat-err-as-bug/err.stderr | 2 +- .../self-in-enum-definition.stderr | 10 --- 102 files changed, 620 insertions(+), 520 deletions(-) delete mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs delete mode 100644 src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr delete mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr delete mode 100644 src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs delete mode 100644 src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs delete mode 100644 src/test/ui/consts/issue-52432.rs delete mode 100644 src/test/ui/consts/issue-52432.stderr diff --git a/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs index 8fe79b97d9ba2..f7af377732dd3 100644 --- a/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs +++ b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs @@ -15,6 +15,7 @@ impl Foo for Def { pub fn test() { let _array = [4; ::Y]; //~^ ERROR constant expression depends on a generic parameter + //~| ERROR failed to evaluate } fn main() { diff --git a/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr index 0bc019b2dc875..6fbffddc90df6 100644 --- a/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr +++ b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr @@ -6,5 +6,11 @@ LL | let _array = [4; ::Y]; | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/associated-const-type-parameter-arrays-2.rs:16:22 + | +LL | let _array = [4; ::Y]; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr index 9ae202bf5368b..e5a2777a47bc5 100644 --- a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr @@ -5,16 +5,6 @@ note: ...which requires simplifying constant for the type system `Tr::A`... | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Tr::A`... - --> $DIR/defaults-cyclic-fail.rs:6:5 - | -LL | const A: u8 = Self::B; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Tr::A`... - --> $DIR/defaults-cyclic-fail.rs:6:5 - | -LL | const A: u8 = Self::B; - | ^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | @@ -26,16 +16,6 @@ note: ...which requires simplifying constant for the type system `Tr::B`... | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Tr::B`... - --> $DIR/defaults-cyclic-fail.rs:8:5 - | -LL | const B: u8 = Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Tr::B`... - --> $DIR/defaults-cyclic-fail.rs:8:5 - | -LL | const B: u8 = Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index aaa9b63c8f5fd..1ec52e019d4c9 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `IMPL LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 - | -LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 - | -LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | @@ -25,16 +15,6 @@ note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index a65832b096fbc..4a6d0c5019ec5 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `DEFA LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 - | -LL | const DEFAULT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 - | -LL | const DEFAULT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | @@ -25,16 +15,6 @@ note: ...which requires simplifying constant for the type system `FooDefault::BA | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `FooDefault::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 - | -LL | const BAR: u32 = DEFAULT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `FooDefault::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 - | -LL | const BAR: u32 = DEFAULT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 1fea9c0dabaf4..727c326e594dc 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `TRAI LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 - | -LL | const TRAIT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 - | -LL | const TRAIT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | @@ -25,16 +15,6 @@ note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 - | -LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 - | -LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs deleted file mode 100644 index 87fdc63f6393e..0000000000000 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(const_generics, const_evaluatable_checked)] -#![allow(incomplete_features)] - -fn test() -> [u8; N - 1] { - todo!() -} - -fn main() { - test::<0>(); - //~^ ERROR failed to evaluate the given constant - //~| ERROR failed to evaluate the given constant -} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr deleted file mode 100644 index e94545235d115..0000000000000 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: failed to evaluate the given constant - --> $DIR/from-sig-fail.rs:9:5 - | -LL | fn test() -> [u8; N - 1] { - | ----- required by this bound in `test` -... -LL | test::<0>(); - | ^^^^^^^^^ - -error: failed to evaluate the given constant - --> $DIR/from-sig-fail.rs:9:5 - | -LL | fn test() -> [u8; N - 1] { - | ----- required by this bound in `test` -... -LL | test::<0>(); - | ^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr deleted file mode 100644 index c38c58897f305..0000000000000 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: failed to evaluate the given constant - --> $DIR/simple_fail.rs:14:5 - | -LL | fn test() -> Arr where Arr: Sized { - | ------ required by this bound in `test` -... -LL | test::<0>(); - | ^^^^^^^^^ - -error: failed to evaluate the given constant - --> $DIR/simple_fail.rs:14:5 - | -LL | test::<0>(); - | ^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs deleted file mode 100644 index f673b918fbcdd..0000000000000 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ /dev/null @@ -1,17 +0,0 @@ -// revisions: full min -#![cfg_attr(full, feature(const_generics))] -#![feature(const_evaluatable_checked)] -#![allow(incomplete_features)] - -type Arr = [u8; N - 1]; -//[min]~^ ERROR generic parameters may not be used in const operations - -fn test() -> Arr where Arr: Sized { - todo!() -} - -fn main() { - test::<0>(); - //[full]~^ ERROR failed to evaluate the given constant - //[full]~| ERROR failed to evaluate the given constant -} diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs index 41a52c7eb0d83..2d6d64bbf4de7 100644 --- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs @@ -1,3 +1,4 @@ struct Foo; //~^ ERROR evaluation of constant value failed +//~| ERROR failed to evaluate fn main() {} diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr index e8ebddade5c16..24ad7a1ad5a67 100644 --- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr @@ -4,6 +4,12 @@ error[E0080]: evaluation of constant value failed LL | struct Foo; | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/default-param-wf-concrete.rs:1:18 + | +LL | struct Foo; + | ^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/defaults/wfness.rs b/src/test/ui/const-generics/defaults/wfness.rs index d366040ba3ea6..e13b07f5ba0cb 100644 --- a/src/test/ui/const-generics/defaults/wfness.rs +++ b/src/test/ui/const-generics/defaults/wfness.rs @@ -1,5 +1,6 @@ struct Ooopsies; //~^ error: evaluation of constant value failed +//~| ERROR failed to evaluate trait Trait {} impl Trait<3> for () {} diff --git a/src/test/ui/const-generics/defaults/wfness.stderr b/src/test/ui/const-generics/defaults/wfness.stderr index facf0ae19f734..a4015479ac488 100644 --- a/src/test/ui/const-generics/defaults/wfness.stderr +++ b/src/test/ui/const-generics/defaults/wfness.stderr @@ -4,8 +4,14 @@ error[E0080]: evaluation of constant value failed LL | struct Ooopsies; | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow +error: failed to evaluate the given constant + --> $DIR/wfness.rs:1:23 + | +LL | struct Ooopsies; + | ^ + error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied - --> $DIR/wfness.rs:6:47 + --> $DIR/wfness.rs:7:47 | LL | struct WhereClause where (): Trait; | ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()` @@ -14,7 +20,7 @@ LL | struct WhereClause where (): Trait; <() as Trait<3_u8>> error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied - --> $DIR/wfness.rs:14:13 + --> $DIR/wfness.rs:15:13 | LL | fn foo() -> DependentDefaultWfness { | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()` @@ -22,12 +28,12 @@ LL | fn foo() -> DependentDefaultWfness { = help: the following implementations were found: <() as Trait<3_u8>> note: required by a bound in `WhereClause` - --> $DIR/wfness.rs:6:47 + --> $DIR/wfness.rs:7:47 | LL | struct WhereClause where (): Trait; | ^^^^^^^^ required by this bound in `WhereClause` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0080, E0277. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs index 90953145944fe..b0b8574f4a85f 100644 --- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs +++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.rs @@ -8,4 +8,6 @@ fn test() -> [u8; N - 1] { fn main() { test::<0>(); + //~^ ERROR failed to evaluate + //~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr index 31ccf97969472..c7a33b2571829 100644 --- a/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/from-sig-fail.stderr @@ -4,6 +4,30 @@ error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed LL | fn test() -> [u8; N - 1] { | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/from-sig-fail.rs:10:5 + | +LL | test::<0>(); + | ^^^^^^^^^ + | +note: required by a bound in `test` + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ required by this bound in `test` + +error: failed to evaluate the given constant + --> $DIR/from-sig-fail.rs:10:5 + | +LL | test::<0>(); + | ^^^^^^^^^^^ + | +note: required by a bound in `test` + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ required by this bound in `test` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-62504.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-62504.min.stderr index 5d45e302888d4..e032a80a95e05 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-62504.min.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-62504.min.stderr @@ -7,13 +7,11 @@ LL | ArrayHolder([0; Self::SIZE]) = note: expected array `[u32; X]` found array `[u32; _]` -error: constant expression depends on a generic parameter +error: failed to evaluate the given constant --> $DIR/issue-62504.rs:18:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-62504.rs b/src/test/ui/const-generics/generic_const_exprs/issue-62504.rs index a97f4b8ff3131..c182c33df78c2 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-62504.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-62504.rs @@ -18,7 +18,7 @@ impl ArrayHolder { ArrayHolder([0; Self::SIZE]) //~^ ERROR mismatched types //[full]~^^ ERROR unconstrained generic constant - //[min]~^^^ ERROR constant expression depends on a generic parameter + //[min]~^^^ ERROR failed to evaluate } } diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-80742.rs b/src/test/ui/const-generics/generic_const_exprs/issue-80742.rs index 275f69953024c..83e3f6f718372 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-80742.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-80742.rs @@ -29,4 +29,5 @@ where fn main() { let dst = Inline::::new(0); //~ ERROR //~^ ERROR + //~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr index 56cb11bacbe6b..ca8126e47ada1 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -1,17 +1,3 @@ -error[E0080]: evaluation of `Inline::::{constant#0}` failed - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | intrinsics::size_of::() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | size_of called on unsized type `dyn Debug` - | inside `std::mem::size_of::` at $SRC_DIR/core/src/mem/mod.rs:LL:COL - | - ::: $DIR/issue-80742.rs:22:10 - | -LL | [u8; size_of::() + 1]: , - | -------------- inside `Inline::::{constant#0}` at $DIR/issue-80742.rs:22:10 - error[E0599]: the function or associated item `new` exists for struct `Inline`, but its trait bounds were not satisfied --> $DIR/issue-80742.rs:30:36 | @@ -35,6 +21,23 @@ LL | pub trait Debug { = note: the following trait bounds were not satisfied: `dyn Debug: Sized` +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/issue-80742.rs:30:15 + | +LL | let dst = Inline::::new(0); + | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Debug` +note: required by a bound in `Inline` + --> $DIR/issue-80742.rs:12:15 + | +LL | struct Inline + | ^ required by this bound in `Inline` +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Inline + | ++++++++ + error[E0080]: evaluation of `Inline::::{constant#0}` failed --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | @@ -49,22 +52,20 @@ LL | intrinsics::size_of::() LL | [u8; size_of::() + 1]: , | -------------- inside `Inline::::{constant#0}` at $DIR/issue-80742.rs:14:10 -error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time +error: failed to evaluate the given constant --> $DIR/issue-80742.rs:30:15 | LL | let dst = Inline::::new(0); - | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^ | - = help: the trait `Sized` is not implemented for `dyn Debug` note: required by a bound in `Inline` - --> $DIR/issue-80742.rs:12:15 + --> $DIR/issue-80742.rs:14:10 | LL | struct Inline - | ^ required by this bound in `Inline` -help: consider relaxing the implicit `Sized` restriction - | -LL | struct Inline - | ++++++++ + | ------ required by a bound in this +LL | where +LL | [u8; size_of::() + 1]: , + | ^^^^^^^^^^^^^^^^^^ required by this bound in `Inline` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs b/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs deleted file mode 100644 index c292361e1cdfd..0000000000000 --- a/src/test/ui/const-generics/generic_const_exprs/silent-selection-err.rs +++ /dev/null @@ -1,43 +0,0 @@ -// run-pass -#![feature(const_generics, const_evaluatable_checked)] -#![allow(incomplete_features)] - -struct Array; - -trait Matrix { - fn do_it(&self) -> usize; -} - -impl Matrix for Array<0> { - fn do_it(&self) -> usize { - 0 - } -} - -impl Matrix for Array<1> { - fn do_it(&self) -> usize { - 1 - } -} - -impl Matrix for Array<2> { - fn do_it(&self) -> usize { - 2 - } -} - -impl Matrix for Array -where - [u8; N - 3]: Sized, -{ - fn do_it(&self) -> usize { - N + 1 - } -} - -fn main() { - assert_eq!(Array::<0>.do_it(), 0); - assert_eq!(Array::<1>.do_it(), 1); - assert_eq!(Array::<2>.do_it(), 2); - assert_eq!(Array::<3>.do_it(), 4); -} diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs index c47a350c7fb43..6a78a6b23cf23 100644 --- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs +++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.rs @@ -11,4 +11,6 @@ fn test() -> Arr where [u8; N - 1]: Sized { fn main() { test::<0>(); + //~^ ERROR failed to evaluate + //~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr index 99fc92fb4f0ad..e3b493c4c8833 100644 --- a/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/simple_fail.stderr @@ -4,12 +4,30 @@ error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed LL | fn test() -> Arr where [u8; N - 1]: Sized { | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow +error: failed to evaluate the given constant + --> $DIR/simple_fail.rs:13:5 + | +LL | test::<0>(); + | ^^^^^^^^^ + | +note: required by a bound in `test` + --> $DIR/simple_fail.rs:7:48 + | +LL | fn test() -> Arr where [u8; N - 1]: Sized { + | ^^^^^ required by this bound in `test` + error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed --> $DIR/simple_fail.rs:4:33 | LL | type Arr = [u8; N - 1]; | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow -error: aborting due to 2 previous errors +error: failed to evaluate the given constant + --> $DIR/simple_fail.rs:13:5 + | +LL | test::<0>(); + | ^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/issues/issue-62878.full.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr index f074a65313f12..b159fc54a8d0e 100644 --- a/src/test/ui/const-generics/issues/issue-62878.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -4,13 +4,25 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^ the type must not depend on the parameter `N` +error: failed to evaluate the given constant + --> $DIR/issue-62878.rs:10:14 + | +LL | foo::<_, {[1]}>(); + | ^^^^^ + +error: failed to evaluate the given constant + --> $DIR/issue-62878.rs:10:14 + | +LL | foo::<_, {[1]}>(); + | ^^^^^ + error[E0308]: mismatched types --> $DIR/issue-62878.rs:10:15 | LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0308, E0770. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index 38f5ff77b56a9..c606b667c1ecf 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -9,4 +9,6 @@ fn foo() {} fn main() { foo::<_, {[1]}>(); //[full]~^ ERROR mismatched types + //[full]~| ERROR failed to evaluate + //[full]~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr index dcbe5b94a6281..d89492f6a6ac5 100644 --- a/src/test/ui/const-generics/issues/issue-67739.min.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -6,5 +6,11 @@ LL | [0u8; mem::size_of::()]; | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-67739.rs:11:15 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index de0eb7f509ae5..26f06d7fcd0c1 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -9,8 +9,9 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //[min]~^ ERROR constant expression depends on a generic parameter - //[full]~^^ ERROR unconstrained generic constant + //[full]~^ ERROR unconstrained generic constant + //[min]~^^ ERROR constant expression depends on a generic parameter + //[min]~| ERROR failed to evaluate 0 } } diff --git a/src/test/ui/const-generics/issues/issue-71169.full.stderr b/src/test/ui/const-generics/issues/issue-71169.full.stderr index 1f5880f368ee2..d735d39ae1820 100644 --- a/src/test/ui/const-generics/issues/issue-71169.full.stderr +++ b/src/test/ui/const-generics/issues/issue-71169.full.stderr @@ -4,6 +4,18 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | fn foo() {} | ^^^ the type must not depend on the parameter `LEN` -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-71169.rs:10:14 + | +LL | foo::<4, DATA>(); + | ^^^^ + +error: failed to evaluate the given constant + --> $DIR/issue-71169.rs:10:14 + | +LL | foo::<4, DATA>(); + | ^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs index 617149a841893..fb96513d0c27c 100644 --- a/src/test/ui/const-generics/issues/issue-71169.rs +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -8,4 +8,6 @@ fn foo() {} fn main() { const DATA: [u8; 4] = *b"ABCD"; foo::<4, DATA>(); + //[full]~^ ERROR failed to evaluate + //[full]~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs index b024decd4e11c..94a8dc104fb73 100644 --- a/src/test/ui/const-generics/issues/issue-86530.rs +++ b/src/test/ui/const-generics/issues/issue-86530.rs @@ -15,6 +15,7 @@ where fn unit_literals() { z(" "); //~^ ERROR: the trait bound `&str: X` is not satisfied + //~| ERROR failed to evaluate } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr index c63857b2314e9..2eccc6a0e0bd5 100644 --- a/src/test/ui/const-generics/issues/issue-86530.stderr +++ b/src/test/ui/const-generics/issues/issue-86530.stderr @@ -15,6 +15,21 @@ LL | where LL | T: X, | ^ required by this bound in `z` -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-86530.rs:16:5 + | +LL | z(" "); + | ^ + | +note: required by a bound in `z` + --> $DIR/issue-86530.rs:11:10 + | +LL | fn z(t: T) + | - required by a bound in this +... +LL | [(); T::Y]: , + | ^^^^ required by this bound in `z` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/legacy-const-generics-bad.rs b/src/test/ui/const-generics/legacy-const-generics-bad.rs index 538eee337cc6d..6d137e873d065 100644 --- a/src/test/ui/const-generics/legacy-const-generics-bad.rs +++ b/src/test/ui/const-generics/legacy-const-generics-bad.rs @@ -6,11 +6,13 @@ fn foo() { let a = 1; legacy_const_generics::foo(0, a, 2); //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR failed to evaluate legacy_const_generics::foo(0, N, 2); legacy_const_generics::foo(0, N + 1, 2); //~^ ERROR generic parameters may not be used in const operations + //~| ERROR failed to evaluate } fn main() {} diff --git a/src/test/ui/const-generics/legacy-const-generics-bad.stderr b/src/test/ui/const-generics/legacy-const-generics-bad.stderr index 3c78dd6c78023..bb9982a8eca7d 100644 --- a/src/test/ui/const-generics/legacy-const-generics-bad.stderr +++ b/src/test/ui/const-generics/legacy-const-generics-bad.stderr @@ -7,7 +7,7 @@ LL | legacy_const_generics::foo(0, a, 2); | ^ non-constant value error: generic parameters may not be used in const operations - --> $DIR/legacy-const-generics-bad.rs:12:35 + --> $DIR/legacy-const-generics-bad.rs:13:35 | LL | legacy_const_generics::foo(0, N + 1, 2); | ^ cannot perform const operation using `N` @@ -15,6 +15,18 @@ LL | legacy_const_generics::foo(0, N + 1, 2); = help: const parameters may only be used as standalone arguments, i.e. `N` = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error: aborting due to 2 previous errors +error: failed to evaluate the given constant + --> $DIR/legacy-const-generics-bad.rs:7:35 + | +LL | legacy_const_generics::foo(0, a, 2); + | ^ + +error: failed to evaluate the given constant + --> $DIR/legacy-const-generics-bad.rs:13:35 + | +LL | legacy_const_generics::foo(0, N + 1, 2); + | ^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs index e12e07a28e763..1c30fbdb2c9ee 100644 --- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs +++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs @@ -4,6 +4,7 @@ const BAR: usize = 42; fn a() { foo::(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn b() { // FIXME(const_generics): these diagnostics are awful, because trait objects without `dyn` were @@ -18,30 +19,38 @@ fn c() { } fn d() { foo::(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn e() { foo::(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn f() { foo::<100 - BAR>(); //~ ERROR expressions must be enclosed in braces } fn g() { foo::()>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn h() { foo::()>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn i() { foo::() + BAR>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn j() { foo::() - BAR>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn k() { foo::()>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } fn l() { foo::()>(); //~ ERROR expected one of + //~| ERROR failed to evaluate } const fn bar() -> usize { diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr index d9bcc523b1fc4..038b3b271c175 100644 --- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr +++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr @@ -10,7 +10,7 @@ LL | foo::<{ BAR + 3 }>(); | + + error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:17:11 + --> $DIR/const-expression-suggest-missing-braces.rs:18:11 | LL | foo::<3 + 3>(); | ^^^^^ @@ -21,7 +21,7 @@ LL | foo::<{ 3 + 3 }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:20:15 + --> $DIR/const-expression-suggest-missing-braces.rs:21:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -32,7 +32,7 @@ LL | foo::<{ BAR - 3 }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:23:15 + --> $DIR/const-expression-suggest-missing-braces.rs:25:15 | LL | foo::(); | ^ expected one of `,` or `>` @@ -43,7 +43,7 @@ LL | foo::<{ BAR - BAR }>(); | + + error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/const-expression-suggest-missing-braces.rs:26:11 + --> $DIR/const-expression-suggest-missing-braces.rs:29:11 | LL | foo::<100 - BAR>(); | ^^^^^^^^^ @@ -54,7 +54,7 @@ LL | foo::<{ 100 - BAR }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:29:19 + --> $DIR/const-expression-suggest-missing-braces.rs:32:19 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -65,7 +65,7 @@ LL | foo::<{ bar() }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:32:21 + --> $DIR/const-expression-suggest-missing-braces.rs:36:21 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -76,7 +76,7 @@ LL | foo::<{ bar::() }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:35:21 + --> $DIR/const-expression-suggest-missing-braces.rs:40:21 | LL | foo::() + BAR>(); | ^ expected one of `,` or `>` @@ -87,7 +87,7 @@ LL | foo::<{ bar::() + BAR }>(); | + + error: expected one of `,` or `>`, found `(` - --> $DIR/const-expression-suggest-missing-braces.rs:38:21 + --> $DIR/const-expression-suggest-missing-braces.rs:44:21 | LL | foo::() - BAR>(); | ^ expected one of `,` or `>` @@ -98,7 +98,7 @@ LL | foo::<{ bar::() - BAR }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:41:15 + --> $DIR/const-expression-suggest-missing-braces.rs:48:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -109,7 +109,7 @@ LL | foo::<{ BAR - bar::() }>(); | + + error: expected one of `,` or `>`, found `-` - --> $DIR/const-expression-suggest-missing-braces.rs:44:15 + --> $DIR/const-expression-suggest-missing-braces.rs:52:15 | LL | foo::()>(); | ^ expected one of `,` or `>` @@ -120,24 +120,78 @@ LL | foo::<{ BAR - bar::() }>(); | + + error[E0404]: expected trait, found constant `BAR` - --> $DIR/const-expression-suggest-missing-braces.rs:11:11 + --> $DIR/const-expression-suggest-missing-braces.rs:12:11 | LL | foo::(); | ^^^ not a trait error[E0404]: expected trait, found constant `BAR` - --> $DIR/const-expression-suggest-missing-braces.rs:11:17 + --> $DIR/const-expression-suggest-missing-braces.rs:12:17 | LL | foo::(); | ^^^ not a trait +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:6:11 + | +LL | foo::(); + | ^^^^^^^ + error[E0747]: type provided when a constant was expected - --> $DIR/const-expression-suggest-missing-braces.rs:11:11 + --> $DIR/const-expression-suggest-missing-braces.rs:12:11 | LL | foo::(); | ^^^^^^^^^ -error: aborting due to 14 previous errors +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:21:11 + | +LL | foo::(); + | ^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:25:11 + | +LL | foo::(); + | ^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:32:11 + | +LL | foo::()>(); + | ^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:36:11 + | +LL | foo::()>(); + | ^^^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:40:11 + | +LL | foo::() + BAR>(); + | ^^^^^^^^^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:44:11 + | +LL | foo::() - BAR>(); + | ^^^^^^^^^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:48:11 + | +LL | foo::()>(); + | ^^^^^^^^^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/const-expression-suggest-missing-braces.rs:52:11 + | +LL | foo::()>(); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 23 previous errors Some errors have detailed explanations: E0404, E0747. For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 415a53a56274a..5d7f4394c1fbe 100644 --- a/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -4,26 +4,50 @@ error[E0308]: mismatched types LL | get_flag::(); | ^^^^ expected `char`, found `u8` +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:29:21 + | +LL | get_flag::(); + | ^^^^ + error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:14 + --> $DIR/invalid-patterns.rs:32:14 | LL | get_flag::<7, 'c'>(); | ^ expected `bool`, found integer +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:32:14 + | +LL | get_flag::<7, 'c'>(); + | ^ + error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 + --> $DIR/invalid-patterns.rs:35:14 | LL | get_flag::<42, 0x5ad>(); | ^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:18 + --> $DIR/invalid-patterns.rs:35:18 | LL | get_flag::<42, 0x5ad>(); | ^^^^^ expected `char`, found `u8` +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:35:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ + +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:35:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ + error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:38:21 + --> $DIR/invalid-patterns.rs:42:21 | LL | get_flag::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -33,8 +57,14 @@ LL | get_flag::(); __ __ __ __ │ ░░░░ } +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:42:21 + | +LL | get_flag::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:40:14 + --> $DIR/invalid-patterns.rs:45:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean @@ -44,8 +74,14 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); 42 │ B } +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:45:14 + | +LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:42:14 + --> $DIR/invalid-patterns.rs:48:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean @@ -56,7 +92,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-patterns.rs:42:47 + --> $DIR/invalid-patterns.rs:48:47 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -66,7 +102,19 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character __ __ __ __ │ ░░░░ } -error: aborting due to 8 previous errors +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:48:14 + | +LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: failed to evaluate the given constant + --> $DIR/invalid-patterns.rs:48:47 + | +LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors Some errors have detailed explanations: E0080, E0308. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/min_const_generics/invalid-patterns.rs b/src/test/ui/const-generics/min_const_generics/invalid-patterns.rs index 682e0eced9dff..54dabfb3446e6 100644 --- a/src/test/ui/const-generics/min_const_generics/invalid-patterns.rs +++ b/src/test/ui/const-generics/min_const_generics/invalid-patterns.rs @@ -28,18 +28,26 @@ fn main() { assert!(get_flag::().is_none()); get_flag::(); //~^ ERROR mismatched types + //~| ERROR failed to evaluate get_flag::<7, 'c'>(); //~^ ERROR mismatched types + //~| ERROR failed to evaluate get_flag::<42, 0x5ad>(); //~^ ERROR mismatched types + //~| ERROR failed to evaluate + //~| ERROR failed to evaluate //~| ERROR mismatched types get_flag::(); //~^ ERROR it is undefined behavior + //~| ERROR failed to evaluate get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); //~^ ERROR it is undefined behavior + //~| ERROR failed to evaluate get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); //~^ ERROR it is undefined behavior //~| ERROR it is undefined behavior + //~| ERROR failed to evaluate + //~| ERROR failed to evaluate } diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr index 9f0b2efae96ce..fbfc0f71a5037 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.full.stderr @@ -1,11 +1,11 @@ error: generic parameters with a default must be trailing - --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12 + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:9:12 | LL | struct Bar(T); | ^ error[E0128]: generic parameters with a default cannot use forward declared identifiers - --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21 + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:9:21 | LL | struct Bar(T); | ^ defaulted generic parameters cannot be forward declared diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index a5e70f6b9e648..05328c3344ac8 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -1,5 +1,5 @@ error: generic parameters with a default must be trailing - --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:12 + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:9:12 | LL | struct Bar(T); | ^ @@ -14,11 +14,23 @@ LL | struct Foo()]>(T, U); = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0128]: generic parameters with a default cannot use forward declared identifiers - --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21 + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:9:21 | LL | struct Bar(T); | ^ defaulted generic parameters cannot be forward declared -error: aborting due to 3 previous errors +error: failed to evaluate the given constant + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:5:15 + | +LL | struct Foo()]>(T, U); + | ^ + +error: failed to evaluate the given constant + --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:9:12 + | +LL | struct Bar(T); + | ^ + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0128`. diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs index b24a7afabd90f..8abb22069cd81 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs @@ -4,9 +4,11 @@ struct Foo()]>(T, U); //[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR failed to evaluate struct Bar(T); //~^ ERROR generic parameters with a default cannot use forward declared identifiers //~| ERROR generic parameters with a default +//[min]~| ERROR failed to evaluate fn main() {} diff --git a/src/test/ui/const-generics/sneaky-array-repeat-expr.rs b/src/test/ui/const-generics/sneaky-array-repeat-expr.rs index b147c246bdac8..0e86246dbc630 100644 --- a/src/test/ui/const-generics/sneaky-array-repeat-expr.rs +++ b/src/test/ui/const-generics/sneaky-array-repeat-expr.rs @@ -10,6 +10,7 @@ impl Trait for () { pub const fn foo() where (): Trait { let bar = [(); <()>::Assoc]; //~^ error: constant expression depends on a generic parameter + //~| ERROR failed to evaluate } trait Trait2 { @@ -24,6 +25,7 @@ impl Trait2 for () { pub const fn foo2() where (): Trait2 { let bar2 = [(); <()>::Assoc2]; //~^ error: constant expression depends on a generic parameter + //~| ERROR failed to evaluate } fn main() { diff --git a/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr b/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr index 5c77375d39934..4eab6b2e6a53a 100644 --- a/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr +++ b/src/test/ui/const-generics/sneaky-array-repeat-expr.stderr @@ -6,13 +6,25 @@ LL | let bar = [(); <()>::Assoc]; | = note: this may fail depending on what value the parameter takes +error: failed to evaluate the given constant + --> $DIR/sneaky-array-repeat-expr.rs:11:20 + | +LL | let bar = [(); <()>::Assoc]; + | ^^^^^^^^^^^ + error: constant expression depends on a generic parameter - --> $DIR/sneaky-array-repeat-expr.rs:25:21 + --> $DIR/sneaky-array-repeat-expr.rs:26:21 | LL | let bar2 = [(); <()>::Assoc2]; | ^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes -error: aborting due to 2 previous errors +error: failed to evaluate the given constant + --> $DIR/sneaky-array-repeat-expr.rs:26:21 + | +LL | let bar2 = [(); <()>::Assoc2]; + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index 480069e67fa28..20590026ad5b5 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -16,6 +16,7 @@ const A_I8_I = [0; (i8::MAX + 1u8) as usize]; //~^ ERROR mismatched types //~| ERROR cannot add `u8` to `i8` +//~| ERROR failed to evaluate fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 2b96b66819286..249ac865b0e59 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,7 +12,13 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add` is not implemented for `i8` -error: aborting due to 2 previous errors +error: failed to evaluate the given constant + --> $DIR/const-eval-overflow-3b.rs:16:11 + | +LL | = [0; (i8::MAX + 1u8) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/const-eval/infinite_loop.rs b/src/test/ui/consts/const-eval/infinite_loop.rs index 3c40c337cd005..08cf043e867ab 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.rs +++ b/src/test/ui/consts/const-eval/infinite_loop.rs @@ -6,6 +6,7 @@ fn main() { while n != 0 { n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed } n }]; diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index b30a53619b574..9770435678984 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -1,3 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/infinite_loop.rs:7:20 + | +LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; + | ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + error: failed to evaluate the given constant --> $DIR/infinite_loop.rs:4:18 | @@ -17,6 +23,6 @@ error[E0080]: evaluation of constant value failed LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; | ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index 5fc869d4ce137..bc3074b10bee6 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -2,15 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-49296.rs:11:16 | LL | const X: u64 = *wat(42); -<<<<<<< HEAD | ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed -======= - | ---------------^^^^^^^^- - | | - | pointer to alloc4 was dereferenced after this allocation got freed - | - = note: `#[deny(const_err)]` on by default ->>>>>>> 9ee0d801b76 (update tests) error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs index 6b8b42d417b35..fe5d52e4b1e49 100644 --- a/src/test/ui/consts/const-eval/issue-52475.rs +++ b/src/test/ui/consts/const-eval/issue-52475.rs @@ -3,7 +3,9 @@ fn main() { let mut x = &0; let mut n = 0; while n < 5 { - n = (n + 1) % 5; //~ ERROR evaluation of constant value failed + n = (n + 1) % 5; + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed x = &0; // Materialize a new AllocId } 0 diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index 5679f51c9ea54..aa09c2925c1f3 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -1,3 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-52475.rs:6:17 + | +LL | n = (n + 1) % 5; + | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + error: failed to evaluate the given constant --> $DIR/issue-52475.rs:2:18 | @@ -17,6 +23,6 @@ error[E0080]: evaluation of constant value failed LL | n = (n + 1) % 5; | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs index 4af97b5487929..7f2a2ed9a0f96 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs @@ -3,6 +3,7 @@ fn main() { // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw // bytes. let _: [u8; 0] = [4; { + //~^ ERROR failed to evaluate match &1 as *const i32 as usize { //~^ ERROR pointers cannot be cast to integers during const eval 0 => 42, diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index 05c3951c1284b..f9ca25f9f9997 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -1,5 +1,5 @@ error: pointers cannot be cast to integers during const eval - --> $DIR/match-test-ptr-null.rs:6:15 + --> $DIR/match-test-ptr-null.rs:7:15 | LL | match &1 as *const i32 as usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,5 +7,18 @@ LL | match &1 as *const i32 as usize { = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/match-test-ptr-null.rs:5:26 + | +LL | let _: [u8; 0] = [4; { + | __________________________^ +LL | | +LL | | match &1 as *const i32 as usize { +LL | | +... | +LL | | } +LL | | }]; + | |_____^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr index 4f7dd5cdf7c73..0d7d1f691ed0e 100644 --- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr @@ -13,22 +13,22 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc9, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc11, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc9────────╼ │ ╾──────╼ + ╾───────alloc11───────╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.: encountered pointer to alloc13, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.: encountered pointer to alloc15, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc13───────╼ │ ╾──────╼ + ╾───────alloc15───────╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -46,22 +46,22 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc19, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc21, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc19───────╼ │ ╾──────╼ + ╾───────alloc21───────╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.: encountered pointer to alloc23, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.: encountered pointer to alloc25, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc23───────╼ │ ╾──────╼ + ╾───────alloc25───────╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -79,11 +79,11 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc29, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered pointer to alloc31, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc29───────╼ │ ╾──────╼ + ╾───────alloc31───────╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 0b1b6f0caf192..82fed16e06ca6 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Foo: LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... - --> $DIR/const-size_of-cycle.rs:4:17 - | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... - --> $DIR/const-size_of-cycle.rs:4:17 - | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | diff --git a/src/test/ui/consts/issue-3521.fixed b/src/test/ui/consts/issue-3521.fixed index f76106dfff187..47f9c90b37629 100644 --- a/src/test/ui/consts/issue-3521.fixed +++ b/src/test/ui/consts/issue-3521.fixed @@ -7,6 +7,7 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR failed to evaluate } println!("{:?}", Stuff::Bar); diff --git a/src/test/ui/consts/issue-3521.rs b/src/test/ui/consts/issue-3521.rs index c425a22df9173..1c754019d2fdf 100644 --- a/src/test/ui/consts/issue-3521.rs +++ b/src/test/ui/consts/issue-3521.rs @@ -7,6 +7,7 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant + //~| ERROR failed to evaluate } println!("{:?}", Stuff::Bar); diff --git a/src/test/ui/consts/issue-3521.stderr b/src/test/ui/consts/issue-3521.stderr index aa42772f12d8a..5a50db450716f 100644 --- a/src/test/ui/consts/issue-3521.stderr +++ b/src/test/ui/consts/issue-3521.stderr @@ -7,6 +7,12 @@ LL | let foo: isize = 100; LL | Bar = foo | ^^^ non-constant value -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-3521.rs:8:15 + | +LL | Bar = foo + | ^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/consts/issue-36163.stderr b/src/test/ui/consts/issue-36163.stderr index 96ab7033e2501..915cf4fafd7bd 100644 --- a/src/test/ui/consts/issue-36163.stderr +++ b/src/test/ui/consts/issue-36163.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Foo: LL | B = A, | ^ | -note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... - --> $DIR/issue-36163.rs:4:9 - | -LL | B = A, - | ^ -note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... - --> $DIR/issue-36163.rs:4:9 - | -LL | B = A, - | ^ note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | @@ -25,16 +15,6 @@ note: ...which requires simplifying constant for the type system `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-36163.rs:1:1 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-36163.rs:1:1 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/consts/issue-44415.stderr b/src/test/ui/consts/issue-44415.stderr index 6a8e09cfcb971..4a9df8206ded1 100644 --- a/src/test/ui/consts/issue-44415.stderr +++ b/src/test/ui/consts/issue-44415.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Foo: LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^ | -note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... - --> $DIR/issue-44415.rs:6:17 - | -LL | bytes: [u8; unsafe { intrinsics::size_of::() }], - | ^^^^^^ -note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... - --> $DIR/issue-44415.rs:6:17 - | -LL | bytes: [u8; unsafe { intrinsics::size_of::() }], - | ^^^^^^ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/issue-44415.rs:6:17 | diff --git a/src/test/ui/consts/issue-52060.rs b/src/test/ui/consts/issue-52060.rs index 13b914c0331d1..c7983194f91bc 100644 --- a/src/test/ui/consts/issue-52060.rs +++ b/src/test/ui/consts/issue-52060.rs @@ -3,5 +3,6 @@ static A: &'static [u32] = &[1]; static B: [u32; 1] = [0; A.len()]; //~^ ERROR [E0013] +//~| ERROR failed to evaluate fn main() {} diff --git a/src/test/ui/consts/issue-52060.stderr b/src/test/ui/consts/issue-52060.stderr index 95e5f2a8282cb..0f73af6dffabb 100644 --- a/src/test/ui/consts/issue-52060.stderr +++ b/src/test/ui/consts/issue-52060.stderr @@ -6,6 +6,12 @@ LL | static B: [u32; 1] = [0; A.len()]; | = help: consider extracting the value of the `static` to a `const`, and referring to that -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-52060.rs:4:26 + | +LL | static B: [u32; 1] = [0; A.len()]; + | ^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/issue-52432.rs b/src/test/ui/consts/issue-52432.rs deleted file mode 100644 index 6be782f95ad37..0000000000000 --- a/src/test/ui/consts/issue-52432.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(const_raw_ptr_to_usize_cast)] - -fn main() { - [(); &(static |x| {}) as *const _ as usize]; - //~^ ERROR: closures cannot be static - //~| ERROR: type annotations needed - [(); &(static || {}) as *const _ as usize]; - //~^ ERROR: closures cannot be static - //~| ERROR: failed to evaluate the given constant -} diff --git a/src/test/ui/consts/issue-52432.stderr b/src/test/ui/consts/issue-52432.stderr deleted file mode 100644 index 2710a72f3a105..0000000000000 --- a/src/test/ui/consts/issue-52432.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0697]: closures cannot be static - --> $DIR/issue-52432.rs:4:12 - | -LL | [(); &(static |x| {}) as *const _ as usize]; - | ^^^^^^^^^^ - -error[E0697]: closures cannot be static - --> $DIR/issue-52432.rs:7:12 - | -LL | [(); &(static || {}) as *const _ as usize]; - | ^^^^^^^^^ - -error[E0282]: type annotations needed - --> $DIR/issue-52432.rs:4:20 - | -LL | [(); &(static |x| {}) as *const _ as usize]; - | ^ consider giving this closure parameter a type - -error: failed to evaluate the given constant - --> $DIR/issue-52432.rs:7:10 - | -LL | [(); &(static || {}) as *const _ as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0282, E0697. -For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.rs b/src/test/ui/consts/issue-66693-panic-in-array-len.rs index fc0dcd7a44daa..b929bd3f351cf 100644 --- a/src/test/ui/consts/issue-66693-panic-in-array-len.rs +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.rs @@ -9,6 +9,8 @@ fn main() { // ensure that conforming panics are handled correctly let _ = [false; panic!()]; //~^ ERROR: evaluation of constant value failed + //~| ERROR: evaluation of constant value failed + //~| ERROR failed to evaluate the given constant // typechecking halts before getting to this one let _ = ['a', panic!("panic in array len")]; diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr index 4ccbeb73c8a25..1ff69c1faef0f 100644 --- a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr @@ -14,6 +14,22 @@ LL | let _ = [false; panic!()]; | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: failed to evaluate the given constant + --> $DIR/issue-66693-panic-in-array-len.rs:10:21 + | +LL | let _ = [false; panic!()]; + | ^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-66693-panic-in-array-len.rs:10:21 + | +LL | let _ = [false; panic!()]; + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:10:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-91434.rs b/src/test/ui/consts/issue-91434.rs index fc7731291b371..20e37adbde606 100644 --- a/src/test/ui/consts/issue-91434.rs +++ b/src/test/ui/consts/issue-91434.rs @@ -3,4 +3,5 @@ fn main() { //~^ ERROR: expected at least one digit in exponent //~| ERROR: cannot find value `h` in this scope [E0425] //~| ERROR: constant expression depends on a generic parameter + //~| ERROR failed to evaluate } diff --git a/src/test/ui/consts/issue-91434.stderr b/src/test/ui/consts/issue-91434.stderr index 9d3fe5f201656..b5c9e09bd4c46 100644 --- a/src/test/ui/consts/issue-91434.stderr +++ b/src/test/ui/consts/issue-91434.stderr @@ -18,6 +18,12 @@ LL | [9; [[9E; h]]]; | = note: this may fail depending on what value the parameter takes -error: aborting due to 3 previous errors +error: failed to evaluate the given constant + --> $DIR/issue-91434.rs:2:9 + | +LL | [9; [[9E; h]]]; + | ^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 8ddc9fe4f5ff9..8d2cfd284e20f 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -4,17 +4,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: ...which immediately requires const-evaluating + checking `FOO` again = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 8ddc9fe4f5ff9..8d2cfd284e20f 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -4,17 +4,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: ...which immediately requires const-evaluating + checking `FOO` again = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs index af494e3734914..a7eabbdc668de 100644 --- a/src/test/ui/consts/too_generic_eval_ice.rs +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -6,7 +6,8 @@ impl Foo { pub fn crash() -> bool { [5; Self::HOST_SIZE] == [6; 0] //~^ ERROR constant expression depends on a generic parameter - //~| ERROR constant expression depends on a generic parameter + //~| ERROR failed to evaluate + //~| ERROR failed to evaluate //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` } } diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index ac104ed4a5a58..ec9c518313a7f 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -6,13 +6,17 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = note: this may fail depending on what value the parameter takes -error: constant expression depends on a generic parameter +error: failed to evaluate the given constant + --> $DIR/too_generic_eval_ice.rs:7:13 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | ^^^^^^^^^^^^^^^ + +error: failed to evaluate the given constant --> $DIR/too_generic_eval_ice.rs:7:30 | LL | [5; Self::HOST_SIZE] == [6; 0] | ^^ - | - = note: this may fail depending on what value the parameter takes error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]` --> $DIR/too_generic_eval_ice.rs:7:30 @@ -22,6 +26,6 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/write-to-static-mut-in-static.stderr b/src/test/ui/consts/write-to-static-mut-in-static.stderr index 6493ddabc4ea0..8916ea3283565 100644 --- a/src/test/ui/consts/write-to-static-mut-in-static.stderr +++ b/src/test/ui/consts/write-to-static-mut-in-static.stderr @@ -10,17 +10,7 @@ error[E0391]: cycle detected when const-evaluating + checking `C` LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `C`... - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `C`... - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `C`, completing the cycle + = note: ...which immediately requires const-evaluating + checking `C` again = note: cycle used when running analysis passes on this crate error: aborting due to 2 previous errors diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs index f927dd189038a..4dc28c7533221 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs @@ -8,6 +8,7 @@ enum MyWeirdOption { None = 0, Some(T) = std::mem::size_of::(), //~^ ERROR generic parameters may not be used in const operations + //~| ERROR failed to evaluate } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.stderr b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.stderr index e4e10468d5348..eb250529e0c22 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.stderr @@ -7,5 +7,11 @@ LL | Some(T) = std::mem::size_of::(), = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-70453-generics-in-discr-ice-2.rs:9:15 + | +LL | Some(T) = std::mem::size_of::(), + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs index a0fb788a5109c..e3ae2ea57927a 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs @@ -9,6 +9,7 @@ enum MyWeirdOption { None = 0, Some = std::mem::size_of::(), //~^ ERROR generic parameters may not be used in const operations + //~| ERROR failed to evaluate } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr index 7ea8a39129ead..2d1d9edb07e27 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr @@ -7,6 +7,12 @@ LL | Some = std::mem::size_of::(), = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions +error: failed to evaluate the given constant + --> $DIR/issue-70453-generics-in-discr-ice.rs:10:12 + | +LL | Some = std::mem::size_of::(), + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0392]: parameter `T` is never used --> $DIR/issue-70453-generics-in-discr-ice.rs:7:20 | @@ -16,6 +22,6 @@ LL | enum MyWeirdOption { = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: usize` instead -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index e62582fb5161a..2c7b53e791ffd 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -8,6 +8,7 @@ enum MyWeirdOption { None = 0, Some(T) = core::mem::size_of::<*mut T>(), //~^ ERROR generic parameters may not be used + //~| ERROR failed to evaluate } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr index 0a7a631606ee4..d0bc47daf2aff 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -7,5 +7,11 @@ LL | Some(T) = core::mem::size_of::<*mut T>(), = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-70453-polymorphic-ctfe.rs:9:15 + | +LL | Some(T) = core::mem::size_of::<*mut T>(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/enum/issue-67945-1.rs b/src/test/ui/enum/issue-67945-1.rs index f4697344cc7a4..5a757eff110a5 100644 --- a/src/test/ui/enum/issue-67945-1.rs +++ b/src/test/ui/enum/issue-67945-1.rs @@ -1,6 +1,8 @@ enum Bug { //~ ERROR parameter `S` is never used Var = { - let x: S = 0; //~ ERROR generic parameters may not be used + //~^ ERROR failed to evaluate the given + let x: S = 0; + //~^ ERROR generic parameters may not be used 0 }, } diff --git a/src/test/ui/enum/issue-67945-1.stderr b/src/test/ui/enum/issue-67945-1.stderr index 8f1b5b38e4c35..c45a9d4ccbb04 100644 --- a/src/test/ui/enum/issue-67945-1.stderr +++ b/src/test/ui/enum/issue-67945-1.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/issue-67945-1.rs:3:16 + --> $DIR/issue-67945-1.rs:4:16 | LL | let x: S = 0; | ^ cannot perform const operation using `S` @@ -7,6 +7,18 @@ LL | let x: S = 0; = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions +error: failed to evaluate the given constant + --> $DIR/issue-67945-1.rs:2:11 + | +LL | Var = { + | ___________^ +LL | | +LL | | let x: S = 0; +LL | | +LL | | 0 +LL | | }, + | |_____^ + error[E0392]: parameter `S` is never used --> $DIR/issue-67945-1.rs:1:10 | @@ -16,6 +28,6 @@ LL | enum Bug { = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `S` to be a const parameter, use `const S: usize` instead -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/enum/issue-67945-2.rs b/src/test/ui/enum/issue-67945-2.rs index e5044468da129..d271a809af843 100644 --- a/src/test/ui/enum/issue-67945-2.rs +++ b/src/test/ui/enum/issue-67945-2.rs @@ -3,6 +3,7 @@ enum Bug { //~ ERROR parameter `S` is never used Var = 0: S, //~^ ERROR generic parameters may not be used + //~| ERROR failed to evaluate the given } fn main() {} diff --git a/src/test/ui/enum/issue-67945-2.stderr b/src/test/ui/enum/issue-67945-2.stderr index 4f5e236a37b45..c601c9a47fc4c 100644 --- a/src/test/ui/enum/issue-67945-2.stderr +++ b/src/test/ui/enum/issue-67945-2.stderr @@ -7,6 +7,12 @@ LL | Var = 0: S, = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions +error: failed to evaluate the given constant + --> $DIR/issue-67945-2.rs:4:11 + | +LL | Var = 0: S, + | ^^^^ + error[E0392]: parameter `S` is never used --> $DIR/issue-67945-2.rs:3:10 | @@ -16,6 +22,6 @@ LL | enum Bug { = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `S` to be a const parameter, use `const S: usize` instead -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/generics/param-in-ct-in-ty-param-default.rs b/src/test/ui/generics/param-in-ct-in-ty-param-default.rs index 3c62e47381c0b..fabf304a32eed 100644 --- a/src/test/ui/generics/param-in-ct-in-ty-param-default.rs +++ b/src/test/ui/generics/param-in-ct-in-ty-param-default.rs @@ -1,4 +1,5 @@ struct Foo()]>(T, U); //~^ ERROR generic parameters may not be used in const operations +//~| ERROR failed to evaluate fn main() {} diff --git a/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr b/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr index ab09ebcae7197..6039e90ffbec9 100644 --- a/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr +++ b/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr @@ -7,5 +7,11 @@ LL | struct Foo()]>(T, U); = note: type parameters may not be used in const expressions = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/param-in-ct-in-ty-param-default.rs:1:15 + | +LL | struct Foo()]>(T, U); + | ^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 2372bbb5ca3d7..86e81a0784830 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -5,16 +5,6 @@ note: ...which requires simplifying constant for the type system `FOO`... | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `FOO`... - --> $DIR/issue-17252.rs:1:1 - | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `FOO`... - --> $DIR/issue-17252.rs:1:1 - | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `FOO`... --> $DIR/issue-17252.rs:1:1 | diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index 4b5a33057f50d..b71d07f10ea9c 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `X::A LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... - --> $DIR/issue-23302-1.rs:4:9 - | -LL | A = X::A as isize, - | ^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... - --> $DIR/issue-23302-1.rs:4:9 - | -LL | A = X::A as isize, - | ^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index e2a0d977cc655..94c68b6ae5e14 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Y::A LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... - --> $DIR/issue-23302-2.rs:4:9 - | -LL | A = Y::B as isize, - | ^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... - --> $DIR/issue-23302-2.rs:4:9 - | -LL | A = Y::B as isize, - | ^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index 66ba9c2f68e7c..441fcdcea04c4 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `A` LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ | -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-23302-3.rs:1:1 - | -LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `A`... - --> $DIR/issue-23302-3.rs:1:1 - | -LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-23302-3.rs:1:1 | @@ -25,16 +15,6 @@ note: ...which requires simplifying constant for the type system `B`... | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `B`... - --> $DIR/issue-23302-3.rs:3:1 - | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires simplifying constant for the type system `B`... - --> $DIR/issue-23302-3.rs:3:1 - | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | diff --git a/src/test/ui/issues/issue-39211.rs b/src/test/ui/issues/issue-39211.rs index c7b6f1d58f33d..b3d599844e5a7 100644 --- a/src/test/ui/issues/issue-39211.rs +++ b/src/test/ui/issues/issue-39211.rs @@ -10,6 +10,7 @@ trait Mat { fn m() { let a = [3; M::Row::DIM]; //~^ ERROR constant expression depends on a generic parameter + //~| ERROR failed to evaluate } fn main() { } diff --git a/src/test/ui/issues/issue-39211.stderr b/src/test/ui/issues/issue-39211.stderr index c555983ea68e0..aedfa7e3994d6 100644 --- a/src/test/ui/issues/issue-39211.stderr +++ b/src/test/ui/issues/issue-39211.stderr @@ -6,5 +6,11 @@ LL | let a = [3; M::Row::DIM]; | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-39211.rs:11:17 + | +LL | let a = [3; M::Row::DIM]; + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs index 2c5257ce063cb..299ed39575873 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,4 +19,6 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; + //~^ ERROR evaluation of constant value failed + //~| ERROR failed to evaluate the given } diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index 8ae0f8b804c93..91fa286cdd071 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,7 +13,19 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -error: aborting due to 2 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 + | +LL | let _ = [0; B::VALUE]; + | ^^^^^^^^ referenced constant has errors + +error: failed to evaluate the given constant + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 + | +LL | let _ = [0; B::VALUE]; + | ^^^^^^^^ + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0046, E0437. +Some errors have detailed explanations: E0046, E0080, E0437. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 966d76d148af3..43e75194ec93e 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,5 +1,6 @@ fn main() { [1; >::VAL]; + //~^ ERROR failed to evaluate } trait TypeVal { const VAL: T; diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index 97bd5ab36b65d..b72063678487a 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/issue-77919.rs:9:9 + --> $DIR/issue-77919.rs:10:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/issue-77919.rs:11:63 + --> $DIR/issue-77919.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | - ^^^ not found in this scope @@ -18,7 +18,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/issue-77919.rs:11:1 + --> $DIR/issue-77919.rs:12:1 | LL | const VAL: T; | ------------- `VAL` from trait @@ -26,7 +26,13 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: failed to evaluate the given constant + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/mir/issue-80742.rs b/src/test/ui/mir/issue-80742.rs index d82f73fc2a189..bf7d4e9ab3131 100644 --- a/src/test/ui/mir/issue-80742.rs +++ b/src/test/ui/mir/issue-80742.rs @@ -3,8 +3,7 @@ // This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place #![allow(incomplete_features)] -#![feature(const_evaluatable_checked)] -#![feature(const_generics)] +#![feature(generic_const_exprs)] use std::fmt::Debug; use std::marker::PhantomData; @@ -29,7 +28,7 @@ where fn main() { let dst = Inline::::new(0); - //~^ ERROR failed to evaluate the given constant + //~^ ERROR the function or associated item `new` exists for struct //~| ERROR the size for values of type - //~| ERROR no function or associated item + //~| ERROR failed to evaluate } diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr index 61992f3b9c407..ca8126e47ada1 100644 --- a/src/test/ui/mir/issue-80742.stderr +++ b/src/test/ui/mir/issue-80742.stderr @@ -1,5 +1,5 @@ -error[E0599]: no function or associated item named `new` found for struct `Inline` in the current scope - --> $DIR/issue-80742.rs:31:36 +error[E0599]: the function or associated item `new` exists for struct `Inline`, but its trait bounds were not satisfied + --> $DIR/issue-80742.rs:30:36 | LL | / struct Inline LL | | where @@ -11,44 +11,63 @@ LL | | } | |_- function or associated item `new` not found for this ... LL | let dst = Inline::::new(0); - | ^^^ function or associated item not found in `Inline` - | + | ^^^ function or associated item cannot be called on `Inline` due to unsatisfied trait bounds + | ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL | LL | pub trait Debug { | --------------- doesn't satisfy `dyn Debug: Sized` | - = note: the method `new` exists but the following trait bounds were not satisfied: + = note: the following trait bounds were not satisfied: `dyn Debug: Sized` error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time - --> $DIR/issue-80742.rs:31:15 + --> $DIR/issue-80742.rs:30:15 | -LL | struct Inline - | - required by this bound in `Inline` -... LL | let dst = Inline::::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `dyn Debug` +note: required by a bound in `Inline` + --> $DIR/issue-80742.rs:12:15 + | +LL | struct Inline + | ^ required by this bound in `Inline` help: consider relaxing the implicit `Sized` restriction | LL | struct Inline - | ^^^^^^^^ + | ++++++++ + +error[E0080]: evaluation of `Inline::::{constant#0}` failed + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + | +LL | intrinsics::size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | size_of called on unsized type `dyn Debug` + | inside `std::mem::size_of::` at $SRC_DIR/core/src/mem/mod.rs:LL:COL + | + ::: $DIR/issue-80742.rs:14:10 + | +LL | [u8; size_of::() + 1]: , + | -------------- inside `Inline::::{constant#0}` at $DIR/issue-80742.rs:14:10 error: failed to evaluate the given constant - --> $DIR/issue-80742.rs:31:15 + --> $DIR/issue-80742.rs:30:15 + | +LL | let dst = Inline::::new(0); + | ^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `Inline` + --> $DIR/issue-80742.rs:14:10 | LL | struct Inline | ------ required by a bound in this LL | where LL | [u8; size_of::() + 1]: , - | ------------------ required by this bound in `Inline` -... -LL | let dst = Inline::::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ required by this bound in `Inline` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0599. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0080, E0277, E0599. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index 42bfa76000b1e..56767f391531b 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -4,17 +4,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: ...which immediately requires const-evaluating + checking `FOO` again = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-50599.rs b/src/test/ui/resolve/issue-50599.rs index 00588735b9a59..00ce288fde019 100644 --- a/src/test/ui/resolve/issue-50599.rs +++ b/src/test/ui/resolve/issue-50599.rs @@ -2,4 +2,5 @@ fn main() { const N: u32 = 1_000; const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; //~ ERROR cannot find value let mut digits = [0u32; M]; + //~^ ERROR failed to evaluate } diff --git a/src/test/ui/resolve/issue-50599.stderr b/src/test/ui/resolve/issue-50599.stderr index 7ec567a06f09d..d37c42f5565a3 100644 --- a/src/test/ui/resolve/issue-50599.stderr +++ b/src/test/ui/resolve/issue-50599.stderr @@ -11,6 +11,12 @@ LL | use std::f32::consts::LOG10_2; LL | use std::f64::consts::LOG10_2; | -error: aborting due to previous error +error: failed to evaluate the given constant + --> $DIR/issue-50599.rs:4:29 + | +LL | let mut digits = [0u32; M]; + | ^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/return/issue-86188-return-not-in-fn-body.rs b/src/test/ui/return/issue-86188-return-not-in-fn-body.rs index 4f076fa069383..f87109e317b3c 100644 --- a/src/test/ui/return/issue-86188-return-not-in-fn-body.rs +++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.rs @@ -8,6 +8,7 @@ const C: [(); 42] = { [(); return || { //~^ ERROR: return statement outside of function body [E0572] + //~| ERROR: failed to evaluate the given constant let tx; }] }; diff --git a/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr b/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr index d7eeb3a729099..b134eb492832e 100644 --- a/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr +++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr @@ -4,12 +4,24 @@ error[E0572]: return statement outside of function body LL | [(); return || { | __________^ LL | | +LL | | +LL | | let tx; +LL | | }] + | |_____^ + +error: failed to evaluate the given constant + --> $DIR/issue-86188-return-not-in-fn-body.rs:9:10 + | +LL | [(); return || { + | __________^ +LL | | +LL | | LL | | let tx; LL | | }] | |_____^ error[E0572]: return statement outside of function body - --> $DIR/issue-86188-return-not-in-fn-body.rs:20:14 + --> $DIR/issue-86188-return-not-in-fn-body.rs:21:14 | LL | / fn bar() { LL | | @@ -21,7 +33,7 @@ LL | | } | |_____- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-86188-return-not-in-fn-body.rs:28:14 + --> $DIR/issue-86188-return-not-in-fn-body.rs:29:14 | LL | / fn foo() { LL | | @@ -33,7 +45,7 @@ LL | | } | |_____- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-86188-return-not-in-fn-body.rs:36:10 + --> $DIR/issue-86188-return-not-in-fn-body.rs:37:10 | LL | / fn main() { LL | | @@ -47,6 +59,6 @@ LL | || }]; LL | | } | |_- ...not the enclosing function body -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0572`. diff --git a/src/test/ui/treat-err-as-bug/err.stderr b/src/test/ui/treat-err-as-bug/err.stderr index 8f67571c2990e..40dc0a8685b20 100644 --- a/src/test/ui/treat-err-as-bug/err.stderr +++ b/src/test/ui/treat-err-as-bug/err.stderr @@ -8,5 +8,5 @@ error: internal compiler error: unexpected panic query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `C` -#1 [eval_to_allocation_raw] const-evaluating + checking `C` +#1 [analysis] running analysis passes on this crate end of query stack diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index 211086e5ec528..c0f67b2889a99 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -4,16 +4,6 @@ error[E0391]: cycle detected when simplifying constant for the type system `Alph LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | -note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... - --> $DIR/self-in-enum-definition.rs:5:10 - | -LL | V3 = Self::V1 {} as u8 + 2, - | ^^^^^^^^ -note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... - --> $DIR/self-in-enum-definition.rs:5:10 - | -LL | V3 = Self::V1 {} as u8 + 2, - | ^^^^^^^^ note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | From bbfaef60c6fa1e5043a6fa83f406809237072024 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 7 Jan 2022 21:10:48 +0100 Subject: [PATCH 12/12] update clippy --- src/tools/clippy/clippy_lints/src/non_copy_const.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 074ba9e92ba4d..d3b251705b604 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -134,7 +134,7 @@ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { fn is_value_unfrozen_raw<'tcx>( cx: &LateContext<'tcx>, - result: Result, ErrorHandled>, + result: Result, ErrorHandled<'tcx>>, ty: Ty<'tcx>, ) -> bool { fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool {