Skip to content

Commit b55453d

Browse files
committed
add opt in attribute for stable-in-unstable items
1 parent a13f300 commit b55453d

File tree

15 files changed

+119
-6
lines changed

15 files changed

+119
-6
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl ConstStability {
137137
pub enum StabilityLevel {
138138
// Reason for the current stability level and the relevant rust-lang issue
139139
Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
140-
Stable { since: Symbol },
140+
Stable { since: Symbol, allowed_through_unstable_modules: bool },
141141
}
142142

143143
impl StabilityLevel {
@@ -172,6 +172,7 @@ where
172172
let mut stab: Option<(Stability, Span)> = None;
173173
let mut const_stab: Option<(ConstStability, Span)> = None;
174174
let mut promotable = false;
175+
let mut allowed_through_unstable_modules = false;
175176

176177
let diagnostic = &sess.parse_sess.span_diagnostic;
177178

@@ -182,6 +183,7 @@ where
182183
sym::unstable,
183184
sym::stable,
184185
sym::rustc_promotable,
186+
sym::rustc_allowed_through_unstable_modules,
185187
]
186188
.iter()
187189
.any(|&s| attr.has_name(s))
@@ -193,6 +195,8 @@ where
193195

194196
if attr.has_name(sym::rustc_promotable) {
195197
promotable = true;
198+
} else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
199+
allowed_through_unstable_modules = true;
196200
}
197201
// attributes with data
198202
else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
@@ -406,7 +410,7 @@ where
406410

407411
match (feature, since) {
408412
(Some(feature), Some(since)) => {
409-
let level = Stable { since };
413+
let level = Stable { since, allowed_through_unstable_modules: false };
410414
if sym::stable == meta_name {
411415
stab = Some((Stability { level, feature }, attr.span));
412416
} else {
@@ -447,6 +451,27 @@ where
447451
}
448452
}
449453

454+
if allowed_through_unstable_modules {
455+
if let Some((
456+
Stability {
457+
level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
458+
..
459+
},
460+
_,
461+
)) = stab
462+
{
463+
*allowed_through_unstable_modules = true;
464+
} else {
465+
struct_span_err!(
466+
diagnostic,
467+
item_sp,
468+
E0788,
469+
"`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute"
470+
)
471+
.emit();
472+
}
473+
}
474+
450475
(stab, const_stab)
451476
}
452477

compiler/rustc_error_codes/src/error_codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,4 +644,5 @@ E0788: include_str!("./error_codes/E0788.md"),
644644
// E0721, // `await` keyword
645645
// E0723, // unstable feature in `const` context
646646
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
647+
E0788, // rustc_allowed_through_unstable_modules without stability attribute
647648
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
512512
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
513513
"allow_internal_unsafe side-steps the unsafe_code lint",
514514
),
515+
rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
516+
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
517+
through unstable paths"),
515518

516519
// ==========================================================================
517520
// Internal attributes: Type system related:

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ impl CheckAttrVisitor<'_> {
139139
| sym::rustc_const_stable
140140
| sym::unstable
141141
| sym::stable
142+
| sym::rustc_allowed_through_unstable_modules
142143
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
143144
_ => true,
144145
};

compiler/rustc_passes/src/stability.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! A pass that annotates every item and method with its stability level,
22
//! propagating default levels lexically from parent to children ast nodes.
33
4+
use attr::StabilityLevel;
45
use rustc_attr::{self as attr, ConstStability, Stability};
56
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
67
use rustc_errors::struct_span_err;
@@ -224,7 +225,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
224225

225226
// Check if deprecated_since < stable_since. If it is,
226227
// this is *almost surely* an accident.
227-
if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
228+
if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
228229
(&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
229230
{
230231
// Explicit version of iter::order::lt to handle parse errors properly
@@ -819,14 +820,30 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
819820
},
820821
);
821822

