about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs8
-rw-r--r--library/core/src/cmp.rs18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs19
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr23
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs19
6 files changed, 100 insertions, 13 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f6fe71fbd4f..466641ea6df 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -12,8 +12,8 @@ use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::{
-    self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
-    ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+    self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
+    ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
 };
 use rustc_span::def_id::DefId;
 
@@ -98,8 +98,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Future(vtable_future)
             }
 
-            FnPointerCandidate { .. } => {
-                let data = self.confirm_fn_pointer_candidate(obligation)?;
+            FnPointerCandidate { is_const } => {
+                let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
                 ImplSource::FnPointer(data)
             }
 
@@ -597,17 +597,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_fn_pointer_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
+        is_const: bool,
     ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
     {
         debug!(?obligation, "confirm_fn_pointer_candidate");
 
+        let tcx = self.tcx();
         let self_ty = self
             .infcx
             .shallow_resolve(obligation.self_ty().no_bound_vars())
             .expect("fn pointer should not capture bound vars from predicate");
-        let sig = self_ty.fn_sig(self.tcx());
+        let sig = self_ty.fn_sig(tcx);
         let trait_ref = closure_trait_ref_and_return_type(
-            self.tcx(),
+            tcx,
             obligation.predicate.def_id(),
             self_ty,
             sig,
@@ -616,9 +618,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         .map_bound(|(trait_ref, _)| trait_ref);
 
         let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+        if obligation.is_const() && !is_const {
+            // function is a trait method
+            if let ty::FnDef(def_id, substs) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) {
+                let trait_ref = TraitRef::from_method(tcx, trait_id, *substs);
+                let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
+                let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred);
+                nested.push(obligation);
+            }
+        }
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
         let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
         let output_ty = normalize_with_depth_to(
             self,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 81e8f9e914c..760b4585f4e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1374,6 +1374,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     FutureCandidate => {}
                     // FnDef where the function is const
                     FnPointerCandidate { is_const: true } => {}
+                    FnPointerCandidate { is_const: false } => {
+                        if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
+                            // Trait methods are not seen as const unless the trait is implemented as const.
+                            // We do not filter that out in here, but nested obligations will be needed to confirm this.
+                        } else {
+                            continue
+                        }
+                    }
                     ConstDestructCandidate(_) => {}
                     _ => {
                         // reject all other types of candidates
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 949896e5748..74fb1aadaf9 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -800,9 +800,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
         Self: Sized,
         Self: ~const Destruct,
     {
-        // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
-        // when trait methods are allowed to be used when a const closure is
-        // expected.
+        #[cfg(not(bootstrap))]
+        {
+            max_by(self, other, Ord::cmp)
+        }
+
+        #[cfg(bootstrap)]
         match self.cmp(&other) {
             Ordering::Less | Ordering::Equal => other,
             Ordering::Greater => self,
@@ -827,9 +830,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
         Self: Sized,
         Self: ~const Destruct,
     {
-        // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
-        // when trait methods are allowed to be used when a const closure is
-        // expected.
+        #[cfg(not(bootstrap))]
+        {
+            min_by(self, other, Ord::cmp)
+        }
+
+        #[cfg(bootstrap)]
         match self.cmp(&other) {
             Ordering::Less | Ordering::Equal => self,
             Ordering::Greater => other,
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs
new file mode 100644
index 00000000000..b5f19e40c03
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.rs
@@ -0,0 +1,19 @@
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+    fn a(self) -> i32;
+}
+
+impl Tr for () {
+    fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+    x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+//~^ ERROR: the trait bound
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
new file mode 100644
index 00000000000..4470e287cc3
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied in `fn(()) -> i32 {<() as Tr>::a}`
+  --> $DIR/const-closure-trait-method-fail.rs:16:42
+   |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+   |                       ------------------ ^^^^^ within `fn(()) -> i32 {<() as Tr>::a}`, the trait `~const Tr` is not implemented for `()`
+   |                       |
+   |                       required by a bound introduced by this call
+   |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+  --> $DIR/const-closure-trait-method-fail.rs:16:42
+   |
+LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
+   |                                          ^^^^^
+   = note: required because it appears within the type `fn(()) -> i32 {<() as Tr>::a}`
+note: required by a bound in `need_const_closure`
+  --> $DIR/const-closure-trait-method-fail.rs:12:32
+   |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `need_const_closure`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs
new file mode 100644
index 00000000000..3e6d1908848
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-closure-trait-method.rs
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Tr {
+    fn a(self) -> i32;
+}
+
+impl const Tr for () {
+    fn a(self) -> i32 { 42 }
+}
+
+const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+    x(())
+}
+
+const _: () = assert!(need_const_closure(Tr::a) == 42);
+
+fn main() {}