Skip to content

Commit 9127834

Browse files
committed
const_eval: implies_by in rustc_const_unstable
Extend support for `implies_by` (from `#[stable]` and `#[unstable]`) to `#[rustc_const_stable]` and `#[rustc_const_unstable]`. Signed-off-by: David Wood <david.wood@huawei.com>
1 parent 6eb9f2d commit 9127834

12 files changed

+177
-7
lines changed

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
1+
use rustc_attr as attr;
12
use rustc_hir as hir;
23
use rustc_hir::def::DefKind;
34
use rustc_hir::def_id::{DefId, LocalDefId};
45
use rustc_middle::ty::query::Providers;
56
use rustc_middle::ty::{DefIdTree, TyCtxt};
67
use rustc_span::symbol::Symbol;
78

8-
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
9-
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
9+
/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
10+
/// it.
11+
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
1012
if tcx.is_const_fn_raw(def_id) {
1113
let const_stab = tcx.lookup_const_stability(def_id)?;
12-
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
14+
match const_stab.level {
15+
attr::StabilityLevel::Unstable { implied_by, .. } => {
16+
Some((const_stab.feature, implied_by))
17+
}
18+
attr::StabilityLevel::Stable { .. } => None,
19+
}
1320
} else {
1421
None
1522
}

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -926,15 +926,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
926926

927927
// If the `const fn` we are trying to call is not const-stable, ensure that we have
928928
// the proper feature gate enabled.
929-
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
929+
if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
930930
trace!(?gate, "calling unstable const fn");
931931
if self.span.allows_unstable(gate) {
932932
return;
933933
}
934+
if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
935+
return;
936+
}
934937

935938
// Calling an unstable function *always* requires that the corresponding gate
936-
// be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
937-
if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
939+
// (or implied gate) be enabled, even if the function has
940+
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
941+
let gate_declared = |gate| {
942+
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
943+
};
944+
let feature_gate_declared = gate_declared(gate);
945+
let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
946+
if !feature_gate_declared && !implied_gate_declared {
938947
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
939948
return;
940949
}
@@ -947,7 +956,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
947956
}
948957

949958
// Otherwise, we are something const-stable calling a const-unstable fn.
950-
951959
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
952960
trace!("rustc_allow_const_fn_unstable gate active");
953961
return;

compiler/rustc_passes/src/stability.rs

+9
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
265265
self.index.implications.insert(implied_by, feature);
266266
}
267267

268+
if let Some(ConstStability {
269+
level: Unstable { implied_by: Some(implied_by), .. },
270+
feature,
271+
..
272+
}) = const_stab
273+
{
274+
self.index.implications.insert(implied_by, feature);
275+
}
276+
268277
self.index.stab_map.insert(def_id, stab);
269278
stab
270279
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api)]
3+
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
4+
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
5+
6+
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
7+
#[rustc_const_stable(feature = "const_foo", since = "1.62.0")]
8+
pub const fn foo() {}
9+
10+
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
11+
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_foo")]
12+
pub const fn foobar() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api)]
3+
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
4+
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
5+
6+
// Tests that `implied_by = "const_bar"` results in an error being emitted if `const_bar` does not
7+
// exist.
8+
9+
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
10+
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
11+
//~^ ERROR feature `const_bar` implying `const_foobar` does not exist
12+
pub const fn foobar() -> u32 {
13+
0
14+
}
15+
16+
const VAR: u32 = foobar();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: feature `const_bar` implying `const_foobar` does not exist
2+
--> $DIR/const-stability-attribute-implies-missing.rs:10:1
3+
|
4+
LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// aux-build:const-stability-attribute-implies.rs
2+
#![crate_type = "lib"]
3+
4+
// Tests that despite the `const_foobar` feature being implied by now-stable feature `const_foo`,
5+
// if `const_foobar` isn't allowed in this crate then an error will be emitted.
6+
7+
extern crate const_stability_attribute_implies;
8+
use const_stability_attribute_implies::{foo, foobar};
9+
10+
pub const fn bar() -> u32 {
11+
foo(); // no error - stable
12+
foobar(); //~ ERROR `foobar` is not yet stable as a const fn
13+
0
14+
}
15+
16+
pub const VAR: u32 = bar();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: `foobar` is not yet stable as a const fn
2+
--> $DIR/const-stability-attribute-implies-no-feature.rs:12:5
3+
|
4+
LL | foobar();
5+
| ^^^^^^^^
6+
|
7+
= help: add `#![feature(const_foobar)]` to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// aux-build:const-stability-attribute-implies.rs
2+
#![crate_type = "lib"]
3+
#![deny(stable_features)]
4+
#![feature(const_foo)]
5+
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
6+
7+
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
8+
// diagnostic mentioning partial stabilization, and that given the implied unstable feature is
9+
// unused (there is no `foobar` call), that the compiler suggests removing the flag.
10+
11+
extern crate const_stability_attribute_implies;
12+
use const_stability_attribute_implies::foo;
13+
14+
pub const fn bar() -> u32 {
15+
foo();
16+
0
17+
}
18+
19+
pub const VAR: u32 = bar();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
2+
--> $DIR/const-stability-attribute-implies-using-stable.rs:4:12
3+
|
4+
LL | #![feature(const_foo)]
5+
| ^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/const-stability-attribute-implies-using-stable.rs:3:9
9+
|
10+
LL | #![deny(stable_features)]
11+
| ^^^^^^^^^^^^^^^
12+
help: if you are using features which are still unstable, change to using `const_foobar`
13+
|
14+
LL | #![feature(const_foobar)]
15+
| ~~~~~~~~~~~~
16+
help: if you are using features which are now stable, remove this line
17+
|
18+
LL - #![feature(const_foo)]
19+
|
20+
21+
error: aborting due to previous error
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// aux-build:const-stability-attribute-implies.rs
2+
#![crate_type = "lib"]
3+
#![deny(stable_features)]
4+
#![feature(const_foo)]
5+
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
6+
7+
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
8+
// diagnostic mentioning partial stabilization and that given the implied unstable feature is
9+
// used (there is a `const_foobar` call), that the compiler suggests changing to that feature and
10+
// doesn't error about its use.
11+
12+
extern crate const_stability_attribute_implies;
13+
use const_stability_attribute_implies::{foo, foobar};
14+
15+
pub const fn bar() -> u32 {
16+
foo();
17+
foobar(); // no error!
18+
0
19+
}
20+
21+
pub const VAR: u32 = bar();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
2+
--> $DIR/const-stability-attribute-implies-using-unstable.rs:4:12
3+
|
4+
LL | #![feature(const_foo)]
5+
| ^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/const-stability-attribute-implies-using-unstable.rs:3:9
9+
|
10+
LL | #![deny(stable_features)]
11+
| ^^^^^^^^^^^^^^^
12+
help: if you are using features which are still unstable, change to using `const_foobar`
13+
|
14+
LL | #![feature(const_foobar)]
15+
| ~~~~~~~~~~~~
16+
help: if you are using features which are now stable, remove this line
17+
|
18+
LL - #![feature(const_foo)]
19+
|
20+
21+
error: aborting due to previous error
22+

0 commit comments

Comments
 (0)