Rollup merge of #100836 - hampuslidin:migrate-attr-crate-diagnostics, r=davidtwco

Migrate `rustc_attr` crate diagnostics

Hi!

This is my first PR to the rustc project, excited to be part of the development! This PR is part of the diagnostics effort, to make diagnostics translatable.

`@rustbot` label +A-translation
This commit is contained in:
Michael Goulet 2022-08-26 15:56:28 -07:00 committed by GitHub
commit d97e616e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 621 additions and 217 deletions

View File

@ -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,8 @@ use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
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 +26,38 @@ 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 });
}
}
}
@ -243,8 +236,6 @@ where
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,
@ -284,7 +275,7 @@ 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
}
};
@ -326,7 +317,7 @@ where
handle_errors(
&sess.parse_sess,
meta.span(),
AttrError::UnsupportedLiteral("unsupported literal", false),
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
);
continue 'outer;
};
@ -350,39 +341,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;
}
@ -440,8 +420,7 @@ where
continue;
}
_ => {
struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'")
.emit();
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
continue;
}
}
@ -494,7 +473,10 @@ where
handle_errors(
&sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral("unsupported literal", false),
AttrError::UnsupportedLiteral(
UnsupportedLiteralReason::Generic,
false,
),
);
continue 'outer;
}
@ -533,14 +515,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 });
}
}
@ -555,13 +530,7 @@ 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 });
}
}
@ -675,25 +644,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();
@ -711,7 +673,7 @@ pub fn eval_condition(
handle_errors(
sess,
mi.span(),
AttrError::UnsupportedLiteral("unsupported literal", false),
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
);
return false;
}
@ -736,13 +698,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;
}
@ -768,21 +726,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() => {
@ -790,7 +743,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(),
),
);
@ -834,7 +787,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 {
@ -870,14 +822,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
@ -899,14 +851,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) {
@ -934,7 +883,7 @@ where
&sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral(
"item in `deprecated` must be a key/value pair",
UnsupportedLiteralReason::DeprecatedKvPair,
false,
),
);
@ -952,7 +901,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;
}
}
@ -1022,19 +971,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
}
@ -1063,57 +1002,32 @@ 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();
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(),
@ -1121,51 +1035,33 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
) || 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::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(),
});
}
}
}
@ -1262,10 +1158,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
})
})
@ -1274,10 +1170,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
})

View File

@ -5,11 +5,14 @@
//! to this crate.
#![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::*;

View File

@ -0,0 +1,397 @@
use std::num::IntErrorKind;
use rustc_ast as ast;
use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_macros::SessionDiagnostic;
use rustc_session::{parse::ParseSess, 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, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
let mut diag = sess.span_diagnostic.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,
}
impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = sess.span_diagnostic.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 {
if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) {
diag.span_suggestion(
self.span,
fluent::attr::unsupported_literal_suggestion,
&lint_str[1..],
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,
}

View File

@ -0,0 +1,107 @@
attr_expected_one_cfg_pattern =
expected 1 cfg-pattern
attr_invalid_predicate =
invalid predicate `{$predicate}`
attr_multiple_item =
multiple '{$item}' items
attr_incorrect_meta_item =
incorrect meta item
attr_unknown_meta_item =
unknown meta item '{$item}'
.label = expected one of {$expected}
attr_missing_since =
missing 'since'
attr_missing_note =
missing 'note'
attr_multiple_stability_levels =
multiple stability levels
attr_invalid_issue_string =
`issue` must be a non-zero numeric string or "none"
.must_not_be_zero = `issue` must not be "0", use "none" instead
.empty = cannot parse integer from empty string
.invalid_digit = invalid digit found in string
.pos_overflow = number too large to fit in target type
.neg_overflow = number too small to fit in target type
attr_missing_feature =
missing 'feature'
attr_non_ident_feature =
'feature' is not an identifier
attr_missing_issue =
missing 'issue'
attr_incorrect_repr_format_packed_one_or_zero_arg =
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
attr_invalid_repr_hint_no_paren =
invalid representation hint: `{$name}` does not take a parenthesized argument list
attr_invalid_repr_hint_no_value =
invalid representation hint: `{$name}` does not take a value
attr_unsupported_literal_generic =
unsupported literal
attr_unsupported_literal_cfg_string =
literal in `cfg` predicate value must be a string
attr_unsupported_literal_deprecated_string =
literal in `deprecated` value must be a string
attr_unsupported_literal_deprecated_kv_pair =
item in `deprecated` must be a key/value pair
attr_unsupported_literal_suggestion =
consider removing the prefix
attr_invalid_repr_align_need_arg =
invalid `repr(align)` attribute: `align` needs an argument
.suggestion = supply an argument here
attr_invalid_repr_generic =
invalid `repr({$repr_arg})` attribute: {$error_part}
attr_incorrect_repr_format_align_one_arg =
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
attr_incorrect_repr_format_generic =
incorrect `repr({$repr_arg})` attribute format
.suggestion = use parentheses instead
attr_rustc_promotable_pairing =
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
attr_rustc_allowed_unstable_pairing =
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
attr_cfg_predicate_identifier =
`cfg` predicate key must be an identifier
attr_deprecated_item_suggestion =
suggestions on deprecated items are unstable
.help = add `#![feature(deprecated_suggestion)]` to the crate root
.note = see #94785 for more details
attr_expected_single_version_literal =
expected single version literal
attr_expected_version_literal =
expected a version literal
attr_expects_feature_list =
`{$name}` expects a list of feature names
attr_expects_features =
`{$name}` expects feature names
attr_soft_no_args =
`soft` should not have any arguments
attr_unknown_version_literal =
unknown version literal format, assuming it refers to a future version

View File

@ -34,6 +34,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
fluent_messages! {
ast_lowering => "../locales/en-US/ast_lowering.ftl",
ast_passes => "../locales/en-US/ast_passes.ftl",
attr => "../locales/en-US/attr.ftl",
borrowck => "../locales/en-US/borrowck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
const_eval => "../locales/en-US/const_eval.ftl",