]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/feature_gate.rs
Rollup merge of #53413 - eddyb:featured-in-the-latest-edition, r=varkor
[rust.git] / src / libsyntax / feature_gate.rs
index f29bcd8ee58c3e2f9aec419c57e2533038ccad91..7a8a7b073185a6477dfeb8fdbb73dec1995d1202 100644 (file)
@@ -32,7 +32,7 @@
 use codemap::Spanned;
 use edition::{ALL_EDITIONS, Edition};
 use syntax_pos::{Span, DUMMY_SP};
-use errors::{DiagnosticBuilder, Handler, FatalError};
+use errors::{DiagnosticBuilder, Handler};
 use visit::{self, FnKind, Visitor};
 use parse::ParseSess;
 use symbol::{keywords, Symbol};
@@ -83,8 +83,14 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
             }
 
             pub fn use_extern_macros(&self) -> bool {
-                // The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
-                self.use_extern_macros || self.decl_macro || self.tool_attributes
+                // A number of "advanced" macro features enable
+                // macro modularization (`use_extern_macros`) implicitly.
+                self.use_extern_macros || self.decl_macro ||
+                self.tool_attributes || self.custom_attribute ||
+                self.macros_in_extern || self.proc_macro_path_invoc ||
+                self.proc_macro_mod || self.proc_macro_expr ||
+                self.proc_macro_non_items || self.proc_macro_gen ||
+                self.stmt_expr_attributes || self.unrestricted_attribute_tokens
             }
         }
     };
@@ -498,6 +504,12 @@ pub fn use_extern_macros(&self) -> bool {
     // impl<I:Iterator> Iterator for &mut Iterator
     // impl Debug for Foo<'_>
     (active, impl_header_lifetime_elision, "1.30.0", Some(15872), Some(Edition::Edition2018)),
+
+    // Support for arbitrary delimited token streams in non-macro attributes.
+    (active, unrestricted_attribute_tokens, "1.30.0", Some(44690), None),
+
+    // Allows `use x::y;` to resolve through `self::x`, not just `::x`.
+    (active, uniform_paths, "1.30.0", Some(53130), None),
 );
 
 declare_features! (
@@ -715,8 +727,7 @@ pub fn is_builtin_attr_name(name: ast::Name) -> bool {
 }
 
 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
-    BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
-    attr.name().as_str().starts_with("rustc_")
+    BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.path == builtin_name)
 }
 
 // Attributes that have a special meaning to rustc or rustdoc
@@ -1365,13 +1376,6 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue
 pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
     "using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
 
-pub const EXPLAIN_MACROS_IN_EXTERN: &'static str =
-    "macro invocations in `extern {}` blocks are experimental.";
-
-// mention proc-macros when enabled
-pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str =
-    "macro and proc-macro invocations in `extern {}` blocks are experimental.";
-
 struct PostExpansionVisitor<'a> {
     context: &'a Context<'a>,
 }
@@ -1522,25 +1526,29 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
             }
         }
 
-        // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
-        let mut allow_attr_literal = false;
-        if attr.path == "repr" {
-            if let Some(content) = attr.meta_item_list() {
-                allow_attr_literal = content.iter().any(
-                    |c| c.check_name("align") || c.check_name("packed"));
-            }
-        }
-
-        if self.context.features.use_extern_macros() && attr::is_known(attr) {
-            return
-        }
+        if !self.context.features.unrestricted_attribute_tokens {
+            // Unfortunately, `parse_meta` cannot be called speculatively because it can report
+            // errors by itself, so we have to call it only if the feature is disabled.
+            match attr.parse_meta(self.context.parse_sess) {
+                Ok(meta) => {
+                    // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
+                    let mut allow_attr_literal = false;
+                    if attr.path == "repr" {
+                        if let Some(content) = meta.meta_item_list() {
+                            allow_attr_literal = content.iter().any(
+                                |c| c.check_name("align") || c.check_name("packed"));
+                        }
+                    }
 
-        if !allow_attr_literal {
-            let meta = panictry!(attr.parse_meta(self.context.parse_sess));
-            if contains_novel_literal(&meta) {
-                gate_feature_post!(&self, attr_literals, attr.span,
-                                   "non-string literals in attributes, or string \
-                                   literals in top-level positions, are experimental");
+                    if !allow_attr_literal && contains_novel_literal(&meta) {
+                        gate_feature_post!(&self, attr_literals, attr.span,
+                                        "non-string literals in attributes, or string \
+                                        literals in top-level positions, are experimental");
+                    }
+                }
+                Err(mut err) => {
+                    err.help("try enabling `#![feature(unrestricted_attribute_tokens)]`").emit()
+                }
             }
         }
     }
@@ -1914,13 +1922,23 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
         err.emit();
     }
 
-    let mut features = Features::new();
-
-    let mut feature_checker = FeatureChecker::default();
+    // Some features are known to be incomplete and using them is likely to have
+    // unanticipated results, such as compiler crashes. We warn the user about these
+    // to alert them.
+    let incomplete_features = ["generic_associated_types"];
 
