1
Fork 0

Auto merge of #118655 - compiler-errors:rollup-vrngyzn, r=compiler-errors

Rollup of 9 pull requests

Successful merges:

 - #117793 (Update variable name to fix `unused_variables` warning)
 - #118123 (Add support for making lib features internal)
 - #118268 (Pretty print `Fn<(..., ...)>` trait refs with parentheses (almost) always)
 - #118346 (Add `deeply_normalize_for_diagnostics`, use it in coherence)
 - #118350 (Simplify Default for tuples)
 - #118450 (Use OnceCell in cell module documentation)
 - #118585 (Fix parser ICE when recovering `dyn`/`impl` after `for<...>`)
 - #118587 (Cleanup error handlers some more)
 - #118642 (bootstrap(builder.rs): Don't explicitly warn against `semicolon_in_expressions_from_macros`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-12-06 04:20:51 +00:00
commit 1dd4db5062
53 changed files with 552 additions and 572 deletions

View file

@ -1,5 +1,5 @@
use rustc_errors::{ use rustc_errors::{
AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan, AddToDiagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan,
SingleLabelManySpans, SingleLabelManySpans,
}; };
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
@ -446,9 +446,9 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
} }
// Hand-written implementation to support custom user messages. // Hand-written implementation to support custom user messages.
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage { impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
#[track_caller] #[track_caller]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
#[expect( #[expect(
rustc::untranslatable_diagnostic, rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages" reason = "cannot translate user-provided messages"
@ -801,8 +801,8 @@ pub(crate) struct AsmClobberNoReg {
pub(crate) clobbers: Vec<Span>, pub(crate) clobbers: Vec<Span>,
} }
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = let mut diag =
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg); handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
diag.set_span(self.spans.clone()); diag.set_span(self.spans.clone());

View file

