Skip to content

Commit 69f360d

Browse files
Check FnPtr/FnDef built-in fn traits correctly with effects
1 parent 2a76340 commit 69f360d

File tree

7 files changed

+84
-24
lines changed

7 files changed

+84
-24
lines changed

compiler/rustc_middle/src/traits/select.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub enum SelectionCandidate<'tcx> {
153153
/// Implementation of a `Fn`-family trait by one of the anonymous
154154
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
155155
FnPointerCandidate {
156-
is_const: bool,
156+
fn_host_effect: ty::Const<'tcx>,
157157
},
158158

159159
TraitAliasCandidate,

compiler/rustc_trait_selection/src/traits/project.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -2327,8 +2327,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
23272327
obligation: &ProjectionTyObligation<'tcx>,
23282328
nested: Vec<PredicateObligation<'tcx>>,
23292329
) -> Progress<'tcx> {
2330+
let tcx = selcx.tcx();
23302331
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
2331-
let sig = fn_type.fn_sig(selcx.tcx());
2332+
let sig = fn_type.fn_sig(tcx);
23322333
let Normalized { value: sig, obligations } = normalize_with_depth(
23332334
selcx,
23342335
obligation.param_env,
@@ -2337,9 +2338,24 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
23372338
sig,
23382339
);
23392340

2340-
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
2341-
.with_addl_obligations(nested)
2342-
.with_addl_obligations(obligations)
2341+
let host_effect_param = match *fn_type.kind() {
2342+
ty::FnDef(def_id, args) => tcx
2343+
.generics_of(def_id)
2344+
.host_effect_index
2345+
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
2346+
ty::FnPtr(_) => tcx.consts.true_,
2347+
_ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
2348+
};
2349+
2350+
confirm_callable_candidate(
2351+
selcx,
2352+
obligation,
2353+
sig,
2354+
util::TupleArgumentsFlag::Yes,
2355+
host_effect_param,
2356+
)
2357+
.with_addl_obligations(nested)
2358+
.with_addl_obligations(obligations)
23432359
}
23442360

23452361
fn confirm_closure_candidate<'cx, 'tcx>(
@@ -2362,16 +2378,24 @@ fn confirm_closure_candidate<'cx, 'tcx>(
23622378

23632379
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
23642380

2365-
confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
2366-
.with_addl_obligations(nested)
2367-
.with_addl_obligations(obligations)
2381+
confirm_callable_candidate(
2382+
selcx,
2383+
obligation,
2384+
closure_sig,
2385+
util::TupleArgumentsFlag::No,
2386+
// FIXME(effects): This doesn't handle const closures correctly!
2387+
selcx.tcx().consts.true_,
2388+
)
2389+
.with_addl_obligations(nested)
2390+
.with_addl_obligations(obligations)
23682391
}
23692392

23702393
fn confirm_callable_candidate<'cx, 'tcx>(
23712394
selcx: &mut SelectionContext<'cx, 'tcx>,
23722395
obligation: &ProjectionTyObligation<'tcx>,
23732396
fn_sig: ty::PolyFnSig<'tcx>,
23742397
flag: util::TupleArgumentsFlag,
2398+
fn_host_effect: ty::Const<'tcx>,
23752399
) -> Progress<'tcx> {
23762400
let tcx = selcx.tcx();
23772401

@@ -2386,6 +2410,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
23862410
obligation.predicate.self_ty(),
23872411
fn_sig,
23882412
flag,
2413+
fn_host_effect,
23892414
)
23902415
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
23912416
projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -355,17 +355,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
355355
// Provide an impl, but only for suitable `fn` pointers.
356356
ty::FnPtr(sig) => {
357357
if sig.is_fn_trait_compatible() {
358-
candidates.vec.push(FnPointerCandidate { is_const: false });
358+
candidates
359+
.vec
360+
.push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
359361
}
360362
}
361363
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
362-
ty::FnDef(def_id, _) => {
363-
if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
364-
&& self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
364+
ty::FnDef(def_id, args) => {
365+
let tcx = self.tcx();
366+
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
367+
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
365368
{
366-
candidates
367-
.vec
368-
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
369+
candidates.vec.push(FnPointerCandidate {
370+
fn_host_effect: tcx
371+
.generics_of(def_id)
372+
.host_effect_index
373+
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
374+
});
369375
}
370376
}
371377
_ => {}

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
103103
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
104104
}
105105

