Add a diagnostic attribute for special casing const bound errors for non-const impls

This commit is contained in:
Oli Scherer 2025-11-06 09:00:38 +00:00
parent 1223f5c168
commit 9218298caa
24 changed files with 319 additions and 27 deletions

View file

@ -1576,9 +1576,10 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>>
map
});
pub fn is_stable_diagnostic_attribute(sym: Symbol, _features: &Features) -> bool {
pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool {
match sym {
sym::on_unimplemented | sym::do_not_recommend => true,
sym::on_const => features.diagnostic_on_const(),
_ => false,
}
}

View file

@ -485,6 +485,8 @@ declare_features! (
(incomplete, deref_patterns, "1.79.0", Some(87121)),
/// Allows deriving the From trait on single-field structs.
(unstable, derive_from, "1.91.0", Some(144889)),
/// Allows giving non-const impls custom diagnostic messages if attempted to be used as const
(unstable, diagnostic_on_const, "CURRENT_RUSTC_VERSION", Some(143874)),
/// Allows `#[doc(cfg(...))]`.
(unstable, doc_cfg, "1.21.0", Some(43781)),
/// Allows `#[doc(masked)]`.

View file

@ -802,6 +802,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().associated_items(def_id);
check_diagnostic_attrs(tcx, def_id);
if of_trait {
let impl_trait_header = tcx.impl_trait_header(def_id);
res = res.and(
@ -824,7 +825,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().associated_items(def_id);
let assoc_items = tcx.associated_items(def_id);
check_on_unimplemented(tcx, def_id);
check_diagnostic_attrs(tcx, def_id);
for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind {
@ -1112,7 +1113,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
})
}
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) {
pub(super) fn check_diagnostic_attrs(tcx: TyCtxt<'_>, def_id: LocalDefId) {
// an error would be reported if this fails.
let _ = OnUnimplementedDirective::of_item(tcx, def_id.to_def_id());
}

View file

@ -96,6 +96,9 @@ passes_deprecated_annotation_has_no_effect =
passes_deprecated_attribute =
deprecated attribute must be paired with either stable or unstable attribute
passes_diagnostic_diagnostic_on_const_only_for_trait_impls =
`#[diagnostic::on_const]` can only be applied to trait impls
passes_diagnostic_diagnostic_on_unimplemented_only_for_traits =
`#[diagnostic::on_unimplemented]` can only be applied to trait definitions

View file

@ -23,8 +23,8 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{
self as hir, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item,
ItemKind, MethodKind, PartialConstStability, Safety, Stability, StabilityLevel, Target,
self as hir, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, Constness, FnSig, ForeignItem, HirId,
Item, ItemKind, MethodKind, PartialConstStability, Safety, Stability, StabilityLevel, Target,
TraitItem, find_attr,
};
use rustc_macros::LintDiagnostic;
@ -55,6 +55,10 @@ use crate::{errors, fluent_generated as fluent};
#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
struct DiagnosticOnUnimplementedOnlyForTraits;
#[derive(LintDiagnostic)]
#[diag(passes_diagnostic_diagnostic_on_const_only_for_trait_impls)]
struct DiagnosticOnConstOnlyForTraitImpls;
fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
@ -293,6 +297,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::diagnostic, sym::on_unimplemented, ..] => {
self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
}
[sym::diagnostic, sym::on_const, ..] => {
self.check_diagnostic_on_const(attr.span(), hir_id, target, item)
}
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
[sym::doc, ..] => self.check_doc_attrs(
attr,
@ -516,6 +523,31 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
/// Checks if `#[diagnostic::on_const]` is applied to a trait impl
fn check_diagnostic_on_const(
&self,
attr_span: Span,
hir_id: HirId,
target: Target,
item: Option<ItemLike<'_>>,
) {
if matches!(target, Target::Impl { of_trait: true }) {
match item.unwrap() {
ItemLike::Item(it) => match it.expect_impl().constness {
Constness::Const => {}
Constness::NotConst => return,
},
ItemLike::ForeignItem => {}
}
}
self.tcx.emit_node_span_lint(
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
DiagnosticOnConstOnlyForTraitImpls,
);
}
/// Checks if an `#[inline]` is applied to a function or a closure.
fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {
match target {

View file

@ -690,10 +690,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
&& let [namespace, attribute, ..] = &*path.segments
&& namespace.ident.name == sym::diagnostic
&& ![sym::on_unimplemented, sym::do_not_recommend].contains(&attribute.ident.name)
&& ![sym::on_unimplemented, sym::do_not_recommend, sym::on_const]
.contains(&attribute.ident.name)
{
let typo_name = find_best_match_for_name(
&[sym::on_unimplemented, sym::do_not_recommend],
&[sym::on_unimplemented, sym::do_not_recommend, sym::on_const],
attribute.ident.name,
Some(5),
);

View file

@ -878,6 +878,7 @@ symbols! {
destructuring_assignment,
diagnostic,
diagnostic_namespace,
diagnostic_on_const,
dialect,
direct,
discriminant_kind,
@ -1593,6 +1594,7 @@ symbols! {
old_name,
omit_gdb_pretty_printer_section,
on,
on_const,
on_unimplemented,
opaque,
opaque_module_name_placeholder: "<opaque>",

View file

@ -42,6 +42,7 @@ use super::{
};
use crate::error_reporting::TypeErrCtxt;
use crate::error_reporting::infer::TyCategory;
use crate::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
use crate::error_reporting::traits::report_dyn_incompatibility;
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn};
use crate::infer::{self, InferCtxt, InferCtxtExt as _};
@ -586,7 +587,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
self.report_host_effect_error(bound_predicate.rebind(predicate), obligation.param_env, span)
self.report_host_effect_error(bound_predicate.rebind(predicate), &obligation, span)
}
ty::PredicateKind::Subtype(predicate) => {
@ -807,20 +808,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn report_host_effect_error(
&self,
predicate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
main_obligation: &PredicateObligation<'tcx>,
span: Span,
) -> Diag<'a> {
// FIXME(const_trait_impl): We should recompute the predicate with `[const]`
// if it's `const`, and if it holds, explain that this bound only
// *conditionally* holds. If that fails, we should also do selection
// to drill this down to an impl or built-in source, so we can
// point at it and explain that while the trait *is* implemented,
// that implementation is not const.
// *conditionally* holds.
let trait_ref = predicate.map_bound(|predicate| ty::TraitPredicate {
trait_ref: predicate.trait_ref,
polarity: ty::PredicatePolarity::Positive,
});
let mut file = None;
let err_msg = self.get_standard_error_message(
trait_ref,
None,
@ -834,7 +833,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let obligation = Obligation::new(
self.tcx,
ObligationCause::dummy(),
param_env,
main_obligation.param_env,
trait_ref,
);
if !self.predicate_may_hold(&obligation) {
@ -867,6 +866,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
impl_span,
format!("trait `{trait_name}` is implemented but not `const`"),
);
let (condition_options, format_args) = self.on_unimplemented_components(
trait_ref,
main_obligation,
diag.long_ty_path(),
);
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, impl_did)
{
let note = command.evaluate(
self.tcx,
predicate.skip_binder().trait_ref,
&condition_options,
&format_args,
);
let OnUnimplementedNote {
message,
label,
notes,
parent_label,
append_const_msg: _,
} = note;
if let Some(message) = message {
diag.primary_message(message);
}
if let Some(label) = label {
diag.span_label(impl_span, label);
}
for note in notes {
diag.note(note);
}
if let Some(parent_label) = parent_label {
diag.span_label(impl_span, parent_label);
}
}
}
}
}

View file

@ -5,6 +5,7 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{AttrArgs, Attribute};
use rustc_macros::LintDiagnostic;
@ -103,7 +104,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if trait_pred.polarity() != ty::PredicatePolarity::Positive {
return OnUnimplementedNote::default();
}
let (condition_options, format_args) =
self.on_unimplemented_components(trait_pred, obligation, long_ty_path);
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_pred.def_id())
{
command.evaluate(
self.tcx,
trait_pred.skip_binder().trait_ref,
&condition_options,
&format_args,
)
} else {
OnUnimplementedNote::default()
}
}
pub(crate) fn on_unimplemented_components(
&self,
trait_pred: ty::PolyTraitPredicate<'tcx>,
obligation: &PredicateObligation<'tcx>,
long_ty_path: &mut Option<PathBuf>,
) -> (ConditionOptions, FormatArgs<'tcx>) {
let (def_id, args) = self
.impl_similar_to(trait_pred, obligation)
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
@ -293,12 +314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.collect();
let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args)
} else {
OnUnimplementedNote::default()
}
(condition_options, format_args)
}
}
@ -325,7 +341,7 @@ pub struct OnUnimplementedDirective {
}
/// For the `#[rustc_on_unimplemented]` attribute
#[derive(Default)]
#[derive(Default, Debug)]
pub struct OnUnimplementedNote {
pub message: Option<String>,
pub label: Option<String>,
@ -562,17 +578,21 @@ impl<'tcx> OnUnimplementedDirective {
}
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
if !tcx.is_trait(item_def_id) {
let attr = if tcx.is_trait(item_def_id) {
sym::on_unimplemented
} else if let DefKind::Impl { of_trait: true } = tcx.def_kind(item_def_id) {
sym::on_const
} else {
// It could be a trait_alias (`trait MyTrait = SomeOtherTrait`)
// or an implementation (`impl MyTrait for Foo {}`)
//
// We don't support those.
return Ok(None);
}
};
if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
return Self::parse_attribute(attr, false, tcx, item_def_id);
} else {
tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented])
tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, attr])
.filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose())
.try_fold(None, |aggr: Option<Self>, directive| {
let directive = directive?;

View file

@ -149,6 +149,7 @@
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(derive_const)]
#![feature(diagnostic_on_const)]
#![feature(doc_cfg)]
#![feature(doc_notable_trait)]
#![feature(extern_types)]

View file

@ -1567,6 +1567,10 @@ impl<T, const N: usize> *const [T; N] {
/// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> PartialEq for *const T {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
@ -1577,10 +1581,18 @@ impl<T: PointeeSized> PartialEq for *const T {
/// Pointer equality is an equivalence relation.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> Eq for *const T {}
/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> Ord for *const T {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
@ -1597,6 +1609,10 @@ impl<T: PointeeSized> Ord for *const T {
/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> PartialOrd for *const T {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]

View file

@ -2520,6 +2520,10 @@ pub fn hash<T: PointeeSized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<F: FnPtr> PartialEq for F {
#[inline]
fn eq(&self, other: &Self) -> bool {
@ -2527,9 +2531,17 @@ impl<F: FnPtr> PartialEq for F {
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<F: FnPtr> Eq for F {}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<F: FnPtr> PartialOrd for F {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@ -2537,6 +2549,10 @@ impl<F: FnPtr> PartialOrd for F {
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<F: FnPtr> Ord for F {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {

View file

@ -2000,6 +2000,10 @@ impl<T, const N: usize> *mut [T; N] {
/// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> PartialEq for *mut T {
#[inline(always)]
#[allow(ambiguous_wide_pointer_comparisons)]
@ -2010,10 +2014,18 @@ impl<T: PointeeSized> PartialEq for *mut T {
/// Pointer equality is an equivalence relation.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> Eq for *mut T {}
/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> Ord for *mut T {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
@ -2030,6 +2042,10 @@ impl<T: PointeeSized> Ord for *mut T {
/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")]
#[diagnostic::on_const(
message = "pointers cannot be reliably compared during const eval",
note = "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information"
)]
impl<T: PointeeSized> PartialOrd for *mut T {
#[inline(always)]
#[allow(ambiguous_wide_pointer_comparisons)]

View file

@ -0,0 +1,23 @@
error[E0277]: pointers cannot be reliably compared during const eval
--> $DIR/const_raw_ptr_ops.rs:7:26
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait `PartialEq` is implemented but not `const`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error[E0277]: pointers cannot be reliably compared during const eval
--> $DIR/const_raw_ptr_ops.rs:9:27
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait `PartialEq` is implemented but not `const`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,3 +1,6 @@
//@revisions: stable gated
#![cfg_attr(gated, feature(const_trait_impl))]
fn main() {}
// unconst and bad, will thus error in miri

View file

@ -1,5 +1,5 @@
error: pointers cannot be reliably compared during const eval
--> $DIR/const_raw_ptr_ops.rs:4:26
--> $DIR/const_raw_ptr_ops.rs:7:26
|
LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -7,7 +7,7 @@ LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error: pointers cannot be reliably compared during const eval
--> $DIR/const_raw_ptr_ops.rs:6:27
--> $DIR/const_raw_ptr_ops.rs:9:27
|
LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,13 @@
error[E0277]: pointers cannot be reliably compared during const eval
--> $DIR/different-fn-ptr-binders-during-ctfe.rs:5:5
|
LL | x == y
| ^^^^^^
|
note: trait `PartialEq` is implemented but not `const`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,3 +1,6 @@
//@revisions: stable gated
#![cfg_attr(gated, feature(const_trait_impl))]
const fn cmp(x: fn(&'static ()), y: for<'a> fn(&'a ())) -> bool {
x == y
//~^ ERROR pointers cannot be reliably compared during const eval

View file

@ -1,5 +1,5 @@
error: pointers cannot be reliably compared during const eval
--> $DIR/different-fn-ptr-binders-during-ctfe.rs:2:5
--> $DIR/different-fn-ptr-binders-during-ctfe.rs:5:5
|
LL | x == y
| ^^^^^^

View file

@ -0,0 +1,32 @@
#![feature(const_trait_impl, const_cmp)]
#![deny(misplaced_diagnostic_attributes)]
#[diagnostic::on_const(message = "tadaa", note = "boing")]
//~^ ERROR: `#[diagnostic::on_const]` can only be applied to trait impls
pub struct Foo;
#[diagnostic::on_const(message = "tadaa", note = "boing")]
//~^ ERROR: `#[diagnostic::on_const]` can only be applied to trait impls
impl const PartialEq for Foo {
fn eq(&self, _other: &Foo) -> bool {
true
}
}
#[diagnostic::on_const(message = "tadaa", note = "boing")]
//~^ ERROR: `#[diagnostic::on_const]` can only be applied to trait impls
impl Foo {
fn eq(&self, _other: &Foo) -> bool {
true
}
}
impl PartialOrd for Foo {
#[diagnostic::on_const(message = "tadaa", note = "boing")]
//~^ ERROR: `#[diagnostic::on_const]` can only be applied to trait impls
fn partial_cmp(&self, other: &Foo) -> Option<std::cmp::Ordering> {
None
}
}
fn main() {}

View file

@ -0,0 +1,32 @@
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:4:1
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/misplaced_attr.rs:2:9
|
LL | #![deny(misplaced_diagnostic_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:8:1
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:16:1
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[diagnostic::on_const]` can only be applied to trait impls
--> $DIR/misplaced_attr.rs:25:5
|
LL | #[diagnostic::on_const(message = "tadaa", note = "boing")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View file

@ -0,0 +1,8 @@
pub struct Foo;
#[diagnostic::on_const(message = "tadaa", note = "boing")]
impl PartialEq for Foo {
fn eq(&self, _other: &Foo) -> bool {
true
}
}

View file

@ -0,0 +1,16 @@
//! This is an unusual feature gate test, as it doesn't test the feature
//! gate, but the fact that not adding the feature gate to
//! the aux crate will cause the diagnostic to not emit the
//! custom diagnostic message
//@ aux-build: diagnostic-on-const.rs
extern crate diagnostic_on_const;
use diagnostic_on_const::Foo;
const fn foo() {
Foo == Foo;
//~^ ERROR: cannot call non-const operator in constant functions
}
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0015]: cannot call non-const operator in constant functions
--> $DIR/feature-gate-diagnostic-on-const.rs:12:5
|
LL | Foo == Foo;
| ^^^^^^^^^^
|
note: impl defined here, but it is not `const`
--> $DIR/auxiliary/diagnostic-on-const.rs:4:1
|
LL | impl PartialEq for Foo {
| ^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0015`.