diff options
Diffstat (limited to 'src/librustc_attr/builtin.rs')
| -rw-r--r-- | src/librustc_attr/builtin.rs | 140 |
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) } |
