]>
Commit | Line | Data |
---|---|---|
064997fb FG |
1 | //! Detecting lib features (i.e., features that are not lang features). |
2 | //! | |
3 | //! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`), | |
4 | //! but are not declared in one single location (unlike lang features), which means we need to | |
5 | //! collect them instead. | |
b7449926 | 6 | |
9ffffee4 | 7 | use rustc_ast::Attribute; |
f2b60f7d | 8 | use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; |
5099ac24 FG |
9 | use rustc_hir::intravisit::Visitor; |
10 | use rustc_middle::hir::nested_filter; | |
ba9703b0 | 11 | use rustc_middle::middle::lib_features::LibFeatures; |
49aad941 | 12 | use rustc_middle::query::Providers; |
ba9703b0 | 13 | use rustc_middle::ty::TyCtxt; |
dfeec247 XL |
14 | use rustc_span::symbol::Symbol; |
15 | use rustc_span::{sym, Span}; | |
60c5eb7d | 16 | |
2b03887a FG |
17 | use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; |
18 | ||
dfeec247 XL |
19 | fn new_lib_features() -> LibFeatures { |
20 | LibFeatures { stable: Default::default(), unstable: Default::default() } | |
b7449926 XL |
21 | } |
22 | ||
dc9dc135 XL |
23 | pub struct LibFeatureCollector<'tcx> { |
24 | tcx: TyCtxt<'tcx>, | |
b7449926 XL |
25 | lib_features: LibFeatures, |
26 | } | |
27 | ||
a2a8927a | 28 | impl<'tcx> LibFeatureCollector<'tcx> { |
dc9dc135 | 29 | fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> { |
dfeec247 | 30 | LibFeatureCollector { tcx, lib_features: new_lib_features() } |
b7449926 XL |
31 | } |
32 | ||
33 | fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> { | |
f2b60f7d FG |
34 | let stab_attrs = [ |
35 | sym::stable, | |
36 | sym::unstable, | |
37 | sym::rustc_const_stable, | |
38 | sym::rustc_const_unstable, | |
39 | sym::rustc_default_body_unstable, | |
40 | ]; | |
b7449926 | 41 | |
5e7ed085 | 42 | // Find a stability attribute: one of #[stable(…)], #[unstable(…)], |
f2b60f7d | 43 | // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable]. |
94222f64 | 44 | if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { |
9ffffee4 | 45 | if let Some(metas) = attr.meta_item_list() { |
b7449926 XL |
46 | let mut feature = None; |
47 | let mut since = None; | |
48 | for meta in metas { | |
49 | if let Some(mi) = meta.meta_item() { | |
50 | // Find the `feature = ".."` meta-item. | |
48663c56 XL |
51 | match (mi.name_or_empty(), mi.value_str()) { |
52 | (sym::feature, val) => feature = val, | |
53 | (sym::since, val) => since = val, | |
b7449926 XL |
54 | _ => {} |
55 | } | |
56 | } | |
57 | } | |
f2b60f7d FG |
58 | |
59 | if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { | |
60 | since = Some(rust_version_symbol()); | |
61 | } | |
62 | ||
b7449926 XL |
63 | if let Some(feature) = feature { |
64 | // This additional check for stability is to make sure we | |
65 | // don't emit additional, irrelevant errors for malformed | |
66 | // attributes. | |
f2b60f7d FG |
67 | let is_unstable = matches!( |
68 | *stab_attr, | |
69 | sym::unstable | |
70 | | sym::rustc_const_unstable | |
71 | | sym::rustc_default_body_unstable | |
72 | ); | |
5e7ed085 | 73 | if since.is_some() || is_unstable { |
b7449926 XL |
74 | return Some((feature, since, attr.span)); |
75 | } | |
76 | } | |
77 | // We need to iterate over the other attributes, because | |
78 | // `rustc_const_unstable` is not mutually exclusive with | |
79 | // the other stability attributes, so we can't just `break` | |
80 | // here. | |
81 | } | |
82 | } | |
83 | ||
84 | None | |
85 | } | |
86 | ||
87 | fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) { | |
88 | let already_in_stable = self.lib_features.stable.contains_key(&feature); | |
064997fb | 89 | let already_in_unstable = self.lib_features.unstable.contains_key(&feature); |
b7449926 XL |
90 | |
91 | match (since, already_in_stable, already_in_unstable) { | |
92 | (Some(since), _, false) => { | |
064997fb | 93 | if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { |
b7449926 | 94 | if *prev_since != since { |
2b03887a | 95 | self.tcx.sess.emit_err(FeatureStableTwice { |
60c5eb7d | 96 | span, |
2b03887a FG |
97 | feature, |
98 | since, | |
99 | prev_since: *prev_since, | |
100 | }); | |
b7449926 XL |
101 | return; |
102 | } | |
103 | } | |
104 | ||
064997fb | 105 | self.lib_features.stable.insert(feature, (since, span)); |
b7449926 XL |
106 | } |
107 | (None, false, _) => { | |
064997fb | 108 | self.lib_features.unstable.insert(feature, span); |
b7449926 XL |
109 | } |
110 | (Some(_), _, true) | (None, true, _) => { | |
2b03887a FG |
111 | let declared = if since.is_some() { "stable" } else { "unstable" }; |
112 | let prev_declared = if since.is_none() { "stable" } else { "unstable" }; | |
113 | self.tcx.sess.emit_err(FeaturePreviouslyDeclared { | |
60c5eb7d | 114 | span, |
2b03887a FG |
115 | feature, |
116 | declared, | |
117 | prev_declared, | |
118 | }); | |
b7449926 XL |
119 | } |
120 | } | |
121 | } | |
122 | } | |
123 | ||
a2a8927a | 124 | impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { |
5099ac24 | 125 | type NestedFilter = nested_filter::All; |
dfeec247 | 126 | |
5099ac24 FG |
127 | fn nested_visit_map(&mut self) -> Self::Map { |
128 | self.tcx.hir() | |
b7449926 XL |
129 | } |
130 | ||
923072b8 | 131 | fn visit_attribute(&mut self, attr: &'tcx Attribute) { |
b7449926 XL |
132 | if let Some((feature, stable, span)) = self.extract(attr) { |
133 | self.collect_feature(feature, stable, span); | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
a2a8927a | 138 | fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { |
9c376795 FG |
139 | // If `staged_api` is not enabled then we aren't allowed to define lib |
140 | // features; there is no point collecting them. | |
141 | if !tcx.features().staged_api { | |
142 | return new_lib_features(); | |
143 | } | |
144 | ||
b7449926 | 145 | let mut collector = LibFeatureCollector::new(tcx); |
c295e0f8 | 146 | tcx.hir().walk_attributes(&mut collector); |
b7449926 XL |
147 | collector.lib_features |
148 | } | |
dfeec247 | 149 | |
f035d41b | 150 | pub fn provide(providers: &mut Providers) { |
a2a8927a | 151 | providers.lib_features = lib_features; |
dfeec247 | 152 | } |