Skip to content

Commit 8dacead

Browse files
committed
require const_impl_trait gate for all conditional and trait const calls
1 parent 62bb2ac commit 8dacead

12 files changed

+217
-239
lines changed

compiler/rustc_const_eval/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ const_eval_closure_fndef_not_const =
2525
function defined here, but it is not `const`
2626
const_eval_closure_non_const =
2727
cannot call non-const closure in {const_eval_const_context}s
28+
const_eval_conditionally_const_or_trait_call =
29+
cannot call conditionally-const or trait fn `{$def_path_str}` in {const_eval_const_context}s
30+
2831
const_eval_consider_dereferencing =
2932
consider dereferencing here
3033

compiler/rustc_const_eval/src/check_consts/check.rs

+30-60
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor;
1515
use rustc_middle::mir::*;
1616
use rustc_middle::span_bug;
1717
use rustc_middle::ty::adjustment::PointerCoercion;
18-
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
18+
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
1919
use rustc_mir_dataflow::Analysis;
2020
use rustc_mir_dataflow::impls::MaybeStorageLive;
2121
use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -361,32 +361,20 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
361361
!is_transient
362362
}
363363

364+
/// Returns whether there are const-conditions.
364365
fn revalidate_conditional_constness(
365366
&mut self,
366367
callee: DefId,
367368
callee_args: ty::GenericArgsRef<'tcx>,
368-
call_source: CallSource,
369369
call_span: Span,
370-
) {
370+
) -> bool {
371371
let tcx = self.tcx;
372372
if !tcx.is_conditionally_const(callee) {
373-
return;
373+
return false;
374374
}
375375

376376
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
377-
// If there are any const conditions on this fn and `const_trait_impl`
378-
// is not enabled, simply bail. We shouldn't be able to call conditionally
379-
// const functions on stable.
380-
if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
381-
self.check_op(ops::FnCallNonConst {
382-
callee,
383-
args: callee_args,
384-
span: call_span,
385-
call_source,
386-
feature: Some(sym::const_trait_impl),
387-
});
388-
return;
389-
}
377+
let have_const_conditions = !const_conditions.is_empty();
390378

391379
let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
392380
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
@@ -421,6 +409,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
421409
tcx.dcx()
422410
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
423411
}
412+
413+
have_const_conditions
424414
}
425415
}
426416

@@ -627,11 +617,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
627617
_ => unreachable!(),
628618
};
629619

630-
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
620+
let ConstCx { tcx, body, .. } = *self.ccx;
631621

632622
let fn_ty = func.ty(body, tcx);
633623

