summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_attr/src/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr/src/builtin.rs')
-rw-r--r--compiler/rustc_attr/src/builtin.rs470
1 files changed, 218 insertions, 252 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index ca4b3662a..ad92d5855 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -3,13 +3,14 @@
use rustc_ast::{self as ast, attr};
use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
use rustc_ast_pretty::pprust;
+use rustc_errors::ErrorGuaranteed;
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
-use rustc_session::Session;
+use rustc_session::{RustcVersion, Session};
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
@@ -22,25 +23,10 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
-pub fn rust_version_symbol() -> Symbol {
- let version = option_env!("CFG_RELEASE").unwrap_or("<current>");
- Symbol::intern(&version)
-}
-
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
}
-enum AttrError {
- MultipleItem(String),
- UnknownMetaItem(String, &'static [&'static str]),
- MissingSince,
- NonIdentFeature,
- MissingFeature,
- MultipleStabilityLevels,
- UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
-}
-
pub(crate) enum UnsupportedLiteralReason {
Generic,
CfgString,
@@ -48,37 +34,6 @@ pub(crate) enum UnsupportedLiteralReason {
DeprecatedKvPair,
}
-fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
- match error {
- AttrError::MultipleItem(item) => {
- sess.emit_err(session_diagnostics::MultipleItem { span, item });
- }
- AttrError::UnknownMetaItem(item, expected) => {
- sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
- }
- AttrError::MissingSince => {
- sess.emit_err(session_diagnostics::MissingSince { span });
- }
- AttrError::NonIdentFeature => {
- sess.emit_err(session_diagnostics::NonIdentFeature { span });
- }
- AttrError::MissingFeature => {
- sess.emit_err(session_diagnostics::MissingFeature { span });
- }
- AttrError::MultipleStabilityLevels => {
- sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
- }
- AttrError::UnsupportedLiteral(reason, is_bytestr) => {
- sess.emit_err(session_diagnostics::UnsupportedLiteral {
- span,
- reason,
- is_bytestr,
- start_point_span: sess.source_map().start_point(span),
- });
- }
- }
-}
-
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum InlineAttr {
None,
@@ -162,7 +117,7 @@ pub enum StabilityLevel {
is_soft: bool,
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
/// then the `implied_by` attribute is used to indicate which now-stable feature previously
- /// contained a item.
+ /// contained an item.
///
/// ```pseudo-Rust
/// #[unstable(feature = "foo", issue = "...")]
@@ -184,13 +139,24 @@ pub enum StabilityLevel {
/// `#[stable]`
Stable {
/// Rust release which stabilized this feature.
- since: Symbol,
+ since: StableSince,
/// Is this item allowed to be referred to on stable, despite being contained in unstable
/// modules?
allowed_through_unstable_modules: bool,
},
}
+/// Rust release in which a feature is stabilized.
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub enum StableSince {
+ Version(RustcVersion),
+ /// Stabilized in the upcoming version, whatever number that is.
+ Current,
+ /// Failed to parse a stabilization version.
+ Err,
+}
+
impl StabilityLevel {
pub fn is_unstable(&self) -> bool {
matches!(self, StabilityLevel::Unstable { .. })
@@ -241,7 +207,7 @@ pub fn find_stability(
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
sym::unstable => {
if stab.is_some() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break;
}
@@ -251,7 +217,7 @@ pub fn find_stability(
}
sym::stable => {
if stab.is_some() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break;
}
if let Some((feature, level)) = parse_stability(sess, attr) {
@@ -295,7 +261,7 @@ pub fn find_const_stability(
sym::rustc_promotable => promotable = true,
sym::rustc_const_unstable => {
if const_stab.is_some() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break;
}
@@ -306,7 +272,7 @@ pub fn find_const_stability(
}
sym::rustc_const_stable => {
if const_stab.is_some() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break;
}
if let Some((feature, level)) = parse_stability(sess, attr) {
@@ -340,7 +306,7 @@ pub fn find_body_stability(
for attr in attrs {
if attr.has_name(sym::rustc_default_body_unstable) {
if body_stab.is_some() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
break;
}
@@ -353,83 +319,83 @@ pub fn find_body_stability(
body_stab
}
+fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
+ if item.is_some() {
+ sess.emit_err(session_diagnostics::MultipleItem {
+ span: meta.span,
+ item: pprust::path_to_string(&meta.path),
+ });
+ None
+ } else if let Some(v) = meta.value_str() {
+ *item = Some(v);
+ Some(())
+ } else {
+ sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
+ None
+ }
+}
+
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
/// its stability information.
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
let meta = attr.meta()?;
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
- let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
- if item.is_some() {
- handle_errors(
- &sess.parse_sess,
- meta.span,
- AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
- );
- return false;
- }
- if let Some(v) = meta.value_str() {
- *item = Some(v);
- true
- } else {
- sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
- false
- }
- };
let mut feature = None;
let mut since = None;
for meta in metas {
let Some(mi) = meta.meta_item() else {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: meta.span(),
+ reason: UnsupportedLiteralReason::Generic,
+ is_bytestr: false,
+ start_point_span: sess.source_map().start_point(meta.span()),
+ });
return None;
};
match mi.name_or_empty() {
- sym::feature => {
- if !insert_or_error(mi, &mut feature) {
- return None;
- }
- }
- sym::since => {
- if !insert_or_error(mi, &mut since) {
- return None;
- }
- }
+ sym::feature => insert_or_error(sess, mi, &mut feature)?,
+ sym::since => insert_or_error(sess, mi, &mut since)?,
_ => {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- &["feature", "since"],
- ),
- );
+ sess.emit_err(session_diagnostics::UnknownMetaItem {
+ span: meta.span(),
+ item: pprust::path_to_string(&mi.path),
+ expected: &["feature", "since"],
+ });
return None;
}
}
}
- if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
- since = Some(rust_version_symbol());
- }
+ let feature = match feature {
+ Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+ Some(_bad_feature) => {
+ Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+ }
+ None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+ };
+
+ let since = if let Some(since) = since {
+ if since.as_str() == VERSION_PLACEHOLDER {
+ StableSince::Current
+ } else if let Some(version) = parse_version(since) {
+ StableSince::Version(version)
+ } else {
+ sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
+ StableSince::Err
+ }
+ } else {
+ sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
+ StableSince::Err
+ };
- match (feature, since) {
- (Some(feature), Some(since)) => {
+ match feature {
+ Ok(feature) => {
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
Some((feature, level))
}
- (None, _) => {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
- None
- }
- _ => {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
- None
- }
+ Err(ErrorGuaranteed { .. }) => None,
}
}
@@ -438,23 +404,6 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
let meta = attr.meta()?;
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
- let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
- if item.is_some() {
- handle_errors(
- &sess.parse_sess,
- meta.span,
- AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
- );
- return false;
- }
- if let Some(v) = meta.value_str() {
- *item = Some(v);
- true
- } else {
- sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
- false
- }
- };
let mut feature = None;
let mut reason = None;
@@ -464,29 +413,20 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
let mut implied_by = None;
for meta in metas {
let Some(mi) = meta.meta_item() else {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: meta.span(),
+ reason: UnsupportedLiteralReason::Generic,
+ is_bytestr: false,
+ start_point_span: sess.source_map().start_point(meta.span()),
+ });
return None;
};
match mi.name_or_empty() {
- sym::feature => {
- if !insert_or_error(mi, &mut feature) {
- return None;
- }
- }
- sym::reason => {
- if !insert_or_error(mi, &mut reason) {
- return None;
- }
- }
+ sym::feature => insert_or_error(sess, mi, &mut feature)?,
+ sym::reason => insert_or_error(sess, mi, &mut reason)?,
sym::issue => {
- if !insert_or_error(mi, &mut issue) {
- return None;
- }
+ insert_or_error(sess, mi, &mut issue)?;
// These unwraps are safe because `insert_or_error` ensures the meta item
// is a name/value pair string literal.
@@ -515,31 +455,31 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
}
is_soft = true;
}
- sym::implied_by => {
- if !insert_or_error(mi, &mut implied_by) {
- return None;
- }
- }
+ sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?,
_ => {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- &["feature", "reason", "issue", "soft", "implied_by"],
- ),
- );
+ sess.emit_err(session_diagnostics::UnknownMetaItem {
+ span: meta.span(),
+ item: pprust::path_to_string(&mi.path),
+ expected: &["feature", "reason", "issue", "soft", "implied_by"],
+ });
return None;
}
}
}
- match (feature, reason, issue) {
- (Some(feature), reason, Some(_)) => {
- if !rustc_lexer::is_ident(feature.as_str()) {
- handle_errors(&sess.parse_sess, attr.span, AttrError::NonIdentFeature);
- return None;
- }
+ let feature = match feature {
+ Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
+ Some(_bad_feature) => {
+ Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+ }
+ None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+ };
+
+ let issue =
+ issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
+
+ match (feature, issue) {
+ (Ok(feature), Ok(_)) => {
let level = StabilityLevel::Unstable {
reason: UnstableReason::from_opt_reason(reason),
issue: issue_num,
@@ -548,14 +488,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
};
Some((feature, level))
}
- (None, _, _) => {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
- return None;
- }
- _ => {
- sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
- return None;
- }
+ (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
}
}
@@ -587,7 +520,11 @@ pub fn cfg_matches(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
- "unexpected `cfg` condition value",
+ if let Some(value) = cfg.value {
+ format!("unexpected `cfg` condition value: `{value}`")
+ } else {
+ format!("unexpected `cfg` condition value: (none)")
+ },
BuiltinLintDiagnostics::UnexpectedCfgValue(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
@@ -599,7 +536,7 @@ pub fn cfg_matches(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
- "unexpected `cfg` condition name",
+ format!("unexpected `cfg` condition name: `{}`", cfg.name),
BuiltinLintDiagnostics::UnexpectedCfgName(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
@@ -627,24 +564,20 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
}
}
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-struct Version {
- major: u16,
- minor: u16,
- patch: u16,
-}
-
-fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
- let mut components = s.split('-');
+/// Parse a rustc version number written inside string literal in an attribute,
+/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
+/// not accepted in this position, unlike when parsing CFG_RELEASE.
+fn parse_version(s: Symbol) -> Option<RustcVersion> {
+ let mut components = s.as_str().split('-');
let d = components.next()?;
- if !allow_appendix && components.next().is_some() {
+ if components.next().is_some() {
return None;
}
let mut digits = d.splitn(3, '.');
let major = digits.next()?.parse().ok()?;
let minor = digits.next()?.parse().ok()?;
let patch = digits.next().unwrap_or("0").parse().ok()?;
- Some(Version { major, minor, patch })
+ Some(RustcVersion { major, minor, patch })
}
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
@@ -676,27 +609,27 @@ pub fn eval_condition(
return false;
}
};
- let Some(min_version) = parse_version(min_version.as_str(), false) else {
+ let Some(min_version) = parse_version(*min_version) else {
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
return false;
};
- let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
if sess.assume_incomplete_release {
- rustc_version > min_version
+ RustcVersion::CURRENT > min_version
} else {
- rustc_version >= min_version
+ RustcVersion::CURRENT >= min_version
}
}
ast::MetaItemKind::List(mis) => {
for mi in mis.iter() {
if !mi.is_meta_item() {
- handle_errors(
- sess,
- mi.span(),
- AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: mi.span(),
+ reason: UnsupportedLiteralReason::Generic,
+ is_bytestr: false,
+ start_point_span: sess.source_map().start_point(mi.span()),
+ });
return false;
}
}
@@ -729,13 +662,16 @@ pub fn eval_condition(
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
}
sym::target => {
- if let Some(features) = features && !features.cfg_target_compact {
+ if let Some(features) = features
+ && !features.cfg_target_compact
+ {
feature_err(
sess,
sym::cfg_target_compact,
cfg.span,
- "compact `cfg(target(..))` is experimental and subject to change"
- ).emit();
+ "compact `cfg(target(..))` is experimental and subject to change",
+ )
+ .emit();
}
mis.iter().fold(true, |res, mi| {
@@ -761,14 +697,12 @@ pub fn eval_condition(
true
}
MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
- handle_errors(
- sess,
- lit.span,
- AttrError::UnsupportedLiteral(
- UnsupportedLiteralReason::CfgString,
- lit.kind.is_bytestr(),
- ),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: lit.span,
+ reason: UnsupportedLiteralReason::CfgString,
+ is_bytestr: lit.kind.is_bytestr(),
+ start_point_span: sess.source_map().start_point(lit.span),
+ });
true
}
ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
@@ -786,17 +720,49 @@ pub fn eval_condition(
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
pub struct Deprecation {
- pub since: Option<Symbol>,
+ pub since: DeprecatedSince,
/// The note to issue a reason.
pub note: Option<Symbol>,
/// A text snippet used to completely replace any use of the deprecated item in an expression.
///
/// This is currently unstable.
pub suggestion: Option<Symbol>,
+}
- /// Whether to treat the since attribute as being a Rust version identifier
- /// (rather than an opaque string).
- pub is_since_rustc_version: bool,
+/// Release in which an API is deprecated.
+#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
+pub enum DeprecatedSince {
+ RustcVersion(RustcVersion),
+ /// Deprecated in the future ("to be determined").
+ Future,
+ /// `feature(staged_api)` is off. Deprecation versions outside the standard
+ /// library are allowed to be arbitrary strings, for better or worse.
+ NonStandard(Symbol),
+ /// Deprecation version is unspecified but optional.
+ Unspecified,
+ /// Failed to parse a deprecation version, or the deprecation version is
+ /// unspecified and required. An error has already been emitted.
+ Err,
+}
+
+impl Deprecation {
+ /// Whether an item marked with #[deprecated(since = "X")] is currently
+ /// deprecated (i.e., whether X is not greater than the current rustc
+ /// version).
+ pub fn is_in_effect(&self) -> bool {
+ match self.since {
+ DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT,
+ DeprecatedSince::Future => false,
+ // The `since` field doesn't have semantic purpose without `#![staged_api]`.
+ DeprecatedSince::NonStandard(_) => true,
+ // Assume deprecation is in effect if "since" field is absent or invalid.
+ DeprecatedSince::Unspecified | DeprecatedSince::Err => true,
+ }
+ }
+
+ pub fn is_since_rustc_version(&self) -> bool {
+ matches!(self.since, DeprecatedSince::RustcVersion(_))
+ }
}
/// Finds the deprecation attribute. `None` if none exists.
@@ -825,11 +791,10 @@ pub fn find_deprecation(
MetaItemKind::List(list) => {
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
- handle_errors(
- &sess.parse_sess,
- meta.span,
- AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
- );
+ sess.emit_err(session_diagnostics::MultipleItem {
+ span: meta.span,
+ item: pprust::path_to_string(&meta.path),
+ });
return false;
}
if let Some(v) = meta.value_str() {
@@ -837,16 +802,14 @@ pub fn find_deprecation(
true
} else {
if let Some(lit) = meta.name_value_literal() {
- handle_errors(
- &sess.parse_sess,
- lit.span,
- AttrError::UnsupportedLiteral(
- UnsupportedLiteralReason::DeprecatedString,
- lit.kind.is_bytestr(),
- ),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: lit.span,
+ reason: UnsupportedLiteralReason::DeprecatedString,
+ is_bytestr: lit.kind.is_bytestr(),
+ start_point_span: sess.source_map().start_point(lit.span),
+ });
} else {
- sess.emit_err(session_diagnostics::IncorrectMetaItem2 {
+ sess.emit_err(session_diagnostics::IncorrectMetaItem {
span: meta.span,
});
}
@@ -882,30 +845,25 @@ pub fn find_deprecation(
}
}
_ => {
- handle_errors(
- &sess.parse_sess,
- meta.span(),
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- if features.deprecated_suggestion {
- &["since", "note", "suggestion"]
- } else {
- &["since", "note"]
- },
- ),
- );
+ sess.emit_err(session_diagnostics::UnknownMetaItem {
+ span: meta.span(),
+ item: pprust::path_to_string(&mi.path),
+ expected: if features.deprecated_suggestion {
+ &["since", "note", "suggestion"]
+ } else {
+ &["since", "note"]
+ },
+ });
continue 'outer;
}
},
NestedMetaItem::Lit(lit) => {
- handle_errors(
- &sess.parse_sess,
- lit.span,
- AttrError::UnsupportedLiteral(
- UnsupportedLiteralReason::DeprecatedKvPair,
- false,
- ),
- );
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span: lit.span,
+ reason: UnsupportedLiteralReason::DeprecatedKvPair,
+ is_bytestr: false,
+ start_point_span: sess.source_map().start_point(lit.span),
+ });
continue 'outer;
}
}
@@ -913,22 +871,30 @@ pub fn find_deprecation(
}
}
- if is_rustc {
- if since.is_none() {
- handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
- continue;
+ let since = if let Some(since) = since {
+ if since.as_str() == "TBD" {
+ DeprecatedSince::Future
+ } else if !is_rustc {
+ DeprecatedSince::NonStandard(since)
+ } else if let Some(version) = parse_version(since) {
+ DeprecatedSince::RustcVersion(version)
+ } else {
+ sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
+ DeprecatedSince::Err
}
+ } else if is_rustc {
+ sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
+ DeprecatedSince::Err
+ } else {
+ DeprecatedSince::Unspecified
+ };
- if note.is_none() {
- sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
- continue;
- }
+ if is_rustc && note.is_none() {
+ sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
+ continue;
}
- depr = Some((
- Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
- attr.span,
- ));
+ depr = Some((Deprecation { since, note, suggestion }, attr.span));
}
depr