Auto merge of #119023 - compiler-errors:fn-trait-constness, r=fee1-dead
Check `FnPtr`/`FnDef` built-in fn traits correctly with effects 1. Teach the (old) trait solver how to handle the constness for built-in impls of the `Fn*` family of traits. This unfortunately doesn't support const closures just yet. 2. Fix the `const_eval_select`. It turns out that the `where` clause bounds on `const_eval_select` force the effect parameter for both fndefs to be `true` -- with effects, we will leave off any explicit where clauses and register these obligations manually. I can elaborate on (2.) if you think it needs a better explanation! r? fee1-dead
This commit is contained in:
commit
3f28fe1334
@ -471,6 +471,65 @@ fn confirm_builtin_call(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(def_id) = def_id
|
||||||
|
&& self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
|
||||||
|
&& self.tcx.is_intrinsic(def_id)
|
||||||
|
&& self.tcx.item_name(def_id) == sym::const_eval_select
|
||||||
|
{
|
||||||
|
let fn_sig = self.resolve_vars_if_possible(fn_sig);
|
||||||
|
for idx in 0..=1 {
|
||||||
|
let arg_ty = fn_sig.inputs()[idx + 1];
|
||||||
|
let span = arg_exprs.get(idx + 1).map_or(call_expr.span, |arg| arg.span);
|
||||||
|
// Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
|
||||||
|
// the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
|
||||||
|
// in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
|
||||||
|
//
|
||||||
|
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
|
||||||
|
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
|
||||||
|
let fn_once_def_id =
|
||||||
|
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
|
||||||
|
let fn_once_output_def_id =
|
||||||
|
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
|
||||||
|
if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() {
|
||||||
|
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
|
||||||
|
self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { span });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let const_param: ty::GenericArg<'tcx> =
|
||||||
|
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
|
||||||
|
self.register_predicate(traits::Obligation::new(
|
||||||
|
self.tcx,
|
||||||
|
self.misc(span),
|
||||||
|
self.param_env,
|
||||||
|
ty::TraitRef::new(
|
||||||
|
self.tcx,
|
||||||
|
fn_once_def_id,
|
||||||
|
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
self.register_predicate(traits::Obligation::new(
|
||||||
|
self.tcx,
|
||||||
|
self.misc(span),
|
||||||
|
self.param_env,
|
||||||
|
ty::ProjectionPredicate {
|
||||||
|
projection_ty: ty::AliasTy::new(
|
||||||
|
self.tcx,
|
||||||
|
fn_once_output_def_id,
|
||||||
|
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
|
||||||
|
),
|
||||||
|
term: fn_sig.output().into(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
self.select_obligations_where_possible(|_| {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn_sig.output()
|
fn_sig.output()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,11 +230,6 @@ pub(in super::super) fn check_argument_types(
|
|||||||
let minimum_input_count = expected_input_tys.len();
|
let minimum_input_count = expected_input_tys.len();
|
||||||
let provided_arg_count = provided_args.len();
|
let provided_arg_count = provided_args.len();
|
||||||
|
|
||||||
let is_const_eval_select = matches!(fn_def_id, Some(def_id) if
|
|
||||||
self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
|
|
||||||
&& self.tcx.is_intrinsic(def_id)
|
|
||||||
&& self.tcx.item_name(def_id) == sym::const_eval_select);
|
|
||||||
|
|
||||||
// We introduce a helper function to demand that a given argument satisfy a given input
|
// We introduce a helper function to demand that a given argument satisfy a given input
|
||||||
// This is more complicated than just checking type equality, as arguments could be coerced
|
// This is more complicated than just checking type equality, as arguments could be coerced
|
||||||
// This version writes those types back so further type checking uses the narrowed types
|
// This version writes those types back so further type checking uses the narrowed types
|
||||||
@ -269,30 +264,6 @@ pub(in super::super) fn check_argument_types(
|
|||||||
return Compatibility::Incompatible(coerce_error);
|
return Compatibility::Incompatible(coerce_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
|
|
||||||
// the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
|
|
||||||
// in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
|
|
||||||
//
|
|
||||||
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
|
|
||||||
if is_const_eval_select && (1..=2).contains(&idx) {
|
|
||||||
if let ty::FnDef(def_id, args) = *checked_ty.kind() {
|
|
||||||
if idx == 1 {
|
|
||||||
if !self.tcx.is_const_fn_raw(def_id) {
|
|
||||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeConst {
|
|
||||||
span: provided_arg.span,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.enforce_context_effects(provided_arg.span, def_id, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeFn {
|
|
||||||
span: provided_arg.span,
|
|
||||||
ty: checked_ty,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Check if the formal type is a supertype of the checked one
|
// 3. Check if the formal type is a supertype of the checked one
|
||||||
// and register any such obligations for future type checks
|
// and register any such obligations for future type checks
|
||||||
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
|
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
|
||||||
|
@ -153,7 +153,7 @@ pub enum SelectionCandidate<'tcx> {
|
|||||||
/// Implementation of a `Fn`-family trait by one of the anonymous
|
/// Implementation of a `Fn`-family trait by one of the anonymous
|
||||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||||
FnPointerCandidate {
|
FnPointerCandidate {
|
||||||
is_const: bool,
|
fn_host_effect: ty::Const<'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
TraitAliasCandidate,
|
TraitAliasCandidate,
|
||||||
|
@ -2327,8 +2327,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
|||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
nested: Vec<PredicateObligation<'tcx>>,
|
nested: Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||||
let sig = fn_type.fn_sig(selcx.tcx());
|
let sig = fn_type.fn_sig(tcx);
|
||||||
let Normalized { value: sig, obligations } = normalize_with_depth(
|
let Normalized { value: sig, obligations } = normalize_with_depth(
|
||||||
selcx,
|
selcx,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
@ -2337,9 +2338,24 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
|||||||
sig,
|
sig,
|
||||||
);
|
);
|
||||||
|
|
||||||
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
|
let host_effect_param = match *fn_type.kind() {
|
||||||
.with_addl_obligations(nested)
|
ty::FnDef(def_id, args) => tcx
|
||||||
.with_addl_obligations(obligations)
|
.generics_of(def_id)
|
||||||
|
.host_effect_index
|
||||||
|
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
|
||||||
|
ty::FnPtr(_) => tcx.consts.true_,
|
||||||
|
_ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
|
||||||
|
};
|
||||||
|
|
||||||
|
confirm_callable_candidate(
|
||||||
|
selcx,
|
||||||
|
obligation,
|
||||||
|
sig,
|
||||||
|
util::TupleArgumentsFlag::Yes,
|
||||||
|
host_effect_param,
|
||||||
|
)
|
||||||
|
.with_addl_obligations(nested)
|
||||||
|
.with_addl_obligations(obligations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_closure_candidate<'cx, 'tcx>(
|
fn confirm_closure_candidate<'cx, 'tcx>(
|
||||||
@ -2362,9 +2378,16 @@ fn confirm_closure_candidate<'cx, 'tcx>(
|
|||||||
|
|
||||||
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
|
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
|
||||||
|
|
||||||
confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
|
confirm_callable_candidate(
|
||||||
.with_addl_obligations(nested)
|
selcx,
|
||||||
.with_addl_obligations(obligations)
|
obligation,
|
||||||
|
closure_sig,
|
||||||
|
util::TupleArgumentsFlag::No,
|
||||||
|
// FIXME(effects): This doesn't handle const closures correctly!
|
||||||
|
selcx.tcx().consts.true_,
|
||||||
|
)
|
||||||
|
.with_addl_obligations(nested)
|
||||||
|
.with_addl_obligations(obligations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_callable_candidate<'cx, 'tcx>(
|
fn confirm_callable_candidate<'cx, 'tcx>(
|
||||||
@ -2372,6 +2395,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
|||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
fn_sig: ty::PolyFnSig<'tcx>,
|
fn_sig: ty::PolyFnSig<'tcx>,
|
||||||
flag: util::TupleArgumentsFlag,
|
flag: util::TupleArgumentsFlag,
|
||||||
|
fn_host_effect: ty::Const<'tcx>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
let tcx = selcx.tcx();
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
@ -2386,6 +2410,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
|||||||
obligation.predicate.self_ty(),
|
obligation.predicate.self_ty(),
|
||||||
fn_sig,
|
fn_sig,
|
||||||
flag,
|
flag,
|
||||||
|
fn_host_effect,
|
||||||
)
|
)
|
||||||
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
|
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
|
||||||
projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
|
projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
|
||||||
|
@ -355,17 +355,23 @@ fn assemble_fn_pointer_candidates(
|
|||||||
// Provide an impl, but only for suitable `fn` pointers.
|
// Provide an impl, but only for suitable `fn` pointers.
|
||||||
ty::FnPtr(sig) => {
|
ty::FnPtr(sig) => {
|
||||||
if sig.is_fn_trait_compatible() {
|
if sig.is_fn_trait_compatible() {
|
||||||
candidates.vec.push(FnPointerCandidate { is_const: false });
|
candidates
|
||||||
|
.vec
|
||||||
|
.push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
||||||
ty::FnDef(def_id, _) => {
|
ty::FnDef(def_id, args) => {
|
||||||
if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
|
let tcx = self.tcx();
|
||||||
&& self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
|
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
|
||||||
|
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||||
{
|
{
|
||||||
candidates
|
candidates.vec.push(FnPointerCandidate {
|
||||||
.vec
|
fn_host_effect: tcx
|
||||||
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
|
.generics_of(def_id)
|
||||||
|
.host_effect_index
|
||||||
|
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -103,8 +103,8 @@ pub(super) fn confirm_candidate(
|
|||||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
|
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
FnPointerCandidate { is_const } => {
|
FnPointerCandidate { fn_host_effect } => {
|
||||||
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
|
let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
|
||||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,8 +653,7 @@ fn confirm_object_candidate(
|
|||||||
fn confirm_fn_pointer_candidate(
|
fn confirm_fn_pointer_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &PolyTraitObligation<'tcx>,
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
// FIXME(effects)
|
fn_host_effect: ty::Const<'tcx>,
|
||||||
_is_const: bool,
|
|
||||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||||
debug!(?obligation, "confirm_fn_pointer_candidate");
|
debug!(?obligation, "confirm_fn_pointer_candidate");
|
||||||
|
|
||||||
@ -675,6 +674,7 @@ fn confirm_fn_pointer_candidate(
|
|||||||
self_ty,
|
self_ty,
|
||||||
sig,
|
sig,
|
||||||
util::TupleArgumentsFlag::Yes,
|
util::TupleArgumentsFlag::Yes,
|
||||||
|
fn_host_effect,
|
||||||
)
|
)
|
||||||
.map_bound(|(trait_ref, _)| trait_ref);
|
.map_bound(|(trait_ref, _)| trait_ref);
|
||||||
|
|
||||||
@ -860,7 +860,8 @@ fn confirm_closure_candidate(
|
|||||||
bug!("closure candidate for non-closure {:?}", obligation);
|
bug!("closure candidate for non-closure {:?}", obligation);
|
||||||
};
|
};
|
||||||
|
|
||||||
let trait_ref = self.closure_trait_ref_unnormalized(obligation, args);
|
let trait_ref =
|
||||||
|
self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_);
|
||||||
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
||||||
|
|
||||||
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
|
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
|
||||||
|
@ -1865,7 +1865,9 @@ fn candidate_should_be_dropped_in_favor_of(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drop otherwise equivalent non-const fn pointer candidates
|
// Drop otherwise equivalent non-const fn pointer candidates
|
||||||
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
|
(FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
|
||||||
|
DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
ParamCandidate(ref other_cand),
|
ParamCandidate(ref other_cand),
|
||||||
@ -2660,6 +2662,7 @@ fn closure_trait_ref_unnormalized(
|
|||||||
&mut self,
|
&mut self,
|
||||||
obligation: &PolyTraitObligation<'tcx>,
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
|
fn_host_effect: ty::Const<'tcx>,
|
||||||
) -> ty::PolyTraitRef<'tcx> {
|
) -> ty::PolyTraitRef<'tcx> {
|
||||||
let closure_sig = args.as_closure().sig();
|
let closure_sig = args.as_closure().sig();
|
||||||
|
|
||||||
@ -2680,6 +2683,7 @@ fn closure_trait_ref_unnormalized(
|
|||||||
self_ty,
|
self_ty,
|
||||||
closure_sig,
|
closure_sig,
|
||||||
util::TupleArgumentsFlag::No,
|
util::TupleArgumentsFlag::No,
|
||||||
|
fn_host_effect,
|
||||||
)
|
)
|
||||||
.map_bound(|(trait_ref, _)| trait_ref)
|
.map_bound(|(trait_ref, _)| trait_ref)
|
||||||
}
|
}
|
||||||
|
@ -264,13 +264,26 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
|
|||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
sig: ty::PolyFnSig<'tcx>,
|
sig: ty::PolyFnSig<'tcx>,
|
||||||
tuple_arguments: TupleArgumentsFlag,
|
tuple_arguments: TupleArgumentsFlag,
|
||||||
|
fn_host_effect: ty::Const<'tcx>,
|
||||||
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
|
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
|
||||||
assert!(!self_ty.has_escaping_bound_vars());
|
assert!(!self_ty.has_escaping_bound_vars());
|
||||||
let arguments_tuple = match tuple_arguments {
|
let arguments_tuple = match tuple_arguments {
|
||||||
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
|
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
|
||||||
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
|
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
|
||||||
};
|
};
|
||||||
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
|
let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() {
|
||||||
|
ty::TraitRef::new(
|
||||||
|
tcx,
|
||||||
|
fn_trait_def_id,
|
||||||
|
[
|
||||||
|
ty::GenericArg::from(self_ty),
|
||||||
|
ty::GenericArg::from(arguments_tuple),
|
||||||
|
ty::GenericArg::from(fn_host_effect),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple])
|
||||||
|
};
|
||||||
sig.map_bound(|sig| (trait_ref, sig.output()))
|
sig.map_bound(|sig| (trait_ref, sig.output()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,15 +16,6 @@ LL | const_eval_select((), || {}, || {});
|
|||||||
= note: expected a function item, found {closure@$DIR/const-eval-select-bad.rs:7:34: 7:36}
|
= note: expected a function item, found {closure@$DIR/const-eval-select-bad.rs:7:34: 7:36}
|
||||||
= help: consult the documentation on `const_eval_select` for more information
|
= help: consult the documentation on `const_eval_select` for more information
|
||||||
|
|
||||||
error: this argument must be a function item
|
|
||||||
--> $DIR/const-eval-select-bad.rs:10:27
|
|
||||||
|
|
|
||||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
|
||||||
| ^^
|
|
||||||
|
|
|
||||||
= note: expected a function item, found {integer}
|
|
||||||
= help: consult the documentation on `const_eval_select` for more information
|
|
||||||
|
|
||||||
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
||||||
--> $DIR/const-eval-select-bad.rs:10:27
|
--> $DIR/const-eval-select-bad.rs:10:27
|
||||||
|
|
|
|
||||||
@ -38,15 +29,6 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
|
|||||||
note: required by a bound in `const_eval_select`
|
note: required by a bound in `const_eval_select`
|
||||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||||
|
|
||||||
error: this argument must be a function item
|
|
||||||
--> $DIR/const-eval-select-bad.rs:10:31
|
|
||||||
|
|
|
||||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
|
||||||
| ^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: expected a function item, found {integer}
|
|
||||||
= help: consult the documentation on `const_eval_select` for more information
|
|
||||||
|
|
||||||
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
||||||
--> $DIR/const-eval-select-bad.rs:10:31
|
--> $DIR/const-eval-select-bad.rs:10:31
|
||||||
|
|
|
|
||||||
@ -60,6 +42,24 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
|
|||||||
note: required by a bound in `const_eval_select`
|
note: required by a bound in `const_eval_select`
|
||||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||||
|
|
||||||
|
error: this argument must be a function item
|
||||||
|
--> $DIR/const-eval-select-bad.rs:10:27
|
||||||
|
|
|
||||||
|
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: expected a function item, found {integer}
|
||||||
|
= help: consult the documentation on `const_eval_select` for more information
|
||||||
|
|
||||||
|
error: this argument must be a function item
|
||||||
|
--> $DIR/const-eval-select-bad.rs:10:31
|
||||||
|
|
|
||||||
|
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: expected a function item, found {integer}
|
||||||
|
= help: consult the documentation on `const_eval_select` for more information
|
||||||
|
|
||||||
error[E0271]: expected `bar` to be a fn item that returns `i32`, but it returns `bool`
|
error[E0271]: expected `bar` to be a fn item that returns `i32`, but it returns `bool`
|
||||||
--> $DIR/const-eval-select-bad.rs:32:34
|
--> $DIR/const-eval-select-bad.rs:32:34
|
||||||
|
|
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
// check-pass
|
// check-pass
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)]
|
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)]
|
||||||
#![feature(fundamental)]
|
#![feature(fundamental)]
|
||||||
#![feature(const_trait_impl, effects, const_mut_refs)]
|
#![feature(const_trait_impl, effects, const_mut_refs)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_core]
|
#![no_core]
|
||||||
|
#![stable(feature = "minicore", since = "1.0.0")]
|
||||||
|
|
||||||
#[lang = "sized"]
|
#[lang = "sized"]
|
||||||
trait Sized {}
|
trait Sized {}
|
||||||
@ -82,6 +83,7 @@ trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
|
|||||||
#[lang = "fn_once"]
|
#[lang = "fn_once"]
|
||||||
#[rustc_paren_sugar]
|
#[rustc_paren_sugar]
|
||||||
trait FnOnce<Args: Tuple> {
|
trait FnOnce<Args: Tuple> {
|
||||||
|
#[lang = "fn_once_output"]
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||||
@ -93,7 +95,7 @@ struct ConstFnMutClosure<CapturedData, Function> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "tuple_trait"]
|
#[lang = "tuple_trait"]
|
||||||
pub trait Tuple {}
|
trait Tuple {}
|
||||||
|
|
||||||
macro_rules! impl_fn_mut_tuple {
|
macro_rules! impl_fn_mut_tuple {
|
||||||
($($var:ident)*) => {
|
($($var:ident)*) => {
|
||||||
@ -509,3 +511,17 @@ trait StructuralPartialEq {}
|
|||||||
trait StructuralEq {}
|
trait StructuralEq {}
|
||||||
|
|
||||||
const fn drop<T: ~const Destruct>(_: T) {}
|
const fn drop<T: ~const Destruct>(_: T) {}
|
||||||
|
|
||||||
|
extern "rust-intrinsic" {
|
||||||
|
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
||||||
|
fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
|
arg: ARG,
|
||||||
|
called_in_const: F,
|
||||||
|
called_at_rt: G,
|
||||||
|
) -> RET
|
||||||
|
/* where clauses enforced by built-in method confirmation:
|
||||||
|
where
|
||||||
|
F: const FnOnce<Arg, Output = RET>,
|
||||||
|
G: FnOnce<Arg, Output = RET>,
|
||||||
|
*/;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user