about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs53
-rw-r--r--tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs22
-rw-r--r--tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr41
3 files changed, 99 insertions, 17 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 885b606326c..163c453bdbe 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
@@ -538,23 +538,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
 
                     ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
-                        // 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.
-                        let err_msg = self.get_standard_error_message(
-                            bound_predicate.rebind(ty::TraitPredicate {
-                                trait_ref: predicate.trait_ref,
-                                polarity: ty::PredicatePolarity::Positive,
-                            }),
-                            None,
-                            Some(predicate.constness),
-                            None,
-                            String::new(),
-                        );
-                        struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg)
+                        self.report_host_effect_error(bound_predicate.rebind(predicate), obligation.param_env, span)
                     }
 
                     ty::PredicateKind::Subtype(predicate) => {
@@ -763,6 +747,41 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         applied_do_not_recommend
     }
 
+    fn report_host_effect_error(
+        &self,
+        predicate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
+        param_env: ty::ParamEnv<'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.
+        let trait_ref = predicate.map_bound(|predicate| ty::TraitPredicate {
+            trait_ref: predicate.trait_ref,
+            polarity: ty::PredicatePolarity::Positive,
+        });
+        let err_msg = self.get_standard_error_message(
+            trait_ref,
+            None,
+            Some(predicate.constness()),
+            None,
+            String::new(),
+        );
+        let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
+        if !self.predicate_may_hold(&Obligation::new(
+            self.tcx,
+            ObligationCause::dummy(),
+            param_env,
+            trait_ref,
+        )) {
+            diag.downgrade_to_delayed_bug();
+        }
+        diag
+    }
+
     fn emit_specialized_closure_kind_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
diff --git a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs
new file mode 100644
index 00000000000..f4b01efe959
--- /dev/null
+++ b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.rs
@@ -0,0 +1,22 @@
+// Make sure we don't issue *two* error messages for the trait predicate *and* host predicate.
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Trait {
+  type Out;
+}
+
+const fn needs_const<T: ~const Trait>(_: &T) {}
+
+const IN_CONST: () = {
+  needs_const(&());
+  //~^ ERROR the trait bound `(): Trait` is not satisfied
+};
+
+const fn conditionally_const() {
+  needs_const(&());
+  //~^ ERROR the trait bound `(): Trait` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr
new file mode 100644
index 00000000000..cd68cdaf8a2
--- /dev/null
+++ b/tests/ui/traits/const-traits/double-error-for-unimplemented-trait.stderr
@@ -0,0 +1,41 @@
+error[E0277]: the trait bound `(): Trait` is not satisfied
+  --> $DIR/double-error-for-unimplemented-trait.rs:13:15
+   |
+LL |   needs_const(&());
+   |   ----------- ^^^ the trait `Trait` is not implemented for `()`
+   |   |
+   |   required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/double-error-for-unimplemented-trait.rs:6:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
+note: required by a bound in `needs_const`
+  --> $DIR/double-error-for-unimplemented-trait.rs:10:25
+   |
+LL | const fn needs_const<T: ~const Trait>(_: &T) {}
+   |                         ^^^^^^^^^^^^ required by this bound in `needs_const`
+
+error[E0277]: the trait bound `(): Trait` is not satisfied
+  --> $DIR/double-error-for-unimplemented-trait.rs:18:15
+   |
+LL |   needs_const(&());
+   |   ----------- ^^^ the trait `Trait` is not implemented for `()`
+   |   |
+   |   required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/double-error-for-unimplemented-trait.rs:6:1
+   |
+LL | trait Trait {
+   | ^^^^^^^^^^^
+note: required by a bound in `needs_const`
+  --> $DIR/double-error-for-unimplemented-trait.rs:10:25
+   |
+LL | const fn needs_const<T: ~const Trait>(_: &T) {}
+   |                         ^^^^^^^^^^^^ required by this bound in `needs_const`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.