diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 948c334949826..d9c4ae4d53f91 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,16 +1,16 @@ // Not in interpret to make sure we do not use private implementation details +use crate::errors::MaxNumNodesInConstErr; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, + Scalar, +}; use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, - Scalar, -}; - mod error; mod eval_queries; mod fn_queries; @@ -72,12 +72,17 @@ pub(crate) fn eval_to_valtree<'tcx>( Ok(valtree) => Ok(Some(valtree)), Err(err) => { let did = cid.instance.def_id(); - let s = cid.display(tcx); + let global_const_id = cid.display(tcx); match err { ValTreeCreationError::NodesOverflow => { - let msg = format!("maximum number of nodes exceeded in constant {}", &s); + let msg = format!( + "maximum number of nodes exceeded in constant {}", + &global_const_id + ); let mut diag = match tcx.hir().span_if_local(did) { - Some(span) => tcx.sess.struct_span_err(span, &msg), + Some(span) => { + tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id }) + } None => tcx.sess.struct_err(&msg), }; diag.emit(); diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 01619dee0e42f..c3547cb3abdf3 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -87,3 +87,110 @@ pub(crate) struct TransientMutBorrowErrRaw { pub span: Span, pub kind: ConstContext, } + +#[derive(SessionDiagnostic)] +#[diag(const_eval::max_num_nodes_in_const)] +pub(crate) struct MaxNumNodesInConstErr { + #[primary_span] + pub span: Span, + pub global_const_id: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_fn_pointer_call)] +pub(crate) struct UnallowedFnPointerCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unstable_const_fn)] +pub(crate) struct UnstableConstFn { + #[primary_span] + pub span: Span, + pub def_path: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_mutable_refs, code = "E0764")] +pub(crate) struct UnallowedMutableRefs { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")] +pub(crate) struct UnallowedMutableRefsRaw { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")] +pub(crate) struct NonConstFmtMacroCall { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::non_const_fn_call, code = "E0015")] +pub(crate) struct NonConstFnCall { + #[primary_span] + pub span: Span, + pub def_path_str: String, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_op_in_const_context)] +pub(crate) struct UnallowedOpInConstContext { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_heap_allocations, code = "E0010")] +pub(crate) struct UnallowedHeapAllocations { + #[primary_span] + #[label] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::unallowed_inline_asm, code = "E0015")] +pub(crate) struct UnallowedInlineAsm { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::interior_mutable_data_refer, code = "E0492")] +pub(crate) struct InteriorMutableDataRefer { + #[primary_span] + #[label] + pub span: Span, + #[help] + pub opt_help: Option<()>, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(const_eval::interior_mutability_borrow)] +pub(crate) struct InteriorMutabilityBorrow { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c9cfc1f3f469c..5fb4bf638b342 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -24,8 +24,11 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors::{ - MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, - TransientMutBorrowErr, TransientMutBorrowErrRaw, + InteriorMutabilityBorrow, InteriorMutableDataRefer, MutDerefErr, NonConstFmtMacroCall, + NonConstFnCall, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr, + TransientMutBorrowErr, TransientMutBorrowErrRaw, UnallowedFnPointerCall, + UnallowedHeapAllocations, UnallowedInlineAsm, UnallowedMutableRefs, UnallowedMutableRefsRaw, + UnallowedOpInConstContext, UnstableConstFn, }; use crate::util::{call_kind, CallDesugaringKind, CallKind}; @@ -97,10 +100,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err( - span, - &format!("function pointer calls are not allowed in {}s", ccx.const_kind()), - ) + ccx.tcx.sess.create_err(UnallowedFnPointerCall { span, kind: ccx.const_kind() }) } } @@ -308,22 +308,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "cannot call non-const formatting macro in {}s", - ccx.const_kind(), - ) + ccx.tcx.sess.create_err(NonConstFmtMacroCall { span, kind: ccx.const_kind() }) } - _ => struct_span_err!( - ccx.tcx.sess, + _ => ccx.tcx.sess.create_err(NonConstFnCall { span, - E0015, - "cannot call non-const fn `{}` in {}s", - ccx.tcx.def_path_str_with_substs(callee, substs), - ccx.const_kind(), - ), + def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs), + kind: ccx.const_kind(), + }), }; err.note(&format!( @@ -354,10 +345,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let FnCallUnstable(def_id, feature) = *self; - let mut err = ccx.tcx.sess.struct_span_err( - span, - &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)), - ); + let mut err = ccx + .tcx + .sess + .create_err(UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); if ccx.is_const_stable_const_fn() { err.help("const-stable functions can only call other const-stable functions"); @@ -392,9 +383,12 @@ impl<'tcx> NonConstOp<'tcx> for Generator { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { - feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) + ccx.tcx.sess.create_feature_err( + UnallowedOpInConstContext { span, msg }, + sym::const_async_blocks, + ) } else { - ccx.tcx.sess.struct_span_err(span, &msg) + ccx.tcx.sess.create_err(UnallowedOpInConstContext { span, msg }) } } } @@ -407,23 +401,11 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, + ccx.tcx.sess.create_err(UnallowedHeapAllocations { span, - E0010, - "allocations are not allowed in {}s", - ccx.const_kind() - ); - err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind())); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "The value of statics and constants must be known at compile time, \ - and they live for the entire lifetime of a program. Creating a boxed \ - value allocates memory on the heap at runtime, and therefore cannot \ - be done at compile time.", - ); - } - err + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), + }) } } @@ -435,13 +417,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "inline assembly is not allowed in {}s", - ccx.const_kind() - ) + ccx.tcx.sess.create_err(UnallowedInlineAsm { span, kind: ccx.const_kind() }) } } @@ -487,12 +463,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_refs_to_cell, - span, - "cannot borrow here, since the borrowed element may contain interior mutability", - ) + ccx.tcx.sess.create_feature_err(InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) } } @@ -507,32 +478,22 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "{}s cannot refer to interior mutable data", - ccx.const_kind(), - ); - err.span_label( - span, - "this borrow of an interior mutable value may end up in the final value", - ); + // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { - err.help( - "to fix this, the value can be extracted to a separate \ - `static` item and then referenced", - ); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A constant containing interior mutable data behind a reference can allow you - to modify that data. This would make multiple uses of a constant to be able to - see different values and allow circumventing the `Send` and `Sync` requirements - for shared mutable data, which is unsound.", - ); + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: Some(()), + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) + } else { + ccx.tcx.sess.create_err(InteriorMutableDataRefer { + span, + opt_help: None, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), + }) } - err } } @@ -558,33 +519,18 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "{}mutable references are not allowed in the final value of {}s", - raw, - ccx.const_kind(), - ); - - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell.", - ); + match self.0 { + hir::BorrowKind::Raw => ccx.tcx.sess.create_err(UnallowedMutableRefsRaw { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), + hir::BorrowKind::Ref => ccx.tcx.sess.create_err(UnallowedMutableRefs { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), + }), } - err } } diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl index 341f05efefdfb..33bb116d6fa23 100644 --- a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl +++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl @@ -29,3 +29,55 @@ const_eval_mut_deref = const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s + +const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} + +const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s + +const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn + +const_eval_unallowed_mutable_refs = + mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_unallowed_mutable_refs_raw = + raw mutable references are not allowed in the final value of {$kind}s + .teach_note = + References in statics and constants may only refer to immutable values.\n\n + Statics are shared everywhere, and if they refer to mutable data one might violate memory + safety since holding multiple mutable references to shared data is not allowed.\n\n + If you really want global mutable state, try using static mut or a global UnsafeCell. + +const_eval_non_const_fmt_macro_call = + cannot call non-const formatting macro in {$kind}s + +const_eval_non_const_fn_call = + cannot call non-const fn `{$def_path_str}` in {$kind}s + +const_eval_unallowed_op_in_const_context = + {$msg} + +const_eval_unallowed_heap_allocations = + allocations are not allowed in {$kind}s + .label = allocation not allowed in {$kind}s + .teach_note = + The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + +const_eval_unallowed_inline_asm = + inline assembly is not allowed in {$kind}s + +const_eval_interior_mutable_data_refer = + {$kind}s cannot refer to interior mutable data + .label = this borrow of an interior mutable value may end up in the final value + .help = to fix this, the value can be extracted to a separate `static` item and then referenced + .teach_note = + A constant containing interior mutable data behind a reference can allow you to modify that data. + This would make multiple uses of a constant to be able to see different values and allow circumventing + the `Send` and `Sync` requirements for shared mutable data, which is unsound. + +const_eval_interior_mutability_borrow = + cannot borrow here, since the borrowed element may contain interior mutability diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 80de451276c2c..edb187ec3f7c5 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -20,8 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, - ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, + error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + EmissionGuarantee, ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -467,6 +467,9 @@ impl Session { feature: Symbol, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = self.parse_sess.create_err(err); + if err.code.is_none() { + err.code = std::option::Option::Some(error_code!(E0658)); + } add_feature_diagnostics(&mut err, &self.parse_sess, feature); err }