Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 9 additions & 15 deletions compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::ops::Range;
use rustc_errors::E0232;
use rustc_hir::AttrPath;
use rustc_hir::attrs::diagnostic::{
AppendConstMessage, Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg,
Name, NameValue, OnUnimplementedCondition, Piece, Predicate,
Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue,
OnUnimplementedCondition, Piece, Predicate,
};
use rustc_hir::lints::{AttributeLintKind, FormatWarning};
use rustc_macros::Diagnostic;
Expand Down Expand Up @@ -92,7 +92,6 @@ fn parse_directive_items<'p, S: Stage>(
let mut notes = ThinVec::new();
let mut parent_label = None;
let mut subcommands = ThinVec::new();
let mut append_const_msg = None;

for item in items {
let span = item.span();
Expand Down Expand Up @@ -131,7 +130,6 @@ fn parse_directive_items<'p, S: Stage>(
let Some(ret) = (||{
Some($($code)*)
})() else {

malformed!()
};
ret
Expand Down Expand Up @@ -159,8 +157,13 @@ fn parse_directive_items<'p, S: Stage>(
let item: &MetaItemParser = or_malformed!(item.meta_item()?);
let name = or_malformed!(item.ident()?).name;

// Some things like `message = "message"` must have a value.
// But with things like `append_const_msg` that is optional.
// Currently, as of April 2026, all arguments of all diagnostic attrs
// must have a value, like `message = "message"`. Thus in a well-formed
// diagnostic attribute this is never `None`.
//
// But we don't assert its presence yet because we don't want to mention it
// if someone does something like `#[diagnostic::on_unimplemented(doesnt_exist)]`.
// That happens in the big `match` below.
let value: Option<Ident> = match item.args().name_value() {
Some(nv) => Some(or_malformed!(nv.value_as_ident()?)),
None => None,
Expand Down Expand Up @@ -223,14 +226,6 @@ fn parse_directive_items<'p, S: Stage>(
let value = or_malformed!(value?);
notes.push(parse_format(value))
}

(Mode::RustcOnUnimplemented, sym::append_const_msg) => {
append_const_msg = if let Some(msg) = value {
Some(AppendConstMessage::Custom(msg.name, item.span()))
} else {
Some(AppendConstMessage::Default)
}
}
(Mode::RustcOnUnimplemented, sym::parent_label) => {
let value = or_malformed!(value?);
if parent_label.is_none() {
Expand Down Expand Up @@ -290,7 +285,6 @@ fn parse_directive_items<'p, S: Stage>(
label,
notes,
parent_label,
append_const_msg,
})
}

Expand Down
16 changes: 0 additions & 16 deletions compiler/rustc_hir/src/attrs/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub struct Directive {
pub label: Option<(Span, FormatString)>,
pub notes: ThinVec<FormatString>,
pub parent_label: Option<FormatString>,
pub append_const_msg: Option<AppendConstMessage>,
}

impl Directive {
Expand Down Expand Up @@ -63,7 +62,6 @@ impl Directive {
let mut label = None;
let mut notes = Vec::new();
let mut parent_label = None;
let mut append_const_msg = None;
info!(
"evaluate_directive({:?}, trait_ref={:?}, options={:?}, args ={:?})",
self, trait_name, condition_options, args
Expand Down Expand Up @@ -91,16 +89,13 @@ impl Directive {
if let Some(ref parent_label_) = command.parent_label {
parent_label = Some(parent_label_.clone());
}

append_const_msg = command.append_const_msg;
}

OnUnimplementedNote {
label: label.map(|l| l.1.format(args)),
message: message.map(|m| m.1.format(args)),
notes: notes.into_iter().map(|n| n.format(args)).collect(),
parent_label: parent_label.map(|e_s| e_s.format(args)),
append_const_msg,
}
}
}
Expand All @@ -111,17 +106,6 @@ pub struct OnUnimplementedNote {
pub label: Option<String>,
pub notes: Vec<String>,
pub parent_label: Option<String>,
// If none, should fall back to a generic message
pub append_const_msg: Option<AppendConstMessage>,
}

/// Append a message for `[const] Trait` errors.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[derive(HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum AppendConstMessage {
#[default]
Default,
Custom(Symbol, Span),
}

