Rollup merge of #120833 - nnethercote:more-internal-emit_diagnostics-cleanups, r=oli-obk
More internal emit diagnostics cleanups Miscellaneous improvements. r? ``@oli-obk``
This commit is contained in:
commit
f08ece38a8
18 changed files with 163 additions and 165 deletions
|
@ -151,7 +151,7 @@ where
|
||||||
let mut err = tcx.dcx().create_err(err);
|
let mut err = tcx.dcx().create_err(err);
|
||||||
|
|
||||||
let msg = error.diagnostic_message();
|
let msg = error.diagnostic_message();
|
||||||
error.add_args(tcx.dcx(), &mut err);
|
error.add_args(&mut err);
|
||||||
|
|
||||||
// Use *our* span to label the interp error
|
// Use *our* span to label the interp error
|
||||||
err.span_label(our_span, msg);
|
err.span_label(our_span, msg);
|
||||||
|
|
|
@ -426,7 +426,7 @@ pub struct UndefinedBehavior {
|
||||||
pub trait ReportErrorExt {
|
pub trait ReportErrorExt {
|
||||||
/// Returns the diagnostic message for this error.
|
/// Returns the diagnostic message for this error.
|
||||||
fn diagnostic_message(&self) -> DiagnosticMessage;
|
fn diagnostic_message(&self) -> DiagnosticMessage;
|
||||||
fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>);
|
||||||
|
|
||||||
fn debug(self) -> String
|
fn debug(self) -> String
|
||||||
where
|
where
|
||||||
|
@ -434,11 +434,11 @@ pub trait ReportErrorExt {
|
||||||
{
|
{
|
||||||
ty::tls::with(move |tcx| {
|
ty::tls::with(move |tcx| {
|
||||||
let dcx = tcx.dcx();
|
let dcx = tcx.dcx();
|
||||||
let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
|
let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
|
||||||
let message = self.diagnostic_message();
|
let message = self.diagnostic_message();
|
||||||
self.add_args(dcx, &mut builder);
|
self.add_args(&mut diag);
|
||||||
let s = dcx.eagerly_translate_to_string(message, builder.args());
|
let s = dcx.eagerly_translate_to_string(message, diag.args());
|
||||||
builder.cancel();
|
diag.cancel();
|
||||||
s
|
s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -505,20 +505,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_args<G: EmissionGuarantee>(
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||||
self,
|
|
||||||
dcx: &DiagCtxt,
|
|
||||||
builder: &mut DiagnosticBuilder<'_, G>,
|
|
||||||
) {
|
|
||||||
use UndefinedBehaviorInfo::*;
|
use UndefinedBehaviorInfo::*;
|
||||||
|
let dcx = diag.dcx;
|
||||||
match self {
|
match self {
|
||||||
Ub(_) => {}
|
Ub(_) => {}
|
||||||
Custom(custom) => {
|
Custom(custom) => {
|
||||||
(custom.add_args)(&mut |name, value| {
|
(custom.add_args)(&mut |name, value| {
|
||||||
builder.arg(name, value);
|
diag.arg(name, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ValidationError(e) => e.add_args(dcx, builder),
|
ValidationError(e) => e.add_args(diag),
|
||||||
|
|
||||||
Unreachable
|
Unreachable
|
||||||
| DivisionByZero
|
| DivisionByZero
|
||||||
|
@ -533,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
| UninhabitedEnumVariantWritten(_)
|
| UninhabitedEnumVariantWritten(_)
|
||||||
| UninhabitedEnumVariantRead(_) => {}
|
| UninhabitedEnumVariantRead(_) => {}
|
||||||
BoundsCheckFailed { len, index } => {
|
BoundsCheckFailed { len, index } => {
|
||||||
builder.arg("len", len);
|
diag.arg("len", len);
|
||||||
builder.arg("index", index);
|
diag.arg("index", index);
|
||||||
}
|
}
|
||||||
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
||||||
builder.arg("pointer", ptr);
|
diag.arg("pointer", ptr);
|
||||||
}
|
}
|
||||||
PointerUseAfterFree(alloc_id, msg) => {
|
PointerUseAfterFree(alloc_id, msg) => {
|
||||||
builder
|
diag.arg("alloc_id", alloc_id)
|
||||||
.arg("alloc_id", alloc_id)
|
|
||||||
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
||||||
}
|
}
|
||||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
|
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
|
||||||
builder
|
diag.arg("alloc_id", alloc_id)
|
||||||
.arg("alloc_id", alloc_id)
|
|
||||||
.arg("alloc_size", alloc_size.bytes())
|
.arg("alloc_size", alloc_size.bytes())
|
||||||
.arg("ptr_offset", ptr_offset)
|
.arg("ptr_offset", ptr_offset)
|
||||||
.arg("ptr_size", ptr_size.bytes())
|
.arg("ptr_size", ptr_size.bytes())
|
||||||
|
@ -554,47 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||||
}
|
}
|
||||||
DanglingIntPointer(ptr, msg) => {
|
DanglingIntPointer(ptr, msg) => {
|
||||||
if ptr != 0 {
|
if ptr != 0 {
|
||||||
builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
|
diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
||||||
}
|
}
|
||||||
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
|
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
|
||||||
builder.arg("required", required.bytes());
|
diag.arg("required", required.bytes());
|
||||||
builder.arg("has", has.bytes());
|
diag.arg("has", has.bytes());
|
||||||
builder.arg("msg", format!("{msg:?}"));
|
diag.arg("msg", format!("{msg:?}"));
|
||||||
}
|
}
|
||||||
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
|
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
|
||||||
builder.arg("allocation", alloc);
|
diag.arg("allocation", alloc);
|
||||||
}
|
}
|
||||||
InvalidBool(b) => {
|
InvalidBool(b) => {
|
||||||
builder.arg("value", format!("{b:02x}"));
|
diag.arg("value", format!("{b:02x}"));
|
||||||
}
|
}
|
||||||
InvalidChar(c) => {
|
InvalidChar(c) => {
|
||||||
builder.arg("value", format!("{c:08x}"));
|
diag.arg("value", format!("{c:08x}"));
|
||||||
}
|
}
|
||||||
InvalidTag(tag) => {
|
InvalidTag(tag) => {
|
||||||
builder.arg("tag", format!("{tag:x}"));
|
diag.arg("tag", format!("{tag:x}"));
|
||||||
}
|
}
|
||||||
InvalidStr(err) => {
|
InvalidStr(err) => {
|
||||||
builder.arg("err", format!("{err}"));
|
diag.arg("err", format!("{err}"));
|
||||||
}
|
}
|
||||||
InvalidUninitBytes(Some((alloc, info))) => {
|
InvalidUninitBytes(Some((alloc, info))) => {
|
||||||
builder.arg("alloc", alloc);
|
diag.arg("alloc", alloc);
|
||||||
builder.arg("access", info.access);
|
diag.arg("access", info.access);
|
||||||
builder.arg("uninit", info.bad);
|
diag.arg("uninit", info.bad);
|
||||||
}
|
}
|
||||||
ScalarSizeMismatch(info) => {
|
ScalarSizeMismatch(info) => {
|
||||||
builder.arg("target_size", info.target_size);
|
diag.arg("target_size", info.target_size);
|
||||||
builder.arg("data_size", info.data_size);
|
diag.arg("data_size", info.data_size);
|
||||||
}
|
}
|
||||||
InvalidNichedEnumVariantWritten { enum_ty } => {
|
InvalidNichedEnumVariantWritten { enum_ty } => {
|
||||||
builder.arg("ty", enum_ty.to_string());
|
diag.arg("ty", enum_ty.to_string());
|
||||||
}
|
}
|
||||||
AbiMismatchArgument { caller_ty, callee_ty }
|
AbiMismatchArgument { caller_ty, callee_ty }
|
||||||
| AbiMismatchReturn { caller_ty, callee_ty } => {
|
| AbiMismatchReturn { caller_ty, callee_ty } => {
|
||||||
builder.arg("caller_ty", caller_ty.to_string());
|
diag.arg("caller_ty", caller_ty.to_string());
|
||||||
builder.arg("callee_ty", callee_ty.to_string());
|
diag.arg("callee_ty", callee_ty.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -674,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
|
fn add_args<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use rustc_middle::mir::interpret::ValidationErrorKind::*;
|
use rustc_middle::mir::interpret::ValidationErrorKind::*;
|
||||||
|
|
||||||
|
@ -684,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = if let Some(path) = self.path {
|
let message = if let Some(path) = self.path {
|
||||||
dcx.eagerly_translate_to_string(
|
err.dcx.eagerly_translate_to_string(
|
||||||
fluent::const_eval_validation_front_matter_invalid_value_with_path,
|
fluent::const_eval_validation_front_matter_invalid_value_with_path,
|
||||||
[("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
|
[("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
dcx.eagerly_translate_to_string(
|
err.dcx.eagerly_translate_to_string(
|
||||||
fluent::const_eval_validation_front_matter_invalid_value,
|
fluent::const_eval_validation_front_matter_invalid_value,
|
||||||
[].into_iter(),
|
[].into_iter(),
|
||||||
)
|
)
|
||||||
|
@ -700,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
fn add_range_arg<G: EmissionGuarantee>(
|
fn add_range_arg<G: EmissionGuarantee>(
|
||||||
r: WrappingRange,
|
r: WrappingRange,
|
||||||
max_hi: u128,
|
max_hi: u128,
|
||||||
dcx: &DiagCtxt,
|
|
||||||
err: &mut DiagnosticBuilder<'_, G>,
|
err: &mut DiagnosticBuilder<'_, G>,
|
||||||
) {
|
) {
|
||||||
let WrappingRange { start: lo, end: hi } = r;
|
let WrappingRange { start: lo, end: hi } = r;
|
||||||
|
@ -724,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
|
("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
|
||||||
];
|
];
|
||||||
let args = args.iter().map(|(a, b)| (a, b));
|
let args = args.iter().map(|(a, b)| (a, b));
|
||||||
let message = dcx.eagerly_translate_to_string(msg, args);
|
let message = err.dcx.eagerly_translate_to_string(msg, args);
|
||||||
err.arg("in_range", message);
|
err.arg("in_range", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
|
ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
|
||||||
ExpectedKind::Str => fluent::const_eval_validation_expected_str,
|
ExpectedKind::Str => fluent::const_eval_validation_expected_str,
|
||||||
};
|
};
|
||||||
let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
|
let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
|
||||||
err.arg("expected", msg);
|
err.arg("expected", msg);
|
||||||
}
|
}
|
||||||
InvalidEnumTag { value }
|
InvalidEnumTag { value }
|
||||||
|
@ -757,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
err.arg("value", value);
|
err.arg("value", value);
|
||||||
}
|
}
|
||||||
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
|
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
|
||||||
add_range_arg(range, max_value, dcx, err)
|
add_range_arg(range, max_value, err)
|
||||||
}
|
}
|
||||||
OutOfRange { range, max_value, value } => {
|
OutOfRange { range, max_value, value } => {
|
||||||
err.arg("value", value);
|
err.arg("value", value);
|
||||||
add_range_arg(range, max_value, dcx, err);
|
add_range_arg(range, max_value, err);
|
||||||
}
|
}
|
||||||
UnalignedPtr { required_bytes, found_bytes, .. } => {
|
UnalignedPtr { required_bytes, found_bytes, .. } => {
|
||||||
err.arg("required_bytes", required_bytes);
|
err.arg("required_bytes", required_bytes);
|
||||||
|
@ -802,13 +796,13 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||||
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
|
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||||
use crate::fluent_generated::*;
|
use crate::fluent_generated::*;
|
||||||
|
|
||||||
use UnsupportedOpInfo::*;
|
use UnsupportedOpInfo::*;
|
||||||
if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
|
if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
|
||||||
builder.help(const_eval_ptr_as_bytes_1);
|
diag.help(const_eval_ptr_as_bytes_1);
|
||||||
builder.help(const_eval_ptr_as_bytes_2);
|
diag.help(const_eval_ptr_as_bytes_2);
|
||||||
}
|
}
|
||||||
match self {
|
match self {
|
||||||
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
|
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
|
||||||
|
@ -816,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||||
// print. So it's not worth the effort of having diagnostics that can print the `info`.
|
// print. So it's not worth the effort of having diagnostics that can print the `info`.
|
||||||
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
|
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
|
||||||
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
||||||
builder.arg("ptr", ptr);
|
diag.arg("ptr", ptr);
|
||||||
}
|
}
|
||||||
ThreadLocalStatic(did) | ExternStatic(did) => {
|
ThreadLocalStatic(did) | ExternStatic(did) => {
|
||||||
builder.arg("did", format!("{did:?}"));
|
diag.arg("did", format!("{did:?}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
|
||||||
InterpError::MachineStop(e) => e.diagnostic_message(),
|
InterpError::MachineStop(e) => e.diagnostic_message(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_args<G: EmissionGuarantee>(
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||||
self,
|
|
||||||
dcx: &DiagCtxt,
|
|
||||||
builder: &mut DiagnosticBuilder<'_, G>,
|
|
||||||
) {
|
|
||||||
match self {
|
match self {
|
||||||
InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
|
InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
|
||||||
InterpError::Unsupported(e) => e.add_args(dcx, builder),
|
InterpError::Unsupported(e) => e.add_args(diag),
|
||||||
InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
|
InterpError::InvalidProgram(e) => e.add_args(diag),
|
||||||
InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
|
InterpError::ResourceExhaustion(e) => e.add_args(diag),
|
||||||
InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
|
InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
|
||||||
builder.arg(name, value);
|
diag.arg(name, value);
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -864,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_args<G: EmissionGuarantee>(
|
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||||
self,
|
|
||||||
dcx: &DiagCtxt,
|
|
||||||
builder: &mut DiagnosticBuilder<'_, G>,
|
|
||||||
) {
|
|
||||||
match self {
|
match self {
|
||||||
InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
|
InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
|
||||||
InvalidProgramInfo::Layout(e) => {
|
InvalidProgramInfo::Layout(e) => {
|
||||||
// The level doesn't matter, `diag` is consumed without it being used.
|
// The level doesn't matter, `dummy_diag` is consumed without it being used.
|
||||||
let dummy_level = Level::Bug;
|
let dummy_level = Level::Bug;
|
||||||
let diag: DiagnosticBuilder<'_, ()> =
|
let dummy_diag: DiagnosticBuilder<'_, ()> =
|
||||||
e.into_diagnostic().into_diagnostic(dcx, dummy_level);
|
e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level);
|
||||||
for (name, val) in diag.args() {
|
for (name, val) in dummy_diag.args() {
|
||||||
builder.arg(name.clone(), val.clone());
|
diag.arg(name.clone(), val.clone());
|
||||||
}
|
}
|
||||||
diag.cancel();
|
dummy_diag.cancel();
|
||||||
}
|
}
|
||||||
InvalidProgramInfo::FnAbiAdjustForForeignAbi(
|
InvalidProgramInfo::FnAbiAdjustForForeignAbi(
|
||||||
AdjustForForeignAbiError::Unsupported { arch, abi },
|
AdjustForForeignAbiError::Unsupported { arch, abi },
|
||||||
) => {
|
) => {
|
||||||
builder.arg("arch", arch);
|
diag.arg("arch", arch);
|
||||||
builder.arg("abi", abi.name());
|
diag.arg("abi", abi.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
|
||||||
ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
|
ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
|
fn add_args<G: EmissionGuarantee>(self, _: &mut DiagnosticBuilder<'_, G>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl rustc_errors::IntoDiagnosticArg for InternKind {
|
impl rustc_errors::IntoDiagnosticArg for InternKind {
|
||||||
|
|
|
@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
let mut diag = dcx.struct_allow("");
|
let mut diag = dcx.struct_allow("");
|
||||||
let msg = e.diagnostic_message();
|
let msg = e.diagnostic_message();
|
||||||
e.add_args(dcx, &mut diag);
|
e.add_args(&mut diag);
|
||||||
let s = dcx.eagerly_translate_to_string(msg, diag.args());
|
let s = dcx.eagerly_translate_to_string(msg, diag.args());
|
||||||
diag.cancel();
|
diag.cancel();
|
||||||
s
|
s
|
||||||
|
|
|
@ -411,8 +411,8 @@ impl CodeSuggestion {
|
||||||
/// or `.span_bug` rather than a failed assertion, etc.
|
/// or `.span_bug` rather than a failed assertion, etc.
|
||||||
pub struct ExplicitBug;
|
pub struct ExplicitBug;
|
||||||
|
|
||||||
/// Signifies that the compiler died with an explicit call to `.delay_*_bug`
|
/// Signifies that the compiler died due to a delayed bug rather than a failed
|
||||||
/// rather than a failed assertion, etc.
|
/// assertion, etc.
|
||||||
pub struct DelayedBugPanic;
|
pub struct DelayedBugPanic;
|
||||||
|
|
||||||
/// A `DiagCtxt` deals with errors and other compiler output.
|
/// A `DiagCtxt` deals with errors and other compiler output.
|
||||||
|
@ -428,10 +428,14 @@ pub struct DiagCtxt {
|
||||||
struct DiagCtxtInner {
|
struct DiagCtxtInner {
|
||||||
flags: DiagCtxtFlags,
|
flags: DiagCtxtFlags,
|
||||||
|
|
||||||
/// The number of lint errors that have been emitted, including duplicates.
|
/// The error guarantees from all emitted errors. The length gives the error count.
|
||||||
lint_err_count: usize,
|
err_guars: Vec<ErrorGuaranteed>,
|
||||||
/// The number of non-lint errors that have been emitted, including duplicates.
|
/// The error guarantee from all emitted lint errors. The length gives the
|
||||||
err_count: usize,
|
/// lint error count.
|
||||||
|
lint_err_guars: Vec<ErrorGuaranteed>,
|
||||||
|
/// The delayed bugs and their error guarantees.
|
||||||
|
delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
|
||||||
|
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
||||||
|
|
||||||
/// The number of stashed errors. Unlike the other counts, this can go up
|
/// The number of stashed errors. Unlike the other counts, this can go up
|
||||||
/// and down, so it doesn't guarantee anything.
|
/// and down, so it doesn't guarantee anything.
|
||||||
|
@ -447,8 +451,6 @@ struct DiagCtxtInner {
|
||||||
has_printed: bool,
|
has_printed: bool,
|
||||||
|
|
||||||
emitter: Box<DynEmitter>,
|
emitter: Box<DynEmitter>,
|
||||||
delayed_bugs: Vec<DelayedDiagnostic>,
|
|
||||||
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
|
||||||
/// This flag indicates that an expected diagnostic was emitted and suppressed.
|
/// This flag indicates that an expected diagnostic was emitted and suppressed.
|
||||||
/// This is used for the `good_path_delayed_bugs` check.
|
/// This is used for the `good_path_delayed_bugs` check.
|
||||||
suppressed_expected_diag: bool,
|
suppressed_expected_diag: bool,
|
||||||
|
@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.emit_stashed_diagnostics();
|
self.emit_stashed_diagnostics();
|
||||||
|
|
||||||
if !self.has_errors() {
|
if self.err_guars.is_empty() {
|
||||||
self.flush_delayed(DelayedBugKind::Normal)
|
self.flush_delayed(DelayedBugKind::Normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,15 +606,15 @@ impl DiagCtxt {
|
||||||
Self {
|
Self {
|
||||||
inner: Lock::new(DiagCtxtInner {
|
inner: Lock::new(DiagCtxtInner {
|
||||||
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
||||||
lint_err_count: 0,
|
err_guars: Vec::new(),
|
||||||
err_count: 0,
|
lint_err_guars: Vec::new(),
|
||||||
|
delayed_bugs: Vec::new(),
|
||||||
|
good_path_delayed_bugs: Vec::new(),
|
||||||
stashed_err_count: 0,
|
stashed_err_count: 0,
|
||||||
deduplicated_err_count: 0,
|
deduplicated_err_count: 0,
|
||||||
deduplicated_warn_count: 0,
|
deduplicated_warn_count: 0,
|
||||||
has_printed: false,
|
has_printed: false,
|
||||||
emitter,
|
emitter,
|
||||||
delayed_bugs: Vec::new(),
|
|
||||||
good_path_delayed_bugs: Vec::new(),
|
|
||||||
suppressed_expected_diag: false,
|
suppressed_expected_diag: false,
|
||||||
taught_diagnostics: Default::default(),
|
taught_diagnostics: Default::default(),
|
||||||
emitted_diagnostic_codes: Default::default(),
|
emitted_diagnostic_codes: Default::default(),
|
||||||
|
@ -661,14 +663,14 @@ impl DiagCtxt {
|
||||||
/// the overall count of emitted error diagnostics.
|
/// the overall count of emitted error diagnostics.
|
||||||
pub fn reset_err_count(&self) {
|
pub fn reset_err_count(&self) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
inner.lint_err_count = 0;
|
|
||||||
inner.err_count = 0;
|
|
||||||
inner.stashed_err_count = 0;
|
inner.stashed_err_count = 0;
|
||||||
inner.deduplicated_err_count = 0;
|
inner.deduplicated_err_count = 0;
|
||||||
inner.deduplicated_warn_count = 0;
|
inner.deduplicated_warn_count = 0;
|
||||||
inner.has_printed = false;
|
inner.has_printed = false;
|
||||||
|
|
||||||
// actually free the underlying memory (which `clear` would not do)
|
// actually free the underlying memory (which `clear` would not do)
|
||||||
|
inner.err_guars = Default::default();
|
||||||
|
inner.lint_err_guars = Default::default();
|
||||||
inner.delayed_bugs = Default::default();
|
inner.delayed_bugs = Default::default();
|
||||||
inner.good_path_delayed_bugs = Default::default();
|
inner.good_path_delayed_bugs = Default::default();
|
||||||
inner.taught_diagnostics = Default::default();
|
inner.taught_diagnostics = Default::default();
|
||||||
|
@ -721,7 +723,7 @@ impl DiagCtxt {
|
||||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn err_count(&self) -> usize {
|
pub fn err_count(&self) -> usize {
|
||||||
self.inner.borrow().err_count
|
self.inner.borrow().err_guars.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This excludes normal errors, lint errors and delayed bugs. Unless
|
/// This excludes normal errors, lint errors and delayed bugs. Unless
|
||||||
|
@ -735,36 +737,19 @@ impl DiagCtxt {
|
||||||
|
|
||||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||||
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||||
self.inner.borrow().has_errors().then(|| {
|
self.inner.borrow().has_errors()
|
||||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
|
||||||
#[allow(deprecated)]
|
|
||||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This excludes delayed bugs and stashed errors. Unless absolutely
|
/// This excludes delayed bugs and stashed errors. Unless absolutely
|
||||||
/// necessary, prefer `has_errors` to this method.
|
/// necessary, prefer `has_errors` to this method.
|
||||||
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||||
let inner = self.inner.borrow();
|
self.inner.borrow().has_errors_or_lint_errors()
|
||||||
let result = inner.has_errors() || inner.lint_err_count > 0;
|
|
||||||
result.then(|| {
|
|
||||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
|
||||||
#[allow(deprecated)]
|
|
||||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This excludes stashed errors. Unless absolutely necessary, prefer
|
/// This excludes stashed errors. Unless absolutely necessary, prefer
|
||||||
/// `has_errors` or `has_errors_or_lint_errors` to this method.
|
/// `has_errors` or `has_errors_or_lint_errors` to this method.
|
||||||
pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||||
let inner = self.inner.borrow();
|
self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs()
|
||||||
let result =
|
|
||||||
inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty();
|
|
||||||
result.then(|| {
|
|
||||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
|
||||||
#[allow(deprecated)]
|
|
||||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_error_count(&self, registry: &Registry) {
|
pub fn print_error_count(&self, registry: &Registry) {
|
||||||
|
@ -797,10 +782,10 @@ impl DiagCtxt {
|
||||||
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
|
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
|
||||||
}
|
}
|
||||||
(_, 0) => {
|
(_, 0) => {
|
||||||
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
|
inner.emit_diagnostic(Diagnostic::new(Error, errors));
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
|
inner.emit_diagnostic(Diagnostic::new(Error, format!("{errors}; {warnings}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +829,7 @@ impl DiagCtxt {
|
||||||
pub fn abort_if_errors(&self) {
|
pub fn abort_if_errors(&self) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
inner.emit_stashed_diagnostics();
|
inner.emit_stashed_diagnostics();
|
||||||
if inner.has_errors() {
|
if !inner.err_guars.is_empty() {
|
||||||
FatalError.raise();
|
FatalError.raise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -886,8 +871,21 @@ impl DiagCtxt {
|
||||||
) {
|
) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
|
// This "error" is an odd duck.
|
||||||
|
// - It's only produce with JSON output.
|
||||||
|
// - It's not emitted the usual way, via `emit_diagnostic`.
|
||||||
|
// - The `$message_type` field is "unused_externs" rather than the usual
|
||||||
|
// "diagnosic".
|
||||||
|
//
|
||||||
|
// We count it as a lint error because it has a lint level. The value
|
||||||
|
// of `loud` (which comes from "unused-externs" or
|
||||||
|
// "unused-externs-silent"), also affects whether it's treated like a
|
||||||
|
// hard error or not.
|
||||||
if loud && lint_level.is_error() {
|
if loud && lint_level.is_error() {
|
||||||
inner.lint_err_count += 1;
|
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||||
|
// `ErrorGuaranteed` for unused_extern errors originates.
|
||||||
|
#[allow(deprecated)]
|
||||||
|
inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
|
||||||
inner.panic_if_treat_err_as_bug();
|
inner.panic_if_treat_err_as_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,7 +1227,7 @@ impl DiagCtxt {
|
||||||
impl DiagCtxtInner {
|
impl DiagCtxtInner {
|
||||||
/// Emit all stashed diagnostics.
|
/// Emit all stashed diagnostics.
|
||||||
fn emit_stashed_diagnostics(&mut self) {
|
fn emit_stashed_diagnostics(&mut self) {
|
||||||
let has_errors = self.has_errors();
|
let has_errors = !self.err_guars.is_empty();
|
||||||
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
|
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
|
||||||
// Decrement the count tracking the stash; emitting will increment it.
|
// Decrement the count tracking the stash; emitting will increment it.
|
||||||
if diag.is_error() {
|
if diag.is_error() {
|
||||||
|
@ -1291,9 +1289,13 @@ impl DiagCtxtInner {
|
||||||
// when an error is first emitted, also), but maybe there's a case
|
// when an error is first emitted, also), but maybe there's a case
|
||||||
// in which that's not sound? otherwise this is really inefficient.
|
// in which that's not sound? otherwise this is really inefficient.
|
||||||
let backtrace = std::backtrace::Backtrace::capture();
|
let backtrace = std::backtrace::Backtrace::capture();
|
||||||
self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||||
|
// `ErrorGuaranteed` for delayed bugs originates.
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
return Some(ErrorGuaranteed::unchecked_error_guaranteed());
|
let guar = ErrorGuaranteed::unchecked_error_guaranteed();
|
||||||
|
self.delayed_bugs
|
||||||
|
.push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
|
||||||
|
return Some(guar);
|
||||||
}
|
}
|
||||||
GoodPathDelayedBug => {
|
GoodPathDelayedBug => {
|
||||||
let backtrace = std::backtrace::Backtrace::capture();
|
let backtrace = std::backtrace::Backtrace::capture();
|
||||||
|
@ -1327,7 +1329,6 @@ impl DiagCtxtInner {
|
||||||
!self.emitted_diagnostics.insert(diagnostic_hash)
|
!self.emitted_diagnostics.insert(diagnostic_hash)
|
||||||
};
|
};
|
||||||
|
|
||||||
let level = diagnostic.level;
|
|
||||||
let is_error = diagnostic.is_error();
|
let is_error = diagnostic.is_error();
|
||||||
let is_lint = diagnostic.is_lint.is_some();
|
let is_lint = diagnostic.is_lint.is_some();
|
||||||
|
|
||||||
|
@ -1366,36 +1367,47 @@ impl DiagCtxtInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_error {
|
if is_error {
|
||||||
|
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||||
|
// `ErrorGuaranteed` for errors and lint errors originates.
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let guar = ErrorGuaranteed::unchecked_error_guaranteed();
|
||||||
|
guaranteed = Some(guar);
|
||||||
if is_lint {
|
if is_lint {
|
||||||
self.lint_err_count += 1;
|
self.lint_err_guars.push(guar);
|
||||||
} else {
|
} else {
|
||||||
self.err_count += 1;
|
self.err_guars.push(guar);
|
||||||
}
|
}
|
||||||
self.panic_if_treat_err_as_bug();
|
self.panic_if_treat_err_as_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
if level == Level::Error {
|
|
||||||
guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
guaranteed
|
guaranteed
|
||||||
}
|
}
|
||||||
|
|
||||||
fn treat_err_as_bug(&self) -> bool {
|
fn treat_err_as_bug(&self) -> bool {
|
||||||
self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
|
self.flags
|
||||||
|
.treat_err_as_bug
|
||||||
|
.is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this one before incrementing `err_count`.
|
// Use this one before incrementing `err_count`.
|
||||||
fn treat_next_err_as_bug(&self) -> bool {
|
fn treat_next_err_as_bug(&self) -> bool {
|
||||||
self.flags
|
self.flags
|
||||||
.treat_err_as_bug
|
.treat_err_as_bug
|
||||||
.is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
|
.is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_errors(&self) -> bool {
|
fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||||
self.err_count > 0
|
self.err_guars.get(0).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||||
|
self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||||
|
self.has_errors_or_lint_errors()
|
||||||
|
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
|
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
|
||||||
|
@ -1405,7 +1417,7 @@ impl DiagCtxtInner {
|
||||||
fn flush_delayed(&mut self, kind: DelayedBugKind) {
|
fn flush_delayed(&mut self, kind: DelayedBugKind) {
|
||||||
let (bugs, note1) = match kind {
|
let (bugs, note1) = match kind {
|
||||||
DelayedBugKind::Normal => (
|
DelayedBugKind::Normal => (
|
||||||
std::mem::take(&mut self.delayed_bugs),
|
std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(),
|
||||||
"no errors encountered even though delayed bugs were created",
|
"no errors encountered even though delayed bugs were created",
|
||||||
),
|
),
|
||||||
DelayedBugKind::GoodPath => (
|
DelayedBugKind::GoodPath => (
|
||||||
|
@ -1427,7 +1439,7 @@ impl DiagCtxtInner {
|
||||||
{
|
{
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut out,
|
&mut out,
|
||||||
"delayed span bug: {}\n{}\n",
|
"delayed bug: {}\n{}\n",
|
||||||
bug.inner
|
bug.inner
|
||||||
.messages
|
.messages
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1470,7 +1482,7 @@ impl DiagCtxtInner {
|
||||||
fn panic_if_treat_err_as_bug(&self) {
|
fn panic_if_treat_err_as_bug(&self) {
|
||||||
if self.treat_err_as_bug() {
|
if self.treat_err_as_bug() {
|
||||||
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
|
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
|
||||||
assert_eq!(n, self.err_count + self.lint_err_count);
|
assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
panic!("aborting due to `-Z treat-err-as-bug=1`");
|
panic!("aborting due to `-Z treat-err-as-bug=1`");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -806,7 +806,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
TEST, rustc_error, Normal,
|
TEST, rustc_error, Normal,
|
||||||
template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||||
),
|
),
|
||||||
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
||||||
|
|
|
@ -118,9 +118,9 @@ where
|
||||||
return Err(err);
|
return Err(err);
|
||||||
} else {
|
} else {
|
||||||
// HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
|
// HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
|
||||||
// causes an error (span_delayed_bug) during normalization, without reporting an error,
|
// causes an delayed bug during normalization, without reporting an error, so we need
|
||||||
// so we need to act as if no error happened, in order to let our callers continue and
|
// to act as if no error happened, in order to let our callers continue and report an
|
||||||
// report an error later in check_impl_items_against_trait.
|
// error later in check_impl_items_against_trait.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
|
||||||
//
|
//
|
||||||
// rust-lang/rust#57464: `impl Trait` can leak local
|
// rust-lang/rust#57464: `impl Trait` can leak local
|
||||||
// scopes (in manner violating typeck). Therefore, use
|
// scopes (in manner violating typeck). Therefore, use
|
||||||
// `span_delayed_bug` to allow type error over an ICE.
|
// `delayed_bug` to allow type error over an ICE.
|
||||||
canonicalizer
|
canonicalizer
|
||||||
.tcx
|
.tcx
|
||||||
.dcx()
|
.dcx()
|
||||||
|
|
|
@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> {
|
||||||
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
|
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
|
||||||
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
|
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
|
||||||
match attr.meta_item_list() {
|
match attr.meta_item_list() {
|
||||||
// Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`.
|
// Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
|
||||||
Some(list)
|
Some(list)
|
||||||
if list.iter().any(|list_item| {
|
if list.iter().any(|list_item| {
|
||||||
matches!(
|
matches!(
|
||||||
list_item.ident().map(|i| i.name),
|
list_item.ident().map(|i| i.name),
|
||||||
Some(sym::span_delayed_bug_from_inside_query)
|
Some(sym::delayed_bug_from_inside_query)
|
||||||
)
|
)
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
tcx.ensure().trigger_span_delayed_bug(def_id);
|
tcx.ensure().trigger_delayed_bug(def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bare `#[rustc_error]`.
|
// Bare `#[rustc_error]`.
|
||||||
|
|
|
@ -108,9 +108,9 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue
|
||||||
// Queries marked with `fatal_cycle` do not need the latter implementation,
|
// Queries marked with `fatal_cycle` do not need the latter implementation,
|
||||||
// as they will raise an fatal error on query cycles instead.
|
// as they will raise an fatal error on query cycles instead.
|
||||||
rustc_queries! {
|
rustc_queries! {
|
||||||
/// This exists purely for testing the interactions between span_delayed_bug and incremental.
|
/// This exists purely for testing the interactions between delayed bugs and incremental.
|
||||||
query trigger_span_delayed_bug(key: DefId) {
|
query trigger_delayed_bug(key: DefId) {
|
||||||
desc { "triggering a span delayed bug for testing incremental" }
|
desc { "triggering a delayed bug for testing incremental" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects the list of all tools registered using `#![register_tool]`.
|
/// Collects the list of all tools registered using `#![register_tool]`.
|
||||||
|
|
|
@ -82,8 +82,8 @@ impl<'tcx> Region<'tcx> {
|
||||||
tcx.intern_region(ty::ReError(reported))
|
tcx.intern_region(ty::ReError(reported))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it
|
/// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets
|
||||||
/// gets used.
|
/// used.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
|
pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
|
||||||
Region::new_error_with_message(
|
Region::new_error_with_message(
|
||||||
|
@ -93,8 +93,8 @@ impl<'tcx> Region<'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given
|
/// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg`
|
||||||
/// `msg` to ensure it gets used.
|
/// to ensure it gets used.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||||
}
|
}
|
||||||
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
||||||
if self.references_error() {
|
if self.references_error() {
|
||||||
// We must include lint errors and span delayed bugs here.
|
// We must include lint errors and delayed bugs here.
|
||||||
if let Some(reported) =
|
if let Some(reported) =
|
||||||
ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
|
ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,16 +38,16 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A query to trigger a `span_delayed_bug`. Clearly, if one has a `tcx` one can already trigger a
|
/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a
|
||||||
/// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s
|
/// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed
|
||||||
/// interactions with the query system and incremental.
|
/// bugs with the query system and incremental.
|
||||||
pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
|
pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
|
||||||
tcx.dcx().span_delayed_bug(
|
tcx.dcx().span_delayed_bug(
|
||||||
tcx.def_span(key),
|
tcx.def_span(key),
|
||||||
"delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]",
|
"delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut crate::query::Providers) {
|
pub fn provide(providers: &mut crate::query::Providers) {
|
||||||
*providers = crate::query::Providers { trigger_span_delayed_bug, ..*providers };
|
*providers = crate::query::Providers { trigger_delayed_bug, ..*providers };
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,6 +655,7 @@ symbols! {
|
||||||
default_method_body_is_const,
|
default_method_body_is_const,
|
||||||
default_type_parameter_fallback,
|
default_type_parameter_fallback,
|
||||||
default_type_params,
|
default_type_params,
|
||||||
|
delayed_bug_from_inside_query,
|
||||||
deny,
|
deny,
|
||||||
deprecated,
|
deprecated,
|
||||||
deprecated_safe,
|
deprecated_safe,
|
||||||
|
@ -1579,7 +1580,6 @@ symbols! {
|
||||||
slice_patterns,
|
slice_patterns,
|
||||||
slicing_syntax,
|
slicing_syntax,
|
||||||
soft,
|
soft,
|
||||||
span_delayed_bug_from_inside_query,
|
|
||||||
specialization,
|
specialization,
|
||||||
speed,
|
speed,
|
||||||
spotlight,
|
spotlight,
|
||||||
|
|
|
@ -77,7 +77,7 @@ fn integration_test() {
|
||||||
// the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic:
|
// the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic:
|
||||||
/*
|
/*
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
#[rustc_error(delayed_bug_from_inside_query)]
|
||||||
fn main() {}
|
fn main() {}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -650,7 +650,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
TEST, rustc_error, Normal,
|
TEST, rustc_error, Normal,
|
||||||
template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||||
),
|
),
|
||||||
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// revisions: cfail1 cfail2
|
// revisions: cfail1 cfail2
|
||||||
// should-ice
|
// should-ice
|
||||||
// error-pattern: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
|
// error-pattern: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
#[rustc_error(delayed_bug_from_inside_query)]
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs
|
// compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs
|
||||||
// failure-status: 101
|
// failure-status: 101
|
||||||
// error-pattern: aborting due to `-Z treat-err-as-bug=1`
|
// error-pattern: aborting due to `-Z treat-err-as-bug=1`
|
||||||
// error-pattern: [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
|
// error-pattern: [trigger_delayed_bug] triggering a delayed bug for testing incremental
|
||||||
// normalize-stderr-test "note: .*\n\n" -> ""
|
// normalize-stderr-test "note: .*\n\n" -> ""
|
||||||
// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
|
// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
|
||||||
// rustc-env:RUST_BACKTRACE=0
|
// rustc-env:RUST_BACKTRACE=0
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
#[rustc_error(delayed_bug_from_inside_query)]
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: internal compiler error: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
|
error: internal compiler error: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
|
||||||
--> $DIR/span_delayed_bug.rs:12:1
|
--> $DIR/span_delayed_bug.rs:12:1
|
||||||
|
|
|
|
||||||
LL | fn main() {}
|
LL | fn main() {}
|
||||||
|
@ -7,5 +7,5 @@ LL | fn main() {}
|
||||||
error: the compiler unexpectedly panicked. this is a bug.
|
error: the compiler unexpectedly panicked. this is a bug.
|
||||||
|
|
||||||
query stack during panic:
|
query stack during panic:
|
||||||
#0 [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
|
#0 [trigger_delayed_bug] triggering a delayed bug for testing incremental
|
||||||
end of query stack
|
end of query stack
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue