Skip to content

Commit 743e842

Browse files
authored
Rollup merge of #88963 - fee1-dead:const-iterator, r=oli-obk
Coerce const FnDefs to implement const Fn traits You can now pass a FnDef to a function expecting `F` where `F: ~const FnTrait`. r? ``@oli-obk`` ``@rustbot`` label T-compiler F-const_trait_impl
2 parents 2bab0a0 + f8aa73d commit 743e842

File tree

11 files changed

+79
-37
lines changed

11 files changed

+79
-37
lines changed

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

+1-18
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,6 @@ use rustc_middle::ty::TyCtxt;
66
use rustc_span::symbol::Symbol;
77
use rustc_target::spec::abi::Abi;
88

9-
/// Whether the `def_id` counts as const fn in your current crate, considering all active
10-
/// feature gates
11-
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
12-
tcx.is_const_fn_raw(def_id)
13-
&& match is_unstable_const_fn(tcx, def_id) {
14-
Some(feature_name) => {
15-
// has a `rustc_const_unstable` attribute, check whether the user enabled the
16-
// corresponding feature gate.
17-
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
18-
}
19-
// functions without const stability are either stable user written
20-
// const fn or the user is using feature gates and we thus don't
21-
// care what they do
22-
None => true,
23-
}
24-
}
25-
269
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
2710
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
2811
if tcx.is_const_fn_raw(def_id) {
@@ -77,7 +60,7 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
7760
}
7861

7962
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
80-
is_const_fn(tcx, def_id)
63+
tcx.is_const_fn(def_id)
8164
&& match tcx.lookup_const_stability(def_id) {
8265
Some(stab) => {
8366
if cfg!(debug_assertions) && stab.promotable {

compiler/rustc_const_eval/src/transform/promote_consts.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use rustc_index::vec::{Idx, IndexVec};
2626
use std::cell::Cell;
2727
use std::{cmp, iter, mem};
2828

29-
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
3029
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
3130
use crate::transform::MirPass;
3231

@@ -658,9 +657,7 @@ impl<'tcx> Validator<'_, 'tcx> {
658657

659658
let is_const_fn = match *fn_ty.kind() {
660659
ty::FnDef(def_id, _) => {
661-
is_const_fn(self.tcx, def_id)
662-
|| is_unstable_const_fn(self.tcx, def_id).is_some()
663-
|| is_lang_panic_fn(self.tcx, def_id)
660+
self.tcx.is_const_fn_raw(def_id) || is_lang_panic_fn(self.tcx, def_id)
664661
}
665662
_ => false,
666663
};
@@ -1081,7 +1078,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
10811078
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
10821079
if let Some((destination_place, _)) = destination {
10831080
if destination_place == place {
1084-
if is_const_fn(ccx.tcx, def_id) {
1081+
if ccx.tcx.is_const_fn(def_id) {
10851082
return true;
10861083
}
10871084
}

compiler/rustc_middle/src/traits/select.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ pub enum SelectionCandidate<'tcx> {
120120

121121
/// Implementation of a `Fn`-family trait by one of the anonymous
122122
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
123-
FnPointerCandidate,
123+
FnPointerCandidate {
124+
is_const: bool,
125+
},
124126

125127
/// Builtin implementation of `DiscriminantKind`.
126128
DiscriminantKindCandidate,

compiler/rustc_middle/src/ty/context.rs

+23
Original file line numberDiff line numberDiff line change
@@ -2701,6 +2701,29 @@ impl<'tcx> TyCtxt<'tcx> {
27012701
pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
27022702
self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id))
27032703
}
2704+
2705+
/// Whether the `def_id` counts as const fn in the current crate, considering all active
2706+
/// feature gates
2707+
pub fn is_const_fn(self, def_id: DefId) -> bool {
2708+
if self.is_const_fn_raw(def_id) {
2709+
match self.lookup_const_stability(def_id) {
2710+
Some(stability) if stability.level.is_unstable() => {
2711+
// has a `rustc_const_unstable` attribute, check whether the user enabled the
2712+
// corresponding feature gate.
2713+
self.features()
2714+
.declared_lib_features
2715+
.iter()
2716+
.any(|&(sym, _)| sym == stability.feature)
2717+
}
2718+
// functions without const stability are either stable user written
2719+
// const fn or the user is using feature gates and we thus don't
2720+
// care what they do
2721+
_ => true,
2722+
}
2723+
} else {
2724+
false
2725+
}
2726+
}
27042727
}
27052728

27062729
impl TyCtxtAt<'tcx> {

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
476476
..
477477
} = self_ty.fn_sig(self.tcx()).skip_binder()
478478
{
479-
candidates.vec.push(FnPointerCandidate);
479+
candidates.vec.push(FnPointerCandidate { is_const: false });
480480
}
481481
}
482482
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
@@ -489,7 +489,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
489489
} = self_ty.fn_sig(self.tcx()).skip_binder()
490490
{
491491
if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
492-
candidates.vec.push(FnPointerCandidate);
492+
candidates
493+
.vec
494+
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
493495
}
494496
}
495497
}

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
9292
Ok(ImplSource::Generator(vtable_generator))
9393
}
9494