822-
if item_is_allowed {
823+
let is_allowed_through_unstable_modules = |def_id| {
824+
self.tcx
825+
.lookup_stability(def_id)
826+
.map(|stab| match stab.level {
827+
StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
828+
allowed_through_unstable_modules
829+
}
830+
_ => false,
831+
})
832+
.unwrap_or(false)
833+
};
834+
835+
if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
823836
// Check parent modules stability as well if the item the path refers to is itself
824837
// stable. We only emit warnings for unstable path segments if the item is stable
825838
// or allowed because stability is often inherited, so the most common case is that
826839
// both the segments and the item are unstable behind the same feature flag.
827840
//
828841
// We check here rather than in `visit_path_segment` to prevent visiting the last
829842
// path segment twice
843+
//
844+
// We include special cases via #[rustc_allowed_through_unstable_modules] for items
845+
// that were accidentally stabilized through unstable paths before this check was
846+
// added, such as `core::intrinsics::transmute`
830847
let parents = path.segments.iter().rev().skip(1);
831848
for path_segment in parents {
832849
if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,7 @@ symbols! {
11911191
rustc_allocator_nounwind,
11921192
rustc_allow_const_fn_unstable,
11931193
rustc_allow_incoherent_impl,
1194+
rustc_allowed_through_unstable_modules,
11941195
rustc_attrs,
11951196
rustc_box,
11961197
rustc_builtin_macro,

library/core/src/intrinsics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,7 @@ extern "rust-intrinsic" {
14571457
/// }
14581458
/// ```
14591459
#[stable(feature = "rust1", since = "1.0.0")]
1460+
#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
14601461
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
14611462
#[rustc_diagnostic_item = "transmute"]
14621463
pub fn transmute<T, U>(e: T) -> U;

src/librustdoc/html/render/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ fn render_stability_since_raw(
854854
}
855855

856856
let const_title_and_stability = match const_stability {
857-
Some(ConstStability { level: StabilityLevel::Stable { since }, .. })
857+
Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
858858
if Some(since) != containing_const_ver =>
859859
{
860860
Some((format!("const since {}", since), format!("const: {}", since)))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![crate_type = "lib"]
2+
extern crate core;
3+
4+
// Known accidental stabilizations with no known users, slated for un-stabilization
5+
// fully stable @ core::char::UNICODE_VERSION
6+
use core::unicode::UNICODE_VERSION; //~ ERROR use of unstable library feature 'unicode_internals'
7+
8+
// Known accidental stabilizations with known users
9+
// fully stable @ core::mem::transmute
10+
use core::intrinsics::transmute; // depended upon by rand_core
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: use of unstable library feature 'unicode_internals'
2+
--> $DIR/accidental-stable-in-unstable.rs:6:5
3+
|
4+
LL | use core::unicode::UNICODE_VERSION;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add `#![feature(unicode_internals)]` to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api)]
3+
#![feature(rustc_attrs)]
4+
#![stable(feature = "foo", since = "1.0.0")]
5+
6+
#[unstable(feature = "bar", issue = "none")]
7+
#[rustc_allowed_through_unstable_modules]
8+
pub struct UnstableType(());
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Test for new `#[rustc_allowed_through_unstable_modules]` attribute
2+
//
3+
// aux-build:allowed-through-unstable-core.rs
4+
#![crate_type = "lib"]
5+
6+
extern crate allowed_through_unstable_core;
7+
8+
use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable;
9+
use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature 'unstable_test_feature'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: use of unstable library feature 'unstable_test_feature'
2+
--> $DIR/allowed-through-unstable.rs:10:5
3+
|
4+
LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
8+
= help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api)]
3+
#![feature(rustc_attrs)]
4+
#![stable(feature = "stable_test_feature", since = "1.2.0")]
5+
6+
#[unstable(feature = "unstable_test_feature", issue = "1")]
7+
pub mod unstable_module {
8+
#[stable(feature = "stable_test_feature", since = "1.2.0")]
9+
#[rustc_allowed_through_unstable_modules]
10+
pub trait OldStableTraitAllowedThoughUnstable {}
11+
12+
#[stable(feature = "stable_test_feature", since = "1.2.0")]
13+
pub trait NewStableTraitNotAllowedThroughUnstable {}
14+
}

src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ fn check_terminator<'a, 'tcx>(
353353
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
354354
tcx.is_const_fn(def_id)
355355
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
356-
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
356+
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
357357
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
358358
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
359359
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.

0 commit comments

Comments
 (0)