/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ symbols! {
anon_assoc,
anonymous_lifetime_in_impl_trait,
any,
append_const_msg,
apx_target_feature,
arbitrary_enum_discriminant,
arbitrary_self_types,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_errors::{
Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, msg,
pluralize, struct_span_code_err,
};
use rustc_hir::attrs::diagnostic::{AppendConstMessage, OnUnimplementedNote};
use rustc_hir::attrs::diagnostic::OnUnimplementedNote;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, LangItem, Node, find_attr};
Expand Down Expand Up @@ -193,10 +193,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
label,
notes,
parent_label,
append_const_msg,
} = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);

let have_alt_message = message.is_some() || label.is_some();

let message = message.unwrap_or_else(|| self.get_standard_error_message(
main_trait_predicate,
None,
post_message,
&mut long_ty_file,
));
let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
let is_question_mark = matches!(
root_obligation.cause.code().peel_derives(),
Expand All @@ -210,16 +216,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let question_mark_message = "the question mark operation (`?`) implicitly \
performs a conversion on the error value \
using the `From` trait";
let (message, notes, append_const_msg) = if is_try_conversion {
let (message, notes) = if is_try_conversion {
let ty = self.tcx.short_string(
main_trait_predicate.skip_binder().self_ty(),
&mut long_ty_file,
);
// We have a `-> Result<_, E1>` and `gives_E2()?`.
(
Some(format!("`?` couldn't convert the error to `{ty}`")),
format!("`?` couldn't convert the error to `{ty}`"),
vec![question_mark_message.to_owned()],
Some(AppendConstMessage::Default),
)
} else if is_question_mark {
let main_trait_predicate =
Expand All @@ -228,26 +233,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when
// `E: Error` isn't met.
(
Some(format!(
format!(
"`?` couldn't convert the error: `{main_trait_predicate}` is \
not satisfied",
)),
),
vec![question_mark_message.to_owned()],
Some(AppendConstMessage::Default),
)
} else {
(message, notes, append_const_msg)
(message, notes)
};

let default_err_msg = || self.get_standard_error_message(
main_trait_predicate,
message,
None,
append_const_msg,
post_message,
&mut long_ty_file,
);

let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(
main_trait_predicate.def_id(),
LangItem::TransmuteTrait,
Expand All @@ -271,15 +266,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
);
}
GetSafeTransmuteErrorAndReason::Default => {
(default_err_msg(), None)
(message, None)
}
GetSafeTransmuteErrorAndReason::Error {
err_msg,
safe_transmute_explanation,
} => (err_msg, safe_transmute_explanation),
}
} else {
(default_err_msg(), None)
(message, None)
};

let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
Expand Down Expand Up @@ -393,7 +388,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s.as_str().to_owned());
err.span_label(span, s);
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))
// When the self type is a type param We don't need to "the trait
// `std::marker::Sized` is not implemented for `T`" as we will point
Expand Down Expand Up @@ -857,9 +852,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {

let err_msg = self.get_standard_error_message(
trait_ref,
None,
Some(predicate.constness()),
None,
String::new(),
&mut file,
);
Expand Down Expand Up @@ -919,7 +912,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
label,
notes,
parent_label,
append_const_msg: _,
} = note;

