Skip to content

Commit 996a8e4

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

13 files changed

+251
-390
lines changed

compiler/rustc_const_eval/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ 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+
29+
const_eval_conditionally_const_or_trait_call =
30+
cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
31+
2832
const_eval_consider_dereferencing =
2933
consider dereferencing here
3034

compiler/rustc_const_eval/src/check_consts/check.rs

+31-59
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,31 +361,21 @@ 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;
377+
if const_conditions.is_empty() {
378+
return false;
389379
}
390380

391381
let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
@@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
421411
tcx.dcx()
422412
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
423413
}
414+
415+
true
424416
}
425417
}
426418

@@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
627619
_ => unreachable!(),
628620
};
629621

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

632624
let fn_ty = func.ty(body, tcx);
633625

634-
let (mut callee, mut fn_args) = match *fn_ty.kind() {
626+
let (callee, fn_args) = match *fn_ty.kind() {
635627
ty::FnDef(def_id, fn_args) => (def_id, fn_args),
636628

637629
ty::FnPtr(..) => {
@@ -645,57 +637,39 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
645637
}
646638
};
647639

648-
self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
640+
let has_const_conditions =
641+
self.revalidate_conditional_constness(callee, fn_args, *fn_span);
649642

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

648+
trace!("attempting to call a trait method");
655649
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-
}
650+
651+
if trait_is_const {
652+
// All trait calls are guarded by this, no matter whether they have
653+
// const-conditions or not.
654+
self.check_op(ops::ConditionallyConstOrTraitCall { callee, args: fn_args });
655+
// FIXME(const_trait_impl): do a more fine-grained check whether this
656+
// particular trait can be const-stably called.
676657
} 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-
};
658+
// Not even a const trait.
688659
self.check_op(ops::FnCallNonConst {
689660
callee,
690661
args: fn_args,
691662
span: *fn_span,
692663
call_source,
693-
feature,
694664
});
695-
// If we allowed this, we're in miri-unleashed mode, so we might
696-
// as well skip the remaining checks.
697-
return;
698665
}
666+
// That's all we can check here.
667+
return;
668+
}
669+
670+
// Even if we know the callee, ensure we can use conditionally-const calls.
671+
if has_const_conditions {
672+
self.check_op(ops::ConditionallyConstOrTraitCall { callee, args: fn_args });
699673
}
700674

701675
// At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -783,14 +757,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
783757
return;
784758
}
785759

786-
// Trait functions are not `const fn` so we have to skip them here.
787-
if !tcx.is_const_fn(callee) && !is_trait {
760+
if !tcx.is_const_fn(callee) {
788761
self.check_op(ops::FnCallNonConst {
789762
callee,
790763
args: fn_args,
791764
span: *fn_span,
792765
call_source,
793-
feature: None,
794766
});
795767
// If we allowed this, we're in miri-unleashed mode, so we might
796768
// as well skip the remaining checks.

compiler/rustc_const_eval/src/check_consts/ops.rs

+29-10
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,49 @@ 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` gate 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+
def_descr: ccx.tcx.def_descr(self.callee),
96+
kind: ccx.const_kind(),
97+
})
98+
}
99+
}
100+
73101
/// A function call where the callee is not marked as `const`.
74102
#[derive(Debug, Clone, Copy)]
75103
pub(crate) struct FnCallNonConst<'tcx> {
76104
pub callee: DefId,
77105
pub args: GenericArgsRef<'tcx>,
78106
pub span: Span,
79107
pub call_source: CallSource,
80-
pub feature: Option<Symbol>,
81108
}
82109

83110
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
84111
// FIXME: make this translatable
85112
#[allow(rustc::diagnostic_outside_of_impl)]
86113
#[allow(rustc::untranslatable_diagnostic)]
87114
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
88-
let FnCallNonConst { callee, args, span, call_source, feature } = *self;
115+
let FnCallNonConst { callee, args, span, call_source } = *self;
89116
let ConstCx { tcx, param_env, .. } = *ccx;
90117
let caller = ccx.def_id();
91118

@@ -285,14 +312,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
285312
ccx.const_kind(),
286313
));
287314

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-
296315
if let ConstContext::Static(_) = ccx.const_kind() {
297316
err.note(fluent_generated::const_eval_lazy_lock);
298317
}

compiler/rustc_const_eval/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ 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 def_descr: &'static str,
186+
pub kind: ConstContext,
187+
}
188+
179189
#[derive(Diagnostic)]
180190
#[diag(const_eval_non_const_fn_call, code = E0015)]
181191
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 method `<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 method `<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 method `<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 associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
1514
}
1615

1716
fn main() {}

0 commit comments

Comments
 (0)