rustc_passes/
lib_features.rs
1use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince};
8use rustc_hir::Attribute;
9use rustc_hir::intravisit::Visitor;
10use rustc_middle::hir::nested_filter;
11use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
12use rustc_middle::query::{LocalCrate, Providers};
13use rustc_middle::ty::TyCtxt;
14use rustc_span::{Span, Symbol, sym};
15
16use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
17
18struct LibFeatureCollector<'tcx> {
19 tcx: TyCtxt<'tcx>,
20 lib_features: LibFeatures,
21}
22
23impl<'tcx> LibFeatureCollector<'tcx> {
24 fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> {
25 LibFeatureCollector { tcx, lib_features: LibFeatures::default() }
26 }
27
28 fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> {
29 let (feature, level, span) = match attr {
30 Attribute::Parsed(AttributeKind::Stability { stability, span }) => {
31 (stability.feature, stability.level, *span)
32 }
33 Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => {
34 (stability.feature, stability.level, *span)
35 }
36 Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => {
37 (stability.feature, stability.level, *span)
38 }
39 _ => return None,
40 };
41
42 let feature_stability = match level {
43 StabilityLevel::Unstable { .. } => FeatureStability::Unstable,
44 StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
45 StableSince::Version(v) => Symbol::intern(&v.to_string()),
46 StableSince::Current => sym::env_CFG_RELEASE,
47 StableSince::Err => return None,
48 }),
49 };
50
51 Some((feature, feature_stability, span))
52 }
53
54 fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) {
55 let existing_stability = self.lib_features.stability.get(&feature).cloned();
56
57 match (stability, existing_stability) {
58 (_, None) => {
59 self.lib_features.stability.insert(feature, (stability, span));
60 }
61 (
62 FeatureStability::AcceptedSince(since),
63 Some((FeatureStability::AcceptedSince(prev_since), _)),
64 ) => {
65 if prev_since != since {
66 self.tcx.dcx().emit_err(FeatureStableTwice {
67 span,
68 feature,
69 since,
70 prev_since,
71 });
72 }
73 }
74 (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => {
75 self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
76 span,
77 feature,
78 declared: "stable",
79 prev_declared: "unstable",
80 });
81 }
82 (FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => {
83 self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
84 span,
85 feature,
86 declared: "unstable",
87 prev_declared: "stable",
88 });
89 }
90 (FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {}
92 }
93 }
94}
95
96impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
97 type NestedFilter = nested_filter::All;
98
99 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
100 self.tcx
101 }
102
103 fn visit_attribute(&mut self, attr: &'tcx Attribute) {
104 if let Some((feature, stable, span)) = self.extract(attr) {
105 self.collect_feature(feature, stable, span);
106 }
107 }
108}
109
110fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
111 if !tcx.features().staged_api() {
114 return LibFeatures::default();
115 }
116
117 let mut collector = LibFeatureCollector::new(tcx);
118 tcx.hir_walk_attributes(&mut collector);
119 collector.lib_features
120}
121
122pub(crate) fn provide(providers: &mut Providers) {
123 providers.lib_features = lib_features;
124}