Skip to content

Commit 5a19abe

Browse files
committed
Add support for removed library features
1 parent 7ad23f4 commit 5a19abe

File tree

22 files changed

+384
-38
lines changed

22 files changed

+384
-38
lines changed

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 148 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::num::NonZero;
22

33
use rustc_errors::ErrorGuaranteed;
44
use rustc_hir::{
5-
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
6-
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
5+
DefaultBodyStability, MethodKind, PartialConstStability, RemovedFeature, Stability,
6+
StabilityLevel, StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
77
};
88

99
use super::prelude::*;
@@ -471,3 +471,149 @@ pub(crate) fn parse_unstability<S: Stage>(
471471
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
472472
}
473473
}
474+
475+
#[allow(dead_code)]
476+
#[derive(Default)]
477+
pub(crate) struct RemovedFeatureParser {
478+
removed: Option<(RemovedFeature, Span)>,
479+
}
480+
481+
impl<S: Stage> AttributeParser<S> for RemovedFeatureParser {
482+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
483+
&[sym::unstable_removed],
484+
template!(List: &[r#"feature = "name", since = "1.2.3", reason = "...", issue = "N|none""#]),
485+
|this, cx, args| {
486+
// same staged-api restriction as other stability attrs
487+
reject_outside_std!(cx);
488+
489+
let ArgParser::List(list) = args else {
490+
cx.expected_list(cx.attr_span);
491+
return;
492+
};
493+
494+
let mut feature_opt: Option<Symbol> = None;
495+
let mut reason_opt: Option<Symbol> = None;
496+
let mut since_opt: Option<StableSince> = None;
497+
498+
for param in list.mixed() {
499+
let param_span = param.span();
500+
let Some(param) = param.meta_item() else {
501+
cx.emit_err(session_diagnostics::UnsupportedLiteral {
502+
span: param_span,
503+
reason: UnsupportedLiteralReason::Generic,
504+
is_bytestr: false,
505+
start_point_span: cx.sess().source_map().start_point(param_span),
506+
});
507+
return;
508+
};
509+
510+
let word = param.path().word();
511+
match word.map(|i| i.name) {
512+
Some(sym::feature) => {
513+
if insert_value_into_option_or_error(
514+
cx,
515+
&param,
516+
&mut feature_opt,
517+
word.unwrap(),
518+
)
519+
.is_none()
520+
{
521+
return;
522+
}
523+
}
524+
Some(sym::reason) => {
525+
if insert_value_into_option_or_error(
526+
cx,
527+
&param,
528+
&mut reason_opt,
529+
word.unwrap(),
530+
)
531+
.is_none()
532+
{
533+
return;
534+
}
535+
}
536+
Some(sym::since) => {
537+
if insert_value_into_option_or_error(
538+
cx,
539+
&param,
540+
&mut None::<Symbol>,
541+
word.unwrap(),
542+
)
543+
.is_none()
544+
{
545+
return;
546+
}
547+
// parse version string
548+
if let Some(s) = param.args().name_value().and_then(|nv| nv.value_as_str())
549+
{
550+
if s.as_str() == VERSION_PLACEHOLDER {
551+
since_opt = Some(StableSince::Current);
552+
} else if let Some(v) = super::util::parse_version(s) {
553+
since_opt = Some(StableSince::Version(v));
554+
} else {
555+
let err = cx.emit_err(session_diagnostics::InvalidSince {
556+
span: cx.attr_span,
557+
});
558+
since_opt = Some(StableSince::Err(err));
559+
}
560+
} else {
561+
cx.expected_name_value(param.span(), Some(word.unwrap().name));
562+
return;
563+
}
564+
}
565+
_ => {
566+
cx.emit_err(session_diagnostics::UnknownMetaItem {
567+
span: param_span,
568+
item: param.path().to_string(),
569+
expected: &["feature", "reason", "since"],
570+
});
571+
return;
572+
}
573+
}
574+
}
575+
576+
// Validate presence and form of fields:
577+
let feature = match feature_opt {
578+
Some(f) if rustc_lexer::is_ident(f.as_str()) => f,
579+
Some(_) => {
580+
cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span });
581+
return;
582+
}
583+
None => {
584+
cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span });
585+
return;
586+
}
587+
};
588+
589+
let since = match since_opt {
590+
Some(s) => s,
591+
None => {
592+
cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
593+
return;
594+
}
595+
};
596+
597+
let since_symbol = match since {
598+
StableSince::Version(v) => Symbol::intern(&v.to_string()), // dynamic string — ok
599+
StableSince::Current => sym::current,
600+
StableSince::Err(_) => sym::err,
601+
};
602+
603+
let removed = RemovedFeature {
604+
feature,
605+
reason: reason_opt.unwrap_or_else(|| sym::no_reason_given),
606+
since: since_symbol,
607+
span: cx.attr_span,
608+
};
609+
610+
this.removed = Some((removed, cx.attr_span));
611+
},
612+
)];
613+
614+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
615+
616+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
617+
self.removed.map(|(removed_feature, _span)| AttributeKind::RemovedFeature(removed_feature))
618+
}
619+
}

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,14 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
468468
Some(hir::ConstStability { level: hir::StabilityLevel::Stable { .. }, .. }) => {
469469
// All good.
470470
}
471+
Some(hir::ConstStability { level: hir::StabilityLevel::Removed { .. }, .. }) => {
472+
// Treat removed like unstable, or hard-error.
473+
// self.dcx().emit_err(errors::RemovedConstFeature {
474+
// span: self.span,
475+
// def_path: self.tcx.def_path_str(def_id),
476+
// });
477+
return;
478+
}
471479
None => {
472480
// This doesn't need a separate const-stability check -- const-stability equals
473481
// regular stability, and regular stability is checked separately.
@@ -879,6 +887,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
879887
|| (!intrinsic.must_be_overridden
880888
&& is_fn_or_trait_safe_to_expose_on_stable(tcx, callee));
881889
match tcx.lookup_const_stability(callee) {
890+
Some(hir::ConstStability {
891+
level: hir::StabilityLevel::Removed { .. },
892+
..
893+
}) => {
894+
// Treat removed like unstable, or hard-error.
895+
// self.dcx().emit_err(errors::RemovedConstFeature {
896+
// span: self.span,
897+
// def_path: self.tcx.def_path_str(def_id),
898+
// });
899+
return;
900+
}
882901
None => {
883902
// This doesn't need a separate const-stability check -- const-stability equals
884903
// regular stability, and regular stability is checked separately.

compiler/rustc_feature/src/removed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ declare_features! (
305305
// `symbol.rs` when that happens.
306306
(removed, concat_idents, "1.90.0", Some(29599),
307307
Some("use the `${concat(..)}` metavariable expression instead"), 142704),
308+
(removed, unstable_removed, "1.89.0", None, Some("test_reason")),
308309
// -------------------------------------------------------------------------
309310
// feature-group-end: removed library features
310311
// -------------------------------------------------------------------------

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use thin_vec::ThinVec;
1515

1616
use crate::attrs::pretty_printing::PrintAttribute;
1717
use crate::limit::Limit;
18+
use crate::stability::RemovedFeature;
1819
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
1920

2021
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
@@ -621,6 +622,9 @@ pub enum AttributeKind {
621622
/// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
622623
RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit },
623624

625+
/// Represents `#[]`
626+
RemovedFeature(RemovedFeature),
627+
624628
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
625629
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
626630

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl AttributeKind {
7878
ProcMacroDerive { .. } => No,
7979
PubTransparent(..) => Yes,
8080
RecursionLimit { .. } => No,
81+
RemovedFeature(..) => No,
8182
Repr { .. } => No,
8283
RustcBuiltinMacro { .. } => Yes,
8384
RustcLayoutScalarValidRangeEnd(..) => Yes,

compiler/rustc_hir/src/stability.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::num::NonZero;
22

33
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
4-
use rustc_span::{ErrorGuaranteed, Symbol, sym};
4+
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
55

66
use crate::RustcVersion;
77
use crate::attrs::PrintAttribute;
@@ -143,6 +143,10 @@ pub enum StabilityLevel {
143143
/// the `Symbol` is the deprecation message printed in that case.
144144
allowed_through_unstable_modules: Option<Symbol>,
145145
},
146+
Removed {
147+
since: Symbol,
148+
reason: Symbol,
149+
},
146150
}
147151

148152
/// Rust release in which a feature is stabilized.
@@ -168,6 +172,7 @@ impl StabilityLevel {
168172
match *self {
169173
StabilityLevel::Stable { since, .. } => Some(since),
170174
StabilityLevel::Unstable { .. } => None,
175+
StabilityLevel::Removed { .. } => None,
171176
}
172177
}
173178
}
@@ -205,3 +210,13 @@ impl UnstableReason {
205210
}
206211
}
207212
}
213+
214+
/// Represents the `#![unstable_removed]` crate-level attribute.
215+
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
216+
#[derive(HashStable_Generic, PrintAttribute)]
217+
pub struct RemovedFeature {
218+
pub span: Span,
219+
pub feature: Symbol,
220+
pub since: Symbol,
221+
pub reason: Symbol,
222+
}

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxIndexMap;
1212
use rustc_data_structures::owned_slice::OwnedSlice;
1313
use rustc_data_structures::sync::Lock;
1414
use rustc_data_structures::unhash::UnhashMap;
15+
use rustc_data_structures::unord::UnordMap;
1516
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
1617
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
1718
use rustc_hir::Safety;
@@ -1214,6 +1215,9 @@ impl<'a> CrateMetadataRef<'a> {
12141215
/// Iterates over all the stability attributes in the given crate.
12151216
fn get_lib_features(self) -> LibFeatures {
12161217
LibFeatures {
1218+
stable: UnordMap::default(),
1219+
unstable: UnordMap::default(),
1220+
removed: UnordMap::default(),
12171221
stability: self
12181222
.root
12191223
.lib_features
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2+
use rustc_data_structures::unord::UnordMap;
3+
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
4+
use rustc_query_system::ich::StableHashingContext;
5+
use rustc_span::{Span, Symbol};
6+
7+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
8+
pub struct RemovedLibFeatureInfo {
9+
/// Reason (short free-form text).
10+
pub reason: Symbol,
11+
/// `since = "..."` version string.
12+
pub since: Symbol,
13+
/// Span where the `#[unstable_removed]` attribute was declared (crate root).
14+
pub span: Span,
15+
}
16+
17+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18+
#[derive(HashStable, TyEncodable, TyDecodable)]
19+
pub enum FeatureStability {
20+
AcceptedSince(Symbol),
21+
Unstable { old_name: Option<Symbol> },
22+
Removed { since: Symbol, reason: Symbol },
23+
}
24+
25+
#[derive(Clone, Debug, Default)]
26+
pub struct LibFeatures {
27+
/// `#[stable(feature = "...", since = "...")]`
28+
pub stable: UnordMap<Symbol, Span>,
29+
/// `#[unstable(feature = "...", issue = "...")]`
30+
pub unstable: UnordMap<Symbol, Span>,
31+
/// `#![unstable_removed(...)]`
32+
pub removed: UnordMap<Symbol, RemovedLibFeatureInfo>,
33+
/// Internal stability tracking
34+
pub stability: UnordMap<Symbol, (FeatureStability, Span)>,
35+
}
36+
37+
impl LibFeatures {
38+
pub fn to_sorted_vec(&self) -> Vec<(Symbol, FeatureStability)> {
39+
self.stability
40+
.to_sorted_stable_ord()
41+
.iter()
42+
.map(|&(&sym, &(stab, _))| (sym, stab))
43+
.collect()
44+
}
45+
46+
pub fn get_removed(&self, name: &Symbol) -> Option<&RemovedLibFeatureInfo> {
47+
self.removed.get(name)
48+
}
49+
}
50+
51+
impl HashStable<StableHashingContext<'_>> for LibFeatures {
52+
fn hash_stable(&self, hcx: &mut StableHashingContext<'_>, hasher: &mut StableHasher) {
53+
// Hash each UnordMap deterministically
54+
self.stable.to_sorted_stable_ord().hash_stable(hcx, hasher);
55+
self.unstable.to_sorted_stable_ord().hash_stable(hcx, hasher);
56+
self.removed.to_sorted_stable_ord().hash_stable(hcx, hasher);
57+
self.stability.to_sorted_stable_ord().hash_stable(hcx, hasher);
58+
}
59+
}

compiler/rustc_middle/src/middle/mod.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,7 @@ pub mod debugger_visualizer;
33
pub mod dependency_format;
44
pub mod exported_symbols;
55
pub mod lang_items;
6-
pub mod lib_features {
7-
use rustc_data_structures::unord::UnordMap;
8-
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
9-
use rustc_span::{Span, Symbol};
10-
11-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12-
#[derive(HashStable, TyEncodable, TyDecodable)]
13-
pub enum FeatureStability {
14-
AcceptedSince(Symbol),
15-
Unstable { old_name: Option<Symbol> },
16-
}
17-
18-
#[derive(HashStable, Debug, Default)]
19-
pub struct LibFeatures {
20-
pub stability: UnordMap<Symbol, (FeatureStability, Span)>,
21-
}
22-
23-
impl LibFeatures {
24-
pub fn to_sorted_vec(&self) -> Vec<(Symbol, FeatureStability)> {
25-
self.stability
26-
.to_sorted_stable_ord()
27-
.iter()
28-
.map(|&(&sym, &(stab, _))| (sym, stab))
29-
.collect()
30-
}
31-
}
32-
}
6+
pub mod lib_features;
337
pub mod privacy;
348
pub mod region;
359
pub mod resolve_bound_vars;

0 commit comments

Comments
 (0)