2019-09-25 12:30:25 -07:00
|
|
|
//! Concrete error types for all operations which may be invalid in a certain const context.
|
|
|
|
|
2022-05-02 09:31:56 +02:00
|
|
|
use hir::def_id::LocalDefId;
|
2022-11-22 17:19:19 +00:00
|
|
|
use hir::{ConstContext, LangItem};
|
2024-02-23 10:20:45 +11:00
|
|
|
use rustc_errors::{codes::*, Diag};
|
2020-05-07 10:24:20 -07:00
|
|
|
use rustc_hir as hir;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::def_id::DefId;
|
2021-12-09 22:42:17 +08:00
|
|
|
use rustc_infer::infer::TyCtxtInferExt;
|
|
|
|
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
2023-06-18 05:24:38 +00:00
|
|
|
use rustc_middle::mir::{self, CallSource};
|
2024-05-08 19:03:14 +10:00
|
|
|
use rustc_middle::span_bug;
|
2024-05-10 14:59:56 -04:00
|
|
|
use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
|
2024-03-06 16:54:36 +11:00
|
|
|
use rustc_middle::ty::{
|
2024-04-16 15:48:47 +10:00
|
|
|
self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef,
|
|
|
|
Param, TraitRef, Ty,
|
2024-03-06 16:54:36 +11:00
|
|
|
};
|
2023-04-16 12:03:39 +02:00
|
|
|
use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind};
|
2020-03-11 12:49:08 +01:00
|
|
|
use rustc_session::parse::feature_err;
|
2020-01-01 19:30:57 +01:00
|
|
|
use rustc_span::symbol::sym;
|
2021-12-09 22:42:17 +08:00
|
|
|
use rustc_span::{BytePos, Pos, Span, Symbol};
|
|
|
|
use rustc_trait_selection::traits::SelectionContext;
|
2024-05-22 14:20:23 +10:00
|
|
|
use tracing::debug;
|
2019-09-20 09:00:18 -07:00
|
|
|
|
2020-05-07 10:24:20 -07:00
|
|
|
use super::ConstCx;
|
2023-02-05 02:09:56 +01:00
|
|
|
use crate::errors;
|
2019-09-20 09:00:18 -07:00
|
|
|
|
2020-09-17 11:10:36 -07:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
2020-09-02 13:25:19 -07:00
|
|
|
pub enum Status {
|
|
|
|
Allowed,
|
|
|
|
Unstable(Symbol),
|
|
|
|
Forbidden,
|
|
|
|
}
|
|
|
|
|
2020-09-29 17:52:12 -07:00
|
|
|
#[derive(Clone, Copy)]
|
2024-02-23 16:20:20 +11:00
|
|
|
pub enum DiagImportance {
|
2020-09-29 17:52:12 -07:00
|
|
|
/// An operation that must be removed for const-checking to pass.
|
|
|
|
Primary,
|
|
|
|
|
|
|
|
/// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
|
|
|
|
Secondary,
|
|
|
|
}
|
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
/// An operation that is not *always* allowed in a const context.
|
2021-12-09 22:42:17 +08:00
|
|
|
pub trait NonConstOp<'tcx>: std::fmt::Debug {
|
2020-09-02 13:25:19 -07:00
|
|
|
/// Returns an enum indicating whether this operation is allowed within the given item.
|
2021-12-09 22:42:17 +08:00
|
|
|
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
2020-09-02 13:25:19 -07:00
|
|
|
Status::Forbidden
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
|
2024-02-23 16:20:20 +11:00
|
|
|
fn importance(&self) -> DiagImportance {
|
|
|
|
DiagImportance::Primary
|
2020-09-29 17:52:12 -07:00
|
|
|
}
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx>;
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
|
2020-09-23 11:53:58 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct FloatingPointOp;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
|
|
|
|
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
2020-09-23 11:53:58 -07:00
|
|
|
if ccx.const_kind() == hir::ConstContext::ConstFn {
|
|
|
|
Status::Unstable(sym::const_fn_floating_point_arithmetic)
|
|
|
|
} else {
|
|
|
|
Status::Allowed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2020-09-23 11:53:58 -07:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&ccx.tcx.sess,
|
2020-09-23 11:53:58 -07:00
|
|
|
sym::const_fn_floating_point_arithmetic,
|
|
|
|
span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
|
2020-09-23 11:53:58 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
/// A function call where the callee is a pointer.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct FnCallIndirect;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A function call where the callee is not marked as `const`.
|
2021-12-09 22:42:17 +08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub struct FnCallNonConst<'tcx> {
|
2022-05-02 09:31:56 +02:00
|
|
|
pub caller: LocalDefId,
|
2021-12-09 22:42:17 +08:00
|
|
|
pub callee: DefId,
|
2023-07-11 22:35:29 +01:00
|
|
|
pub args: GenericArgsRef<'tcx>,
|
2021-12-09 22:42:17 +08:00
|
|
|
pub span: Span,
|
2023-06-18 05:24:38 +00:00
|
|
|
pub call_source: CallSource,
|
2022-12-21 15:47:33 +00:00
|
|
|
pub feature: Option<Symbol>,
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
2021-11-03 17:34:30 +08:00
|
|
|
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 16:44:30 +11:00
|
|
|
// FIXME: make this translatable
|
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
|
|
|
#[allow(rustc::untranslatable_diagnostic)]
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
|
2023-07-11 22:35:29 +01:00
|
|
|
let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self;
|
2024-03-07 22:09:00 +00:00
|
|
|
let ConstCx { tcx, param_env, body, .. } = *ccx;
|
2021-12-09 22:42:17 +08:00
|
|
|
|
2022-01-23 20:41:46 +00:00
|
|
|
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
2023-07-11 22:35:29 +01:00
|
|
|
let trait_ref = TraitRef::from_method(tcx, trait_id, args);
|
2021-12-09 22:42:17 +08:00
|
|
|
|
|
|
|
match self_ty.kind() {
|
|
|
|
Param(param_ty) => {
|
|
|
|
debug!(?param_ty);
|
2023-12-01 05:28:34 -08:00
|
|
|
if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
|
2022-02-16 13:04:48 -05:00
|
|
|
let constraint = with_no_trimmed_paths!(format!(
|
|
|
|
"~const {}",
|
2024-05-29 21:42:40 +00:00
|
|
|
trait_ref.print_trait_sugared(),
|
2022-02-16 13:04:48 -05:00
|
|
|
));
|
2021-12-09 22:42:17 +08:00
|
|
|
suggest_constraining_type_param(
|
|
|
|
tcx,
|
|
|
|
generics,
|
2022-01-23 20:41:46 +00:00
|
|
|
err,
|
2023-11-21 20:07:32 +01:00
|
|
|
param_ty.name.as_str(),
|
2021-12-09 22:42:17 +08:00
|
|
|
&constraint,
|
|
|
|
None,
|
2023-02-04 17:09:19 -08:00
|
|
|
None,
|
2021-12-09 22:42:17 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2024-04-16 15:48:47 +10:00
|
|
|
ty::Adt(..) => {
|
2023-07-03 22:23:37 +00:00
|
|
|
let obligation =
|
|
|
|
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
|
2021-12-09 22:42:17 +08:00
|
|
|
|
|
|
|
let infcx = tcx.infer_ctxt().build();
|
|
|
|
let mut selcx = SelectionContext::new(&infcx);
|
|
|
|
let implsrc = selcx.select(&obligation);
|
|
|
|
|
|
|
|
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
2023-07-25 05:58:53 +00:00
|
|
|
// FIXME(effects) revisit this
|
|
|
|
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
|
|
|
|
let span = tcx.def_span(data.impl_def_id);
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(errors::NonConstImplNote { span });
|
2023-07-25 05:58:53 +00:00
|
|
|
}
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-06-18 05:24:38 +00:00
|
|
|
let call_kind =
|
2023-07-11 22:35:29 +01:00
|
|
|
call_kind(tcx, ccx.param_env, callee, args, span, call_source.from_hir_call(), None);
|
2021-12-09 22:42:17 +08:00
|
|
|
|
|
|
|
debug!(?call_kind);
|
|
|
|
|
|
|
|
let mut err = match call_kind {
|
|
|
|
CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
|
|
|
|
macro_rules! error {
|
2023-05-17 10:30:14 +00:00
|
|
|
($err:ident) => {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().create_err(errors::$err {
|
2023-05-17 10:30:14 +00:00
|
|
|
span,
|
|
|
|
ty: self_ty,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
})
|
2021-12-09 22:42:17 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-01-23 20:41:46 +00:00
|
|
|
let mut err = match kind {
|
2021-12-09 22:42:17 +08:00
|
|
|
CallDesugaringKind::ForLoopIntoIter => {
|
2023-05-17 10:30:14 +00:00
|
|
|
error!(NonConstForLoopIntoIter)
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
|
|
|
CallDesugaringKind::QuestionBranch => {
|
2023-05-17 10:30:14 +00:00
|
|
|
error!(NonConstQuestionBranch)
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
|
|
|
CallDesugaringKind::QuestionFromResidual => {
|
2023-05-17 10:30:14 +00:00
|
|
|
error!(NonConstQuestionFromResidual)
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
|
|
|
CallDesugaringKind::TryBlockFromOutput => {
|
2023-05-17 10:30:14 +00:00
|
|
|
error!(NonConstTryBlockFromOutput)
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
2023-04-25 19:48:59 +00:00
|
|
|
CallDesugaringKind::Await => {
|
2023-05-17 10:30:14 +00:00
|
|
|
error!(NonConstAwait)
|
2023-04-25 19:48:59 +00:00
|
|
|
}
|
2021-12-09 22:42:17 +08:00
|
|
|
};
|
|
|
|
|
2022-01-23 20:41:46 +00:00
|
|
|
diag_trait(&mut err, self_ty, kind.trait_def_id(tcx));
|
|
|
|
err
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
2021-12-29 17:05:54 +08:00
|
|
|
CallKind::FnCall { fn_trait_id, self_ty } => {
|
2023-05-17 10:30:14 +00:00
|
|
|
let note = match self_ty.kind() {
|
2021-12-29 17:05:54 +08:00
|
|
|
FnDef(def_id, ..) => {
|
2022-07-04 17:23:24 +09:00
|
|
|
let span = tcx.def_span(*def_id);
|
2021-12-29 17:05:54 +08:00
|
|
|
if ccx.tcx.is_const_fn_raw(*def_id) {
|
|
|
|
span_bug!(span, "calling const FnDef errored when it shouldn't");
|
|
|
|
}
|
|
|
|
|
2023-05-17 10:30:14 +00:00
|
|
|
Some(errors::NonConstClosureNote::FnDef { span })
|
2021-12-29 17:05:54 +08:00
|
|
|
}
|
2023-05-17 10:30:14 +00:00
|
|
|
FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr),
|
|
|
|
Closure(..) => Some(errors::NonConstClosureNote::Closure),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2023-12-18 22:21:37 +11:00
|
|
|
let mut err = tcx.dcx().create_err(errors::NonConstClosure {
|
2023-05-17 10:30:14 +00:00
|
|
|
span,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
note,
|
|
|
|
});
|
2021-12-29 17:05:54 +08:00
|
|
|
|
2022-01-23 20:41:46 +00:00
|
|
|
diag_trait(&mut err, self_ty, fn_trait_id);
|
|
|
|
err
|
2021-12-29 17:05:54 +08:00
|
|
|
}
|
2021-12-09 22:42:17 +08:00
|
|
|
CallKind::Operator { trait_id, self_ty, .. } => {
|
2023-06-18 05:24:38 +00:00
|
|
|
let mut err = if let CallSource::MatchCmp = call_source {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().create_err(errors::NonConstMatchEq {
|
2023-06-18 05:24:38 +00:00
|
|
|
span,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
ty: self_ty,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
let mut sugg = None;
|
2021-12-09 22:42:17 +08:00
|
|
|
|
2024-06-14 14:46:32 -04:00
|
|
|
if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) {
|
2023-07-11 22:35:29 +01:00
|
|
|
match (args[0].unpack(), args[1].unpack()) {
|
2023-06-18 05:24:38 +00:00
|
|
|
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
|
|
|
|
if self_ty == rhs_ty
|
|
|
|
&& self_ty.is_ref()
|
|
|
|
&& self_ty.peel_refs().is_primitive() =>
|
|
|
|
{
|
|
|
|
let mut num_refs = 0;
|
|
|
|
let mut tmp_ty = self_ty;
|
|
|
|
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
|
|
|
|
num_refs += 1;
|
|
|
|
tmp_ty = *inner_ty;
|
|
|
|
}
|
|
|
|
let deref = "*".repeat(num_refs);
|
2021-11-03 17:34:30 +08:00
|
|
|
|
2023-06-18 05:24:38 +00:00
|
|
|
if let Ok(call_str) =
|
|
|
|
ccx.tcx.sess.source_map().span_to_snippet(span)
|
|
|
|
{
|
|
|
|
if let Some(eq_idx) = call_str.find("==") {
|
|
|
|
if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
|
|
|
|
.find(|c: char| !c.is_whitespace())
|
|
|
|
{
|
|
|
|
let rhs_pos = span.lo()
|
|
|
|
+ BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
|
|
|
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
|
|
|
sugg = Some(errors::ConsiderDereferencing {
|
|
|
|
deref,
|
|
|
|
span: span.shrink_to_lo(),
|
|
|
|
rhs_span,
|
|
|
|
});
|
|
|
|
}
|
2021-11-26 23:10:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-06-18 05:24:38 +00:00
|
|
|
_ => {}
|
2021-11-26 23:10:46 +01:00
|
|
|
}
|
|
|
|
}
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().create_err(errors::NonConstOperator {
|
2023-06-18 05:24:38 +00:00
|
|
|
span,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
sugg,
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2022-01-23 20:41:46 +00:00
|
|
|
diag_trait(&mut err, self_ty, trait_id);
|
|
|
|
err
|
2021-11-26 23:10:46 +01:00
|
|
|
}
|
2021-12-09 22:42:17 +08:00
|
|
|
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
|
|
|
|
// Check first whether the source is accessible (issue #87060)
|
2023-05-17 10:30:14 +00:00
|
|
|
let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
|
|
|
|
Some(deref_target)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2023-12-18 22:21:37 +11:00
|
|
|
let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
|
2023-05-17 10:30:14 +00:00
|
|
|
span,
|
|
|
|
ty: self_ty,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
target_ty: deref_target_ty,
|
|
|
|
deref_target: target,
|
|
|
|
});
|
2021-12-09 22:42:17 +08:00
|
|
|
|
2022-11-22 17:19:19 +00:00
|
|
|
diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
|
2022-01-23 20:41:46 +00:00
|
|
|
err
|
2021-12-09 22:42:17 +08:00
|
|
|
}
|
2023-12-18 22:21:37 +11:00
|
|
|
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
|
|
|
|
ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() })
|
|
|
|
}
|
|
|
|
_ => ccx.dcx().create_err(errors::NonConstFnCall {
|
2021-12-09 22:42:17 +08:00
|
|
|
span,
|
2023-07-11 22:35:29 +01:00
|
|
|
def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
|
2022-08-19 15:36:09 -03:00
|
|
|
kind: ccx.const_kind(),
|
|
|
|
}),
|
2021-12-09 22:42:17 +08:00
|
|
|
};
|
|
|
|
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.note(format!(
|
2021-12-09 22:42:17 +08:00
|
|
|
"calls in {}s are limited to constant functions, \
|
|
|
|
tuple structs and tuple variants",
|
|
|
|
ccx.const_kind(),
|
|
|
|
));
|
2021-11-26 23:10:46 +01:00
|
|
|
|
2024-03-07 22:09:00 +00:00
|
|
|
if let Some(feature) = feature {
|
|
|
|
ccx.tcx.disabled_nightly_features(
|
|
|
|
&mut err,
|
|
|
|
body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)),
|
|
|
|
[(String::new(), feature)],
|
|
|
|
);
|
2022-12-21 15:47:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-14 23:07:47 +01:00
|
|
|
if let ConstContext::Static(_) = ccx.const_kind() {
|
2024-02-20 20:55:13 -07:00
|
|
|
err.note("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`");
|
2022-08-14 23:07:47 +01:00
|
|
|
}
|
|
|
|
|
2021-11-26 23:10:46 +01:00
|
|
|
err
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-22 17:27:18 +02:00
|
|
|
/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
|
2019-09-20 09:00:18 -07:00
|
|
|
///
|
|
|
|
/// Contains the name of the feature that would allow the use of this function.
|
|
|
|
#[derive(Debug)]
|
2020-09-17 11:12:13 -07:00
|
|
|
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
|
|
|
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2019-09-20 09:00:18 -07:00
|
|
|
let FnCallUnstable(def_id, feature) = *self;
|
|
|
|
|
2022-08-20 16:27:41 -03:00
|
|
|
let mut err = ccx
|
2023-12-18 22:21:37 +11:00
|
|
|
.dcx()
|
2023-02-05 02:09:56 +01:00
|
|
|
.create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
|
2020-09-17 11:12:13 -07:00
|
|
|
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 16:44:30 +11:00
|
|
|
// FIXME: make this translatable
|
|
|
|
#[allow(rustc::untranslatable_diagnostic)]
|
2020-09-17 11:12:13 -07:00
|
|
|
if ccx.is_const_stable_const_fn() {
|
2021-10-03 14:28:39 +09:00
|
|
|
err.help("const-stable functions can only call other const-stable functions");
|
2020-10-10 14:27:52 -04:00
|
|
|
} else if ccx.tcx.sess.is_nightly_build() {
|
2020-09-17 11:12:13 -07:00
|
|
|
if let Some(feature) = feature {
|
2023-07-25 23:17:39 +02:00
|
|
|
err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
|
2020-09-17 11:12:13 -07:00
|
|
|
}
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
2020-09-29 11:19:40 -07:00
|
|
|
|
|
|
|
err
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-17 11:12:13 -07:00
|
|
|
#[derive(Debug)]
|
2023-10-19 16:06:43 +00:00
|
|
|
pub struct Coroutine(pub hir::CoroutineKind);
|
|
|
|
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
2021-12-09 22:42:17 +08:00
|
|
|
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
2023-12-21 18:49:20 +00:00
|
|
|
if let hir::CoroutineKind::Desugared(
|
|
|
|
hir::CoroutineDesugaring::Async,
|
|
|
|
hir::CoroutineSource::Block,
|
|
|
|
) = self.0
|
|
|
|
{
|
2021-05-16 02:04:58 +02:00
|
|
|
Status::Unstable(sym::const_async_blocks)
|
|
|
|
} else {
|
|
|
|
Status::Forbidden
|
|
|
|
}
|
2020-09-17 11:12:13 -07:00
|
|
|
}
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-10-25 16:37:21 +00:00
|
|
|
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
|
2023-12-21 18:49:20 +00:00
|
|
|
if let hir::CoroutineKind::Desugared(
|
|
|
|
hir::CoroutineDesugaring::Async,
|
|
|
|
hir::CoroutineSource::Block,
|
|
|
|
) = self.0
|
|
|
|
{
|
2022-08-19 15:36:09 -03:00
|
|
|
ccx.tcx.sess.create_feature_err(
|
2023-02-05 02:09:56 +01:00
|
|
|
errors::UnallowedOpInConstContext { span, msg },
|
2022-08-19 15:36:09 -03:00
|
|
|
sym::const_async_blocks,
|
|
|
|
)
|
2021-05-16 02:04:58 +02:00
|
|
|
} else {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
|
2021-05-16 02:04:58 +02:00
|
|
|
}
|
2020-09-17 11:12:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct HeapAllocation;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::UnallowedHeapAllocations {
|
2019-09-20 09:00:18 -07:00
|
|
|
span,
|
2022-08-19 15:36:09 -03:00
|
|
|
kind: ccx.const_kind(),
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
teach: ccx.tcx.sess.teach(E0010).then_some(()),
|
2022-08-19 15:36:09 -03:00
|
|
|
})
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-19 16:03:35 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct InlineAsm;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
|
2020-09-29 21:01:35 -07:00
|
|
|
}
|
|
|
|
}
|
2020-04-19 16:03:35 -07:00
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
2022-09-23 14:22:36 +00:00
|
|
|
pub struct LiveDrop<'tcx> {
|
2020-09-02 14:54:55 -07:00
|
|
|
pub dropped_at: Option<Span>,
|
2022-09-23 14:22:36 +00:00
|
|
|
pub dropped_ty: Ty<'tcx>,
|
2020-09-02 14:54:55 -07:00
|
|
|
}
|
2022-09-23 14:22:36 +00:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::LiveDrop {
|
2022-09-23 14:22:36 +00:00
|
|
|
span,
|
2023-05-17 10:30:14 +00:00
|
|
|
dropped_ty: self.dropped_ty,
|
|
|
|
kind: ccx.const_kind(),
|
|
|
|
dropped_at: self.dropped_at,
|
|
|
|
})
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 17:33:56 +00:00
|
|
|
#[derive(Debug)]
|
2020-12-30 17:20:38 +00:00
|
|
|
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
|
|
|
|
/// the final value of the constant.
|
|
|
|
pub struct TransientCellBorrow;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
|
|
|
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
2020-12-27 17:33:56 +00:00
|
|
|
Status::Unstable(sym::const_refs_to_cell)
|
|
|
|
}
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-02-05 02:09:56 +01:00
|
|
|
ccx.tcx
|
|
|
|
.sess
|
|
|
|
.create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
|
2020-12-27 17:33:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
2021-01-03 14:20:51 +01:00
|
|
|
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
|
2020-12-30 17:20:38 +00:00
|
|
|
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
|
|
|
|
/// it in the future for static items.
|
2019-11-26 10:00:41 -05:00
|
|
|
pub struct CellBorrow;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
|
2024-02-23 16:20:20 +11:00
|
|
|
fn importance(&self) -> DiagImportance {
|
2024-02-11 14:59:38 +01:00
|
|
|
// Most likely the code will try to do mutation with these borrows, which
|
|
|
|
// triggers its own errors. Only show this one if that does not happen.
|
2024-02-23 16:20:20 +11:00
|
|
|
DiagImportance::Secondary
|
2024-02-11 14:59:38 +01:00
|
|
|
}
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2022-08-19 15:36:09 -03:00
|
|
|
// FIXME: Maybe a more elegant solution to this if else case
|
2021-01-03 14:46:19 +00:00
|
|
|
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
|
2022-08-19 15:36:09 -03:00
|
|
|
span,
|
|
|
|
opt_help: Some(()),
|
|
|
|
kind: ccx.const_kind(),
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
teach: ccx.tcx.sess.teach(E0492).then_some(()),
|
2022-08-19 15:36:09 -03:00
|
|
|
})
|
|
|
|
} else {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
|
2022-08-19 15:36:09 -03:00
|
|
|
span,
|
|
|
|
opt_help: None,
|
|
|
|
kind: ccx.const_kind(),
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
teach: ccx.tcx.sess.teach(E0492).then_some(()),
|
2022-08-19 15:36:09 -03:00
|
|
|
})
|
2021-01-03 14:46:19 +00:00
|
|
|
}
|
2019-11-26 10:00:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-01-03 18:46:20 +00:00
|
|
|
/// This op is for `&mut` borrows in the trailing expression of a constant
|
|
|
|
/// which uses the "enclosing scopes rule" to leak its locals into anonymous
|
|
|
|
/// static or const items.
|
2020-10-01 11:03:16 -07:00
|
|
|
pub struct MutBorrow(pub hir::BorrowKind);
|
|
|
|
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for MutBorrow {
|
|
|
|
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
2021-01-16 18:06:12 +00:00
|
|
|
Status::Forbidden
|
2019-11-21 14:33:39 -05:00
|
|
|
}
|
|
|
|
|
2024-02-23 16:20:20 +11:00
|
|
|
fn importance(&self) -> DiagImportance {
|
2024-02-11 14:59:38 +01:00
|
|
|
// Most likely the code will try to do mutation with these borrows, which
|
|
|
|
// triggers its own errors. Only show this one if that does not happen.
|
2024-02-23 16:20:20 +11:00
|
|
|
DiagImportance::Secondary
|
2021-01-03 18:46:20 +00:00
|
|
|
}
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2022-08-19 15:36:09 -03:00
|
|
|
match self.0 {
|
2023-12-17 11:24:34 +01:00
|
|
|
hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw {
|
2022-08-19 15:36:09 -03:00
|
|
|
span,
|
|
|
|
kind: ccx.const_kind(),
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
teach: ccx.tcx.sess.teach(E0764).then_some(()),
|
2022-08-19 15:36:09 -03:00
|
|
|
}),
|
2023-12-18 22:21:37 +11:00
|
|
|
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs {
|
2022-08-19 15:36:09 -03:00
|
|
|
span,
|
|
|
|
kind: ccx.const_kind(),
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-14 10:57:07 +11:00
|
|
|
teach: ccx.tcx.sess.teach(E0764).then_some(()),
|
2022-08-19 15:36:09 -03:00
|
|
|
}),
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-03 18:46:20 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TransientMutBorrow(pub hir::BorrowKind);
|
|
|
|
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
|
|
|
|
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
2021-01-03 18:46:20 +00:00
|
|
|
Status::Unstable(sym::const_mut_refs)
|
|
|
|
}
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2022-06-28 23:22:15 -07:00
|
|
|
let kind = ccx.const_kind();
|
|
|
|
match self.0 {
|
2023-12-17 11:24:34 +01:00
|
|
|
hir::BorrowKind::Raw => ccx
|
|
|
|
.tcx
|
|
|
|
.sess
|
|
|
|
.create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs),
|
2023-02-05 02:09:56 +01:00
|
|
|
hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err(
|
|
|
|
errors::TransientMutBorrowErr { span, kind },
|
|
|
|
sym::const_mut_refs,
|
|
|
|
),
|
2022-06-28 23:22:15 -07:00
|
|
|
}
|
2021-01-03 18:46:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct MutDeref;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for MutDeref {
|
|
|
|
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
2020-09-02 13:25:19 -07:00
|
|
|
Status::Unstable(sym::const_mut_refs)
|
2019-11-22 19:59:34 -05:00
|
|
|
}
|
2020-09-29 14:40:14 -07:00
|
|
|
|
2024-02-23 16:20:20 +11:00
|
|
|
fn importance(&self) -> DiagImportance {
|
2021-01-03 18:46:20 +00:00
|
|
|
// Usually a side-effect of a `TransientMutBorrow` somewhere.
|
2024-02-23 16:20:20 +11:00
|
|
|
DiagImportance::Secondary
|
2020-09-29 17:52:12 -07:00
|
|
|
}
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-02-05 02:09:56 +01:00
|
|
|
ccx.tcx.sess.create_feature_err(
|
|
|
|
errors::MutDerefErr { span, kind: ccx.const_kind() },
|
|
|
|
sym::const_mut_refs,
|
|
|
|
)
|
2020-09-29 14:40:14 -07:00
|
|
|
}
|
2019-11-22 19:59:34 -05:00
|
|
|
}
|
2019-09-20 09:00:18 -07:00
|
|
|
|
2021-01-05 13:54:28 -08:00
|
|
|
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PanicNonStr;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::PanicNonStrErr { span })
|
2021-01-05 13:54:28 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-10 11:33:42 +02:00
|
|
|
/// Comparing raw pointers for equality.
|
|
|
|
/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
|
|
|
|
/// allocation base addresses that are not known at compile-time.
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct RawPtrComparison;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-04-16 09:25:48 +00:00
|
|
|
// FIXME(const_trait_impl): revert to span_bug?
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::RawPtrComparisonErr { span })
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-10-05 04:55:57 -04:00
|
|
|
pub struct RawMutPtrDeref;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
|
2020-09-02 13:25:19 -07:00
|
|
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
2021-10-05 04:55:57 -04:00
|
|
|
Status::Unstable(sym::const_mut_refs)
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2019-11-30 07:40:28 +01:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&ccx.tcx.sess,
|
2021-10-05 04:55:57 -04:00
|
|
|
sym::const_mut_refs,
|
2019-11-30 07:40:28 +01:00
|
|
|
span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
|
2019-11-30 07:40:28 +01:00
|
|
|
)
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-10 11:33:42 +02:00
|
|
|
/// Casting raw pointer or function pointer to an integer.
|
|
|
|
/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
|
|
|
|
/// allocation base addresses that are not known at compile-time.
|
2019-09-20 09:00:18 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct RawPtrToIntCast;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2023-12-18 22:21:37 +11:00
|
|
|
ccx.dcx().create_err(errors::RawPtrToIntErr { span })
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An access to a (non-thread-local) `static`.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct StaticAccess;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
|
|
|
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
2020-09-02 13:25:19 -07:00
|
|
|
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
|
|
|
Status::Allowed
|
|
|
|
} else {
|
2024-01-05 12:18:11 +01:00
|
|
|
Status::Unstable(sym::const_refs_to_static)
|
2020-09-02 13:25:19 -07:00
|
|
|
}
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2024-01-05 12:18:11 +01:00
|
|
|
let mut err = feature_err(
|
|
|
|
&ccx.tcx.sess,
|
|
|
|
sym::const_refs_to_static,
|
2019-09-20 09:00:18 -07:00
|
|
|
span,
|
2024-01-05 12:18:11 +01:00
|
|
|
format!("referencing statics in {}s is unstable", ccx.const_kind(),),
|
|
|
|
);
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 16:44:30 +11:00
|
|
|
// FIXME: make this translatable
|
|
|
|
#[allow(rustc::untranslatable_diagnostic)]
|
2024-01-05 12:18:11 +01:00
|
|
|
err
|
|
|
|
.note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.")
|
|
|
|
.help("to fix this, the value can be extracted to a `const` and then used.");
|
|
|
|
err
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An access to a thread-local `static`.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ThreadLocalAccess;
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2024-01-05 12:18:11 +01:00
|
|
|
ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
|
2019-09-20 09:00:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Types that cannot appear in the signature or locals of a `const fn`.
|
2024-04-16 15:48:47 +10:00
|
|
|
pub mod mut_ref {
|
2020-09-17 11:12:13 -07:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-09-29 17:52:12 -07:00
|
|
|
pub struct MutRef(pub mir::LocalKind);
|
2021-12-09 22:42:17 +08:00
|
|
|
impl<'tcx> NonConstOp<'tcx> for MutRef {
|
|
|
|
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
2020-09-17 11:12:13 -07:00
|
|
|
Status::Unstable(sym::const_mut_refs)
|
|
|
|
}
|
|
|
|
|
2024-02-23 16:20:20 +11:00
|
|
|
fn importance(&self) -> DiagImportance {
|
2020-09-29 17:52:12 -07:00
|
|
|
match self.0 {
|
2024-02-23 16:20:20 +11:00
|
|
|
mir::LocalKind::Temp => DiagImportance::Secondary,
|
|
|
|
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary,
|
2020-09-29 17:52:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
2024-02-23 10:20:45 +11:00
|
|
|
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
2020-09-23 21:04:07 -07:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&ccx.tcx.sess,
|
2020-09-23 21:04:07 -07:00
|
|
|
sym::const_mut_refs,
|
|
|
|
span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!("mutable references are not allowed in {}s", ccx.const_kind()),
|
2020-09-23 21:04:07 -07:00
|
|
|
)
|
2020-09-17 11:12:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|