mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
add opt in attribute for stable-in-unstable items
This commit is contained in:
parent
a13f30036a
commit
b55453dbad
@ -137,7 +137,7 @@ impl ConstStability {
|
||||
pub enum StabilityLevel {
|
||||
// Reason for the current stability level and the relevant rust-lang issue
|
||||
Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
|
||||
Stable { since: Symbol },
|
||||
Stable { since: Symbol, allowed_through_unstable_modules: bool },
|
||||
}
|
||||
|
||||
impl StabilityLevel {
|
||||
@ -172,6 +172,7 @@ where
|
||||
let mut stab: Option<(Stability, Span)> = None;
|
||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||
let mut promotable = false;
|
||||
let mut allowed_through_unstable_modules = false;
|
||||
|
||||
let diagnostic = &sess.parse_sess.span_diagnostic;
|
||||
|
||||
@ -182,6 +183,7 @@ where
|
||||
sym::unstable,
|
||||
sym::stable,
|
||||
sym::rustc_promotable,
|
||||
sym::rustc_allowed_through_unstable_modules,
|
||||
]
|
||||
.iter()
|
||||
.any(|&s| attr.has_name(s))
|
||||
@ -193,6 +195,8 @@ where
|
||||
|
||||
if attr.has_name(sym::rustc_promotable) {
|
||||
promotable = true;
|
||||
} else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
|
||||
allowed_through_unstable_modules = true;
|
||||
}
|
||||
// attributes with data
|
||||
else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
|
||||
@ -406,7 +410,7 @@ where
|
||||
|
||||
match (feature, since) {
|
||||
(Some(feature), Some(since)) => {
|
||||
let level = Stable { since };
|
||||
let level = Stable { since, allowed_through_unstable_modules: false };
|
||||
if sym::stable == meta_name {
|
||||
stab = Some((Stability { level, feature }, attr.span));
|
||||
} else {
|
||||
@ -447,6 +451,27 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if allowed_through_unstable_modules {
|
||||
if let Some((
|
||||
Stability {
|
||||
level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
|
||||
..
|
||||
},
|
||||
_,
|
||||
)) = stab
|
||||
{
|
||||
*allowed_through_unstable_modules = true;
|
||||
} else {
|
||||
struct_span_err!(
|
||||
diagnostic,
|
||||
item_sp,
|
||||
E0788,
|
||||
"`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
(stab, const_stab)
|
||||
}
|
||||
|
||||
|
@ -644,4 +644,5 @@ E0788: include_str!("./error_codes/E0788.md"),
|
||||
// E0721, // `await` keyword
|
||||
// E0723, // unstable feature in `const` context
|
||||
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
|
||||
E0788, // rustc_allowed_through_unstable_modules without stability attribute
|
||||
}
|
||||
|
@ -512,6 +512,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
|
||||
"allow_internal_unsafe side-steps the unsafe_code lint",
|
||||
),
|
||||
rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
|
||||
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
|
||||
through unstable paths"),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Type system related:
|
||||
|
@ -139,6 +139,7 @@ impl CheckAttrVisitor<'_> {
|
||||
| sym::rustc_const_stable
|
||||
| sym::unstable
|
||||
| sym::stable
|
||||
| sym::rustc_allowed_through_unstable_modules
|
||||
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
|
||||
_ => true,
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! A pass that annotates every item and method with its stability level,
|
||||
//! propagating default levels lexically from parent to children ast nodes.
|
||||
|
||||
use attr::StabilityLevel;
|
||||
use rustc_attr::{self as attr, ConstStability, Stability};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::struct_span_err;
|
||||
@ -224,7 +225,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
|
||||
// Check if deprecated_since < stable_since. If it is,
|
||||
// this is *almost surely* an accident.
|
||||
if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
|
||||
if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
|
||||
(&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
|
||||
{
|
||||
// Explicit version of iter::order::lt to handle parse errors properly
|
||||
@ -819,7 +820,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
},
|
||||
);
|
||||
|
||||
if item_is_allowed {
|
||||
let is_allowed_through_unstable_modules = |def_id| {
|
||||
self.tcx
|
||||
.lookup_stability(def_id)
|
||||
.map(|stab| match stab.level {
|
||||
StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
|
||||
allowed_through_unstable_modules
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
|
||||
// Check parent modules stability as well if the item the path refers to is itself
|
||||
// stable. We only emit warnings for unstable path segments if the item is stable
|
||||
// or allowed because stability is often inherited, so the most common case is that
|
||||
@ -827,6 +840,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
//
|
||||
// We check here rather than in `visit_path_segment` to prevent visiting the last
|
||||
// path segment twice
|
||||
//
|
||||
// We include special cases via #[rustc_allowed_through_unstable_modules] for items
|
||||
// that were accidentally stabilized through unstable paths before this check was
|
||||
// added, such as `core::intrinsics::transmute`
|
||||
let parents = path.segments.iter().rev().skip(1);
|
||||
for path_segment in parents {
|
||||
if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) {
|
||||
|
@ -1191,6 +1191,7 @@ symbols! {
|
||||
rustc_allocator_nounwind,
|
||||
rustc_allow_const_fn_unstable,
|
||||
rustc_allow_incoherent_impl,
|
||||
rustc_allowed_through_unstable_modules,
|
||||
rustc_attrs,
|
||||
rustc_box,
|
||||
rustc_builtin_macro,
|
||||
|
@ -1457,6 +1457,7 @@ extern "rust-intrinsic" {
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
|
||||
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
|
||||
#[rustc_diagnostic_item = "transmute"]
|
||||
pub fn transmute<T, U>(e: T) -> U;
|
||||
|
@ -854,7 +854,7 @@ fn render_stability_since_raw(
|
||||
}
|
||||
|
||||
let const_title_and_stability = match const_stability {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { since }, .. })
|
||||
Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
|
||||
if Some(since) != containing_const_ver =>
|
||||
{
|
||||
Some((format!("const since {}", since), format!("const: {}", since)))
|
||||
|
@ -0,0 +1,10 @@
|
||||
#![crate_type = "lib"]
|
||||
extern crate core;
|
||||
|
||||
// Known accidental stabilizations with no known users, slated for un-stabilization
|
||||
// fully stable @ core::char::UNICODE_VERSION
|
||||
use core::unicode::UNICODE_VERSION; //~ ERROR use of unstable library feature 'unicode_internals'
|
||||
|
||||
// Known accidental stabilizations with known users
|
||||
// fully stable @ core::mem::transmute
|
||||
use core::intrinsics::transmute; // depended upon by rand_core
|
@ -0,0 +1,11 @@
|
||||
error[E0658]: use of unstable library feature 'unicode_internals'
|
||||
--> $DIR/accidental-stable-in-unstable.rs:6:5
|
||||
|
|
||||
LL | use core::unicode::UNICODE_VERSION;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(unicode_internals)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,8 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(staged_api)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![stable(feature = "foo", since = "1.0.0")]
|
||||
|
||||
#[unstable(feature = "bar", issue = "none")]
|
||||
#[rustc_allowed_through_unstable_modules]
|
||||
pub struct UnstableType(());
|
@ -0,0 +1,9 @@
|
||||
// Test for new `#[rustc_allowed_through_unstable_modules]` attribute
|
||||
//
|
||||
// aux-build:allowed-through-unstable-core.rs
|
||||
#![crate_type = "lib"]
|
||||
|
||||
extern crate allowed_through_unstable_core;
|
||||
|
||||
use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable;
|
||||
use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature 'unstable_test_feature'
|
@ -0,0 +1,12 @@
|
||||
error[E0658]: use of unstable library feature 'unstable_test_feature'
|
||||
--> $DIR/allowed-through-unstable.rs:10:5
|
||||
|
|
||||
LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||
= help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,14 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(staged_api)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![stable(feature = "stable_test_feature", since = "1.2.0")]
|
||||
|
||||
#[unstable(feature = "unstable_test_feature", issue = "1")]
|
||||
pub mod unstable_module {
|
||||
#[stable(feature = "stable_test_feature", since = "1.2.0")]
|
||||
#[rustc_allowed_through_unstable_modules]
|
||||
pub trait OldStableTraitAllowedThoughUnstable {}
|
||||
|
||||
#[stable(feature = "stable_test_feature", since = "1.2.0")]
|
||||
pub trait NewStableTraitNotAllowedThroughUnstable {}
|
||||
}
|
@ -353,7 +353,7 @@ fn check_terminator<'a, 'tcx>(
|
||||
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
|
||||
tcx.is_const_fn(def_id)
|
||||
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
|
||||
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
|
||||
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
|
||||
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
|
||||
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
|
||||
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
|
||||
|
Loading…
Reference in New Issue
Block a user