Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate some diagnostics from rustc_const_eval to SessionDiagnostic #98657

Merged
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3813,6 +3813,7 @@ dependencies = [
"atty",
"rustc_data_structures",
"rustc_error_messages",
"rustc_hir",
"rustc_lint_defs",
"rustc_macros",
"rustc_serialize",
Expand Down
89 changes: 89 additions & 0 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use rustc_hir::ConstContext;
use rustc_macros::SessionDiagnostic;
use rustc_span::Span;

#[derive(SessionDiagnostic)]
#[error(const_eval::unstable_in_stable)]
pub(crate) struct UnstableInStable {
pub gate: String,
#[primary_span]
pub span: Span,
#[suggestion(
const_eval::unstable_sugg,
code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
applicability = "has-placeholders"
)]
#[suggestion(
const_eval::bypass_sugg,
code = "#[rustc_allow_const_fn_unstable({gate})]\n",
applicability = "has-placeholders"
)]
pub attr_span: Span,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::thread_local_access, code = "E0625")]
pub(crate) struct NonConstOpErr {
#[primary_span]
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::static_access, code = "E0013")]
#[help]
pub(crate) struct StaticAccessErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
#[note(const_eval::teach_note)]
#[help(const_eval::teach_help)]
pub teach: Option<()>,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::raw_ptr_to_int)]
#[note]
#[note(const_eval::note2)]
pub(crate) struct RawPtrToIntErr {
#[primary_span]
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::raw_ptr_comparison)]
#[note]
pub(crate) struct RawPtrComparisonErr {
#[primary_span]
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::panic_non_str)]
pub(crate) struct PanicNonStrErr {
#[primary_span]
pub span: Span,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::mut_deref, code = "E0658")]
pub(crate) struct MutDerefErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::transient_mut_borrow, code = "E0658")]
pub(crate) struct TransientMutBorrowErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}

#[derive(SessionDiagnostic)]
#[error(const_eval::transient_mut_borrow_raw, code = "E0658")]
pub(crate) struct TransientMutBorrowErrRaw {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern crate tracing;
extern crate rustc_middle;

pub mod const_eval;
mod errors;
pub mod interpret;
pub mod transform;
pub mod util;
Expand Down
23 changes: 3 additions & 20 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.

use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
Expand All @@ -24,6 +24,7 @@ use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDro
use super::resolver::FlowSensitiveAnalysis;
use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
use crate::errors::UnstableInStable;

type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
Expand Down Expand Up @@ -1026,23 +1027,5 @@ fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();

ccx.tcx
.sess
.struct_span_err(
span,
&format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
)
.span_suggestion(
attr_span,
"if it is not part of the public API, make this function unstably const",
concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n'),
Applicability::HasPlaceholders,
)
.span_suggestion(
attr_span,
"otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks",
format!("#[rustc_allow_const_fn_unstable({})]\n", gate),
Applicability::MaybeIncorrect,
)
.emit();
ccx.tcx.sess.emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
}
93 changes: 29 additions & 64 deletions compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Concrete error types for all operations which may be invalid in a certain const context.

use hir::def_id::LocalDefId;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{
error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
Expand All @@ -20,6 +22,10 @@ use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::traits::SelectionContext;

use super::ConstCx;
use crate::errors::{
MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr,
StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw,
};
use crate::util::{call_kind, CallDesugaringKind, CallKind};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -590,17 +596,17 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
};

feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
&format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
)
let kind = ccx.const_kind();
match self.0 {
hir::BorrowKind::Raw => ccx
.tcx
.sess
.create_feature_err(TransientMutBorrowErrRaw { span, kind }, sym::const_mut_refs),
hir::BorrowKind::Ref => ccx
.tcx
.sess
.create_feature_err(TransientMutBorrowErr { span, kind }, sym::const_mut_refs),
}
}
}

Expand All @@ -621,12 +627,9 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
&format!("mutation through a reference is not allowed in {}s", ccx.const_kind()),
)
ccx.tcx
.sess
.create_feature_err(MutDerefErr { span, kind: ccx.const_kind() }, sym::const_mut_refs)
}
}