+    let mut features = Features::new();
     let mut edition_enabled_features = FxHashMap();
 
-    for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+    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(Symbol::intern(edition.feature_name()), edition);
+        }
+    }
+
+    for &(name, .., f_edition, set) in ACTIVE_FEATURES {
         if let Some(f_edition) = f_edition {
             if f_edition <= crate_edition {
                 set(&mut features, DUMMY_SP);
@@ -1929,6 +1947,8 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
         }
     }
 
+    // Process the edition umbrella feature-gates first, to ensure
+    // `edition_enabled_features` is completed before it's queried.
     for attr in krate_attrs {
         if !attr.check_name("feature") {
             continue
@@ -1936,28 +1956,32 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
 
         let list = match attr.meta_item_list() {
             Some(list) => list,
-            None => {
-                span_err!(span_handler, attr.span, E0555,
-                          "malformed feature attribute, expected #![feature(...)]");
-                continue
-            }
+            None => continue,
         };
 
         for mi in list {
             let name = if let Some(word) = mi.word() {
                 word.name()
             } else {
-                span_err!(span_handler, mi.span, E0556,
-                          "malformed feature, expected just one word");
                 continue
             };
 
+            if incomplete_features.iter().any(|f| *f == name.as_str()) {
+                span_handler.struct_span_warn(
+                    mi.span,
+                    &format!(
+                        "the feature `{}` is incomplete and may cause the compiler to crash",
+                        name
+                    )
+                ).emit();
+            }
+
             if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
                 if *edition <= crate_edition {
-                    continue
+                    continue;
                 }
 
-                for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+                for &(name, .., f_edition, set) in ACTIVE_FEATURES {
                     if let Some(f_edition) = f_edition {
                         if f_edition <= *edition {
                             // FIXME(Manishearth) there is currently no way to set
@@ -1967,25 +1991,53 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
                         }
                     }
                 }
+            }
+        }
+    }
+
+    for attr in krate_attrs {
+        if !attr.check_name("feature") {
+            continue
+        }
+
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
+            None => {
+                span_err!(span_handler, attr.span, E0555,
+                          "malformed feature attribute, expected #![feature(...)]");
+                continue
+            }
+        };
 
+        for mi in list {
+            let name = if let Some(word) = mi.word() {
+                word.name()
+            } else {
+                span_err!(span_handler, mi.span, E0556,
+                          "malformed feature, expected just one word");
                 continue
+            };
+
+            if let Some(edition) = edition_enabled_features.get(&name) {
+                struct_span_warn!(
+                    span_handler,
+                    mi.span,
+                    E0705,
+                    "the feature `{}` is included in the Rust {} edition",
+                    name,
+                    edition,
+                ).emit();
+                continue;
+            }
+
+            if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
+                // Handled in the separate loop above.
+                continue;
             }
 
             if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
-                if let Some(edition) = edition_enabled_features.get(&name) {
-                    struct_span_warn!(
-                        span_handler,
-                        mi.span,
-                        E0705,
-                        "the feature `{}` is included in the Rust {} edition",
-                        name,
-                        edition,
-                    ).emit();
-                } else {
-                    set(&mut features, mi.span);
-                    feature_checker.collect(&features, mi.span);
-                    features.declared_lang_features.push((name, mi.span, None));
-                }
+                set(&mut features, mi.span);
+                features.declared_lang_features.push((name, mi.span, None));
                 continue
             }
 
@@ -2006,45 +2058,9 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
         }
     }
 
-    feature_checker.check(span_handler);
-
     features
 }
 
-/// A collector for mutually exclusive and interdependent features and their flag spans.
-#[derive(Default)]
-struct FeatureChecker {
-    use_extern_macros: Option<Span>,
-    custom_attribute: Option<Span>,
-}
-
-impl FeatureChecker {
-    // If this method turns out to be a hotspot due to branching,
-    // the branching can be eliminated by modifying `set!()` to set these spans
-    // only for the features that need to be checked for mutual exclusion.
-    fn collect(&mut self, features: &Features, span: Span) {
-        if features.use_extern_macros() {
-            // If self.use_extern_macros is None, set to Some(span)
-            self.use_extern_macros = self.use_extern_macros.or(Some(span));
-        }
-
-        if features.custom_attribute {
-            self.custom_attribute = self.custom_attribute.or(Some(span));
-        }
-    }
-
-    fn check(self, handler: &Handler) {
-        if let (Some(pm_span), Some(ca_span)) = (self.use_extern_macros, self.custom_attribute) {
-            handler.struct_span_err(pm_span, "Cannot use `#![feature(use_extern_macros)]` and \
-                                              `#![feature(custom_attribute)] at the same time")
-                .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
-                .emit();
-
-            FatalError.raise();
-        }
-    }
-}
-
 pub fn check_crate(krate: &ast::Crate,
                    sess: &ParseSess,
                    features: &Features,