about summary refs log tree commit diff
path: root/src/librustc_attr/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_attr/builtin.rs')
-rw-r--r--src/librustc_attr/builtin.rs140
1 files changed, 73 insertions, 67 deletions
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index ac1a191fa23..a592bbc2bf9 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -2,6 +2,7 @@
 
 use super::{find_by_name, mark_used};
 
+use rustc_ast::ast::{self, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, Handler};
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
@@ -10,7 +11,7 @@ use rustc_session::parse::{feature_err, ParseSess};
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
-use syntax::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem};
+use version_check::Version;
 
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
@@ -53,7 +54,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
                     err.span_suggestion(
                         span,
                         "consider removing the prefix",
-                        format!("{}", &lint_str[1..]),
+                        lint_str[1..].to_string(),
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -98,7 +99,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                         }
                     }
 
-                    diagnostic.map(|d| {
+                    if let Some(d) = diagnostic {
                         struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
                             .span_label(attr.span, "invalid argument")
                             .span_suggestions(
@@ -110,7 +111,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                                 Applicability::MachineApplicable,
                             )
                             .emit();
-                    });
+                    };
                 }
             }
         }
@@ -119,36 +120,22 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
     })
 }
 
-/// Represents the #[stable], #[unstable], #[rustc_deprecated] attributes.
-#[derive(
-    RustcEncodable,
-    RustcDecodable,
-    Copy,
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    HashStable_Generic
-)]
+/// Represents the following attributes:
+///
+/// - `#[stable]`
+/// - `#[unstable]`
+/// - `#[rustc_deprecated]`
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
     pub rustc_depr: Option<RustcDeprecation>,
 }
 
-/// Represents the #[rustc_const_unstable] and #[rustc_const_stable] attributes.
-#[derive(
-    RustcEncodable,
-    RustcDecodable,
-    Copy,
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    HashStable_Generic
-)]
+/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
 pub struct ConstStability {
     pub level: StabilityLevel,
     pub feature: Symbol,
@@ -159,18 +146,8 @@ pub struct ConstStability {
 }
 
 /// The available stability levels.
-#[derive(
-    RustcEncodable,
-    RustcDecodable,
-    PartialEq,
-    PartialOrd,
-    Copy,
-    Clone,
-    Debug,
-    Eq,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
     Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
@@ -186,18 +163,8 @@ impl StabilityLevel {
     }
 }
 
-#[derive(
-    RustcEncodable,
-    RustcDecodable,
-    PartialEq,
-    PartialOrd,
-    Copy,
-    Clone,
-    Debug,
-    Eq,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
 pub struct RustcDeprecation {
     pub since: Symbol,
     pub reason: Symbol,
@@ -602,11 +569,8 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
-    eval_condition(cfg, sess, &mut |cfg| {
-        let gate = find_gated_cfg(|sym| cfg.check_name(sym));
-        if let (Some(feats), Some(gated_cfg)) = (features, gate) {
-            gate_cfg(&gated_cfg, cfg.span, sess, feats);
-        }
+    eval_condition(cfg, sess, features, &mut |cfg| {
+        try_gate_cfg(cfg, sess, features);
         let error = |span, msg| {
             sess.span_diagnostic.span_err(span, msg);
             true
@@ -637,6 +601,13 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
     })
 }
 
+fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) {
+    let gate = find_gated_cfg(|sym| cfg.check_name(sym));
+    if let (Some(feats), Some(gated_cfg)) = (features, gate) {
+        gate_cfg(&gated_cfg, cfg.span, sess, feats);
+    }
+}
+
 fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) {
     let (cfg, feature, has_feature) = gated_cfg;
     if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
@@ -650,9 +621,44 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
 pub fn eval_condition(
     cfg: &ast::MetaItem,
     sess: &ParseSess,
+    features: Option<&Features>,
     eval: &mut impl FnMut(&ast::MetaItem) -> bool,
 ) -> bool {
     match cfg.kind {
+        ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
+            try_gate_cfg(cfg, sess, features);
+            let (min_version, span) = match &mis[..] {
+                [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
+                    (sym, span)
+                }
+                [NestedMetaItem::Literal(Lit { span, .. })
+                | NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
+                    sess.span_diagnostic
+                        .struct_span_err(*span, &*format!("expected a version literal"))
+                        .emit();
+                    return false;
+                }
+                [..] => {
+                    sess.span_diagnostic
+                        .struct_span_err(cfg.span, "expected single version literal")
+                        .emit();
+                    return false;
+                }
+            };
+            let min_version = match Version::parse(&min_version.as_str()) {
+                Some(ver) => ver,
+                None => {
+                    sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit();
+                    return false;
+                }
+            };
+            let channel = env!("CFG_RELEASE_CHANNEL");
+            let nightly = channel == "nightly" || channel == "dev";
+            let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap();
+
+            // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details
+            if nightly { rustc_version > min_version } else { rustc_version >= min_version }
+        }
         ast::MetaItemKind::List(ref mis) => {
             for mi in mis.iter() {
                 if !mi.is_meta_item() {
@@ -668,12 +674,12 @@ pub fn eval_condition(
             // The unwraps below may look dangerous, but we've already asserted
             // that they won't fail with the loop above.
             match cfg.name_or_empty() {
-                sym::any => {
-                    mis.iter().any(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval))
-                }
-                sym::all => {
-                    mis.iter().all(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval))
-                }
+                sym::any => mis
+                    .iter()
+                    .any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
+                sym::all => mis
+                    .iter()
+                    .all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)),
                 sym::not => {
                     if mis.len() != 1 {
                         struct_span_err!(
@@ -686,7 +692,7 @@ pub fn eval_condition(
                         return false;
                     }
 
-                    !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
+                    !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
                 }
                 _ => {
                     struct_span_err!(
@@ -908,7 +914,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                     let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
                         if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
                             if literal.is_power_of_two() {
-                                // rustc::ty::layout::Align restricts align to <= 2^29
+                                // rustc_middle::ty::layout::Align restricts align to <= 2^29
                                 if *literal <= 1 << 29 {
                                     Ok(*literal as u32)
                                 } else {
@@ -1024,7 +1030,7 @@ pub enum TransparencyError {
 
 pub fn find_transparency(
     attrs: &[Attribute],
-    is_legacy: bool,
+    macro_rules: bool,
 ) -> (Transparency, Option<TransparencyError>) {
     let mut transparency = None;
     let mut error = None;
@@ -1049,7 +1055,7 @@ pub fn find_transparency(
             }
         }
     }
-    let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque };
+    let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque };
     (transparency.map_or(fallback, |t| t.0), error)
 }