634-
let (mut callee, mut fn_args) = match *fn_ty.kind() {
624+
let (callee, fn_args) = match *fn_ty.kind() {
635625
ty::FnDef(def_id, fn_args) => (def_id, fn_args),
636626

637627
ty::FnPtr(..) => {
@@ -645,57 +635,39 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
645635
}
646636
};
647637

648-
self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
638+
let has_const_conditions =
639+
self.revalidate_conditional_constness(callee, fn_args, *fn_span);
649640

650-
let mut is_trait = false;
651641
// Attempting to call a trait method?
652642
if let Some(trait_did) = tcx.trait_of_item(callee) {
653-
trace!("attempting to call a trait method");
643+
// We can't determine the actual callee here, so we have to do different checks
644+
// than usual.
654645

646+
trace!("attempting to call a trait method");
655647
let trait_is_const = tcx.is_const_trait(trait_did);
656-
// trait method calls are only permitted when `effects` is enabled.
657-
// typeck ensures the conditions for calling a const trait method are met,
658-
// so we only error if the trait isn't const. We try to resolve the trait
659-
// into the concrete method, and uses that for const stability checks.
660-
// FIXME(const_trait_impl) we might consider moving const stability checks
661-
// to typeck as well.
662-
if tcx.features().const_trait_impl() && trait_is_const {
663-
// This skips the check below that ensures we only call `const fn`.
664-
is_trait = true;
665-
666-
if let Ok(Some(instance)) =
667-
Instance::try_resolve(tcx, param_env, callee, fn_args)
668-
&& let InstanceKind::Item(def) = instance.def
669-
{
670-
// Resolve a trait method call to its concrete implementation, which may be in a
671-
// `const` trait impl. This is only used for the const stability check below, since
672-
// we want to look at the concrete impl's stability.
673-
fn_args = instance.args;
674-
callee = def;
675-
}
648+
649+
if trait_is_const {
650+
// All trait calls are guarded by this, no matter whether they have
651+
// const-conditions or not.
652+
self.check_op(ops::ConditionallyConstOrTraitCall { callee, args: fn_args });
653+
// FIXME(const_trait_impl): do a more fine-grained check whether this
654+
// particular trait can be const-stably called.
676655
} else {
677-
// if the trait is const but the user has not enabled the feature(s),
678-
// suggest them.
679-
let feature = if trait_is_const {
680-
Some(if tcx.features().const_trait_impl() {
681-
sym::effects
682-
} else {
683-
sym::const_trait_impl
684-
})
685-
} else {
686-
None
687-
};
656+
// Not even a const trait.
688657
self.check_op(ops::FnCallNonConst {
689658
callee,
690659
args: fn_args,
691660
span: *fn_span,
692661
call_source,
693-
feature,
694662
});
695-
// If we allowed this, we're in miri-unleashed mode, so we might
696-
// as well skip the remaining checks.
697-
return;
698663
}
664+
// That's all we can check here.
665+
return;
666+
}
667+
668+
// Even if we know the callee, ensure we can use conditionally-const calls.
669+
if has_const_conditions {
670+
self.check_op(ops::ConditionallyConstOrTraitCall { callee, args: fn_args });
699671
}
700672

701673
// At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -783,14 +755,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
783755
return;
784756
}
785757

786-
// Trait functions are not `const fn` so we have to skip them here.
787-
if !tcx.is_const_fn(callee) && !is_trait {
758+
if !tcx.is_const_fn(callee) {
788759
self.check_op(ops::FnCallNonConst {
789760
callee,
790761
args: fn_args,
791762
span: *fn_span,
792763
call_source,
793-
feature: None,
794764
});
795765
// If we allowed this, we're in miri-unleashed mode, so we might
796766
// as well skip the remaining checks.

compiler/rustc_const_eval/src/check_consts/ops.rs

+28-10
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,48 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
7070
}
7171
}
7272

73+
/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
74+
#[derive(Debug)]
75+
pub(crate) struct ConditionallyConstOrTraitCall<'tcx> {
76+
pub callee: DefId,
77+
pub args: GenericArgsRef<'tcx>,
78+
}
79+
80+
impl<'tcx> NonConstOp<'tcx> for ConditionallyConstOrTraitCall<'tcx> {
81+
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
82+
// We use the `const_trait_impl` for all conditionally-const calls.
83+
Status::Unstable {
84+
gate: sym::const_trait_impl,
85+
safe_to_expose_on_stable: false,
86+
// We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
87+
is_function_call: false,
88+
}
89+
}
90+
91+
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
92+
ccx.dcx().create_err(errors::ConditionallyConstOrTraitCall {
93+
span,
94+
def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
95+
kind: ccx.const_kind(),
96+
})
97+
}
98+
}
99+
73100
/// A function call where the callee is not marked as `const`.
74101
#[derive(Debug, Clone, Copy)]
75102
pub(crate) struct FnCallNonConst<'tcx> {
76103
pub callee: DefId,
77104
pub args: GenericArgsRef<'tcx>,
78105
pub span: Span,
79106
pub call_source: CallSource,
80-
pub feature: Option<Symbol>,
81107
}
82108

83109
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
84110
// FIXME: make this translatable
85111
#[allow(rustc::diagnostic_outside_of_impl)]
86112
#[allow(rustc::untranslatable_diagnostic)]
87113
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
88-
let FnCallNonConst { callee, args, span, call_source, feature } = *self;
114+
let FnCallNonConst { callee, args, span, call_source } = *self;
89115
let ConstCx { tcx, param_env, .. } = *ccx;
90116
let caller = ccx.def_id();
91117

@@ -285,14 +311,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
285311
ccx.const_kind(),
286312
));
287313

288-
if let Some(feature) = feature {
289-
ccx.tcx.disabled_nightly_features(
290-
&mut err,
291-
Some(ccx.tcx.local_def_id_to_hir_id(caller)),
292-
[(String::new(), feature)],
293-
);
294-
}
295-
296314
if let ConstContext::Static(_) = ccx.const_kind() {
297315
err.note(fluent_generated::const_eval_lazy_lock);
298316
}

