about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2023-10-05 10:17:42 +1100
committerNicholas Nethercote <n.nethercote@gmail.com>2023-10-05 11:16:05 +1100
commite24f39440478dcddddb83b9999aa724d4a093d8f (patch)
treebf7b43fe2ecbbe4d002cd5d708af10c1b98b8e79
parent1ddb2872ddeb5d56f7bdecfd4175fb13fc510069 (diff)
downloadrust-e24f39440478dcddddb83b9999aa724d4a093d8f.tar.gz
rust-e24f39440478dcddddb83b9999aa724d4a093d8f.zip
Add comments to `config::features`.
I found this function very confusing, and it took me quite some time to
work out what it was doing. These comments capture that hard-earned
knowledge.
-rw-r--r--compiler/rustc_expand/src/config.rs35
1 files changed, 30 insertions, 5 deletions
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index b2546caa345..9cb16e0b0c9 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -58,21 +58,28 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
     let mut edition_enabled_features = FxHashMap::default();
     let crate_edition = sess.edition();
 
+    // Enable edition umbrella feature-gates based on the crate edition.
+    // - enable `rust_2015_preview` always
+    // - enable `rust_2018_preview` if the crate edition is 2018 or higher
+    // - enable `rust_2021_preview` if the crate edition is 2021 or higher
+    // - etc.
     for &edition in ALL_EDITIONS {
         if edition <= crate_edition {
-            // The `crate_edition` implies its respective umbrella feature-gate
-            // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
             edition_enabled_features.insert(edition.feature_name(), edition);
         }
     }
 
+    // Enable edition-dependent features based on the crate edition.
+    // - E.g. `test_2018_feature` if the crate edition is 2018 or higher
     for feature in active_features_up_to(crate_edition) {
         feature.set(&mut features);
         edition_enabled_features.insert(feature.name, crate_edition);
     }
 
-    // Process the edition umbrella feature-gates first, to ensure
-    // `edition_enabled_features` is completed before it's queried.
+    // Enable edition umbrella feature-gates that are declared in the code. If
+    // present, enable edition-specific features based on that.
+    // - E.g. enable `test_2018_feature` if the crate edition is 2015 but
+    //   `rust_2018_preview` is present
     for attr in krate_attrs {
         if !attr.has_name(sym::feature) {
             continue;
@@ -105,6 +112,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
         }
     }
 
+    // Process all features declared in the code.
     for attr in krate_attrs {
         if !attr.has_name(sym::feature) {
             continue;
@@ -136,6 +144,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 }
             };
 
+            // If the declared feature is edition-specific and already enabled
+            // due to the crate edition or a declared edition umbrella
+            // feature-gate, give a warning.
+            // - E.g. warn if `test_2018_feature` is declared when the crate
+            //   edition is 2018 or higher
+            // - E.g. warn if `test_2018_feature` is declared when
+            //   `rust_2018_preview` or higher is declared.
             if let Some(&edition) = edition_enabled_features.get(&name) {
                 sess.emit_warning(FeatureIncludedInEdition {
                     span: mi.span(),
@@ -145,11 +160,14 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 continue;
             }
 
+            // If the declared feature is an edition umbrella feature-gate,
+            // ignore it, because it was already handled above.
+            // - E.g. `rust_20XX_preview`
             if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
-                // Handled in the separate loop above.
                 continue;
             }
 
+            // If the declared feature is removed, issue an error.
             let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
             let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
             if let Some(Feature { state, .. }) = removed.or(stable_removed) {
@@ -161,6 +179,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 }
             }
 
+            // If the declared feature is stable, record it.
             if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
                 let since = Some(Symbol::intern(since));
                 features.declared_lang_features.push((name, mi.span(), since));
@@ -168,6 +187,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 continue;
             }
 
+            // If `-Z allow-features` is used and the declared feature is
+            // unstable and not also listed as one of the allowed features,
+            // issue an error.
             if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
                 if allowed.iter().all(|f| name.as_str() != f) {
                     sess.emit_err(FeatureNotAllowed { span: mi.span(), name });
@@ -175,6 +197,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 }
             }
 
+            // If the declared feature is unstable, record it.
             if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
                 f.set(&mut features);
                 features.declared_lang_features.push((name, mi.span(), None));
@@ -182,6 +205,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
                 continue;
             }
 
+            // Otherwise, the feature is unknown. Record it at a lib feature.
+            // It will be checked later.
             features.declared_lib_features.push((name, mi.span()));
             features.active_features.insert(name);
         }