about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2021-09-15 11:28:10 +0000
committerDeadbeef <ent3rm4n@gmail.com>2021-09-15 11:48:27 +0000
commitf8aa73d3dd951d69903e962054f2614b083c5b9c (patch)
tree505a93c3c6e2f02e2ef3af176a3bcc0c93ae13f0
parentd3f981b144c742c3e886a6234002a716a177bc98 (diff)
downloadrust-f8aa73d3dd951d69903e962054f2614b083c5b9c.tar.gz
rust-f8aa73d3dd951d69903e962054f2614b083c5b9c.zip
Coerce const FnDefs to implement const Fn traits
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs3
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs17
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-closures.rs31
7 files changed, 55 insertions, 13 deletions
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 35c6ae20103..c1cb5326ca3 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -655,8 +655,7 @@ impl<'tcx> Validator<'_, 'tcx> {
 
         let is_const_fn = match *fn_ty.kind() {
             ty::FnDef(def_id, _) => {
-                self.tcx.is_const_fn_raw(def_id)
-                    || is_lang_panic_fn(self.tcx, def_id)
+                self.tcx.is_const_fn_raw(def_id) || is_lang_panic_fn(self.tcx, def_id)
             }
             _ => false,
         };
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 3c0fedb3608..e236c4712c8 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -120,7 +120,9 @@ pub enum SelectionCandidate<'tcx> {
 
     /// Implementation of a `Fn`-family trait by one of the anonymous
     /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
-    FnPointerCandidate,
+    FnPointerCandidate {
+        is_const: bool,
+    },
 
     /// Builtin implementation of `DiscriminantKind`.
     DiscriminantKindCandidate,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2521b34a6b9..8cbae81f673 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2750,7 +2750,10 @@ impl<'tcx> TyCtxt<'tcx> {
                 Some(stability) if stability.level.is_unstable() => {
                     // has a `rustc_const_unstable` attribute, check whether the user enabled the
                     // corresponding feature gate.
-                    self.features().declared_lib_features.iter().any(|&(sym, _)| sym == stability.feature)
+                    self.features()
+                        .declared_lib_features
+                        .iter()
+                        .any(|&(sym, _)| sym == stability.feature)
                 }
                 // functions without const stability are either stable user written
                 // const fn or the user is using feature gates and we thus don't
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 6d64dc8254b..d31ae216d3a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -475,7 +475,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ..
                 } = self_ty.fn_sig(self.tcx()).skip_binder()
                 {
-                    candidates.vec.push(FnPointerCandidate);
+                    candidates.vec.push(FnPointerCandidate { is_const: false });
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
@@ -488,7 +488,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 } = self_ty.fn_sig(self.tcx()).skip_binder()
                 {
                     if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
-                        candidates.vec.push(FnPointerCandidate);
+                        candidates
+                            .vec
+                            .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
                     }
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 3b6555de912..b3ebd1cb1c4 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -92,7 +92,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(ImplSource::Generator(vtable_generator))
             }
 
-            FnPointerCandidate => {
+            FnPointerCandidate { .. } => {
                 let data = self.confirm_fn_pointer_candidate(obligation)?;
                 Ok(ImplSource::FnPointer(data))
             }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7b948a0939f..8dfd71e9cfb 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1100,6 +1100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // generator, this will raise error in other places
                 // or ignore error with const_async_blocks feature
                 GeneratorCandidate => {}
+                // FnDef where the function is const
+                FnPointerCandidate { is_const: true } => {}
                 ConstDropCandidate => {}
                 _ => {
                     // reject all other types of candidates
@@ -1513,6 +1515,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
+            // Drop otherwise equivalent non-const fn pointer candidates
+            (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
+
             // Global bounds from the where clause should be ignored
             // here (see issue #50825). Otherwise, we have a where
             // clause so don't go around looking for impls.
@@ -1523,7 +1528,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1541,7 +1546,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1571,7 +1576,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1583,7 +1588,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1664,7 +1669,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1673,7 +1678,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
new file mode 100644
index 00000000000..99e608797ff
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
@@ -0,0 +1,31 @@
+// run-pass
+
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+
+const fn answer_p1<F>(f: &F) -> u8
+    where
+        F: ~const FnOnce() -> u8,
+        F: ~const FnMut() -> u8,
+        F: ~const Fn() -> u8,
+{
+    f() * 7
+}
+
+const fn three() -> u8 {
+    3
+}
+
+const fn answer_p2() -> u8 {
+    answer_p1(&three)
+}
+
+const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+    f() + f()
+}
+
+const ANSWER: u8 = answer(&answer_p2);
+
+fn main() {
+    assert_eq!(ANSWER, 42)
+}