Skip to content

Commit b229be0

Browse files
committed
Overhaul config::features.
The new way of doing things: - Avoids some code duplication. - Distinguishes the `crate_edition` (which comes from `--edition`) and the `features_edition` (which combines `--edition` along with any `rustc_20XX_preview` features), which is useful. - Has a simpler initial loop, one that just looks for `rustc_20XX_preview` features in order to compute `features_edition`. - Creates a fallible alternative to `Features::enabled`, which is useful. It's not easy to see how exactly the old and new code are equivalent, but it's reassuring to know that the test coverage is quite good for this stuff.
1 parent 8ba9137 commit b229be0

File tree

1 file changed

+46
-57
lines changed

1 file changed

+46
-57
lines changed

compiler/rustc_expand/src/config.rs

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast::NodeId;
1313
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
1414
use rustc_attr as attr;
1515
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
16-
use rustc_data_structures::fx::FxHashMap;
16+
use rustc_data_structures::fx::FxHashSet;
1717
use rustc_feature::{Feature, Features, State as FeatureState};
1818
use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES};
1919
use rustc_parse::validate_attr;
@@ -55,55 +55,37 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
5555
}
5656

5757
let mut features = Features::default();
58-
let mut edition_enabled_features = FxHashMap::default();
59-
let crate_edition = sess.edition();
60-
61-
// Enable edition umbrella feature-gates based on the crate edition.
62-
// - enable `rust_2015_preview` always
63-
// - enable `rust_2018_preview` if the crate edition is 2018 or higher
64-
// - enable `rust_2021_preview` if the crate edition is 2021 or higher
65-
// - etc.
66-
for &edition in ALL_EDITIONS {
67-
if edition <= crate_edition {
68-
edition_enabled_features.insert(edition.feature_name(), edition);
69-
}
70-
}
7158

72-
// Enable edition-dependent features based on the crate edition.
73-
// - E.g. `test_2018_feature` if the crate edition is 2018 or higher
74-
for feature in active_features_up_to(crate_edition) {
75-
feature.set(&mut features);
76-
edition_enabled_features.insert(feature.name, crate_edition);
77-
}
59+
// The edition from `--edition`.
60+
let crate_edition = sess.edition();
7861

79-
// Enable edition umbrella feature-gates that are declared in the code. If
80-
// present, enable edition-specific features based on that.
81-
// - E.g. enable `test_2018_feature` if the crate edition is 2015 but
82-
// `rust_2018_preview` is present
62+
// The maximum of (a) the edition from `--edition` and (b) any edition
63+
// umbrella feature-gates declared in the code.
64+
// - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
65+
// `feature_edition` is 2018
66+
let mut features_edition = crate_edition;
8367
for attr in krate_attrs {
8468
for mi in feature_list(attr) {
85-
if !mi.is_word() {
86-
continue;
87-
}
88-
89-
let name = mi.name_or_empty();
90-
91-
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
92-
if let Some(edition) = edition {
93-
if edition <= crate_edition {
94-
continue;
95-
}
96-
97-
for feature in active_features_up_to(edition) {
98-
// FIXME(Manishearth) there is currently no way to set
99-
// lib features by edition
100-
feature.set(&mut features);
101-
edition_enabled_features.insert(feature.name, edition);
69+
if mi.is_word() {
70+
let name = mi.name_or_empty();
71+
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
72+
if let Some(edition) = edition && edition > features_edition {
73+
features_edition = edition;
10274
}
10375
}
10476
}
10577
}
10678

79+
// Enable edition-dependent features based on `features_edition`.
80+
// - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
81+
let mut edition_enabled_features = FxHashSet::default();
82+
for feature in active_features_up_to(features_edition) {
83+
// FIXME(Manishearth) there is currently no way to set lib features by
84+
// edition.
85+
edition_enabled_features.insert(feature.name);
86+
feature.set(&mut features);
87+
}
88+
10789
// Process all features declared in the code.
10890
for attr in krate_attrs {
10991
for mi in feature_list(attr) {
@@ -128,30 +110,37 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
128110
}
129111
};
130112

131-
// If the declared feature is edition-specific and already enabled
132-
// due to the crate edition or a declared edition umbrella
133-
// feature-gate, give a warning.
134-
// - E.g. warn if `test_2018_feature` is declared when the crate
135-
// edition is 2018 or higher
113+
// If the declared feature is an edition umbrella feature-gate,
114+
// warn if it was redundant w.r.t. `crate_edition`.
115+
// - E.g. warn if `rust_2018_preview` is declared when
116+
// `crate_edition` is 2018
117+
// - E.g. don't warn if `rust_2018_preview` is declared when
118+
// `crate_edition` is 2015.
119+
if let Some(&edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
120+
if edition <= crate_edition {
121+
sess.emit_warning(FeatureIncludedInEdition {
122+
span: mi.span(),
123+
feature: name,
124+
edition,
125+
});
126+
}
127+
continue;
128+
}
129+
130+
// If the declared feature is edition-dependent and was already
131+
// enabled due to `feature_edition`, give a warning.
136132
// - E.g. warn if `test_2018_feature` is declared when
137-
// `rust_2018_preview` or higher is declared.
138-
if let Some(&edition) = edition_enabled_features.get(&name) {
133+
// `feature_edition` is 2018 or higher.
134+
if edition_enabled_features.contains(&name) {
139135
sess.emit_warning(FeatureIncludedInEdition {
140136
span: mi.span(),
141137
feature: name,
142-
edition,
138+
edition: features_edition,
143139
});
144140
continue;
145141
}
146142

147-
// If the declared feature is an edition umbrella feature-gate,
148-
// ignore it, because it was already handled above.
149-
// - E.g. `rust_20XX_preview`
150-
if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
151-
continue;
152-
}
153-
154-
// If the declared feature is removed, issue an error.
143+
// If the declared feature has been removed, issue an error.
155144
if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) {
156145
if let FeatureState::Removed { reason } = state {
157146
sess.emit_err(FeatureRemoved {

0 commit comments

Comments
 (0)