Expand All @@ -639,10 +642,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
ccx.tcx.sess.struct_span_err(
span,
"argument to `panic!()` in a const context must have type `&str`",
)
ccx.tcx.sess.create_err(PanicNonStrErr { span })
}
}

Expand All @@ -657,15 +657,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = ccx
.tcx
.sess
.struct_span_err(span, "pointers cannot be reliably compared during const eval");
err.note(
"see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
for more information",
);
err
ccx.tcx.sess.create_err(RawPtrComparisonErr { span })
}
}

Expand Down Expand Up @@ -701,15 +693,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = ccx
.tcx
.sess
.struct_span_err(span, "pointers cannot be cast to integers during const eval");
err.note("at compile-time, pointers do not have an integer value");
err.note(
"avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
);
err
ccx.tcx.sess.create_err(RawPtrToIntErr { span })
}
}

Expand All @@ -730,24 +714,11 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
ccx.tcx.sess,
ccx.tcx.sess.create_err(StaticAccessErr {
span,
E0013,
"{}s cannot refer to statics",
ccx.const_kind()
);
err.help(
"consider extracting the value of the `static` to a `const`, and referring to that",
);
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"`static` and `const` variables can refer to other `const` variables. \
A `const` variable, however, cannot refer to a `static` variable.",
);
err.help("To fix this, the value can be extracted to a `const` and then used.");
}
err
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()),
})
}
}

Expand All @@ -760,13 +731,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(
ccx.tcx.sess,
span,
E0625,
"thread-local statics cannot be \
accessed at compile-time"
)
ccx.tcx.sess.create_err(NonConstOpErr { span })
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
builtin_macros-requires-cfg-pattern =
builtin-macros-requires-cfg-pattern =
macro requires a cfg-pattern as an argument
.label = cfg-pattern required

builtin_macros-expected-one-cfg-pattern = expected 1 cfg-pattern
builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern
31 changes: 31 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/const_eval.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const-eval-unstable-in-stable =
const-stable function cannot use `#[feature({$gate})]`
.unstable-sugg = if it is not part of the public API, make this function unstably const
.bypass-sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks

const-eval-thread-local-access =
thread-local statics cannot be accessed at compile-time

const-eval-static-access =
{$kind}s cannot refer to statics
.help = consider extracting the value of the `static` to a `const`, and referring to that
.teach-note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
.teach-help = To fix this, the value can be extracted to a `const` and then used.

const-eval-raw-ptr-to-int =
pointers cannot be cast to integers during const eval
.note = at compile-time, pointers do not have an integer value
.note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior

const-eval-raw-ptr-comparison =
pointers cannot be reliably compared during const eval
.note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information

const-eval-panic-non-str = argument to `panic!()` in a const context must have type `&str`

const-eval-mut-deref =
mutation through a reference is not allowed in {$kind}s

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
1 change: 1 addition & 0 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ fluent_messages! {
parser => "../locales/en-US/parser.ftl",
privacy => "../locales/en-US/privacy.ftl",
typeck => "../locales/en-US/typeck.ftl",
const_eval => "../locales/en-US/const_eval.ftl",
}

pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_errors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
unicode-width = "0.1.4"
atty = "0.2"
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_error_messages::FluentValue;
use rustc_hir as hir;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol};
Expand Down Expand Up @@ -160,6 +161,16 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
}
}

impl IntoDiagnosticArg for hir::ConstContext {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(match self {
hir::ConstContext::ConstFn => "constant function",
hir::ConstContext::Static(_) => "static",
hir::ConstContext::Const => "constant",
}))
}
}

/// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
#[rustc_diagnostic_item = "AddSubdiagnostic"]
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,9 @@ impl fmt::Display for ConstContext {
}
}

// NOTE: `IntoDiagnosticArg` impl for `ConstContext` lives in `rustc_errors`
// due to a cyclical dependency between hir that crate.

/// A literal.
pub type Lit = Spanned<LitKind>;

Expand Down
Loading