Skip to content

Commit 9760983

Browse files
committed
check_consts: fix error requesting feature gate when that gate is not actually needed
1 parent 44f233f commit 9760983

3 files changed

Lines changed: 37 additions & 13 deletions

File tree

‎compiler/rustc_const_eval/src/check_consts/check.rs‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,18 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
272272
/// context.
273273
pubfncheck_op_spanned<O:NonConstOp<'tcx>>(&mutself,op:O,span:Span){
274274
let gate = match op.status_in_item(self.ccx){
275-
Status::Unstable{ gate, safe_to_expose_on_stable, is_function_call }
276-
ifself.tcx.features().enabled(gate) =>
277-
{
275+
Status::Unstable{
276+
gate,
277+
safe_to_expose_on_stable,
278+
is_function_call,
279+
gate_already_checked,
280+
}if gate_already_checked || self.tcx.features().enabled(gate) => {
281+
if gate_already_checked {
282+
assert!(
283+
!safe_to_expose_on_stable,
284+
"setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense"
285+
);
286+
}
278287
// Generally this is allowed since the feature gate is enabled -- except
279288
// if this function wants to be safe-to-expose-on-stable.
280289
if !safe_to_expose_on_stable
@@ -745,7 +754,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
745754
self.check_op(ops::IntrinsicUnstable{
746755
name: intrinsic.name,
747756
feature,
748-
const_stable: is_const_stable,
757+
const_stable_indirect: is_const_stable,
749758
});
750759
}
751760
Some(ConstStability{level:StabilityLevel::Stable{ .. }, .. }) => {
@@ -800,6 +809,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
800809

801810
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
802811
// the callee is safe to expose, to avoid bypassing recursive stability.
812+
// This is not ideal since it means the user sees an error, not the macro
813+
// author, but that's also the case if one forgets to set
814+
// `#[allow_internal_unstable]` in the first place. Note that this cannot be
815+
// integrated in the check below since we want to enforce
816+
// `callee_safe_to_expose_on_stable` even if
817+
// `!self.enforce_recursive_const_stability()`.
803818
if(self.span.allows_unstable(feature)
804819
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
805820
&& callee_safe_to_expose_on_stable
@@ -830,15 +845,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
830845
&& issue == NonZero::new(27812)
831846
&& self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
832847
};
833-
// We do *not* honor this if we are in the "danger zone": we have to enforce
834-
// recursive const-stability and the callee is not safe-to-expose. In that
835-
// case we need `check_op` to do the check.
836-
let danger_zone = !callee_safe_to_expose_on_stable
837-
&& self.enforce_recursive_const_stability();
838-
if danger_zone || !feature_enabled {
848+
// Even if the feature is enabled, we still need check_op to double-check
849+
// this if the callee is not safe to expose on stable.
850+
if !feature_enabled || !callee_safe_to_expose_on_stable {
839851
self.check_op(ops::FnCallUnstable{
840852
def_id: callee,
841853
feature,
854+
feature_enabled,
842855
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
843856
});
844857
}

‎compiler/rustc_const_eval/src/check_consts/ops.rs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub enum Status {
2828
Unstable{
2929
/// The feature that must be enabled to use this operation.
3030
gate:Symbol,
31+
/// Whether the feature gate was already checked (because the logic is a bit more
32+
/// complicated than just checking a single gate).
33+
gate_already_checked:bool,
3134
/// Whether it is allowed to use this operation from stable `const fn`.
3235
/// This will usually be `false`.
3336
safe_to_expose_on_stable:bool,
@@ -82,6 +85,7 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
8285
// We use the `const_trait_impl` gate for all conditionally-const calls.
8386
Status::Unstable{
8487
gate: sym::const_trait_impl,
88+
gate_already_checked:false,
8589
safe_to_expose_on_stable:false,
8690
// We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
8791
is_function_call:false,
@@ -330,19 +334,24 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
330334
pub(crate)structFnCallUnstable{
331335
pubdef_id:DefId,
332336
pubfeature:Symbol,
337+
/// If this is true, then the feature is enabled, but we need to still check if it is safe to
338+
/// expose on stable.
339+
pubfeature_enabled:bool,
333340
pubsafe_to_expose_on_stable:bool,
334341
}
335342

336343
impl<'tcx>NonConstOp<'tcx>forFnCallUnstable{
337344
fnstatus_in_item(&self,_ccx:&ConstCx<'_,'tcx>) -> Status{
338345
Status::Unstable{
339346
gate:self.feature,
347+
gate_already_checked:self.feature_enabled,
340348
safe_to_expose_on_stable:self.safe_to_expose_on_stable,
341349
is_function_call:true,
342350
}
343351
}
344352

345353
fnbuild_error(&self,ccx:&ConstCx<'_,'tcx>,span:Span) -> Diag<'tcx>{
354+
assert!(!self.feature_enabled);
346355
letmut err = ccx.dcx().create_err(errors::UnstableConstFn{
347356
span,
348357
def_path: ccx.tcx.def_path_str(self.def_id),
@@ -376,14 +385,15 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
376385
pub(crate)structIntrinsicUnstable{
377386
pubname:Symbol,
378387
pubfeature:Symbol,
379-
pubconst_stable:bool,
388+
pubconst_stable_indirect:bool,
380389
}
381390

382391
impl<'tcx>NonConstOp<'tcx>forIntrinsicUnstable{
383392
fnstatus_in_item(&self,_ccx:&ConstCx<'_,'tcx>) -> Status{
384393
Status::Unstable{
385394
gate:self.feature,
386-
safe_to_expose_on_stable:self.const_stable,
395+
gate_already_checked:false,
396+
safe_to_expose_on_stable:self.const_stable_indirect,
387397
// We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
388398
// that's not a trivial change!
389399
is_function_call:false,
@@ -410,6 +420,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
410420
{
411421
Status::Unstable{
412422
gate: sym::const_async_blocks,
423+
gate_already_checked:false,
413424
safe_to_expose_on_stable:false,
414425
is_function_call:false,
415426
}

‎tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ compile-flags: -Zforce-unstable-if-unmarked
22
//@ edition: 2021
3-
#![feature(const_async_blocks, rustc_attrs, rustc_private)]
3+
#![feature(const_async_blocks, rustc_attrs)]
44

55
pubconstfnnot_stably_const(){
66
// We need to do something const-unstable here.

0 commit comments

Comments
 (0)