From 0189eeb18d73b37c85e134600fc84c01d3156d3e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 6 Nov 2025 12:05:48 +0000 Subject: [PATCH 1/2] Resolve to a concrete impl instead of using fuzzy search --- .../error_reporting/traits/fulfillment_errors.rs | 15 +++++++++------ tests/ui/consts/issue-94675.stderr | 8 ++++++++ .../const-traits/call-generic-method-fail.stderr | 5 ----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d2f2c92dda080..0d0f0b6676f8e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -831,18 +831,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); *diag.long_ty_path() = file; - if !self.predicate_may_hold(&Obligation::new( + let obligation = Obligation::new( self.tcx, ObligationCause::dummy(), param_env, trait_ref, - )) { + ); + if !self.predicate_may_hold(&obligation) { diag.downgrade_to_delayed_bug(); } - for candidate in self.find_similar_impl_candidates(trait_ref) { - let CandidateSimilarity::Exact { .. } = candidate.similarity else { continue }; - let impl_did = candidate.impl_def_id; - let trait_did = candidate.trait_ref.def_id; + + if let Ok(Some(ImplSource::UserDefined(impl_data))) = + SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref.skip_binder())) + { + let impl_did = impl_data.impl_def_id; + let trait_did = trait_ref.def_id(); let impl_span = self.tcx.def_span(impl_did); let trait_name = self.tcx.item_name(trait_did); diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index d7664de5c07a7..771f2a14c3053 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -3,12 +3,18 @@ error[E0277]: the trait bound `Vec: [const] Index<_>` is not satisfied | LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ + | +note: trait `Index` is implemented but not `const` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the trait bound `Vec: [const] IndexMut` is not satisfied --> $DIR/issue-94675.rs:11:9 | LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ + | +note: trait `IndexMut` is implemented but not `const` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the trait bound `Vec: [const] Index` is not satisfied --> $DIR/issue-94675.rs:11:9 @@ -16,6 +22,8 @@ error[E0277]: the trait bound `Vec: [const] Index` is not satisfie LL | self.bar[0] = baz.len(); | ^^^^^^^^^^^ | +note: trait `Index` is implemented but not `const` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL note: required by a bound in `std::ops::IndexMut::index_mut` --> $SRC_DIR/core/src/ops/index.rs:LL:COL diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr index 6e75730b9b513..a2fba141f7b89 100644 --- a/tests/ui/traits/const-traits/call-generic-method-fail.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr @@ -3,11 +3,6 @@ error[E0277]: the trait bound `T: [const] PartialEq` is not satisfied | LL | *t == *t | ^^^^^^^^ - | -note: trait `PartialEq` is implemented but not `const` - --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL -note: trait `PartialEq` is implemented but not `const` - --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL error: aborting due to 1 previous error From d04c00d28a08f1f259fbedc8fbb5339f92857ee4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 6 Nov 2025 09:00:38 +0000 Subject: [PATCH 2/2] Add a diagnostic attribute for special casing const bound errors for non-const impls --- compiler/rustc_feature/src/builtin_attrs.rs | 3 +- compiler/rustc_feature/src/unstable.rs | 2 + .../rustc_hir_analysis/src/check/check.rs | 5 +- compiler/rustc_passes/messages.ftl | 3 ++ compiler/rustc_passes/src/check_attr.rs | 19 +++++++ compiler/rustc_resolve/src/macros.rs | 5 +- compiler/rustc_span/src/symbol.rs | 2 + .../traits/fulfillment_errors.rs | 49 ++++++++++++++++--- .../traits/on_unimplemented.rs | 40 +++++++++++---- library/core/src/lib.rs | 1 + library/core/src/ptr/const_ptr.rs | 16 ++++++ library/core/src/ptr/mod.rs | 16 ++++++ library/core/src/ptr/mut_ptr.rs | 16 ++++++ .../const-eval/const_raw_ptr_ops.gated.stderr | 23 +++++++++ .../ui/consts/const-eval/const_raw_ptr_ops.rs | 3 ++ ...stderr => const_raw_ptr_ops.stable.stderr} | 4 +- ...nt-fn-ptr-binders-during-ctfe.gated.stderr | 13 +++++ .../different-fn-ptr-binders-during-ctfe.rs | 3 ++ ...-fn-ptr-binders-during-ctfe.stable.stderr} | 2 +- .../auxiliary/diagnostic-on-const.rs | 8 +++ .../feature-gate-diagnostic-on-const.rs | 16 ++++++ .../feature-gate-diagnostic-on-const.stderr | 16 ++++++ 22 files changed, 240 insertions(+), 25 deletions(-) create mode 100644 tests/ui/consts/const-eval/const_raw_ptr_ops.gated.stderr rename tests/ui/consts/const-eval/{const_raw_ptr_ops.stderr => const_raw_ptr_ops.stable.stderr} (89%) create mode 100644 tests/ui/consts/different-fn-ptr-binders-during-ctfe.gated.stderr rename tests/ui/consts/{different-fn-ptr-binders-during-ctfe.stderr => different-fn-ptr-binders-during-ctfe.stable.stderr} (81%) create mode 100644 tests/ui/feature-gates/auxiliary/diagnostic-on-const.rs create mode 100644 tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs create mode 100644 tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5dcb5df55720c..3484370e2ba6b 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1567,9 +1567,10 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> 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, } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8397cd294e0a9..58c11b670e24e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -482,6 +482,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)]`. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1e12adbbfc6e0..5f29c94721c0c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -806,6 +806,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( @@ -828,7 +829,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 { @@ -1078,7 +1079,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()); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c668bf0733d14..9e10005899f92 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5944a1e8da5d1..e42b51430c817 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -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, @@ -296,6 +300,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) + } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), [sym::doc, ..] => self.check_doc_attrs( attr, @@ -519,6 +526,18 @@ 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) { + if !matches!(target, Target::Impl { of_trait: true }) { + 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 { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4a5894c9ffa86..b737a4f852a6d 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -687,10 +687,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), ); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 38718bad9e57e..e0d0b23f371d0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -872,6 +872,7 @@ symbols! { destructuring_assignment, diagnostic, diagnostic_namespace, + diagnostic_on_const, dialect, direct, discriminant_kind, @@ -1587,6 +1588,7 @@ symbols! { old_name, omit_gdb_pretty_printer_section, on, + on_const, on_unimplemented, opaque, opaque_module_name_placeholder: "", diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0d0f0b6676f8e..4d0ef6a67fe35 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -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); + } + } } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index a5cb374ea0eb1..0a6af42e122b6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -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, + ) -> (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, pub label: Option, @@ -562,17 +578,21 @@ impl<'tcx> OnUnimplementedDirective { } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, 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, directive| { let directive = directive?; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f1948fc778ce2..431dee8884a27 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -150,6 +150,7 @@ #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(derive_const)] +#![feature(diagnostic_on_const)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] #![feature(extern_types)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 451092709443b..3e58d205f7fb8 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1566,6 +1566,10 @@ impl *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 for more information" +)] impl PartialEq for *const T { #[inline] #[allow(ambiguous_wide_pointer_comparisons)] @@ -1576,10 +1580,18 @@ impl 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 for more information" +)] impl 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 for more information" +)] impl Ord for *const T { #[inline] #[allow(ambiguous_wide_pointer_comparisons)] @@ -1596,6 +1608,10 @@ impl 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 for more information" +)] impl PartialOrd for *const T { #[inline] #[allow(ambiguous_wide_pointer_comparisons)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fd067d19fcd98..a17a9302e6db4 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2556,6 +2556,10 @@ pub fn hash(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 for more information" +)] impl PartialEq for F { #[inline] fn eq(&self, other: &Self) -> bool { @@ -2563,9 +2567,17 @@ impl 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 for more information" +)] impl 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 for more information" +)] impl PartialOrd for F { #[inline] fn partial_cmp(&self, other: &Self) -> Option { @@ -2573,6 +2585,10 @@ impl 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 for more information" +)] impl Ord for F { #[inline] fn cmp(&self, other: &Self) -> Ordering { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 24ee92bdd6e1b..f50f35791c45d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1999,6 +1999,10 @@ impl *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 for more information" +)] impl PartialEq for *mut T { #[inline(always)] #[allow(ambiguous_wide_pointer_comparisons)] @@ -2009,10 +2013,18 @@ impl 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 for more information" +)] impl 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 for more information" +)] impl Ord for *mut T { #[inline] #[allow(ambiguous_wide_pointer_comparisons)] @@ -2029,6 +2041,10 @@ impl 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 for more information" +)] impl PartialOrd for *mut T { #[inline(always)] #[allow(ambiguous_wide_pointer_comparisons)] diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.gated.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops.gated.stderr new file mode 100644 index 0000000000000..c39048c8f283c --- /dev/null +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.gated.stderr @@ -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 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 for more information + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops.rs index 432a05756d305..c26ef164ebab9 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops.rs +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.rs @@ -1,3 +1,6 @@ +//@revisions: stable gated +#![cfg_attr(gated, feature(const_trait_impl))] + fn main() {} // unconst and bad, will thus error in miri diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr similarity index 89% rename from tests/ui/consts/const-eval/const_raw_ptr_ops.stderr rename to tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr index 1f5bca273d3b0..2c7e6e8671351 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops.stable.stderr @@ -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 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 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.gated.stderr b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.gated.stderr new file mode 100644 index 0000000000000..f13e0c6661814 --- /dev/null +++ b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.gated.stderr @@ -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 for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.rs b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.rs index b378542e5730c..7f963eabd6d56 100644 --- a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.rs +++ b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.rs @@ -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 diff --git a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stderr b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr similarity index 81% rename from tests/ui/consts/different-fn-ptr-binders-during-ctfe.stderr rename to tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr index 43a7b9ce66ce0..92b09e7db0d45 100644 --- a/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stderr +++ b/tests/ui/consts/different-fn-ptr-binders-during-ctfe.stable.stderr @@ -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 | ^^^^^^ diff --git a/tests/ui/feature-gates/auxiliary/diagnostic-on-const.rs b/tests/ui/feature-gates/auxiliary/diagnostic-on-const.rs new file mode 100644 index 0000000000000..3d2b5b9a9239f --- /dev/null +++ b/tests/ui/feature-gates/auxiliary/diagnostic-on-const.rs @@ -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 + } +} diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs new file mode 100644 index 0000000000000..398fa30e74047 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.rs @@ -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() {} diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr new file mode 100644 index 0000000000000..04c901f4f938b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-const.stderr @@ -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`.