compiler/rustc_const_eval/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ pub(crate) struct NonConstFmtMacroCall {
176176
pub kind: ConstContext,
177177
}
178178

179+
#[derive(Diagnostic)]
180+
#[diag(const_eval_conditionally_const_or_trait_call)]
181+
pub(crate) struct ConditionallyConstOrTraitCall {
182+
#[primary_span]
183+
pub span: Span,
184+
pub def_path_str: String,
185+
pub kind: ConstContext,
186+
}
187+
179188
#[derive(Diagnostic)]
180189
#[diag(const_eval_non_const_fn_call, code = E0015)]
181190
pub(crate) struct NonConstFnCall {

tests/ui/traits/const-traits/cross-crate.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ const fn const_context() {
1818
#[cfg(any(stocknc, gatednc))]
1919
NonConst.func();
2020
//[stocknc]~^ ERROR: cannot call
21-
//[stocknc]~| ERROR: cannot call
22-
//[gatednc]~^^^ ERROR: the trait bound
21+
//[gatednc]~^^ ERROR: the trait bound
2322
Const.func();
2423
//[stock,stocknc]~^ ERROR: cannot call
25-
//[stock,stocknc]~| ERROR: cannot call
2624
}
2725

2826
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,8 @@
1-
error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
2-
--> $DIR/cross-crate.rs:23:11
1+
error: cannot call conditionally-const or trait fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
2+
--> $DIR/cross-crate.rs:22:5
33
|
44
LL | Const.func();
5-
| ^^^^^^
6-
|
7-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
8-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
9-
|
10-
LL + #![feature(const_trait_impl)]
11-
|
12-
13-
error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
14-
--> $DIR/cross-crate.rs:23:11
15-
|
16-
LL | Const.func();
17-
| ^^^^^^
18-
|
19-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
20-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
21-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
22-
|
23-
LL + #![feature(const_trait_impl)]
24-
|
5+
| ^^^^^^^^^^^^
256

26-
error: aborting due to 2 previous errors
7+
error: aborting due to 1 previous error
278

28-
For more information about this error, try `rustc --explain E0015`.
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,14 @@
1-
error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
2-
--> $DIR/cross-crate.rs:19:14
1+
error: cannot call conditionally-const or trait fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
2+
--> $DIR/cross-crate.rs:19:5
33
|
44
LL | NonConst.func();
5-
| ^^^^^^
6-
|
7-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
8-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
9-
|
10-
LL + #![feature(const_trait_impl)]
11-
|
12-
13-
error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
14-
--> $DIR/cross-crate.rs:19:14
15-
|
16-
LL | NonConst.func();
17-
| ^^^^^^
18-
|
19-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
20-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
21-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
22-
|
23-
LL + #![feature(const_trait_impl)]
24-
|
5+
| ^^^^^^^^^^^^^^^
256

26-
error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
27-
--> $DIR/cross-crate.rs:23:11
7+
error: cannot call conditionally-const or trait fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
8+
--> $DIR/cross-crate.rs:22:5
289
|
2910
LL | Const.func();
30-
| ^^^^^^
31-
|
32-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
33-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
34-
|
35-
LL + #![feature(const_trait_impl)]
36-
|
37-
38-
error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
39-
--> $DIR/cross-crate.rs:23:11
40-
|
41-
LL | Const.func();
42-
| ^^^^^^
43-
|
44-
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
45-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
46-
help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
47-
|
48-
LL + #![feature(const_trait_impl)]
49-
|
11+
| ^^^^^^^^^^^^
5012

51-
error: aborting due to 4 previous errors
13+
error: aborting due to 2 previous errors
5214

53-
For more information about this error, try `rustc --explain E0015`.

tests/ui/traits/const-traits/staged-api-user-crate.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ fn non_const_context() {
1010

1111
const fn stable_const_context() {
1212
Unstable::func();
13-
//~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
14-
//~| ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
13+
//~^ ERROR cannot call conditionally-const or trait fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
1514
}
1615

1716
fn main() {}

0 commit comments

Comments
 (0)