95-
FnPointerCandidate => {
95+
FnPointerCandidate { .. } => {
9696
let data = self.confirm_fn_pointer_candidate(obligation)?;
9797
Ok(ImplSource::FnPointer(data))
9898
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11121112
// generator, this will raise error in other places
11131113
// or ignore error with const_async_blocks feature
11141114
GeneratorCandidate => {}
1115+
// FnDef where the function is const
1116+
FnPointerCandidate { is_const: true } => {}
11151117
ConstDropCandidate => {}
11161118
_ => {
11171119
// reject all other types of candidates
@@ -1539,6 +1541,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15391541
}
15401542
}
15411543

1544+
// Drop otherwise equivalent non-const fn pointer candidates
1545+
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
1546+
15421547
// Global bounds from the where clause should be ignored
15431548
// here (see issue #50825). Otherwise, we have a where
15441549
// clause so don't go around looking for impls.
@@ -1549,7 +1554,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15491554
ImplCandidate(..)
15501555
| ClosureCandidate
15511556
| GeneratorCandidate
1552-
| FnPointerCandidate
1557+
| FnPointerCandidate { .. }
15531558
| BuiltinObjectCandidate
15541559
| BuiltinUnsizeCandidate
15551560
| TraitUpcastingUnsizeCandidate(_)
@@ -1567,7 +1572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15671572
ImplCandidate(_)
15681573
| ClosureCandidate
15691574
| GeneratorCandidate
1570-
| FnPointerCandidate
1575+
| FnPointerCandidate { .. }
15711576
| BuiltinObjectCandidate
15721577
| BuiltinUnsizeCandidate
15731578
| TraitUpcastingUnsizeCandidate(_)
@@ -1597,7 +1602,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15971602
ImplCandidate(..)
15981603
| ClosureCandidate
15991604
| GeneratorCandidate
1600-
| FnPointerCandidate
1605+
| FnPointerCandidate { .. }
16011606
| BuiltinObjectCandidate
16021607
| BuiltinUnsizeCandidate
16031608
| TraitUpcastingUnsizeCandidate(_)
@@ -1609,7 +1614,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16091614
ImplCandidate(..)
16101615
| ClosureCandidate
16111616
| GeneratorCandidate
1612-
| FnPointerCandidate
1617+
| FnPointerCandidate { .. }
16131618
| BuiltinObjectCandidate
16141619
| BuiltinUnsizeCandidate
16151620
| TraitUpcastingUnsizeCandidate(_)
@@ -1690,7 +1695,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16901695
ImplCandidate(_)
16911696
| ClosureCandidate
16921697
| GeneratorCandidate
1693-
| FnPointerCandidate
1698+
| FnPointerCandidate { .. }
16941699
| BuiltinObjectCandidate
16951700
| BuiltinUnsizeCandidate
16961701
| TraitUpcastingUnsizeCandidate(_)
@@ -1699,7 +1704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16991704
ImplCandidate(_)
17001705
| ClosureCandidate
17011706
| GeneratorCandidate
1702-
| FnPointerCandidate
1707+
| FnPointerCandidate { .. }
17031708
| BuiltinObjectCandidate
17041709
| BuiltinUnsizeCandidate
17051710
| TraitUpcastingUnsizeCandidate(_)

src/librustdoc/clean/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ crate mod utils;
1111

1212
use rustc_ast as ast;
1313
use rustc_attr as attr;
14-
use rustc_const_eval::const_eval::{is_const_fn, is_unstable_const_fn};
14+
use rustc_const_eval::const_eval::is_unstable_const_fn;
1515
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1616
use rustc_hir as hir;
1717
use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -787,7 +787,7 @@ fn clean_fn_or_proc_macro(
787787
let mut func = (sig, generics, body_id).clean(cx);
788788
let def_id = item.def_id.to_def_id();
789789
func.header.constness =
790-
if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
790+
if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
791791
hir::Constness::Const
792792
} else {
793793
hir::Constness::NotConst
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// run-pass
2+
3+
#![feature(const_trait_impl)]
4+
#![feature(const_fn_trait_bound)]
5+
6+
const fn answer_p1<F>(f: &F) -> u8
7+
where
8+
F: ~const FnOnce() -> u8,
9+
F: ~const FnMut() -> u8,
10+
F: ~const Fn() -> u8,
11+
{
12+
f() * 7
13+
}
14+
15+
const fn three() -> u8 {
16+
3
17+
}
18+
19+
const fn answer_p2() -> u8 {
20+
answer_p1(&three)
21+
}
22+
23+
const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
24+
f() + f()
25+
}
26+
27+
const ANSWER: u8 = answer(&answer_p2);
28+
29+
fn main() {
30+
assert_eq!(ANSWER, 42)
31+
}

src/tools/clippy/clippy_utils/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
extern crate rustc_ast;
1919
extern crate rustc_ast_pretty;
2020
extern crate rustc_attr;
21-
extern crate rustc_const_eval;
2221
extern crate rustc_data_structures;
2322
extern crate rustc_errors;
2423
extern crate rustc_hir;

src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ fn check_terminator(
364364
}
365365

366366
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool {
367-
rustc_const_eval::const_eval::is_const_fn(tcx, def_id)
367+
tcx.is_const_fn(def_id)
368368
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
369369
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
370370
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire

0 commit comments

Comments
 (0)