if let Some(message) = message {
Expand Down Expand Up @@ -2836,40 +2828,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn get_standard_error_message(
&self,
trait_predicate: ty::PolyTraitPredicate<'tcx>,
message: Option<String>,
predicate_constness: Option<ty::BoundConstness>,
append_const_msg: Option<AppendConstMessage>,
post_message: String,
long_ty_path: &mut Option<PathBuf>,
Comment on lines 2828 to 2833
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function was always called with one of message and predicate_constness being None, thus making much of the code here unreachable.

) -> String {
message
.and_then(|cannot_do_this| {
match (predicate_constness, append_const_msg) {
// do nothing if predicate is not const
(None, _) => Some(cannot_do_this),
// suggested using default post message
(
Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe),
Some(AppendConstMessage::Default),
) => Some(format!("{cannot_do_this} in const contexts")),
// overridden post message
(
Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe),
Some(AppendConstMessage::Custom(custom_msg, _)),
) => Some(format!("{cannot_do_this}{custom_msg}")),
// fallback to generic message
(Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), None) => None,
}
})
.unwrap_or_else(|| {
format!(
"the trait bound `{}` is not satisfied{post_message}",
self.tcx.short_string(
trait_predicate.print_with_bound_constness(predicate_constness),
long_ty_path,
),
)
})
format!(
"the trait bound `{}` is not satisfied{post_message}",
self.tcx.short_string(
trait_predicate.print_with_bound_constness(predicate_constness),
long_ty_path,
),
)
}

fn select_transmute_obligation_for_reporting(
Expand Down
10 changes: 4 additions & 6 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,9 @@ use crate::ops::ControlFlow;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "==")]
#[doc(alias = "!=")]
#[rustc_on_unimplemented(
#[diagnostic::on_unimplemented(
message = "can't compare `{Self}` with `{Rhs}`",
label = "no implementation for `{Self} == {Rhs}`",
append_const_msg
label = "no implementation for `{Self} == {Rhs}`"
)]
#[rustc_diagnostic_item = "PartialEq"]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
Expand Down Expand Up @@ -1356,10 +1355,9 @@ pub macro Ord($item:item) {
#[doc(alias = "<")]
#[doc(alias = "<=")]
#[doc(alias = ">=")]
#[rustc_on_unimplemented(
#[diagnostic::on_unimplemented(
message = "can't compare `{Self}` with `{Rhs}`",
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
append_const_msg
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`"
)]
#[rustc_diagnostic_item = "PartialOrd"]
#[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6
/// The *successor* operation moves towards values that compare greater.
/// The *predecessor* operation moves towards values that compare lesser.
#[rustc_diagnostic_item = "range_step"]
#[rustc_on_unimplemented(
#[diagnostic::on_unimplemented(
message = "`std::ops::Range<{Self}>` is not an iterator",
label = "`Range<{Self}>` is not an iterator",
note = "`Range` only implements `Iterator` for select types in the standard library, \
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ marker_impls! {
#[unstable(feature = "const_destruct", issue = "133214")]
#[rustc_const_unstable(feature = "const_destruct", issue = "133214")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[diagnostic::on_unimplemented(message = "can't drop `{Self}`")]
#[rustc_deny_explicit_impl]
#[rustc_dyn_incompatible_trait]
pub const trait Destruct: PointeeSized {}
Expand Down
8 changes: 3 additions & 5 deletions library/core/src/ops/arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@
on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
message = "cannot add `{Rhs}` to `{Self}`",
label = "no implementation for `{Self} + {Rhs}`",
append_const_msg
label = "no implementation for `{Self} + {Rhs}`"
)]
#[doc(alias = "+")]
pub const trait Add<Rhs = Self> {
Expand Down Expand Up @@ -181,10 +180,9 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128
#[lang = "sub"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
#[rustc_on_unimplemented(
#[diagnostic::on_unimplemented(
message = "cannot subtract `{Rhs}` from `{Self}`",
label = "no implementation for `{Self} - {Rhs}`",
append_const_msg
label = "no implementation for `{Self} - {Rhs}`"
)]
#[doc(alias = "-")]
pub const trait Sub<Rhs = Self> {
Expand Down
2 changes: 1 addition & 1 deletion tests/auxiliary/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub trait MetaSized: PointeeSized {}
pub trait Sized: MetaSized {}

#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[diagnostic::on_unimplemented(message = "can't drop `{Self}`")]
pub trait Destruct: PointeeSized {}

#[lang = "legacy_receiver"]
Expand Down
Loading