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) -> 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 u8>(f: &F) -> u8 { + f() + f() +} + +const ANSWER: u8 = answer(&answer_p2); + +fn main() { + assert_eq!(ANSWER, 42) +}