summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_attr
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr')
-rw-r--r--compiler/rustc_attr/src/builtin.rs398
-rw-r--r--compiler/rustc_attr/src/lib.rs5
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs398
3 files changed, 570 insertions, 231 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 10a9cfb62..753f62dd5 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -3,7 +3,6 @@
use rustc_ast as ast;
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability};
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
@@ -14,6 +13,20 @@ use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
+use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
+
+/// The version placeholder that recently stabilized features contain inside the
+/// `since` field of the `#[stable]` attribute.
+///
+/// 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_VERSION").unwrap_or("<current>");
+ let version = version.split(' ').next().unwrap();
+ Symbol::intern(&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()
}
@@ -25,46 +38,43 @@ enum AttrError {
NonIdentFeature,
MissingFeature,
MultipleStabilityLevels,
- UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
+ UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
+}
+
+pub(crate) enum UnsupportedLiteralReason {
+ Generic,
+ CfgString,
+ DeprecatedString,
+ DeprecatedKvPair,
}
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
- let diag = &sess.span_diagnostic;
match error {
AttrError::MultipleItem(item) => {
- struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
+ sess.emit_err(session_diagnostics::MultipleItem { span, item });
}
AttrError::UnknownMetaItem(item, expected) => {
- let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
- struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
- .span_label(span, format!("expected one of {}", expected.join(", ")))
- .emit();
+ sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
}
AttrError::MissingSince => {
- struct_span_err!(diag, span, E0542, "missing 'since'").emit();
+ sess.emit_err(session_diagnostics::MissingSince { span });
}
AttrError::NonIdentFeature => {
- struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
+ sess.emit_err(session_diagnostics::NonIdentFeature { span });
}
AttrError::MissingFeature => {
- struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
+ sess.emit_err(session_diagnostics::MissingFeature { span });
}
AttrError::MultipleStabilityLevels => {
- struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
+ sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
}
- AttrError::UnsupportedLiteral(msg, is_bytestr) => {
- let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
- if is_bytestr {
- if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
- err.span_suggestion(
- span,
- "consider removing the prefix",
- &lint_str[1..],
- Applicability::MaybeIncorrect,
- );
- }
- }
- err.emit();
+ AttrError::UnsupportedLiteral(reason, is_bytestr) => {
+ sess.emit_err(session_diagnostics::UnsupportedLiteral {
+ span,
+ reason,
+ is_bytestr,
+ start_point_span: sess.source_map().start_point(span),
+ });
}
}
}
@@ -131,6 +141,14 @@ impl ConstStability {
}
}
+/// Represents the `#[rustc_default_body_unstable]` attribute.
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub struct DefaultBodyStability {
+ pub level: StabilityLevel,
+ pub feature: Symbol,
+}
+
/// The available stability levels.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
@@ -214,7 +232,8 @@ pub fn find_stability(
sess: &Session,
attrs: &[Attribute],
item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
+{
find_stability_generic(sess, attrs.iter(), item_sp)
}
@@ -222,7 +241,7 @@ fn find_stability_generic<'a, I>(
sess: &Session,
attrs_iter: I,
item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
where
I: Iterator<Item = &'a Attribute>,
{
@@ -230,11 +249,10 @@ where
let mut stab: Option<(Stability, Span)> = None;
let mut const_stab: Option<(ConstStability, Span)> = None;
+ let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
let mut promotable = false;
let mut allowed_through_unstable_modules = false;
- let diagnostic = &sess.parse_sess.span_diagnostic;
-
'outer: for attr in attrs_iter {
if ![
sym::rustc_const_unstable,
@@ -243,6 +261,7 @@ where
sym::stable,
sym::rustc_promotable,
sym::rustc_allowed_through_unstable_modules,
+ sym::rustc_default_body_unstable,
]
.iter()
.any(|&s| attr.has_name(s))
@@ -273,14 +292,14 @@ where
*item = Some(v);
true
} else {
- struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit();
+ sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
false
}
};
let meta_name = meta.name_or_empty();
match meta_name {
- sym::rustc_const_unstable | sym::unstable => {
+ sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
handle_errors(
&sess.parse_sess,
@@ -295,6 +314,13 @@ where
AttrError::MultipleStabilityLevels,
);
break;
+ } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
+ break;
}
let mut feature = None;
@@ -308,7 +334,7 @@ where
handle_errors(
&sess.parse_sess,
meta.span(),
- AttrError::UnsupportedLiteral("unsupported literal", false),
+ AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
);
continue 'outer;
};
@@ -332,39 +358,28 @@ where
// is a name/value pair string literal.
issue_num = match issue.unwrap().as_str() {
"none" => None,
- issue => {
- let emit_diag = |msg: &str| {
- struct_span_err!(
- diagnostic,
- mi.span,
- E0545,
- "`issue` must be a non-zero numeric string \
- or \"none\"",
- )
- .span_label(mi.name_value_literal_span().unwrap(), msg)
- .emit();
- };
- match issue.parse() {
- Ok(0) => {
- emit_diag(
- "`issue` must not be \"0\", \
- use \"none\" instead",
- );
- continue 'outer;
- }
- Ok(num) => NonZeroU32::new(num),
- Err(err) => {
- emit_diag(&err.to_string());
- continue 'outer;
- }
+ 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() {
- let msg = "`soft` should not have any arguments";
- sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
+ sess.emit_err(session_diagnostics::SoftNoArgs {
+ span: mi.span,
+ });
}
is_soft = true;
}
@@ -405,11 +420,16 @@ where
};
if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span));
- } else {
+ } 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, _, _) => {
@@ -417,8 +437,7 @@ where
continue;
}
_ => {
- struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'")
- .emit();
+ sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
continue;
}
}
@@ -471,13 +490,20 @@ where
handle_errors(
&sess.parse_sess,
lit.span,
- AttrError::UnsupportedLiteral("unsupported literal", false),
+ 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 };
@@ -510,14 +536,7 @@ where
if let Some((ref mut stab, _)) = const_stab {
stab.promotable = promotable;
} else {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0717,
- "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \
- or a `rustc_const_stable` attribute"
- )
- .emit();
+ sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp });
}
}
@@ -532,17 +551,11 @@ where
{
*allowed_through_unstable_modules = true;
} else {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0789,
- "`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute"
- )
- .emit();
+ sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
}
}
- (stab, const_stab)
+ (stab, const_stab, body_stab)
}
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
@@ -652,25 +665,18 @@ pub fn eval_condition(
NestedMetaItem::Literal(Lit { span, .. })
| NestedMetaItem::MetaItem(MetaItem { span, .. }),
] => {
- sess.span_diagnostic
- .struct_span_err(*span, "expected a version literal")
- .emit();
+ sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
return false;
}
[..] => {
- sess.span_diagnostic
- .struct_span_err(cfg.span, "expected single version literal")
- .emit();
+ sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
+ span: cfg.span,
+ });
return false;
}
};
let Some(min_version) = parse_version(min_version.as_str(), false) else {
- sess.span_diagnostic
- .struct_span_warn(
- *span,
- "unknown version literal format, assuming it refers to a future version",
- )
- .emit();
+ sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
return false;
};
let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
@@ -688,7 +694,7 @@ pub fn eval_condition(
handle_errors(
sess,
mi.span(),
- AttrError::UnsupportedLiteral("unsupported literal", false),
+ AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
);
return false;
}
@@ -713,13 +719,9 @@ pub fn eval_condition(
}),
sym::not => {
if mis.len() != 1 {
- struct_span_err!(
- sess.span_diagnostic,
- cfg.span,
- E0536,
- "expected 1 cfg-pattern"
- )
- .emit();
+ sess.emit_err(session_diagnostics::ExpectedOneCfgPattern {
+ span: cfg.span,
+ });
return false;
}
@@ -745,21 +747,16 @@ pub fn eval_condition(
})
}
_ => {
- struct_span_err!(
- sess.span_diagnostic,
- cfg.span,
- E0537,
- "invalid predicate `{}`",
- pprust::path_to_string(&cfg.path)
- )
- .emit();
+ sess.emit_err(session_diagnostics::InvalidPredicate {
+ span: cfg.span,
+ predicate: pprust::path_to_string(&cfg.path),
+ });
false
}
}
}
ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
- sess.span_diagnostic
- .span_err(cfg.path.span, "`cfg` predicate key must be an identifier");
+ sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
true
}
MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
@@ -767,7 +764,7 @@ pub fn eval_condition(
sess,
lit.span,
AttrError::UnsupportedLiteral(
- "literal in `cfg` predicate value must be a string",
+ UnsupportedLiteralReason::CfgString,
lit.kind.is_bytestr(),
),
);
@@ -811,7 +808,6 @@ where
I: Iterator<Item = &'a Attribute>,
{
let mut depr: Option<(Deprecation, Span)> = None;
- let diagnostic = &sess.parse_sess.span_diagnostic;
let is_rustc = sess.features_untracked().staged_api;
'outer: for attr in attrs_iter {
@@ -847,14 +843,14 @@ where
&sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral(
- "literal in `deprecated` \
- value must be a string",
+ UnsupportedLiteralReason::DeprecatedString,
lit.kind.is_bytestr(),
),
);
} else {
- struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item")
- .emit();
+ sess.emit_err(session_diagnostics::IncorrectMetaItem2 {
+ span: meta.span,
+ });
}
false
@@ -876,14 +872,11 @@ where
}
sym::suggestion => {
if !sess.features_untracked().deprecated_suggestion {
- let mut diag = sess.struct_span_err(
- mi.span,
- "suggestions on deprecated items are unstable",
- );
- if sess.is_nightly_build() {
- diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
- }
- diag.note("see #94785 for more details").emit();
+ sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
+ span: mi.span,
+ is_nightly: sess.is_nightly_build().then_some(()),
+ details: (),
+ });
}
if !get(mi, &mut suggestion) {
@@ -911,7 +904,7 @@ where
&sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral(
- "item in `deprecated` must be a key/value pair",
+ UnsupportedLiteralReason::DeprecatedKvPair,
false,
),
);
@@ -929,7 +922,7 @@ where
}
if note.is_none() {
- struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
+ sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
continue;
}
}
@@ -999,19 +992,9 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent),
sym::align => {
- let mut err = struct_span_err!(
- diagnostic,
- item.span(),
- E0589,
- "invalid `repr(align)` attribute: `align` needs an argument"
- );
- err.span_suggestion(
- item.span(),
- "supply an argument here",
- "align(...)",
- Applicability::HasPlaceholders,
- );
- err.emit();
+ sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg {
+ span: item.span(),
+ });
recognised = true;
None
}
@@ -1040,109 +1023,64 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|| int_type_of_word(name).is_some()
{
recognised = true;
- struct_span_err!(
- diagnostic,
- item.span(),
- E0552,
- "invalid representation hint: `{}` does not take a parenthesized argument list",
- name.to_ident_string(),
- ).emit();
+ sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
+ span: item.span(),
+ name: name.to_ident_string(),
+ });
}
if let Some(literal_error) = literal_error {
- struct_span_err!(
- diagnostic,
- item.span(),
- E0589,
- "invalid `repr({})` attribute: {}",
- name.to_ident_string(),
- literal_error
- )
- .emit();
+ sess.emit_err(session_diagnostics::InvalidReprGeneric {
+ span: item.span(),
+ repr_arg: name.to_ident_string(),
+ error_part: literal_error,
+ });
}
} else if let Some(meta_item) = item.meta_item() {
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
let name = meta_item.name_or_empty().to_ident_string();
recognised = true;
- let mut err = struct_span_err!(
- diagnostic,
- item.span(),
- E0693,
- "incorrect `repr({})` attribute format",
- name,
- );
- match value.kind {
- ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
- err.span_suggestion(
- item.span(),
- "use parentheses instead",
- format!("{}({})", name, int),
- Applicability::MachineApplicable,
- );
- }
- ast::LitKind::Str(s, _) => {
- err.span_suggestion(
- item.span(),
- "use parentheses instead",
- format!("{}({})", name, s),
- Applicability::MachineApplicable,
- );
- }
- _ => {}
- }
- err.emit();
- } else {
- if matches!(
- meta_item.name_or_empty(),
- sym::C | sym::simd | sym::transparent
- ) || int_type_of_word(meta_item.name_or_empty()).is_some()
- {
- recognised = true;
- struct_span_err!(
- diagnostic,
- meta_item.span,
- E0552,
- "invalid representation hint: `{}` does not take a value",
- meta_item.name_or_empty().to_ident_string(),
- )
- .emit();
- }
+ sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
+ span: item.span(),
+ repr_arg: &name,
+ cause: IncorrectReprFormatGenericCause::from_lit_kind(
+ item.span(),
+ &value.kind,
+ &name,
+ ),
+ });
+ } else if matches!(
+ meta_item.name_or_empty(),
+ sym::C | sym::simd | sym::transparent
+ ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+ {
+ recognised = true;
+ sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+ span: meta_item.span,
+ name: meta_item.name_or_empty().to_ident_string(),
+ });
}
} else if let MetaItemKind::List(_) = meta_item.kind {
if meta_item.has_name(sym::align) {
recognised = true;
- struct_span_err!(
- diagnostic,
- meta_item.span,
- E0693,
- "incorrect `repr(align)` attribute format: \
- `align` takes exactly one argument in parentheses"
- )
- .emit();
+ sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
+ span: meta_item.span,
+ });
} else if meta_item.has_name(sym::packed) {
recognised = true;
- struct_span_err!(
- diagnostic,
- meta_item.span,
- E0552,
- "incorrect `repr(packed)` attribute format: \
- `packed` takes exactly one parenthesized argument, \
- or no parentheses at all"
- )
- .emit();
+ sess.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
+ span: meta_item.span,
+ });
} else if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
- struct_span_err!(
- diagnostic,
- meta_item.span,
- E0552,
- "invalid representation hint: `{}` does not take a parenthesized argument list",
- meta_item.name_or_empty().to_ident_string(),
- ).emit();
+ sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
+ span: meta_item.span,
+ name: meta_item.name_or_empty().to_ident_string(),
+ });
}
}
}
@@ -1239,10 +1177,10 @@ fn allow_unstable<'a>(
let list = attrs
.filter_map(move |attr| {
attr.meta_item_list().or_else(|| {
- sess.diagnostic().span_err(
- attr.span,
- &format!("`{}` expects a list of feature names", symbol.to_ident_string()),
- );
+ sess.emit_err(session_diagnostics::ExpectsFeatureList {
+ span: attr.span,
+ name: symbol.to_ident_string(),
+ });
None
})
})
@@ -1251,10 +1189,10 @@ fn allow_unstable<'a>(
list.into_iter().filter_map(move |it| {
let name = it.ident().map(|ident| ident.name);
if name.is_none() {
- sess.diagnostic().span_err(
- it.span(),
- &format!("`{}` expects feature names", symbol.to_ident_string()),
- );
+ sess.emit_err(session_diagnostics::ExpectsFeatures {
+ span: it.span(),
+ name: symbol.to_ident_string(),
+ });
}
name
})
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index c3f9f0cf3..52e65a9c7 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -5,12 +5,15 @@
//! to this crate.
#![feature(let_chains)]
-#![feature(let_else)]
+#![cfg_attr(bootstrap, feature(let_else))]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
extern crate rustc_macros;
mod builtin;
+mod session_diagnostics;
pub use builtin::*;
pub use IntType::*;
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
new file mode 100644
index 000000000..085175d4b
--- /dev/null
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -0,0 +1,398 @@
+use std::num::IntErrorKind;
+
+use rustc_ast as ast;
+use rustc_errors::{
+ error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler,
+};
+use rustc_macros::SessionDiagnostic;
+use rustc_session::SessionDiagnostic;
+use rustc_span::{Span, Symbol};
+
+use crate::UnsupportedLiteralReason;
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::expected_one_cfg_pattern, code = "E0536")]
+pub(crate) struct ExpectedOneCfgPattern {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_predicate, code = "E0537")]
+pub(crate) struct InvalidPredicate {
+ #[primary_span]
+ pub span: Span,
+
+ pub predicate: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::multiple_item, code = "E0538")]
+pub(crate) struct MultipleItem {
+ #[primary_span]
+ pub span: Span,
+
+ pub item: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::incorrect_meta_item, code = "E0539")]
+pub(crate) struct IncorrectMetaItem {
+ #[primary_span]
+ pub span: Span,
+}
+
+// Error code: E0541
+pub(crate) struct UnknownMetaItem<'a> {
+ pub span: Span,
+ pub item: String,
+ pub expected: &'a [&'a str],
+}
+
+// Manual implementation to be able to format `expected` items correctly.
+impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
+ let mut diag = handler.struct_span_err_with_code(
+ self.span,
+ fluent::attr::unknown_meta_item,
+ error_code!(E0541),
+ );
+ diag.set_arg("item", self.item);
+ diag.set_arg("expected", expected.join(", "));
+ diag.span_label(self.span, fluent::attr::label);
+ diag
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::missing_since, code = "E0542")]
+pub(crate) struct MissingSince {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::missing_note, code = "E0543")]
+pub(crate) struct MissingNote {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::multiple_stability_levels, code = "E0544")]
+pub(crate) struct MultipleStabilityLevels {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_issue_string, code = "E0545")]
+pub(crate) struct InvalidIssueString {
+ #[primary_span]
+ pub span: Span,
+
+ #[subdiagnostic]
+ pub cause: Option<InvalidIssueStringCause>,
+}
+
+// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
+// translatable.
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidIssueStringCause {
+ #[label(attr::must_not_be_zero)]
+ MustNotBeZero {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(attr::empty)]
+ Empty {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(attr::invalid_digit)]
+ InvalidDigit {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(attr::pos_overflow)]
+ PosOverflow {
+ #[primary_span]
+ span: Span,
+ },
+
+ #[label(attr::neg_overflow)]
+ NegOverflow {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+impl InvalidIssueStringCause {
+ pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
+ match kind {
+ IntErrorKind::Empty => Some(Self::Empty { span }),
+ IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
+ IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
+ IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
+ IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
+ _ => None,
+ }
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::missing_feature, code = "E0546")]
+pub(crate) struct MissingFeature {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::non_ident_feature, code = "E0546")]
+pub(crate) struct NonIdentFeature {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::missing_issue, code = "E0547")]
+pub(crate) struct MissingIssue {
+ #[primary_span]
+ pub span: Span,
+}
+
+// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider
+// changing this to `IncorrectMetaItem`. See #51489.
+#[derive(SessionDiagnostic)]
+#[diag(attr::incorrect_meta_item, code = "E0551")]
+pub(crate) struct IncorrectMetaItem2 {
+ #[primary_span]
+ pub span: Span,
+}
+
+// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
+// It is more similar to `IncorrectReprFormatGeneric`.
+#[derive(SessionDiagnostic)]
+#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
+pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")]
+pub(crate) struct InvalidReprHintNoParen {
+ #[primary_span]
+ pub span: Span,
+
+ pub name: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_repr_hint_no_value, code = "E0552")]
+pub(crate) struct InvalidReprHintNoValue {
+ #[primary_span]
+ pub span: Span,
+
+ pub name: String,
+}
+
+// Error code: E0565
+pub(crate) struct UnsupportedLiteral {
+ pub span: Span,
+ pub reason: UnsupportedLiteralReason,
+ pub is_bytestr: bool,
+ pub start_point_span: Span,
+}
+
+impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ let mut diag = handler.struct_span_err_with_code(
+ self.span,
+ match self.reason {
+ UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
+ UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
+ UnsupportedLiteralReason::DeprecatedString => {
+ fluent::attr::unsupported_literal_deprecated_string
+ }
+ UnsupportedLiteralReason::DeprecatedKvPair => {
+ fluent::attr::unsupported_literal_deprecated_kv_pair
+ }
+ },
+ error_code!(E0565),
+ );
+ if self.is_bytestr {
+ diag.span_suggestion(
+ self.start_point_span,
+ fluent::attr::unsupported_literal_suggestion,
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_repr_align_need_arg, code = "E0589")]
+pub(crate) struct InvalidReprAlignNeedArg {
+ #[primary_span]
+ #[suggestion(code = "align(...)", applicability = "has-placeholders")]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::invalid_repr_generic, code = "E0589")]
+pub(crate) struct InvalidReprGeneric<'a> {
+ #[primary_span]
+ pub span: Span,
+
+ pub repr_arg: String,
+ pub error_part: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")]
+pub(crate) struct IncorrectReprFormatAlignOneArg {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::incorrect_repr_format_generic, code = "E0693")]
+pub(crate) struct IncorrectReprFormatGeneric<'a> {
+ #[primary_span]
+ pub span: Span,
+
+ pub repr_arg: &'a str,
+
+ #[subdiagnostic]
+ pub cause: Option<IncorrectReprFormatGenericCause<'a>>,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum IncorrectReprFormatGenericCause<'a> {
+ #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")]
+ Int {
+ #[primary_span]
+ span: Span,
+
+ #[skip_arg]
+ name: &'a str,
+
+ #[skip_arg]
+ int: u128,
+ },
+
+ #[suggestion(
+ attr::suggestion,
+ code = "{name}({symbol})",
+ applicability = "machine-applicable"
+ )]
+ Symbol {
+ #[primary_span]
+ span: Span,
+
+ #[skip_arg]
+ name: &'a str,
+
+ #[skip_arg]
+ symbol: Symbol,
+ },
+}
+
+impl<'a> IncorrectReprFormatGenericCause<'a> {
+ pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option<Self> {
+ match kind {
+ ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
+ Some(Self::Int { span, name, int: *int })
+ }
+ ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }),
+ _ => None,
+ }
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::rustc_promotable_pairing, code = "E0717")]
+pub(crate) struct RustcPromotablePairing {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")]
+pub(crate) struct RustcAllowedUnstablePairing {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::cfg_predicate_identifier)]
+pub(crate) struct CfgPredicateIdentifier {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::deprecated_item_suggestion)]
+pub(crate) struct DeprecatedItemSuggestion {
+ #[primary_span]
+ pub span: Span,
+
+ #[help]
+ pub is_nightly: Option<()>,
+
+ #[note]
+ pub details: (),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::expected_single_version_literal)]
+pub(crate) struct ExpectedSingleVersionLiteral {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::expected_version_literal)]
+pub(crate) struct ExpectedVersionLiteral {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::expects_feature_list)]
+pub(crate) struct ExpectsFeatureList {
+ #[primary_span]
+ pub span: Span,
+
+ pub name: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::expects_features)]
+pub(crate) struct ExpectsFeatures {
+ #[primary_span]
+ pub span: Span,
+
+ pub name: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::soft_no_args)]
+pub(crate) struct SoftNoArgs {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(attr::unknown_version_literal)]
+pub(crate) struct UnknownVersionLiteral {
+ #[primary_span]
+ pub span: Span,
+}