@ -64,7 +64,7 @@ impl ConcurrencyLimiter {
// Make sure to drop the mutex guard first to prevent poisoning the mutex. // Make sure to drop the mutex guard first to prevent poisoning the mutex.
drop(state); drop(state);
if let Some(err) = err { if let Some(err) = err {
handler.fatal(err).raise(); handler.fatal(err);
} else { } else {
// The error was already emitted, but compilation continued. Raise a silent // The error was already emitted, but compilation continued. Raise a silent
// fatal error. // fatal error.

View file

@ -111,8 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
pub(crate) struct MissingFeatures; pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
if let Some(span) = self.span { if let Some(span) = self.span {
diag.set_span(span); diag.set_span(span);
}; };

View file

@ -5,7 +5,7 @@ use std::path::Path;
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{ use rustc_errors::{
DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, Handler, IntoDiagnostic,
}; };
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span; use rustc_span::Span;
@ -101,13 +101,13 @@ pub(crate) struct DynamicLinkingWithLTO;
pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> { impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, FatalError> {
let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(sess); let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(handler);
let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
let message = sess.eagerly_translate_to_string(message.clone(), diag.args()); let message = handler.eagerly_translate_to_string(message.clone(), diag.args());
let mut diag = sess.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config); let mut diag = handler.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config);
diag.set_arg("error", message); diag.set_arg("error", message);
diag diag
} }
@ -124,8 +124,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
pub(crate) struct MissingFeatures; pub(crate) struct MissingFeatures;
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); let mut diag = handler.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
if let Some(span) = self.span { if let Some(span) = self.span {
diag.set_span(span); diag.set_span(span);
}; };
@ -183,8 +183,8 @@ pub enum LlvmError<'a> {
pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> {
use LlvmError::*; use LlvmError::*;
let msg_with_llvm_err = match &self.0 { let msg_with_llvm_err = match &self.0 {
WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
@ -201,7 +201,7 @@ impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> {
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
}; };
let mut diag = self.0.into_diagnostic(sess); let mut diag = self.0.into_diagnostic(handler);
diag.set_primary_message(msg_with_llvm_err); diag.set_primary_message(msg_with_llvm_err);
diag.set_arg("llvm_err", self.1); diag.set_arg("llvm_err", self.1);
diag diag

View file

@ -239,7 +239,7 @@ impl Diagnostic {
} }
#[track_caller] #[track_caller]
pub fn new_with_code<M: Into<DiagnosticMessage>>( pub(crate) fn new_with_code<M: Into<DiagnosticMessage>>(
level: Level, level: Level,
code: Option<DiagnosticId>, code: Option<DiagnosticId>,
message: M, message: M,
@ -281,7 +281,7 @@ impl Diagnostic {
} }
} }
pub fn update_unstable_expectation_id( pub(crate) fn update_unstable_expectation_id(
&mut self, &mut self,
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
) { ) {
@ -307,14 +307,14 @@ impl Diagnostic {
} }
/// Indicates whether this diagnostic should show up in cargo's future breakage report. /// Indicates whether this diagnostic should show up in cargo's future breakage report.
pub fn has_future_breakage(&self) -> bool { pub(crate) fn has_future_breakage(&self) -> bool {
match self.code { match self.code {
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
_ => false, _ => false,
} }
} }
pub fn is_force_warn(&self) -> bool { pub(crate) fn is_force_warn(&self) -> bool {
match self.code { match self.code {
Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn, Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
_ => false, _ => false,
@ -391,29 +391,6 @@ impl Diagnostic {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
} }
pub fn note_unsuccessful_coercion(
&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
) -> &mut Self {
let mut msg: Vec<_> =
vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)];
msg.extend(expected.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
}));
msg.push((Cow::from("` to type '"), Style::NoStyle));
msg.extend(found.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle),
StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight),
}));
msg.push((Cow::from("`"), Style::NoStyle));
// For now, just attach these as notes
self.highlighted_note(msg);
self
}
pub fn note_expected_found_extra( pub fn note_expected_found_extra(
&mut self, &mut self,
expected_label: &dyn fmt::Display, expected_label: &dyn fmt::Display,
@ -475,7 +452,7 @@ impl Diagnostic {
self self
} }
pub fn highlighted_note<M: Into<SubdiagnosticMessage>>( fn highlighted_note<M: Into<SubdiagnosticMessage>>(
&mut self, &mut self,
msg: Vec<(M, Style)>, msg: Vec<(M, Style)>,
) -> &mut Self { ) -> &mut Self {
@ -572,14 +549,6 @@ impl Diagnostic {
self self
} }
/// Clear any existing suggestions.
pub fn clear_suggestions(&mut self) -> &mut Self {
if let Ok(suggestions) = &mut self.suggestions {
suggestions.clear();
}
self
}
/// Helper for pushing to `self.suggestions`, if available (not disable). /// Helper for pushing to `self.suggestions`, if available (not disable).
fn push_suggestion(&mut self, suggestion: CodeSuggestion) { fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
if let Ok(suggestions) = &mut self.suggestions { if let Ok(suggestions) = &mut self.suggestions {
@ -992,7 +961,7 @@ impl Diagnostic {
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
/// passes the user's string along). /// passes the user's string along).
pub(crate) fn subdiagnostic_message_to_diagnostic_message( fn subdiagnostic_message_to_diagnostic_message(
&self, &self,
attr: impl Into<SubdiagnosticMessage>, attr: impl Into<SubdiagnosticMessage>,
) -> DiagnosticMessage { ) -> DiagnosticMessage {

View file

@ -18,18 +18,18 @@ use std::thread::panicking;
/// Trait implemented by error types. This should not be implemented manually. Instead, use /// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
#[rustc_diagnostic_item = "IntoDiagnostic"] #[rustc_diagnostic_item = "IntoDiagnostic"]
pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
/// Write out as a diagnostic out of `Handler`. /// Write out as a diagnostic out of `Handler`.
#[must_use] #[must_use]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G>;
} }
impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned<T> impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
where where
T: IntoDiagnostic<'a, E>, T: IntoDiagnostic<'a, G>,
E: EmissionGuarantee, G: EmissionGuarantee,
{ {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
let mut diag = self.node.into_diagnostic(handler); let mut diag = self.node.into_diagnostic(handler);
diag.set_span(self.span); diag.set_span(self.span);
diag diag
@ -116,26 +116,6 @@ pub trait EmissionGuarantee: Sized {
} }
impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
message: M,
) -> Self {
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(Diagnostic::new_with_code(
Level::Error { lint: false },
None,
message,
)),
},
_marker: PhantomData,
}
}
/// Discard the guarantee `.emit()` would return, in favor of having the /// Discard the guarantee `.emit()` would return, in favor of having the
/// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there
/// is a common codepath handling both errors and warnings. /// is a common codepath handling both errors and warnings.
@ -189,35 +169,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
handler: &Handler, handler: &Handler,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> { ) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_guaranteeing_error(handler, msg) DiagnosticBuilder::new(handler, Level::Error { lint: false }, msg)
}
}
impl<'a> DiagnosticBuilder<'a, ()> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new_with_code(level, None, message);
Self::new_diagnostic(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
#[track_caller]
pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
} }
} }
@ -249,28 +201,6 @@ impl EmissionGuarantee for () {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Noted; pub struct Noted;
impl<'a> DiagnosticBuilder<'a, Noted> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
Self::new_diagnostic_note(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Noted { impl EmissionGuarantee for Noted {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state { match db.inner.state {
@ -290,7 +220,7 @@ impl EmissionGuarantee for Noted {
handler: &Handler, handler: &Handler,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> { ) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_note(handler, msg) DiagnosticBuilder::new(handler, Level::Note, msg)
} }
} }
@ -299,29 +229,6 @@ impl EmissionGuarantee for Noted {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Bug; pub struct Bug;
impl<'a> DiagnosticBuilder<'a, Bug> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message);
Self::new_diagnostic_bug(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic bug");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Bug { impl EmissionGuarantee for Bug {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state { match db.inner.state {
@ -342,22 +249,7 @@ impl EmissionGuarantee for Bug {
handler: &Handler, handler: &Handler,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> { ) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_bug(handler, msg) DiagnosticBuilder::new(handler, Level::Bug, msg)
}
}
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, message)),
},
_marker: PhantomData,
}
} }
} }
@ -381,36 +273,7 @@ impl EmissionGuarantee for ! {
handler: &Handler, handler: &Handler,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> { ) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_fatal(handler, msg) DiagnosticBuilder::new(handler, Level::Fatal, msg)
}
}
impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_almost_fatal(
handler: &'a Handler,
message: impl Into<DiagnosticMessage>,
) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
Self::new_diagnostic_almost_fatal(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_almost_fatal(
handler: &'a Handler,
diagnostic: Diagnostic,
) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
} }
} }
@ -434,7 +297,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
handler: &Handler, handler: &Handler,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> { ) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_almost_fatal(handler, msg) DiagnosticBuilder::new(handler, Level::Fatal, msg)
} }
} }
@ -476,6 +339,32 @@ impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
} }
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new(level, message);
Self::new_diagnostic(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
#[track_caller]
pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
/// Emit the diagnostic. /// Emit the diagnostic.
#[track_caller] #[track_caller]
pub fn emit(&mut self) -> G { pub fn emit(&mut self) -> G {
@ -626,12 +515,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
found_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn note_unsuccessful_coercion(
&mut self,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
) -> &mut Self);
forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_note( forward!(pub fn span_note(
@ -660,7 +543,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
forward!(pub fn clear_suggestions(&mut self,) -> &mut Self);
forward!(pub fn multipart_suggestion( forward!(pub fn multipart_suggestion(
&mut self, &mut self,

View file

@ -554,7 +554,8 @@ impl Drop for HandlerInner {
// instead of "require some error happened". Sadly that isn't ideal, as // instead of "require some error happened". Sadly that isn't ideal, as
// lints can be `#[allow]`'d, potentially leading to this triggering. // lints can be `#[allow]`'d, potentially leading to this triggering.
// Also, "good path" should be replaced with a better naming. // Also, "good path" should be replaced with a better naming.
if !self.has_any_message() && !self.suppressed_expected_diag && !std::thread::panicking() { let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0;
if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
self.flush_delayed( self.flush_delayed(
bugs, bugs,
@ -675,15 +676,46 @@ impl Handler {
/// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key.
/// Retrieve a stashed diagnostic with `steal_diagnostic`. /// Retrieve a stashed diagnostic with `steal_diagnostic`.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
self.inner.borrow_mut().stash((span.with_parent(None), key), diag); let mut inner = self.inner.borrow_mut();
let key = (span.with_parent(None), key);
if diag.is_error() {
if matches!(diag.level, Level::Error { lint: true }) {
inner.lint_err_count += 1;
} else {
inner.err_count += 1;
}
} else {
// Warnings are only automatically flushed if they're forced.
if diag.is_force_warn() {
inner.warn_count += 1;
}
}
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
// See the PR for a discussion.
inner.stashed_diagnostics.insert(key, diag);
} }
/// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key. /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> { pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
self.inner let mut inner = self.inner.borrow_mut();
.borrow_mut() let key = (span.with_parent(None), key);
.steal((span.with_parent(None), key)) let diag = inner.stashed_diagnostics.remove(&key)?;
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) if diag.is_error() {
if matches!(diag.level, Level::Error { lint: true }) {
inner.lint_err_count -= 1;
} else {
inner.err_count -= 1;
}
} else {
if diag.is_force_warn() {
inner.warn_count -= 1;
}
}
Some(DiagnosticBuilder::new_diagnostic(self, diag))
} }
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool { pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
@ -847,7 +879,7 @@ impl Handler {
&self, &self,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
DiagnosticBuilder::new_guaranteeing_error(self, msg) DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
} }
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
@ -914,7 +946,7 @@ impl Handler {
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
#[track_caller] #[track_caller]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new_fatal(self, msg) DiagnosticBuilder::new(self, Level::Fatal, msg)
} }
/// Construct a builder at the `Help` level with the `msg`. /// Construct a builder at the `Help` level with the `msg`.
@ -996,19 +1028,42 @@ impl Handler {
} }
/// For documentation on this, see `Session::span_delayed_bug`. /// For documentation on this, see `Session::span_delayed_bug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_bug`, `span_err`, etc.
#[track_caller] #[track_caller]
pub fn span_delayed_bug( pub fn span_delayed_bug(
&self, &self,
span: impl Into<MultiSpan>, sp: impl Into<MultiSpan>,
msg: impl Into<String>, msg: impl Into<String>,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
self.inner.borrow_mut().span_delayed_bug(span, msg) let mut inner = self.inner.borrow_mut();
// This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
if inner.flags.treat_err_as_bug.is_some_and(|c| {
inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
inner.span_bug(sp, msg.into());
}
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
diagnostic.set_span(sp.into());
inner.emit_diagnostic(&mut diagnostic).unwrap()
} }
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed). // where the explanation of what "good path" is (also, it should be renamed).
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
self.inner.borrow_mut().good_path_delayed_bug(msg) let mut inner = self.inner.borrow_mut();
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
if inner.flags.report_delayed_bugs {
inner.emit_diagnostic(&mut diagnostic);
}
let backtrace = std::backtrace::Backtrace::capture();
inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
} }
#[track_caller] #[track_caller]
@ -1034,34 +1089,34 @@ impl Handler {
db db
} }
// NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError { pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().fatal(msg) DiagnosticBuilder::<FatalError>::new(self, Fatal, msg).emit().raise()
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.inner.borrow_mut().err(msg) DiagnosticBuilder::<ErrorGuaranteed>::new(self, Error { lint: false }, msg).emit()
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) { pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Warning(None), msg).emit(); DiagnosticBuilder::<()>::new(self, Warning(None), msg).emit();
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn note(&self, msg: impl Into<DiagnosticMessage>) { pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Note, msg).emit(); DiagnosticBuilder::<()>::new(self, Note, msg).emit();
} }
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! { pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().bug(msg) DiagnosticBuilder::<diagnostic_builder::Bug>::new(self, Bug, msg).emit();
panic::panic_any(ExplicitBug);
} }
#[inline] #[inline]
pub fn err_count(&self) -> usize { pub fn err_count(&self) -> usize {
self.inner.borrow().err_count() self.inner.borrow().err_count
} }
pub fn has_errors(&self) -> Option<ErrorGuaranteed> { pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
@ -1072,26 +1127,103 @@ impl Handler {
} }
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> { pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_lint_errors().then(|| { let inner = self.inner.borrow();
let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0;
has_errors_or_lint_errors.then(|| {
#[allow(deprecated)] #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted() ErrorGuaranteed::unchecked_claim_error_was_emitted()
}) })
} }
pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> { pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_span_delayed_bugs().then(|| { let inner = self.inner.borrow();
let has_errors_or_span_delayed_bugs =
inner.has_errors() || !inner.span_delayed_bugs.is_empty();
has_errors_or_span_delayed_bugs.then(|| {
#[allow(deprecated)] #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted() ErrorGuaranteed::unchecked_claim_error_was_emitted()
}) })
} }
pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> { pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().is_compilation_going_to_fail().then(|| { let inner = self.inner.borrow();
let will_fail =
inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty();
will_fail.then(|| {
#[allow(deprecated)] #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted() ErrorGuaranteed::unchecked_claim_error_was_emitted()
}) })
} }
pub fn print_error_count(&self, registry: &Registry) { pub fn print_error_count(&self, registry: &Registry) {
self.inner.borrow_mut().print_error_count(registry) let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
let warnings = match inner.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match inner.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("aborting due to 1 previous error"),
count => Cow::from(format!("aborting due to {count} previous errors")),
};
if inner.treat_err_as_bug() {
return;
}
match (errors.len(), warnings.len()) {
(0, 0) => return,
(0, _) => inner.emitter.emit_diagnostic(&Diagnostic::new(
Level::Warning(None),
DiagnosticMessage::Str(warnings),
)),
(_, 0) => {
inner.emit_diagnostic(&mut Diagnostic::new(Fatal, errors));
}
(_, _) => {
inner.emit_diagnostic(&mut Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
}
}
let can_show_explain = inner.emitter.should_show_explain();
let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty();
if can_show_explain && are_there_diagnostics {
let mut error_codes = inner
.emitted_diagnostic_codes
.iter()
.filter_map(|x| match &x {
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
Some(s.clone())
}
_ => None,
})
.collect::<Vec<_>>();
if !error_codes.is_empty() {
error_codes.sort();
if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
inner.failure_note(format!(
"Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." }
));
inner.failure_note(format!(
"For more information about an error, try \
`rustc --explain {}`.",
&error_codes[0]
));
} else {
inner.failure_note(format!(
"For more information about this error, try \
`rustc --explain {}`.",
&error_codes[0]
));
}
}
}
} }
pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> { pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
@ -1099,7 +1231,11 @@ impl Handler {
} }
pub fn abort_if_errors(&self) { pub fn abort_if_errors(&self) {
self.inner.borrow_mut().abort_if_errors() let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
if inner.has_errors() {
FatalError.raise();
}
} }
/// `true` if we haven't taught a diagnostic with this code already. /// `true` if we haven't taught a diagnostic with this code already.
@ -1108,11 +1244,11 @@ impl Handler {
/// Used to suppress emitting the same error multiple times with extended explanation when /// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`. /// calling `-Zteach`.
pub fn must_teach(&self, code: &DiagnosticId) -> bool { pub fn must_teach(&self, code: &DiagnosticId) -> bool {
self.inner.borrow_mut().must_teach(code) self.inner.borrow_mut().taught_diagnostics.insert(code.clone())
} }
pub fn force_print_diagnostic(&self, db: Diagnostic) { pub fn force_print_diagnostic(&self, db: Diagnostic) {
self.inner.borrow_mut().force_print_diagnostic(db) self.inner.borrow_mut().emitter.emit_diagnostic(&db);
} }
pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> { pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
@ -1196,11 +1332,11 @@ impl Handler {
mut diag: Diagnostic, mut diag: Diagnostic,
sp: impl Into<MultiSpan>, sp: impl Into<MultiSpan>,
) -> Option<ErrorGuaranteed> { ) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diag.set_span(sp)) self.emit_diagnostic(diag.set_span(sp))
} }
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type) self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
} }
pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) { pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
@ -1219,7 +1355,7 @@ impl Handler {
inner.bump_err_count(); inner.bump_err_count();
} }
inner.emit_unused_externs(lint_level, unused_externs) inner.emitter.emit_unused_externs(lint_level, unused_externs)
} }
pub fn update_unstable_expectation_id( pub fn update_unstable_expectation_id(
@ -1270,15 +1406,11 @@ impl Handler {
} }
} }
// Note: we prefer implementing operations on `Handler`, rather than
// `HandlerInner`, whenever possible. This minimizes functions where
// `Handler::foo()` just borrows `inner` and forwards a call to
// `HanderInner::foo`.
impl HandlerInner { impl HandlerInner {
fn must_teach(&mut self, code: &DiagnosticId) -> bool {
self.taught_diagnostics.insert(code.clone())
}
fn force_print_diagnostic(&mut self, db: Diagnostic) {
self.emitter.emit_diagnostic(&db);
}
/// Emit all stashed diagnostics. /// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> { fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
let has_errors = self.has_errors(); let has_errors = self.has_errors();
@ -1312,6 +1444,11 @@ impl HandlerInner {
// FIXME(eddyb) this should ideally take `diagnostic` by value. // FIXME(eddyb) this should ideally take `diagnostic` by value.
fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> { fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug()
{
diagnostic.level = Level::Bug;
}
// The `LintExpectationId` can be stable or unstable depending on when it was created. // The `LintExpectationId` can be stable or unstable depending on when it was created.
// Diagnostics created before the definition of `HirId`s are unstable and can not yet // Diagnostics created before the definition of `HirId`s are unstable and can not yet
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
@ -1427,17 +1564,9 @@ impl HandlerInner {
guaranteed guaranteed
} }
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
self.emitter.emit_artifact_notification(path, artifact_type);
}
fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
self.emitter.emit_unused_externs(lint_level, unused_externs);
}
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.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get() self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get()
}) })
} }
@ -1445,141 +1574,8 @@ impl HandlerInner {
self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len() self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len()
} }
fn print_error_count(&mut self, registry: &Registry) {
self.emit_stashed_diagnostics();
let warnings = match self.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match self.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("aborting due to 1 previous error"),
count => Cow::from(format!("aborting due to {count} previous errors")),
};
if self.treat_err_as_bug() {
return;
}
match (errors.len(), warnings.len()) {
(0, 0) => return,
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
Level::Warning(None),
DiagnosticMessage::Str(warnings),
)),
(_, 0) => {
let _ = self.fatal(errors);
}
(_, _) => {
let _ = self.fatal(format!("{errors}; {warnings}"));
}
}
let can_show_explain = self.emitter.should_show_explain();
let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
if can_show_explain && are_there_diagnostics {
let mut error_codes = self
.emitted_diagnostic_codes
.iter()
.filter_map(|x| match &x {
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
Some(s.clone())
}
_ => None,
})
.collect::<Vec<_>>();
if !error_codes.is_empty() {
error_codes.sort();
if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
self.failure_note(format!(
"Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." }
));
self.failure_note(format!(
"For more information about an error, try \
`rustc --explain {}`.",
&error_codes[0]
));
} else {
self.failure_note(format!(
"For more information about this error, try \
`rustc --explain {}`.",
&error_codes[0]
));
}
}
}
}
fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
// Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
// yet; that happens when we actually emit the diagnostic.
if diagnostic.is_error() {
if matches!(diagnostic.level, Level::Error { lint: true }) {
self.lint_err_count += 1;
} else {
self.err_count += 1;
}
} else {
// Warnings are only automatically flushed if they're forced.
if diagnostic.is_force_warn() {
self.warn_count += 1;
}
}
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
// See the PR for a discussion.
self.stashed_diagnostics.insert(key, diagnostic);
}
fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
let diagnostic = self.stashed_diagnostics.remove(&key)?;
if diagnostic.is_error() {
if matches!(diagnostic.level, Level::Error { lint: true }) {
self.lint_err_count -= 1;
} else {
self.err_count -= 1;
}
} else {
if diagnostic.is_force_warn() {
self.warn_count -= 1;
}
}
Some(diagnostic)
}
#[inline]
fn err_count(&self) -> usize {
self.err_count
}
fn has_errors(&self) -> bool { fn has_errors(&self) -> bool {
self.err_count() > 0 self.err_count > 0
}
fn has_errors_or_lint_errors(&self) -> bool {
self.has_errors() || self.lint_err_count > 0
}
fn has_errors_or_span_delayed_bugs(&self) -> bool {
self.has_errors() || !self.span_delayed_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn is_compilation_going_to_fail(&self) -> bool {
self.has_errors() || self.lint_err_count > 0 || !self.span_delayed_bugs.is_empty()
}
fn abort_if_errors(&mut self) {
self.emit_stashed_diagnostics();
if self.has_errors() {
FatalError.raise();
}
} }
#[track_caller] #[track_caller]
@ -1592,67 +1588,10 @@ impl HandlerInner {
self.emit_diagnostic(diag.set_span(sp)); self.emit_diagnostic(diag.set_span(sp));
} }
/// For documentation on this, see `Session::span_delayed_bug`.
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_bug`, `span_err`, etc.
#[track_caller]
fn span_delayed_bug(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<String>,
) -> ErrorGuaranteed {
// This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
if self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg.into());
}
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
diagnostic.set_span(sp.into());
self.emit_diagnostic(&mut diagnostic).unwrap()
}
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed).
fn good_path_delayed_bug(&mut self, msg: impl Into<DiagnosticMessage>) {
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
if self.flags.report_delayed_bugs {
self.emit_diagnostic(&mut diagnostic);
}
let backtrace = std::backtrace::Backtrace::capture();
self.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
}
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) { fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
} }
fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.emit(Fatal, msg);
FatalError
}
fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.emit(Error { lint: false }, msg)
}
/// Emit an error; level should be `Error` or `Fatal`.
fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap()
}
fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diagnostic(&mut Diagnostic::new(Bug, msg));
panic::panic_any(ExplicitBug);
}
fn flush_delayed( fn flush_delayed(
&mut self, &mut self,
bugs: impl IntoIterator<Item = DelayedDiagnostic>, bugs: impl IntoIterator<Item = DelayedDiagnostic>,
@ -1723,7 +1662,7 @@ impl HandlerInner {
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() {
match ( match (
self.err_count() + self.lint_err_count, self.err_count + self.lint_err_count,
self.delayed_bug_count(), self.delayed_bug_count(),
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
) { ) {

View file

@ -1145,11 +1145,6 @@ impl<'a> ExtCtxt<'a> {
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.diagnostic().span_err(sp, msg); self.sess.diagnostic().span_err(sp, msg);
} }
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.diagnostic().span_warn(sp, msg);
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! { pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! {
self.sess.diagnostic().span_bug(sp, msg); self.sess.diagnostic().span_bug(sp, msg);
} }

View file

@ -56,8 +56,10 @@ macro_rules! declare_features {
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct Features { pub struct Features {
/// `#![feature]` attrs for language features, for error reporting. /// `#![feature]` attrs for language features, for error reporting.
/// "declared" here means that the feature is actually enabled in the current crate.
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features. /// `#![feature]` attrs for non-language (library) features.
/// "declared" here means that the feature is actually enabled in the current crate.
pub declared_lib_features: Vec<(Symbol, Span)>, pub declared_lib_features: Vec<(Symbol, Span)>,
/// `declared_lang_features` + `declared_lib_features`. /// `declared_lang_features` + `declared_lib_features`.
pub declared_features: FxHashSet<Symbol>, pub declared_features: FxHashSet<Symbol>,
@ -133,9 +135,18 @@ macro_rules! declare_features {
$( $(
sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
)* )*
_ if self.declared_features.contains(&feature) => {
// This could be accepted/removed, or a libs feature.
// Accepted/removed features aren't in this file but are never internal // Accepted/removed features aren't in this file but are never internal
// (a removed feature might have been internal, but that's now irrelevant). // (a removed feature might have been internal, but that's now irrelevant).
_ if self.declared_features.contains(&feature) => false, // Libs features are internal if they end in `_internal` or `_internals`.
// As a special exception we also consider `core_intrinsics` internal;
// renaming that age-old feature is just not worth the hassle.
// We just always test the name; it's not a big deal if we accidentally hit
// an accepted/removed lang feature that way.
let name = feature.as_str();
name == "core_intrinsics" || name.ends_with("_internal") || name.ends_with("_internals")
}
_ => panic!("`{}` was not listed in `declare_features`", feature), _ => panic!("`{}` was not listed in `declare_features`", feature),
} }
} }
@ -215,9 +226,6 @@ declare_features! (
(internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), (internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
/// Added for testing unstable lints; perma-unstable. /// Added for testing unstable lints; perma-unstable.
(internal, test_unstable_lint, "1.60.0", None, None), (internal, test_unstable_lint, "1.60.0", None, None),
/// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
/// Marked `internal` since perma-unstable and unsound.
(internal, unsafe_pin_internals, "1.60.0", None, None),
/// Use for stable + negative coherence and strict coherence depending on trait's /// Use for stable + negative coherence and strict coherence depending on trait's
/// rustc_strict_coherence value. /// rustc_strict_coherence value.
(unstable, with_negative_coherence, "1.60.0", None, None), (unstable, with_negative_coherence, "1.60.0", None, None),

View file

@ -1182,10 +1182,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(bound_span) = bound_span { if let Some(bound_span) = bound_span {
err.span_label( err.span_label(
bound_span, bound_span,
format!( format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),),
"ambiguous `{assoc_name}` from `{}`",
bound.print_only_trait_path(),
),
); );
if let Some(constraint) = &is_equality { if let Some(constraint) = &is_equality {
where_bounds.push(format!( where_bounds.push(format!(

View file

@ -106,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait here instead: `trait NewTrait: {} {{}}`", trait here instead: `trait NewTrait: {} {{}}`",
regular_traits regular_traits
.iter() .iter()
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string()) .map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" + "), .join(" + "),

View file

@ -23,7 +23,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.def_span(def_id), tcx.def_span(def_id),
E0199, E0199,
"implementing the trait `{}` is not unsafe", "implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path() trait_ref.print_trait_sugared()
) )
.span_suggestion_verbose( .span_suggestion_verbose(
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
@ -40,13 +40,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.def_span(def_id), tcx.def_span(def_id),
E0200, E0200,
"the trait `{}` requires an `unsafe impl` declaration", "the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path() trait_ref.print_trait_sugared()
) )
.note(format!( .note(format!(
"the trait `{}` enforces invariants that the compiler can't check. \ "the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \ Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword", upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_only_trait_path() trait_ref.print_trait_sugared()
)) ))
.span_suggestion_verbose( .span_suggestion_verbose(
item.span.shrink_to_lo(), item.span.shrink_to_lo(),
@ -69,7 +69,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"the trait `{}` enforces invariants that the compiler can't check. \ "the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \ Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword", upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_only_trait_path() trait_ref.print_trait_sugared()
)) ))
.span_suggestion_verbose( .span_suggestion_verbose(
item.span.shrink_to_lo(), item.span.shrink_to_lo(),

View file

@ -2288,7 +2288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Adt(def, _) if def.did().is_local() => { ty::Adt(def, _) if def.did().is_local() => {
spans.push_span_label( spans.push_span_label(
self.tcx.def_span(def.did()), self.tcx.def_span(def.did()),
format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), format!("must implement `{}`", pred.trait_ref.print_trait_sugared()),
); );
} }
_ => {} _ => {}
@ -2299,7 +2299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = if preds.len() == 1 { let msg = if preds.len() == 1 {
format!( format!(
"an implementation of `{}` might be missing for `{}`", "an implementation of `{}` might be missing for `{}`",
preds[0].trait_ref.print_only_trait_path(), preds[0].trait_ref.print_trait_sugared(),
preds[0].self_ty() preds[0].self_ty()
) )
} else { } else {

View file

@ -2219,8 +2219,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
infer::PolyTraitRefs(exp_found) => { infer::PolyTraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound { let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(), expected: exp_found.expected.print_trait_sugared(),
found: exp_found.found.print_only_trait_path(), found: exp_found.found.print_trait_sugared(),
}; };
match self.expected_found_str(pretty_exp_found) { match self.expected_found_str(pretty_exp_found) {
Some((expected, found, _, _)) if expected == found => { Some((expected, found, _, _)) if expected == found => {

View file

@ -2640,6 +2640,23 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
} }
} }
/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
/// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds.
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>);
impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
self.to_string().into_diagnostic_arg()
}
}
impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
/// the trait name. That is, it will print `Trait` instead of /// the trait name. That is, it will print `Trait` instead of
/// `<T as Trait<U>>`. /// `<T as Trait<U>>`.
@ -2657,6 +2674,10 @@ impl<'tcx> ty::TraitRef<'tcx> {
TraitRefPrintOnlyTraitPath(self) TraitRefPrintOnlyTraitPath(self)
} }
pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> {
TraitRefPrintSugared(self)
}
pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
TraitRefPrintOnlyTraitName(self) TraitRefPrintOnlyTraitName(self)
} }
@ -2666,6 +2687,10 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
self.map_bound(|tr| tr.print_only_trait_path()) self.map_bound(|tr| tr.print_only_trait_path())
} }
pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
self.map_bound(|tr| tr.print_trait_sugared())
}
} }
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
@ -2745,6 +2770,7 @@ forward_display_to_print! {
ty::PolyExistentialTraitRef<'tcx>, ty::PolyExistentialTraitRef<'tcx>,
ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, ty::TraitRef<'tcx>>,
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>,
ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>,
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
@ -2844,6 +2870,24 @@ define_print_and_forward_display! {
p!(print_def_path(self.0.def_id, self.0.args)); p!(print_def_path(self.0.def_id, self.0.args));
} }
TraitRefPrintSugared<'tcx> {
if !with_no_queries()
&& let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id)
&& let ty::Tuple(args) = self.0.args.type_at(1).kind()
{
p!(write("{}", kind.as_str()), "(");
for (i, arg) in args.iter().enumerate() {
if i > 0 {
p!(", ");
}
p!(print(arg));
}
p!(")");
} else {
p!(print_def_path(self.0.def_id, self.0.args));
}
}
TraitRefPrintOnlyTraitName<'tcx> { TraitRefPrintOnlyTraitName<'tcx> {
p!(print_def_path(self.0.def_id, &[])); p!(print_def_path(self.0.def_id, &[]));
} }
@ -2892,7 +2936,7 @@ define_print_and_forward_display! {
if let ty::ImplPolarity::Negative = self.polarity { if let ty::ImplPolarity::Negative = self.polarity {
p!("!"); p!("!");
} }
p!(print(self.trait_ref.print_only_trait_path())) p!(print(self.trait_ref.print_trait_sugared()))
} }
ty::ProjectionPredicate<'tcx> { ty::ProjectionPredicate<'tcx> {

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_errors::{ use rustc_errors::{
Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage,
EmissionGuarantee, Handler, IntoDiagnostic, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
}; };
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
@ -62,9 +62,9 @@ pub(crate) struct RequiresUnsafe {
// so we need to eagerly translate the label here, which isn't supported by the derive API // so we need to eagerly translate the label here, which isn't supported by the derive API
// We could also exhaustively list out the primary messages for all unsafe violations, // We could also exhaustively list out the primary messages for all unsafe violations,
// but this would result in a lot of duplication. // but this would result in a lot of duplication.
impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe { impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe {
#[track_caller] #[track_caller]
fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> { fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> {
let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe); let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe);
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
diag.set_span(self.span); diag.set_span(self.span);

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_ast::token::Token; use rustc_ast::token::Token;
use rustc_ast::{Path, Visibility}; use rustc_ast::{Path, Visibility};
use rustc_errors::{AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; use rustc_errors::{AddToDiagnostic, Applicability, ErrorGuaranteed, IntoDiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
@ -1045,12 +1045,12 @@ pub(crate) struct ExpectedIdentifier {
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
} }
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
#[track_caller] #[track_caller]
fn into_diagnostic( fn into_diagnostic(
self, self,
handler: &'a rustc_errors::Handler, handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, G> { ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let token_descr = TokenDescription::from_token(&self.token); let token_descr = TokenDescription::from_token(&self.token);
let mut diag = handler.struct_diagnostic(match token_descr { let mut diag = handler.struct_diagnostic(match token_descr {
@ -1102,12 +1102,12 @@ pub(crate) struct ExpectedSemi {
pub sugg: ExpectedSemiSugg, pub sugg: ExpectedSemiSugg,
} }
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
#[track_caller] #[track_caller]
fn into_diagnostic( fn into_diagnostic(
self, self,
handler: &'a rustc_errors::Handler, handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, G> { ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let token_descr = TokenDescription::from_token(&self.token); let token_descr = TokenDescription::from_token(&self.token);
let mut diag = handler.struct_diagnostic(match token_descr { let mut diag = handler.struct_diagnostic(match token_descr {

View file

@ -304,23 +304,25 @@ impl<'a> Parser<'a> {
if self.may_recover() if self.may_recover()
&& (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn)) && (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn))
{ {
let kw = self.prev_token.ident().unwrap().0.name; let kw = self.prev_token.ident().unwrap().0;
let mut err = self.sess.create_err(errors::TransposeDynOrImpl { let removal_span = kw.span.with_hi(self.token.span.lo());
span: self.prev_token.span,
kw: kw.as_str(),
sugg: errors::TransposeDynOrImplSugg {
removal_span: self.prev_token.span.with_hi(self.token.span.lo()),
insertion_span: for_span.shrink_to_lo(),
kw: kw.as_str(),
},
});
let path = self.parse_path(PathStyle::Type)?; let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
let kind = let kind =
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?;
let mut err = self.sess.create_err(errors::TransposeDynOrImpl {
span: kw.span,
kw: kw.name.as_str(),
sugg: errors::TransposeDynOrImplSugg {
removal_span,
insertion_span: for_span.shrink_to_lo(),
kw: kw.name.as_str(),
},
});
// Take the parsed bare trait object and turn it either // Take the parsed bare trait object and turn it either
// into a `dyn` object or an `impl Trait`. // into a `dyn` object or an `impl Trait`.
let kind = match (kind, kw) { let kind = match (kind, kw.name) {
(TyKind::TraitObject(bounds, _), kw::Dyn) => { (TyKind::TraitObject(bounds, _), kw::Dyn) => {
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
} }

View file

@ -3,7 +3,7 @@
#![feature(hash_raw_entry)] #![feature(hash_raw_entry)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(let_chains)] #![feature(let_chains)]
#![allow(rustc::potential_query_instability)] #![allow(rustc::potential_query_instability, internal_features)]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]

View file

@ -3,7 +3,7 @@ use std::num::NonZeroU32;
use crate::parse::ParseSess; use crate::parse::ParseSess;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::util::literal::LitError; use rustc_ast::util::literal::LitError;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan}; use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic; use rustc_macros::Diagnostic;
use rustc_span::{BytePos, Span, Symbol}; use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
@ -13,12 +13,12 @@ pub struct FeatureGateError {
pub explain: DiagnosticMessage, pub explain: DiagnosticMessage,
} }
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError {
#[track_caller] #[track_caller]
fn into_diagnostic( fn into_diagnostic(
self, self,
handler: &'a rustc_errors::Handler, handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, T> { ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = handler.struct_diagnostic(self.explain); let mut diag = handler.struct_diagnostic(self.explain);
diag.set_span(self.span); diag.set_span(self.span);
diag.code(error_code!(E0658)); diag.code(error_code!(E0658));

View file

@ -461,7 +461,7 @@ impl Session {
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! { pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().fatal(msg).raise() self.diagnostic().fatal(msg)
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
#[track_caller] #[track_caller]

View file

@ -41,7 +41,9 @@ mod trait_goals;
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
pub use fulfill::FulfillmentCtxt; pub use fulfill::FulfillmentCtxt;
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; pub(crate) use normalize::{
deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes,
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum SolverMode { enum SolverMode {

View file

@ -4,12 +4,13 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::TraitEngineExt;
use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::traits::Reveal; use rustc_middle::traits::{ObligationCause, Reveal};
use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
use super::FulfillmentCtxt; use super::FulfillmentCtxt;
@ -230,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
} }
} }
} }
// Deeply normalize a value and return it
pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
t: T,
) -> T {
t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
at: infcx.at(&ObligationCause::dummy(), param_env),
})
}
struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
at: At<'a, 'tcx>,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.at.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
deeply_normalize_with_skipped_universes(
self.at,
ty,
vec![None; ty.outer_exclusive_binder().as_usize()],
)
.unwrap_or_else(|_| ty.super_fold_with(self))
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
deeply_normalize_with_skipped_universes(
self.at,
ct,
vec![None; ct.outer_exclusive_binder().as_usize()],
)
.unwrap_or_else(|_| ct.super_fold_with(self))
}
}

View file

@ -6,8 +6,8 @@
use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk; use crate::infer::InferOk;
use crate::solve::inspect;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
use crate::traits::engine::TraitEngineExt; use crate::traits::engine::TraitEngineExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
@ -245,7 +245,7 @@ fn overlap<'tcx>(
let trait_ref = infcx.resolve_vars_if_possible(trait_ref); let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
format!( format!(
"of `{}` for `{}`", "of `{}` for `{}`",
trait_ref.print_only_trait_path(), trait_ref.print_trait_sugared(),
trait_ref.self_ty() trait_ref.self_ty()
) )
} }
@ -308,7 +308,13 @@ fn overlap<'tcx>(
.iter() .iter()
.any(|c| c.0.involves_placeholders()); .any(|c| c.0.involves_placeholders());
let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
// Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
if infcx.next_trait_solver() {
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
}
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
} }
@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
Ok(Err(conflict)) => { Ok(Err(conflict)) => {
if !trait_ref.references_error() { if !trait_ref.references_error() {
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
let trait_ref =
deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
let self_ty = trait_ref.self_ty(); let self_ty = trait_ref.self_ty();
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
ambiguity_cause = Some(match conflict { ambiguity_cause = Some(match conflict {

View file

@ -184,14 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
flags.push((sym::cause, Some("MainFunctionType".to_string()))); flags.push((sym::cause, Some("MainFunctionType".to_string())));
} }
if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string())));
&& let ty::Tuple(args) = trait_ref.args.type_at(1).kind()
{
let args = args.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", ");
flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str()))));
} else {
flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string())));
}
// Add all types without trimmed paths or visible paths, ensuring they end up with // Add all types without trimmed paths or visible paths, ensuring they end up with
// their "canonical" def path. // their "canonical" def path.

View file

@ -622,7 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
span.shrink_to_hi(), span.shrink_to_hi(),
format!( format!(
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
cand.print_only_trait_path(), cand.print_trait_sugared(),
cand.self_ty(), cand.self_ty(),
), ),
format!(" as {}", cand.self_ty()), format!(" as {}", cand.self_ty()),
@ -1785,7 +1785,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
}); });
err.highlighted_help(vec![ err.highlighted_help(vec![
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight), ("is".to_string(), Style::Highlight),
(" implemented for `".to_string(), Style::NoStyle), (" implemented for `".to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight), (cand.self_ty().to_string(), Style::Highlight),
@ -1821,7 +1821,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => (" implemented for `", ""), _ => (" implemented for `", ""),
}; };
err.highlighted_help(vec![ err.highlighted_help(vec![
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight), ("is".to_string(), Style::Highlight),
(desc.to_string(), Style::NoStyle), (desc.to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight), (cand.self_ty().to_string(), Style::Highlight),
@ -1854,7 +1854,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(format!( err.help(format!(
"the following {other}types implement trait `{}`:{}{}", "the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(), trait_ref.print_trait_sugared(),
candidates[..end].join(""), candidates[..end].join(""),
if candidates.len() > 9 { if candidates.len() > 9 {
format!("\nand {} others", candidates.len() - 8) format!("\nand {} others", candidates.len() - 8)

View file

@ -78,7 +78,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> {
IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => {
format!( format!(
"downstream crates may implement trait `{trait_desc}`{self_desc}", "downstream crates may implement trait `{trait_desc}`{self_desc}",
trait_desc = trait_ref.print_only_trait_path(), trait_desc = trait_ref.print_trait_sugared(),
self_desc = if let Some(self_ty) = self_ty { self_desc = if let Some(self_ty) = self_ty {
format!(" for type `{self_ty}`") format!(" for type `{self_ty}`")
} else { } else {
@ -90,7 +90,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> {
format!( format!(
"upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \
in future versions", in future versions",
trait_desc = trait_ref.print_only_trait_path(), trait_desc = trait_ref.print_trait_sugared(),
self_desc = if let Some(self_ty) = self_ty { self_desc = if let Some(self_ty) = self_ty {
format!(" for type `{self_ty}`") format!(" for type `{self_ty}`")
} else { } else {

View file

@ -412,7 +412,7 @@ fn report_conflicting_impls<'tcx>(
let msg = DelayDm(|| { let msg = DelayDm(|| {
format!( format!(
"conflicting implementations of trait `{}`{}{}", "conflicting implementations of trait `{}`{}{}",
overlap.trait_ref.print_only_trait_path(), overlap.trait_ref.print_trait_sugared(),
overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
match used_to_be_allowed { match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)", Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",

View file

@ -41,6 +41,7 @@
#![feature(thin_box)] #![feature(thin_box)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(drain_keep_rest)] #![feature(drain_keep_rest)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)] #![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]

View file

@ -143,17 +143,17 @@
//! //!
//! ``` //! ```
//! # #![allow(dead_code)] //! # #![allow(dead_code)]
//! use std::cell::RefCell; //! use std::cell::OnceCell;
//! //!
//! struct Graph { //! struct Graph {
//! edges: Vec<(i32, i32)>, //! edges: Vec<(i32, i32)>,
//! span_tree_cache: RefCell<Option<Vec<(i32, i32)>>> //! span_tree_cache: OnceCell<Vec<(i32, i32)>>
//! } //! }
//! //!
//! impl Graph { //! impl Graph {
//! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> { //! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> {
//! self.span_tree_cache.borrow_mut() //! self.span_tree_cache
//! .get_or_insert_with(|| self.calc_span_tree()) //! .get_or_init(|| self.calc_span_tree())
//! .clone() //! .clone()
//! } //! }
//! //!

View file

@ -1906,6 +1906,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::ctlz; /// use std::intrinsics::ctlz;
/// ///
@ -1918,6 +1919,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::ctlz; /// use std::intrinsics::ctlz;
/// ///
@ -1939,6 +1941,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::ctlz_nonzero; /// use std::intrinsics::ctlz_nonzero;
/// ///
@ -1965,6 +1968,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::cttz; /// use std::intrinsics::cttz;
/// ///
@ -1977,6 +1981,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::cttz; /// use std::intrinsics::cttz;
/// ///
@ -1998,6 +2003,7 @@ extern "rust-intrinsic" {
/// ///
/// ``` /// ```
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// ///
/// use std::intrinsics::cttz_nonzero; /// use std::intrinsics::cttz_nonzero;
/// ///
@ -2463,6 +2469,7 @@ extern "rust-intrinsic" {
/// ```no_run /// ```no_run
/// #![feature(const_eval_select)] /// #![feature(const_eval_select)]
/// #![feature(core_intrinsics)] /// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// use std::hint::unreachable_unchecked; /// use std::hint::unreachable_unchecked;
/// use std::intrinsics::const_eval_select; /// use std::intrinsics::const_eval_select;
/// ///

View file

@ -50,22 +50,19 @@ macro_rules! tuple_impls {
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[unstable(feature = "structural_match", issue = "31434")] #[unstable(feature = "structural_match", issue = "31434")]
impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) {}
{}
} }
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[unstable(feature = "structural_match", issue = "31434")] #[unstable(feature = "structural_match", issue = "31434")]
impl<$($T),+> StructuralPartialEq for ($($T,)+) impl<$($T),+> StructuralPartialEq for ($($T,)+) {}
{}
} }
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[unstable(feature = "structural_match", issue = "31434")] #[unstable(feature = "structural_match", issue = "31434")]
impl<$($T),+> StructuralEq for ($($T,)+) impl<$($T),+> StructuralEq for ($($T,)+) {}
{}
} }
maybe_tuple_doc! { maybe_tuple_doc! {
@ -118,7 +115,7 @@ macro_rules! tuple_impls {
impl<$($T: Default),+> Default for ($($T,)+) { impl<$($T: Default),+> Default for ($($T,)+) {
#[inline] #[inline]
fn default() -> ($($T,)+) { fn default() -> ($($T,)+) {
($({ let x: $T = Default::default(); x},)+) ($($T::default(),)+)
} }
} }
} }

View file

@ -117,6 +117,7 @@
#![feature(get_many_mut)] #![feature(get_many_mut)]
#![feature(offset_of)] #![feature(offset_of)]
#![feature(iter_map_windows)] #![feature(iter_map_windows)]
#![allow(internal_features)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)] #![deny(fuzzy_provenance_casts)]

View file

@ -180,7 +180,7 @@ pub fn getcwd() -> io::Result<PathBuf> {
} }
#[cfg(target_os = "espidf")] #[cfg(target_os = "espidf")]
pub fn chdir(p: &path::Path) -> io::Result<()> { pub fn chdir(_p: &path::Path) -> io::Result<()> {
super::unsupported::unsupported() super::unsupported::unsupported()
} }

View file

@ -1872,7 +1872,6 @@ impl<'a> Builder<'a> {
// some code doesn't go through this `rustc` wrapper. // some code doesn't go through this `rustc` wrapper.
lint_flags.push("-Wrust_2018_idioms"); lint_flags.push("-Wrust_2018_idioms");
lint_flags.push("-Wunused_lifetimes"); lint_flags.push("-Wunused_lifetimes");
lint_flags.push("-Wsemicolon_in_expressions_from_macros");
if self.config.deny_warnings { if self.config.deny_warnings {
lint_flags.push("-Dwarnings"); lint_flags.push("-Dwarnings");

View file

@ -13,7 +13,7 @@
#![cfg(feature = "sysroot-abi")] #![cfg(feature = "sysroot-abi")]
#![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)]
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#![allow(unreachable_pub)] #![allow(unreachable_pub, internal_features)]
extern crate proc_macro; extern crate proc_macro;

View file

@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)`
--> $DIR/normalize-for-errors.rs:16:1
|
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
| ------------------------------------------------------ first implementation here
LL |
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)`
|
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View file

@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)`
--> $DIR/normalize-for-errors.rs:16:1
|
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
| ------------------------------------------------------ first implementation here
LL |
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
|
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View file

@ -0,0 +1,21 @@
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next
struct MyType;
trait MyTrait<S> {}
trait Mirror {
type Assoc;
}
impl<T> Mirror for T {
type Assoc = T;
}
impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
//~^ NOTE first implementation here
impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
//~| NOTE conflicting implementation for `(Box<(MyType,)>,
//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
fn main() {}

View file

@ -55,7 +55,7 @@ error[E0283]: type annotations needed
LL | bfnr(x); LL | bfnr(x);
| ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr` | ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
| |
= note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`: = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`:
- impl<A, F> Fn<A> for &F - impl<A, F> Fn<A> for &F
where A: Tuple, F: Fn<A>, F: ?Sized; where A: Tuple, F: Fn<A>, F: ?Sized;
- impl<Args, F, A> Fn<Args> for Box<F, A> - impl<Args, F, A> Fn<Args> for Box<F, A>

View file

@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | foo(bar, "string", |s| s.len() == 5); LL | foo(bar, "string", |s| s.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
found trait `for<'a> FnOnce<(&'a &str,)>` found trait `for<'a> FnOnce(&'a &str)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:45:24 --> $DIR/issue-71955.rs:45:24
| |
@ -23,8 +23,8 @@ error[E0308]: mismatched types
LL | foo(bar, "string", |s| s.len() == 5); LL | foo(bar, "string", |s| s.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
found trait `for<'a> FnOnce<(&'a &str,)>` found trait `for<'a> FnOnce(&'a &str)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:45:24 --> $DIR/issue-71955.rs:45:24
| |
@ -42,8 +42,8 @@ error[E0308]: mismatched types
LL | foo(baz, "string", |s| s.0.len() == 5); LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:48:24 --> $DIR/issue-71955.rs:48:24
| |
@ -61,8 +61,8 @@ error[E0308]: mismatched types
LL | foo(baz, "string", |s| s.0.len() == 5); LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-71955.rs:48:24 --> $DIR/issue-71955.rs:48:24
| |

View file

@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | thing(f); LL | thing(f);
| ^^^^^^^^ one type is more general than the other | ^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-105675.rs:4:13 --> $DIR/issue-105675.rs:4:13
| |
@ -27,8 +27,8 @@ error[E0308]: mismatched types
LL | thing(f); LL | thing(f);
| ^^^^^^^^ one type is more general than the other | ^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-105675.rs:4:13 --> $DIR/issue-105675.rs:4:13
| |
@ -46,8 +46,8 @@ error[E0308]: mismatched types
LL | thing(f); LL | thing(f);
| ^^^^^^^^ one type is more general than the other | ^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
found trait `FnOnce<(&u32, &u32, u32)>` found trait `FnOnce(&u32, &u32, u32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-105675.rs:8:13 --> $DIR/issue-105675.rs:8:13
| |
@ -69,8 +69,8 @@ error[E0308]: mismatched types
LL | thing(f); LL | thing(f);
| ^^^^^^^^ one type is more general than the other | ^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
found trait `FnOnce<(&u32, &u32, u32)>` found trait `FnOnce(&u32, &u32, u32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-105675.rs:8:13 --> $DIR/issue-105675.rs:8:13
| |

View file

@ -31,8 +31,8 @@ error[E0308]: mismatched types
LL | take_foo(|a| a); LL | take_foo(|a| a);
| ^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> Fn<(&'a i32,)>` = note: expected trait `for<'a> Fn(&'a i32)`
found trait `Fn<(&i32,)>` found trait `Fn(&i32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-79187-2.rs:8:14 --> $DIR/issue-79187-2.rs:8:14
| |

View file

@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | thing(f); LL | thing(f);
| ^^^^^^^^ one type is more general than the other | ^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> FnOnce<(&'a u32,)>` = note: expected trait `for<'a> FnOnce(&'a u32)`
found trait `FnOnce<(&u32,)>` found trait `FnOnce(&u32)`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-79187.rs:4:13 --> $DIR/issue-79187.rs:4:13
| |

View file

@ -18,8 +18,8 @@ error[E0308]: mismatched types
LL | f(data, identity) LL | f(data, identity)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> Fn<(&'a T,)>` = note: expected trait `for<'a> Fn(&'a T)`
found trait `Fn<(&T,)>` found trait `Fn(&T)`
note: the lifetime requirement is introduced here note: the lifetime requirement is introduced here
--> $DIR/issue_74400.rs:8:34 --> $DIR/issue_74400.rs:8:34
| |

View file

@ -0,0 +1,11 @@
#![forbid(internal_features)]
// A lang feature and a lib feature.
#![feature(intrinsics, panic_internals)]
//~^ ERROR: internal
//~| ERROR: internal
extern "rust-intrinsic" {
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
fn main() {}

View file

@ -0,0 +1,23 @@
error: the feature `intrinsics` is internal to the compiler or standard library
--> $DIR/internal_features.rs:3:12
|
LL | #![feature(intrinsics, panic_internals)]
| ^^^^^^^^^^
|
= note: using it is strongly discouraged
note: the lint level is defined here
--> $DIR/internal_features.rs:1:11
|
LL | #![forbid(internal_features)]
| ^^^^^^^^^^^^^^^^^
error: the feature `panic_internals` is internal to the compiler or standard library
--> $DIR/internal_features.rs:3:24
|
LL | #![feature(intrinsics, panic_internals)]
| ^^^^^^^^^^^^^^^
|
= note: using it is strongly discouraged
error: aborting due to 2 previous errors

View file

@ -13,8 +13,8 @@ error[E0308]: mismatched types
LL | baz(|_| ()); LL | baz(|_| ());
| ^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> Fn<(&'a (),)>` = note: expected trait `for<'a> Fn(&'a ())`
found trait `Fn<(&(),)>` found trait `Fn(&())`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/closure-mismatch.rs:8:9 --> $DIR/closure-mismatch.rs:8:9
| |
@ -45,8 +45,8 @@ error[E0308]: mismatched types
LL | baz(|x| ()); LL | baz(|x| ());
| ^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> Fn<(&'a (),)>` = note: expected trait `for<'a> Fn(&'a ())`
found trait `Fn<(&(),)>` found trait `Fn(&())`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/closure-mismatch.rs:11:9 --> $DIR/closure-mismatch.rs:11:9
| |

View file

@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | accept(callback); LL | accept(callback);
| ^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> FnOnce<(&'a (),)>` = note: expected trait `for<'a> FnOnce(&'a ())`
found trait `FnOnce<(&(),)>` found trait `FnOnce(&())`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/missing-universe-cause-issue-114907.rs:32:20 --> $DIR/missing-universe-cause-issue-114907.rs:32:20
| |
@ -46,8 +46,8 @@ error[E0308]: mismatched types
LL | accept(callback); LL | accept(callback);
| ^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^ one type is more general than the other
| |
= note: expected trait `for<'a> FnOnce<(&'a (),)>` = note: expected trait `for<'a> FnOnce(&'a ())`
found trait `FnOnce<(&(),)>` found trait `FnOnce(&())`
note: this closure does not fulfill the lifetime requirements note: this closure does not fulfill the lifetime requirements
--> $DIR/missing-universe-cause-issue-114907.rs:32:20 --> $DIR/missing-universe-cause-issue-114907.rs:32:20
| |

View file

@ -6,4 +6,8 @@ fn test(_: &for<'a> dyn Trait) {}
fn test2(_: for<'a> impl Trait) {} fn test2(_: for<'a> impl Trait) {}
//~^ ERROR `for<...>` expected after `impl`, not before //~^ ERROR `for<...>` expected after `impl`, not before
// Issue #118564
type A2 = dyn<for<> dyn>;
//~^ ERROR expected identifier, found `>`
fn main() {} fn main() {}

View file

@ -22,5 +22,11 @@ LL - fn test2(_: for<'a> impl Trait) {}
LL + fn test2(_: impl for<'a> Trait) {} LL + fn test2(_: impl for<'a> Trait) {}
| |
error: aborting due to 2 previous errors error: expected identifier, found `>`
--> $DIR/recover-hrtb-before-dyn-impl-kw.rs:10:24
|
LL | type A2 = dyn<for<> dyn>;
| ^ expected identifier
error: aborting due to 3 previous errors

View file

@ -4,8 +4,8 @@ error[E0308]: mismatched types
LL | f: &id, LL | f: &id,
| ^^^ one type is more general than the other | ^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
found trait `Fn<(&Foo<'_>,)>` found trait `Fn(&Foo<'_>)`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/rfc1623-2.rs:28:8 --> $DIR/rfc1623-2.rs:28:8
@ -13,8 +13,8 @@ error[E0308]: mismatched types
LL | f: &id, LL | f: &id,
| ^^^ one type is more general than the other | ^^^ one type is more general than the other
| |
= note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
found trait `Fn<(&Foo<'_>,)>` found trait `Fn(&Foo<'_>)`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: implementation of `FnOnce` is not general enough error: implementation of `FnOnce` is not general enough

View file

@ -1,10 +1,10 @@
error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>` error[E0283]: type annotations needed: cannot satisfy `T: FnMut(&'a ())`
--> $DIR/issue-85735.rs:7:8 --> $DIR/issue-85735.rs:7:8
| |
LL | T: FnMut(&'a ()), LL | T: FnMut(&'a ()),
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found note: multiple `impl`s or `where` clauses satisfying `T: FnMut(&'a ())` found
--> $DIR/issue-85735.rs:7:8 --> $DIR/issue-85735.rs:7:8
| |
LL | T: FnMut(&'a ()), LL | T: FnMut(&'a ()),