106-
FnPointerCandidate { is_const } => {
107-
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
106+
FnPointerCandidate { fn_host_effect } => {
107+
let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
108108
ImplSource::Builtin(BuiltinImplSource::Misc, data)
109109
}
110110

@@ -653,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
653653
fn confirm_fn_pointer_candidate(
654654
&mut self,
655655
obligation: &PolyTraitObligation<'tcx>,
656-
// FIXME(effects)
657-
_is_const: bool,
656+
fn_host_effect: ty::Const<'tcx>,
658657
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
659658
debug!(?obligation, "confirm_fn_pointer_candidate");
660659

@@ -675,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
675674
self_ty,
676675
sig,
677676
util::TupleArgumentsFlag::Yes,
677+
fn_host_effect,
678678
)
679679
.map_bound(|(trait_ref, _)| trait_ref);
680680

@@ -860,7 +860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
860860
bug!("closure candidate for non-closure {:?}", obligation);
861861
};
862862

863-
let trait_ref = self.closure_trait_ref_unnormalized(obligation, args);
863+
let trait_ref =
864+
self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_);
864865
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
865866

866867
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -1865,7 +1865,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18651865
}
18661866

18671867
// Drop otherwise equivalent non-const fn pointer candidates
1868-
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
1868+
(FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
1869+
DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
1870+
}
18691871

18701872
(
18711873
ParamCandidate(ref other_cand),
@@ -2660,6 +2662,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
26602662
&mut self,
26612663
obligation: &PolyTraitObligation<'tcx>,
26622664
args: GenericArgsRef<'tcx>,
2665+
fn_host_effect: ty::Const<'tcx>,
26632666
) -> ty::PolyTraitRef<'tcx> {
26642667
let closure_sig = args.as_closure().sig();
26652668

@@ -2680,6 +2683,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
26802683
self_ty,
26812684
closure_sig,
26822685
util::TupleArgumentsFlag::No,
2686+
fn_host_effect,
26832687
)
26842688
.map_bound(|(trait_ref, _)| trait_ref)
26852689
}

compiler/rustc_trait_selection/src/traits/util.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,26 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
264264
self_ty: Ty<'tcx>,
265265
sig: ty::PolyFnSig<'tcx>,
266266
tuple_arguments: TupleArgumentsFlag,
267+
fn_host_effect: ty::Const<'tcx>,
267268
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
268269
assert!(!self_ty.has_escaping_bound_vars());
269270
let arguments_tuple = match tuple_arguments {
270271
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
271272
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
272273
};
273-
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
274+
let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() {
275+
ty::TraitRef::new(
276+
tcx,
277+
fn_trait_def_id,
278+
[
279+
ty::GenericArg::from(self_ty),
280+
ty::GenericArg::from(arguments_tuple),
281+
ty::GenericArg::from(fn_host_effect),
282+
],
283+
)
284+
} else {
285+
ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple])
286+
};
274287
sig.map_bound(|sig| (trait_ref, sig.output()))
275288
}
276289

tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// check-pass
22

33
#![crate_type = "lib"]
4-
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)]
4+
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)]
55
#![feature(fundamental)]
66
#![feature(const_trait_impl, effects, const_mut_refs)]
77
#![allow(internal_features)]
88
#![no_std]
99
#![no_core]
10+
#![stable(feature = "minicore", since = "1.0.0")]
1011

1112
#[lang = "sized"]
1213
trait Sized {}
@@ -82,6 +83,7 @@ trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
8283
#[lang = "fn_once"]
8384
#[rustc_paren_sugar]
8485
trait FnOnce<Args: Tuple> {
86+
#[lang = "fn_once_output"]
8587
type Output;
8688

8789
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
@@ -93,7 +95,7 @@ struct ConstFnMutClosure<CapturedData, Function> {
9395
}
9496

9597
#[lang = "tuple_trait"]
96-
pub trait Tuple {}
98+
trait Tuple {}
9799

98100
macro_rules! impl_fn_mut_tuple {
99101
($($var:ident)*) => {
@@ -509,3 +511,12 @@ trait StructuralPartialEq {}
509511
trait StructuralEq {}
510512

511513
const fn drop<T: ~const Destruct>(_: T) {}
514+
515+
extern "rust-intrinsic" {
516+
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
517+
fn const_eval_select<ARG: Tuple, F, G, RET>(
518+
arg: ARG,
519+
called_in_const: F,
520+
called_at_rt: G,
521+
) -> RET;
522+
}

0 commit comments

Comments
 (0)