Extract parse_stability and parse_unstability.
This commit is contained in:
parent
df7fd9995f
commit
17f1db672e
1 changed files with 224 additions and 205 deletions
|
@ -245,15 +245,13 @@ fn find_stability_generic<'a, I>(
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Attribute>,
|
I: Iterator<Item = &'a Attribute>,
|
||||||
{
|
{
|
||||||
use StabilityLevel::*;
|
|
||||||
|
|
||||||
let mut stab: Option<(Stability, Span)> = None;
|
let mut stab: Option<(Stability, Span)> = None;
|
||||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||||
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
||||||
let mut promotable = false;
|
let mut promotable = false;
|
||||||
let mut allowed_through_unstable_modules = false;
|
let mut allowed_through_unstable_modules = false;
|
||||||
|
|
||||||
'outer: for attr in attrs_iter {
|
for attr in attrs_iter {
|
||||||
if ![
|
if ![
|
||||||
sym::rustc_const_unstable,
|
sym::rustc_const_unstable,
|
||||||
sym::rustc_const_stable,
|
sym::rustc_const_stable,
|
||||||
|
@ -275,27 +273,7 @@ where
|
||||||
promotable = true;
|
promotable = true;
|
||||||
} else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
|
} else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
|
||||||
allowed_through_unstable_modules = true;
|
allowed_through_unstable_modules = true;
|
||||||
}
|
} else if let Some(meta) = &meta {
|
||||||
// attributes with data
|
|
||||||
else if let Some(meta @ MetaItem { kind: MetaItemKind::List(metas), .. }) = &meta {
|
|
||||||
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)),
|
|
||||||
);
|
|
||||||
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 meta_name = meta.name_or_empty();
|
let meta_name = meta.name_or_empty();
|
||||||
match meta_name {
|
match meta_name {
|
||||||
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
|
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
|
||||||
|
@ -322,122 +300,18 @@ where
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut feature = None;
|
if let Some((feature, level)) = parse_unstability(sess, attr) {
|
||||||
let mut reason = None;
|
if sym::unstable == meta_name {
|
||||||
let mut issue = None;
|
stab = Some((Stability { level, feature }, attr.span));
|
||||||
let mut issue_num = None;
|
} else if sym::rustc_const_unstable == meta_name {
|
||||||
let mut is_soft = false;
|
const_stab = Some((
|
||||||
let mut implied_by = None;
|
ConstStability { level, feature, promotable: false },
|
||||||
for meta in metas {
|
attr.span,
|
||||||
let Some(mi) = meta.meta_item() else {
|
));
|
||||||
handle_errors(
|
} else if sym::rustc_default_body_unstable == meta_name {
|
||||||
&sess.parse_sess,
|
body_stab = Some((DefaultBodyStability { level, feature }, attr.span));
|
||||||
meta.span(),
|
} else {
|
||||||
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
unreachable!("Unknown stability attribute {meta_name}");
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
};
|
|
||||||
match mi.name_or_empty() {
|
|
||||||
sym::feature => {
|
|
||||||
if !get(mi, &mut feature) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::reason => {
|
|
||||||
if !get(mi, &mut reason) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::issue => {
|
|
||||||
if !get(mi, &mut issue) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These unwraps are safe because `get` ensures the meta item
|
|
||||||
// is a name/value pair string literal.
|
|
||||||
issue_num = match issue.unwrap().as_str() {
|
|
||||||
"none" => None,
|
|
||||||
issue => match issue.parse::<NonZeroU32>() {
|
|
||||||
Ok(num) => Some(num),
|
|
||||||
Err(err) => {
|
|
||||||
sess.emit_err(
|
|
||||||
session_diagnostics::InvalidIssueString {
|
|
||||||
span: mi.span,
|
|
||||||
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
|
||||||
mi.name_value_literal_span().unwrap(),
|
|
||||||
err.kind(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
sym::soft => {
|
|
||||||
if !mi.is_word() {
|
|
||||||
sess.emit_err(session_diagnostics::SoftNoArgs {
|
|
||||||
span: mi.span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
is_soft = true;
|
|
||||||
}
|
|
||||||
sym::implied_by => {
|
|
||||||
if !get(mi, &mut implied_by) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span(),
|
|
||||||
AttrError::UnknownMetaItem(
|
|
||||||
pprust::path_to_string(&mi.path),
|
|
||||||
&["feature", "reason", "issue", "soft"],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let level = Unstable {
|
|
||||||
reason: UnstableReason::from_opt_reason(reason),
|
|
||||||
issue: issue_num,
|
|
||||||
is_soft,
|
|
||||||
implied_by,
|
|
||||||
};
|
|
||||||
if sym::unstable == meta_name {
|
|
||||||
stab = Some((Stability { level, feature }, attr.span));
|
|
||||||
} else if sym::rustc_const_unstable == meta_name {
|
|
||||||
const_stab = Some((
|
|
||||||
ConstStability { level, feature, promotable: false },
|
|
||||||
attr.span,
|
|
||||||
));
|
|
||||||
} else if sym::rustc_default_body_unstable == meta_name {
|
|
||||||
body_stab =
|
|
||||||
Some((DefaultBodyStability { level, feature }, attr.span));
|
|
||||||
} else {
|
|
||||||
unreachable!("Unknown stability attribute {meta_name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, _, _) => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,71 +331,14 @@ where
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||||
let mut feature = None;
|
if sym::stable == meta_name {
|
||||||
let mut since = None;
|
stab = Some((Stability { level, feature }, attr.span));
|
||||||
for meta in metas {
|
} else {
|
||||||
match meta {
|
const_stab = Some((
|
||||||
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
|
ConstStability { level, feature, promotable: false },
|
||||||
sym::feature => {
|
attr.span,
|
||||||
if !get(mi, &mut feature) {
|
));
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::since => {
|
|
||||||
if !get(mi, &mut since) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span(),
|
|
||||||
AttrError::UnknownMetaItem(
|
|
||||||
pprust::path_to_string(&mi.path),
|
|
||||||
&["feature", "since"],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NestedMetaItem::Lit(lit) => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
lit.span,
|
|
||||||
AttrError::UnsupportedLiteral(
|
|
||||||
UnsupportedLiteralReason::Generic,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
|
||||||
since = Some(rust_version_symbol());
|
|
||||||
}
|
|
||||||
|
|
||||||
match (feature, since) {
|
|
||||||
(Some(feature), Some(since)) => {
|
|
||||||
let level = Stable { since, allowed_through_unstable_modules: false };
|
|
||||||
if sym::stable == meta_name {
|
|
||||||
stab = Some((Stability { level, feature }, attr.span));
|
|
||||||
} else {
|
|
||||||
const_stab = Some((
|
|
||||||
ConstStability { level, feature, promotable: false },
|
|
||||||
attr.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, _) => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,6 +373,208 @@ where
|
||||||
(stab, const_stab, body_stab)
|
(stab, const_stab, body_stab)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = |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),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
match mi.name_or_empty() {
|
||||||
|
sym::feature => {
|
||||||
|
if !insert(mi, &mut feature) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::since => {
|
||||||
|
if !insert(mi, &mut since) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnknownMetaItem(
|
||||||
|
pprust::path_to_string(&mi.path),
|
||||||
|
&["feature", "since"],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
||||||
|
since = Some(rust_version_symbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
match (feature, since) {
|
||||||
|
(Some(feature), Some(since)) => {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = |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;
|
||||||
|
let mut issue = None;
|
||||||
|
let mut issue_num = None;
|
||||||
|
let mut is_soft = false;
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
match mi.name_or_empty() {
|
||||||
|
sym::feature => {
|
||||||
|
if !insert(mi, &mut feature) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::reason => {
|
||||||
|
if !insert(mi, &mut reason) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::issue => {
|
||||||
|
if !insert(mi, &mut issue) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These unwraps are safe because `insert` ensures the meta item
|
||||||
|
// is a name/value pair string literal.
|
||||||
|
issue_num = match issue.unwrap().as_str() {
|
||||||
|
"none" => None,
|
||||||
|
issue => match issue.parse::<NonZeroU32>() {
|
||||||
|
Ok(num) => Some(num),
|
||||||
|
Err(err) => {
|
||||||
|
sess.emit_err(
|
||||||
|
session_diagnostics::InvalidIssueString {
|
||||||
|
span: mi.span,
|
||||||
|
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
||||||
|
mi.name_value_literal_span().unwrap(),
|
||||||
|
err.kind(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
sym::soft => {
|
||||||
|
if !mi.is_word() {
|
||||||
|
sess.emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
|
||||||
|
}
|
||||||
|
is_soft = true;
|
||||||
|
}
|
||||||
|
sym::implied_by => {
|
||||||
|
if !insert(mi, &mut implied_by) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnknownMetaItem(
|
||||||
|
pprust::path_to_string(&mi.path),
|
||||||
|
&["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 level = StabilityLevel::Unstable {
|
||||||
|
reason: UnstableReason::from_opt_reason(reason),
|
||||||
|
issue: issue_num,
|
||||||
|
is_soft,
|
||||||
|
implied_by,
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
||||||
attr::first_attr_value_str_by_name(attrs, sym::crate_name)
|
attr::first_attr_value_str_by_name(attrs, sym::crate_name)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue