Rollup merge of #107801 - davidtwco:stability-implies-const, r=Nilstrieb
const_eval: `implies_by` in `rustc_const_unstable` Fixes #107605. Extend support for `implies_by` (from `#[stable]` and `#[unstable]`) to `#[rustc_const_stable]` and `#[rustc_const_unstable]`. cc ``@steffahn``
This commit is contained in:
commit
9c99a4ca2b
12 changed files with 177 additions and 7 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use rustc_attr as attr;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -5,11 +6,17 @@ use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
|
|
||||||
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
|
||||||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
/// it.
|
||||||
|
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
|
||||||
if tcx.is_const_fn_raw(def_id) {
|
if tcx.is_const_fn_raw(def_id) {
|
||||||
let const_stab = tcx.lookup_const_stability(def_id)?;
|
let const_stab = tcx.lookup_const_stability(def_id)?;
|
||||||
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
|
match const_stab.level {
|
||||||
|
attr::StabilityLevel::Unstable { implied_by, .. } => {
|
||||||
|
Some((const_stab.feature, implied_by))
|
||||||
|
}
|
||||||
|
attr::StabilityLevel::Stable { .. } => None,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -926,15 +926,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
|
|
||||||
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
||||||
// the proper feature gate enabled.
|
// the proper feature gate enabled.
|
||||||
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
|
if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
|
||||||
trace!(?gate, "calling unstable const fn");
|
trace!(?gate, "calling unstable const fn");
|
||||||
if self.span.allows_unstable(gate) {
|
if self.span.allows_unstable(gate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Calling an unstable function *always* requires that the corresponding gate
|
// Calling an unstable function *always* requires that the corresponding gate
|
||||||
// be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
|
// (or implied gate) be enabled, even if the function has
|
||||||
if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
|
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
|
||||||
|
let gate_declared = |gate| {
|
||||||
|
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
|
||||||
|
};
|
||||||
|
let feature_gate_declared = gate_declared(gate);
|
||||||
|
let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
|
||||||
|
if !feature_gate_declared && !implied_gate_declared {
|
||||||
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -947,7 +956,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we are something const-stable calling a const-unstable fn.
|
// Otherwise, we are something const-stable calling a const-unstable fn.
|
||||||
|
|
||||||
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
|
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
|
||||||
trace!("rustc_allow_const_fn_unstable gate active");
|
trace!("rustc_allow_const_fn_unstable gate active");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -265,6 +265,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
self.index.implications.insert(implied_by, feature);
|
self.index.implications.insert(implied_by, feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ConstStability {
|
||||||
|
level: Unstable { implied_by: Some(implied_by), .. },
|
||||||
|
feature,
|
||||||
|
..
|
||||||
|
}) = const_stab
|
||||||
|
{
|
||||||
|
self.index.implications.insert(implied_by, feature);
|
||||||
|
}
|
||||||
|
|
||||||
self.index.stab_map.insert(def_id, stab);
|
self.index.stab_map.insert(def_id, stab);
|
||||||
stab
|
stab
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(staged_api)]
|
||||||
|
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
|
||||||
|
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
#[rustc_const_stable(feature = "const_foo", since = "1.62.0")]
|
||||||
|
pub const fn foo() {}
|
||||||
|
|
||||||
|
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_foo")]
|
||||||
|
pub const fn foobar() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(staged_api)]
|
||||||
|
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
|
||||||
|
// Tests that `implied_by = "const_bar"` results in an error being emitted if `const_bar` does not
|
||||||
|
// exist.
|
||||||
|
|
||||||
|
#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
|
||||||
|
//~^ ERROR feature `const_bar` implying `const_foobar` does not exist
|
||||||
|
pub const fn foobar() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
const VAR: u32 = foobar();
|
|
@ -0,0 +1,8 @@
|
||||||
|
error: feature `const_bar` implying `const_foobar` does not exist
|
||||||
|
--> $DIR/const-stability-attribute-implies-missing.rs:10:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// aux-build:const-stability-attribute-implies.rs
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
// Tests that despite the `const_foobar` feature being implied by now-stable feature `const_foo`,
|
||||||
|
// if `const_foobar` isn't allowed in this crate then an error will be emitted.
|
||||||
|
|
||||||
|
extern crate const_stability_attribute_implies;
|
||||||
|
use const_stability_attribute_implies::{foo, foobar};
|
||||||
|
|
||||||
|
pub const fn bar() -> u32 {
|
||||||
|
foo(); // no error - stable
|
||||||
|
foobar(); //~ ERROR `foobar` is not yet stable as a const fn
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const VAR: u32 = bar();
|
|
@ -0,0 +1,10 @@
|
||||||
|
error: `foobar` is not yet stable as a const fn
|
||||||
|
--> $DIR/const-stability-attribute-implies-no-feature.rs:12:5
|
||||||
|
|
|
||||||
|
LL | foobar();
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(const_foobar)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// aux-build:const-stability-attribute-implies.rs
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(stable_features)]
|
||||||
|
#![feature(const_foo)]
|
||||||
|
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
|
||||||
|
|
||||||
|
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
|
||||||
|
// diagnostic mentioning partial stabilization, and that given the implied unstable feature is
|
||||||
|
// unused (there is no `foobar` call), that the compiler suggests removing the flag.
|
||||||
|
|
||||||
|
extern crate const_stability_attribute_implies;
|
||||||
|
use const_stability_attribute_implies::foo;
|
||||||
|
|
||||||
|
pub const fn bar() -> u32 {
|
||||||
|
foo();
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const VAR: u32 = bar();
|
|
@ -0,0 +1,22 @@
|
||||||
|
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
|
||||||
|
--> $DIR/const-stability-attribute-implies-using-stable.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #![feature(const_foo)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/const-stability-attribute-implies-using-stable.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(stable_features)]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
help: if you are using features which are still unstable, change to using `const_foobar`
|
||||||
|
|
|
||||||
|
LL | #![feature(const_foobar)]
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
help: if you are using features which are now stable, remove this line
|
||||||
|
|
|
||||||
|
LL - #![feature(const_foo)]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// aux-build:const-stability-attribute-implies.rs
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(stable_features)]
|
||||||
|
#![feature(const_foo)]
|
||||||
|
//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
|
||||||
|
|
||||||
|
// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
|
||||||
|
// diagnostic mentioning partial stabilization and that given the implied unstable feature is
|
||||||
|
// used (there is a `const_foobar` call), that the compiler suggests changing to that feature and
|
||||||
|
// doesn't error about its use.
|
||||||
|
|
||||||
|
extern crate const_stability_attribute_implies;
|
||||||
|
use const_stability_attribute_implies::{foo, foobar};
|
||||||
|
|
||||||
|
pub const fn bar() -> u32 {
|
||||||
|
foo();
|
||||||
|
foobar(); // no error!
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const VAR: u32 = bar();
|
|
@ -0,0 +1,22 @@
|
||||||
|
error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
|
||||||
|
--> $DIR/const-stability-attribute-implies-using-unstable.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #![feature(const_foo)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/const-stability-attribute-implies-using-unstable.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(stable_features)]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
help: if you are using features which are still unstable, change to using `const_foobar`
|
||||||
|
|
|
||||||
|
LL | #![feature(const_foobar)]
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
help: if you are using features which are now stable, remove this line
|
||||||
|
|
|
||||||
|
LL - #![feature(const_foo)]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue