about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs37
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs21
-rw-r--r--library/core/src/cmp.rs34
-rw-r--r--library/core/src/ops/arith.rs35
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr2
8 files changed, 112 insertions, 22 deletions
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 52d52752b15..d99bdd3bdd5 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -321,6 +321,7 @@ symbols! {
         and,
         and_then,
         any,
+        append_const_msg,
         arbitrary_enum_discriminant,
         arbitrary_self_types,
         arith_offset,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ffc742dd307..213084cdcd6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -310,13 +310,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             })
                             .unwrap_or_default();
 
-                        let OnUnimplementedNote { message, label, note, enclosing_scope } =
-                            self.on_unimplemented_note(trait_ref, &obligation);
+                        let OnUnimplementedNote {
+                            message,
+                            label,
+                            note,
+                            enclosing_scope,
+                            append_const_msg,
+                        } = self.on_unimplemented_note(trait_ref, &obligation);
                         let have_alt_message = message.is_some() || label.is_some();
                         let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
                         let is_unsize =
                             { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
-                        let (message, note) = if is_try_conversion {
+                        let (message, note, append_const_msg) = if is_try_conversion {
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
@@ -327,9 +332,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                         conversion on the error value using the `From` trait"
                                         .to_owned(),
                                 ),
+                                Some(None),
                             )
                         } else {
-                            (message, note)
+                            (message, note, append_const_msg)
                         };
 
                         let mut err = struct_span_err!(
@@ -337,12 +343,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             span,
                             E0277,
                             "{}",
-                            (!predicate_is_const).then(|| message).flatten().unwrap_or_else(
-                                || format!(
+                            message
+                                .and_then(|cannot_do_this| {
+                                    match (predicate_is_const, append_const_msg) {
+                                        // do nothing if predicate is not const
+                                        (false, _) => Some(cannot_do_this),
+                                        // suggested using default post message
+                                        (true, Some(None)) => {
+                                            Some(format!("{cannot_do_this} in const contexts"))
+                                        }
+                                        // overriden post message
+                                        (true, Some(Some(post_message))) => {
+                                            Some(format!("{cannot_do_this}{post_message}"))
+                                        }
+                                        // fallback to generic message
+                                        (true, None) => None,
+                                    }
+                                })
+                                .unwrap_or_else(|| format!(
                                     "the trait bound `{}` is not satisfied{}",
                                     trait_predicate, post_message,
-                                )
-                            )
+                                ))
                         );
 
                         if is_try_conversion {
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 4840995275a..6b20476b955 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -19,6 +19,7 @@ pub struct OnUnimplementedDirective {
     pub label: Option<OnUnimplementedFormatString>,
     pub note: Option<OnUnimplementedFormatString>,
     pub enclosing_scope: Option<OnUnimplementedFormatString>,
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 #[derive(Default)]
@@ -27,6 +28,11 @@ pub struct OnUnimplementedNote {
     pub label: Option<String>,
     pub note: Option<String>,
     pub enclosing_scope: Option<String>,
+    /// Append a message for `~const Trait` errors. `None` means not requested and
+    /// should fallback to a generic message, `Some(None)` suggests using the default
+    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+    /// default one..
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 fn parse_error(
@@ -89,6 +95,7 @@ impl<'tcx> OnUnimplementedDirective {
         let mut note = None;
         let mut enclosing_scope = None;
         let mut subcommands = vec![];
+        let mut append_const_msg = None;
 
         let parse_value = |value_str| {
             OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
@@ -131,6 +138,14 @@ impl<'tcx> OnUnimplementedDirective {
                     }
                     continue;
                 }
+            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+                if let Some(msg) = item.value_str() {
+                    append_const_msg = Some(Some(msg));
+                    continue;
+                } else if item.is_word() {
+                    append_const_msg = Some(None);
+                    continue;
+                }
             }
 
             // nothing found
@@ -153,6 +168,7 @@ impl<'tcx> OnUnimplementedDirective {
                 label,
                 note,
                 enclosing_scope,
+                append_const_msg,
             })
         }
     }
@@ -183,6 +199,7 @@ impl<'tcx> OnUnimplementedDirective {
                 )?),
                 note: None,
                 enclosing_scope: None,
+                append_const_msg: None,
             }))
         } else {
             return Err(ErrorReported);
@@ -201,6 +218,7 @@ impl<'tcx> OnUnimplementedDirective {
         let mut label = None;
         let mut note = None;
         let mut enclosing_scope = None;
+        let mut append_const_msg = None;
         info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
@@ -235,6 +253,8 @@ impl<'tcx> OnUnimplementedDirective {
             if let Some(ref enclosing_scope_) = command.enclosing_scope {
                 enclosing_scope = Some(enclosing_scope_.clone());
             }
+
+            append_const_msg = command.append_const_msg.clone();
         }
 
         let options: FxHashMap<Symbol, String> =
@@ -244,6 +264,7 @@ impl<'tcx> OnUnimplementedDirective {
             message: message.map(|m| m.format(tcx, trait_ref, &options)),
             note: note.map(|n| n.format(tcx, trait_ref, &options)),
             enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
+            append_const_msg,
         }
     }
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index f89cf812e97..1af352d542a 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -199,9 +199,20 @@ use self::Ordering::*;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(alias = "==")]
 #[doc(alias = "!=")]
-#[rustc_on_unimplemented(
-    message = "can't compare `{Self}` with `{Rhs}`",
-    label = "no implementation for `{Self} == {Rhs}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} == {Rhs}`"
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} == {Rhs}`",
+        append_const_msg,
+    )
 )]
 #[rustc_diagnostic_item = "PartialEq"]
 pub trait PartialEq<Rhs: ?Sized = Self> {
@@ -1031,9 +1042,20 @@ impl PartialOrd for Ordering {
 #[doc(alias = "<")]
 #[doc(alias = "<=")]
 #[doc(alias = ">=")]
-#[rustc_on_unimplemented(
-    message = "can't compare `{Self}` with `{Rhs}`",
-    label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+        append_const_msg,
+    )
 )]
 #[rustc_diagnostic_item = "PartialOrd"]
 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index e9547429389..e367be8c167 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -65,11 +65,36 @@
 /// ```
 #[lang = "add"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
-    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}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        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}`"
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        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,
+    )
 )]
 #[doc(alias = "+")]
 pub trait Add<Rhs = Self> {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
index 2d6e7b39f57..99eacaa837f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
@@ -16,7 +16,7 @@ trait Foo {
 
 impl const Foo for NonConstAdd {
     type Bar = NonConstAdd;
-    //~^ ERROR: the trait bound `NonConstAdd: ~const Add` is not satisfied
+    //~^ ERROR: cannot add `NonConstAdd` to `NonConstAdd` in const contexts
 }
 
 trait Baz {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index 05fce15f10b..429b9f3364b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied
+error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` in const contexts
   --> $DIR/assoc-type.rs:18:16
    |
 LL |     type Bar = NonConstAdd;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
index cf44b2a740a..13cffaba91a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `S: ~const PartialEq` is not satisfied
+error[E0277]: can't compare `S` with `S` in const contexts
   --> $DIR/call-generic-method-nonconst.rs:19:34
    |
 LL | pub const EQ: bool = equals_self(&S);