mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Migrate most of rustc_builtin_macros
to diagnostic impls
Co-authored-by: Joe ST <joe@fbstj.net> Co-authored-by: Michael Goulet <michael@errs.io>
This commit is contained in:
parent
b6f6104a1f
commit
64f7597776
@ -3,3 +3,149 @@ builtin_macros_requires_cfg_pattern =
|
||||
.label = cfg-pattern required
|
||||
|
||||
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
|
||||
|
||||
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
|
||||
|
||||
builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
|
||||
.label = boolean expression required
|
||||
|
||||
builtin_macros_assert_requires_expression = macro requires an expression as an argument
|
||||
.suggestion = try removing semicolon
|
||||
|
||||
builtin_macros_assert_missing_comma = unexpected string literal
|
||||
.suggestion = try adding a comma
|
||||
|
||||
builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
|
||||
builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
|
||||
builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
|
||||
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
|
||||
|
||||
builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not
|
||||
|
||||
builtin_macros_concat_bytestr = cannot concatenate a byte string literal
|
||||
|
||||
builtin_macros_concat_missing_literal = expected a literal
|
||||
.note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
|
||||
|
||||
builtin_macros_concat_bytes_missing_literal = expected a byte literal
|
||||
.note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
|
||||
.byte_char = try using a byte character
|
||||
.byte_str = try using a byte string
|
||||
.number_array = try wrapping the number in an array
|
||||
|
||||
builtin_macros_concat_bytes_oob = numeric literal is out of bounds
|
||||
|
||||
builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
|
||||
|
||||
builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
|
||||
.note = byte strings are treated as arrays of bytes
|
||||
.help = try flattening the array
|
||||
|
||||
builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
|
||||
|
||||
builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
|
||||
builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
|
||||
builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
|
||||
|
||||
builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
|
||||
.label = not applicable here
|
||||
.label2 = not a `struct`, `enum` or `union`
|
||||
|
||||
builtin_macros_unexpected_lit = expected path to a trait, found literal
|
||||
.label = not a trait
|
||||
.str_lit = try using `#[derive({$sym})]`
|
||||
.other = for example, write `#[derive(Debug)]` for `Debug`
|
||||
|
||||
builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments
|
||||
.suggestion = remove the arguments
|
||||
|
||||
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
|
||||
|
||||
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
|
||||
|
||||
builtin_macros_no_default_variant = no default declared
|
||||
.help = make a unit variant default by placing `#[default]` above it
|
||||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_multiple_defaults = multiple declared defaults
|
||||
.label = first default
|
||||
.additional = additional default
|
||||
.note = only one variant can be default
|
||||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
||||
.label = declared `#[non_exhaustive]` here
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
.label_again = `#[default]` used again here
|
||||
.help = try removing {$only_one ->
|
||||
[true] this
|
||||
*[false] these
|
||||
}
|
||||
|
||||
builtin_macros_default_arg = `#[default]` attribute does not accept a value
|
||||
.suggestion = try using `#[default]`
|
||||
|
||||
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
|
||||
.other = use `std::env::var("{$var}")` to read the variable at run time
|
||||
|
||||
builtin_macros_format_requires_string = requires at least a format string argument
|
||||
|
||||
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
|
||||
.label1 = previously here
|
||||
.label2 = duplicate argument
|
||||
|
||||
builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments
|
||||
.label = positional arguments must be before named arguments
|
||||
.named_args = named argument
|
||||
|
||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||
.label = {$label1} in format string
|
||||
.note = {$note}
|
||||
.second_label = {$label}
|
||||
|
||||
builtin_macros_sugg = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_format_no_arg_named = there is no argument named `{$name}`
|
||||
.note = did you intend to capture a variable `{$name}` from the surrounding scope?
|
||||
.note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
|
||||
|
||||
builtin_macros_format_unknown_trait = unknown format trait `{$ty}`
|
||||
.note = the only appropriate formatting traits are:
|
||||
- ``, which uses the `Display` trait
|
||||
- `?`, which uses the `Debug` trait
|
||||
- `e`, which uses the `LowerExp` trait
|
||||
- `E`, which uses the `UpperExp` trait
|
||||
- `o`, which uses the `Octal` trait
|
||||
- `p`, which uses the `Pointer` trait
|
||||
- `b`, which uses the `Binary` trait
|
||||
- `x`, which uses the `LowerHex` trait
|
||||
- `X`, which uses the `UpperHex` trait
|
||||
.suggestion = use the `{$trait_name}` trait
|
||||
|
||||
builtin_macros_format_unused_arg = {$named ->
|
||||
[true] named argument
|
||||
*[false] argument
|
||||
} never used
|
||||
|
||||
builtin_macros_format_unused_args = multiple unused formatting arguments
|
||||
.label = multiple missing formatting specifiers
|
||||
|
||||
builtin_macros_format_pos_mismatch = {$n} positional {$n ->
|
||||
[one] argument
|
||||
*[more] arguments
|
||||
} in format string, but {$desc}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::errors;
|
||||
use crate::util::check_builtin_macro_attribute;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
@ -31,7 +32,7 @@ pub fn expand(
|
||||
{
|
||||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else {
|
||||
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function");
|
||||
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
mod context;
|
||||
|
||||
use crate::edition_panic::use_panic_2021;
|
||||
use crate::errors;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, MacDelimiter, Path, PathSegment, UnOp};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
@ -114,9 +115,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
let mut parser = cx.new_parser_from_tts(stream);
|
||||
|
||||
if parser.token == token::Eof {
|
||||
let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument");
|
||||
err.span_label(sp, "boolean expression required");
|
||||
return Err(err);
|
||||
return Err(cx.create_err(errors::AssertRequiresBoolean { span: sp }));
|
||||
}
|
||||
|
||||
let cond_expr = parser.parse_expr()?;
|
||||
@ -129,15 +128,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
//
|
||||
// Emit an error about semicolon and suggest removing it.
|
||||
if parser.token == token::Semi {
|
||||
let mut err = cx.struct_span_err(sp, "macro requires an expression as an argument");
|
||||
err.span_suggestion(
|
||||
parser.token.span,
|
||||
"try removing semicolon",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
|
||||
cx.emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
|
||||
parser.bump();
|
||||
}
|
||||
|
||||
@ -149,15 +140,8 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
|
||||
// Emit an error and suggest inserting a comma.
|
||||
let custom_message =
|
||||
if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
|
||||
let mut err = cx.struct_span_err(parser.token.span, "unexpected string literal");
|
||||
let comma_span = parser.prev_token.span.shrink_to_hi();
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"try adding a comma",
|
||||
", ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
let comma = parser.prev_token.span.shrink_to_hi();
|
||||
cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
|
||||
|
||||
parse_custom_message(&mut parser)
|
||||
} else if parser.eat(&token::Comma) {
|
||||
|
@ -2,13 +2,13 @@
|
||||
//! a literal `true` or `false` based on whether the given cfg matches the
|
||||
//! current compilation environment.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr as attr;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub fn expand_cfg(
|
||||
@ -35,26 +35,11 @@ pub fn expand_cfg(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_requires_cfg_pattern)]
|
||||
struct RequiresCfgPattern {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_expected_one_cfg_pattern)]
|
||||
struct OneCfgPattern {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
||||
let mut p = cx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(cx.create_err(RequiresCfgPattern { span }));
|
||||
return Err(cx.create_err(errors::RequiresCfgPattern { span }));
|
||||
}
|
||||
|
||||
let cfg = p.parse_meta_item()?;
|
||||
@ -62,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
|
||||
let _ = p.eat(&token::Comma);
|
||||
|
||||
if !p.eat(&token::Eof) {
|
||||
return Err(cx.create_err(OneCfgPattern { span }));
|
||||
return Err(cx.create_err(errors::OneCfgPattern { span }));
|
||||
}
|
||||
|
||||
Ok(cfg)
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
@ -10,15 +11,22 @@ use rustc_span::Span;
|
||||
pub(crate) struct Expander;
|
||||
|
||||
fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
|
||||
use errors::CfgAccessibleInvalid::*;
|
||||
match mi.meta_item_list() {
|
||||
None => {}
|
||||
Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"),
|
||||
Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"),
|
||||
Some([]) => {
|
||||
ecx.emit_err(UnspecifiedPath(mi.span));
|
||||
}
|
||||
Some([_, .., l]) => {
|
||||
ecx.emit_err(MultiplePaths(l.span()));
|
||||
}
|
||||
Some([nmi]) => match nmi.meta_item() {
|
||||
None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"),
|
||||
None => {
|
||||
ecx.emit_err(LiteralPath(nmi.span()));
|
||||
}
|
||||
Some(mi) => {
|
||||
if !mi.is_word() {
|
||||
ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments");
|
||||
ecx.emit_err(HasArguments(mi.span));
|
||||
}
|
||||
return Some(&mi.path);
|
||||
}
|
||||
@ -53,7 +61,7 @@ impl MultiItemModifier for Expander {
|
||||
Ok(true) => ExpandResult::Ready(vec![item]),
|
||||
Ok(false) => ExpandResult::Ready(Vec::new()),
|
||||
Err(Indeterminate) if ecx.force_mode => {
|
||||
ecx.span_err(span, "cannot determine whether the path is accessible or not");
|
||||
ecx.emit_err(errors::CfgAccessibleIndeterminate { span });
|
||||
ExpandResult::Ready(vec![item])
|
||||
}
|
||||
Err(Indeterminate) => ExpandResult::Retry(item),
|
||||
|
@ -13,6 +13,11 @@ pub fn expand_compile_error<'cx>(
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
|
||||
#[expect(
|
||||
rustc::diagnostic_outside_of_impl,
|
||||
reason = "diagnostic message is specified by user"
|
||||
)]
|
||||
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
|
||||
cx.span_err(sp, var.as_str());
|
||||
|
||||
DummyResult::any(sp)
|
||||
|
@ -4,6 +4,8 @@ use rustc_expand::base::{self, DummyResult};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_concat(
|
||||
cx: &mut base::ExtCtxt<'_>,
|
||||
sp: rustc_span::Span,
|
||||
@ -31,7 +33,7 @@ pub fn expand_concat(
|
||||
accumulator.push_str(&b.to_string());
|
||||
}
|
||||
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
|
||||
cx.span_err(e.span, "cannot concatenate a byte string literal");
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
has_errors = true;
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {
|
||||
@ -55,7 +57,7 @@ pub fn expand_concat(
|
||||
}
|
||||
}
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
cx.span_err(e.span, "cannot concatenate a byte string literal")
|
||||
cx.emit_err(errors::ConcatBytestr { span: e.span });
|
||||
}
|
||||
ast::ExprKind::Err => {
|
||||
has_errors = true;
|
||||
@ -67,9 +69,7 @@ pub fn expand_concat(
|
||||
}
|
||||
|
||||
if !missing_literal.is_empty() {
|
||||
let mut err = cx.struct_span_err(missing_literal, "expected a literal");
|
||||
err.note("only literals (like `\"foo\"`, `-42` and `3.14`) can be passed to `concat!()`");
|
||||
err.emit();
|
||||
cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
|
||||
return DummyResult::any(sp);
|
||||
} else if has_errors {
|
||||
return DummyResult::any(sp);
|
||||
|
@ -1,10 +1,11 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{ptr::P, tokenstream::TokenStream};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{self, DummyResult};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// Emits errors for literal expressions that are invalid inside and outside of an array.
|
||||
fn invalid_type_err(
|
||||
cx: &mut base::ExtCtxt<'_>,
|
||||
@ -12,62 +13,46 @@ fn invalid_type_err(
|
||||
span: Span,
|
||||
is_nested: bool,
|
||||
) {
|
||||
use errors::{
|
||||
ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
|
||||
};
|
||||
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
|
||||
match ast::LitKind::from_token_lit(token_lit) {
|
||||
Ok(ast::LitKind::Char(_)) => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate character literals");
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try using a byte character",
|
||||
format!("b{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
|
||||
cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Str(_, _)) => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate string literals");
|
||||
// suggestion would be invalid if we are nested
|
||||
if !is_nested {
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try using a byte string",
|
||||
format!("b{}", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
let sugg = if !is_nested {
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Float(_, _)) => {
|
||||
cx.span_err(span, "cannot concatenate float literals");
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Bool(_)) => {
|
||||
cx.span_err(span, "cannot concatenate boolean literals");
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
|
||||
}
|
||||
Ok(ast::LitKind::Err) => {}
|
||||
Ok(ast::LitKind::Int(_, _)) if !is_nested => {
|
||||
let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals");
|
||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"try wrapping the number in an array",
|
||||
format!("[{}]", snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
let sugg =
|
||||
snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
|
||||
cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
|
||||
}
|
||||
Ok(ast::LitKind::Int(
|
||||
val,
|
||||
ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
|
||||
)) => {
|
||||
assert!(val > u8::MAX.into()); // must be an error
|
||||
cx.span_err(span, "numeric literal is out of bounds");
|
||||
cx.emit_err(ConcatBytesOob { span });
|
||||
}
|
||||
Ok(ast::LitKind::Int(_, _)) => {
|
||||
cx.span_err(span, "numeric literal is not a `u8`");
|
||||
cx.emit_err(ConcatBytesNonU8 { span });
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
|
||||
Err(err) => {
|
||||
@ -85,7 +70,7 @@ fn handle_array_element(
|
||||
match expr.kind {
|
||||
ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
|
||||
if !*has_errors {
|
||||
cx.span_err(expr.span, "cannot concatenate doubly nested array");
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -99,10 +84,7 @@ fn handle_array_element(
|
||||
Ok(ast::LitKind::Byte(val)) => Some(val),
|
||||
Ok(ast::LitKind::ByteStr(..)) => {
|
||||
if !*has_errors {
|
||||
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
|
||||
.note("byte strings are treated as arrays of bytes")
|
||||
.help("try flattening the array")
|
||||
.emit();
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -117,10 +99,7 @@ fn handle_array_element(
|
||||
},
|
||||
ast::ExprKind::IncludedBytes(..) => {
|
||||
if !*has_errors {
|
||||
cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
|
||||
.note("byte strings are treated as arrays of bytes")
|
||||
.help("try flattening the array")
|
||||
.emit();
|
||||
cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
|
||||
}
|
||||
*has_errors = true;
|
||||
None
|
||||
@ -167,7 +146,7 @@ pub fn expand_concat_bytes(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cx.span_err(count.value.span, "repeat count is not a positive number");
|
||||
cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span });
|
||||
}
|
||||
}
|
||||
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
||||
@ -196,9 +175,7 @@ pub fn expand_concat_bytes(
|
||||
}
|
||||
}
|
||||
if !missing_literals.is_empty() {
|
||||
let mut err = cx.struct_span_err(missing_literals, "expected a byte literal");
|
||||
err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
|
||||
err.emit();
|
||||
cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
} else if has_errors {
|
||||
return base::MacEager::expr(DummyResult::raw_expr(sp, true));
|
||||
|
@ -6,13 +6,15 @@ use rustc_expand::base::{self, *};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_concat_idents<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
if tts.is_empty() {
|
||||
cx.span_err(sp, "concat_idents! takes 1 or more arguments");
|
||||
cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
@ -22,7 +24,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
match e {
|
||||
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
|
||||
_ => {
|
||||
cx.span_err(sp, "concat_idents! expecting comma");
|
||||
cx.emit_err(errors::ConcatIdentsMissingComma { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
@ -34,7 +36,7 @@ pub fn expand_concat_idents<'cx>(
|
||||
}
|
||||
}
|
||||
|
||||
cx.span_err(sp, "concat_idents! requires ident args");
|
||||
cx.emit_err(errors::ConcatIdentsIdentArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::cfg_eval::cfg_eval;
|
||||
use crate::errors;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
@ -116,49 +116,33 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||
let bad_target =
|
||||
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
|
||||
if bad_target {
|
||||
struct_span_err!(
|
||||
sess,
|
||||
span,
|
||||
E0774,
|
||||
"`derive` may only be applied to `struct`s, `enum`s and `union`s",
|
||||
)
|
||||
.span_label(span, "not applicable here")
|
||||
.span_label(item.span(), "not a `struct`, `enum` or `union`")
|
||||
.emit();
|
||||
sess.emit_err(errors::BadDeriveTarget { span, item: item.span() });
|
||||
}
|
||||
bad_target
|
||||
}
|
||||
|
||||
fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
|
||||
let help_msg = match lit.kind {
|
||||
let help = match lit.kind {
|
||||
ast::LitKind::Str(_, ast::StrStyle::Cooked)
|
||||
if rustc_lexer::is_ident(lit.symbol.as_str()) =>
|
||||
{
|
||||
format!("try using `#[derive({})]`", lit.symbol)
|
||||
errors::BadDeriveLitHelp::StrLit { sym: lit.symbol }
|
||||
}
|
||||
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||
_ => errors::BadDeriveLitHelp::Other,
|
||||
};
|
||||
struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
|
||||
.span_label(lit.span, "not a trait")
|
||||
.help(&help_msg)
|
||||
.emit();
|
||||
sess.emit_err(errors::BadDeriveLit { span: lit.span, help });
|
||||
}
|
||||
|
||||
fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
let report_error = |title, action| {
|
||||
let span = meta.span.with_lo(meta.path.span.hi());
|
||||
sess.struct_span_err(span, title)
|
||||
.span_suggestion(span, action, "", Applicability::MachineApplicable)
|
||||
.emit();
|
||||
};
|
||||
let span = meta.span.with_lo(meta.path.span.hi());
|
||||
|
||||
match meta.kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(..) => report_error(
|
||||
"traits in `#[derive(...)]` don't accept arguments",
|
||||
"remove the arguments",
|
||||
),
|
||||
MetaItemKind::List(..) => {
|
||||
sess.emit_err(errors::DerivePathArgsList { span });
|
||||
}
|
||||
MetaItemKind::NameValue(..) => {
|
||||
report_error("traits in `#[derive(...)]` don't accept values", "remove the value")
|
||||
sess.emit_err(errors::DerivePathArgsValue { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{attr, walk_list, EnumDef, VariantData};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
@ -118,67 +118,50 @@ fn extract_default_variant<'a>(
|
||||
.filter(|variant| matches!(variant.data, VariantData::Unit(..)))
|
||||
.filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));
|
||||
|
||||
let mut diag = cx.struct_span_err(trait_span, "no default declared");
|
||||
diag.help("make a unit variant default by placing `#[default]` above it");
|
||||
for variant in possible_defaults {
|
||||
// Suggest making each unit variant default.
|
||||
diag.tool_only_span_suggestion(
|
||||
variant.span,
|
||||
&format!("make `{}` default", variant.ident),
|
||||
format!("#[default] {}", variant.ident),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
let suggs = possible_defaults
|
||||
.map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
|
||||
.collect();
|
||||
cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
[first, rest @ ..] => {
|
||||
let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults");
|
||||
diag.span_label(first.span, "first default");
|
||||
diag.span_labels(rest.iter().map(|variant| variant.span), "additional default");
|
||||
diag.note("only one variant can be default");
|
||||
for variant in &default_variants {
|
||||
// Suggest making each variant already tagged default.
|
||||
let suggestion = default_variants
|
||||
.iter()
|
||||
.filter_map(|v| {
|
||||
if v.span == variant.span {
|
||||
None
|
||||
} else {
|
||||
Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new()))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
diag.tool_only_multipart_suggestion(
|
||||
&format!("make `{}` default", variant.ident),
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
|
||||
let suggs = default_variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let spans = default_variants
|
||||
.iter()
|
||||
.filter_map(|v| {
|
||||
if v.span == variant.span {
|
||||
None
|
||||
} else {
|
||||
Some(attr::find_by_name(&v.attrs, kw::Default)?.span)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
errors::MultipleDefaultsSugg { spans, ident: variant.ident }
|
||||
})
|
||||
.collect();
|
||||
cx.emit_err(errors::MultipleDefaults {
|
||||
span: trait_span,
|
||||
first: first.span,
|
||||
additional: rest.iter().map(|v| v.span).collect(),
|
||||
suggs,
|
||||
});
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
if !matches!(variant.data, VariantData::Unit(..)) {
|
||||
cx.struct_span_err(
|
||||
variant.ident.span,
|
||||
"the `#[default]` attribute may only be used on unit enum variants",
|
||||
)
|
||||
.help("consider a manual implementation of `Default`")
|
||||
.emit();
|
||||
|
||||
cx.emit_err(errors::NonUnitDefault { span: variant.ident.span });
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
|
||||
cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
|
||||
.span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
|
||||
.help("consider a manual implementation of `Default`")
|
||||
.emit();
|
||||
cx.emit_err(errors::NonExhaustiveDefault {
|
||||
span: variant.ident.span,
|
||||
non_exhaustive: non_exhaustive_attr.span,
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -199,35 +182,23 @@ fn validate_default_attribute(
|
||||
"this method must only be called with a variant that has a `#[default]` attribute",
|
||||
),
|
||||
[first, rest @ ..] => {
|
||||
let suggestion_text =
|
||||
if rest.len() == 1 { "try removing this" } else { "try removing these" };
|
||||
|
||||
cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes")
|
||||
.note("only one `#[default]` attribute is needed")
|
||||
.span_label(first.span, "`#[default]` used here")
|
||||
.span_label(rest[0].span, "`#[default]` used again here")
|
||||
.span_help(rest.iter().map(|attr| attr.span).collect::<Vec<_>>(), suggestion_text)
|
||||
// This would otherwise display the empty replacement, hence the otherwise
|
||||
// repetitive `.span_help` call above.
|
||||
.tool_only_multipart_suggestion(
|
||||
suggestion_text,
|
||||
rest.iter().map(|attr| (attr.span, String::new())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
let sugg = errors::MultipleDefaultAttrsSugg {
|
||||
spans: rest.iter().map(|attr| attr.span).collect(),
|
||||
};
|
||||
cx.emit_err(errors::MultipleDefaultAttrs {
|
||||
span: default_variant.ident.span,
|
||||
first: first.span,
|
||||
first_rest: rest[0].span,
|
||||
rest: rest.iter().map(|attr| attr.span).collect::<Vec<_>>().into(),
|
||||
only_one: rest.len() == 1,
|
||||
sugg,
|
||||
});
|
||||
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
if !attr.is_word() {
|
||||
cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value")
|
||||
.span_suggestion_hidden(
|
||||
attr.span,
|
||||
"try using `#[default]`",
|
||||
"#[default]",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
cx.emit_err(errors::DefaultHasArg { span: attr.span });
|
||||
|
||||
return Err(());
|
||||
}
|
||||
@ -241,12 +212,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
|
||||
if attr.has_name(kw::Default) {
|
||||
self.cx
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"the `#[default]` attribute may only be used on unit enum variants",
|
||||
)
|
||||
.emit();
|
||||
self.cx.emit_err(errors::NonUnitDefault { span: attr.span });
|
||||
}
|
||||
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
|
@ -162,7 +162,7 @@
|
||||
pub use StaticFields::*;
|
||||
pub use SubstructureFields::*;
|
||||
|
||||
use crate::deriving;
|
||||
use crate::{deriving, errors};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
||||
@ -415,7 +415,7 @@ fn find_type_parameters(
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
||||
self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
|
||||
self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() });
|
||||
}
|
||||
}
|
||||
|
||||
@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> {
|
||||
is_packed,
|
||||
)
|
||||
} else {
|
||||
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
||||
cx.emit_err(errors::DeriveUnion { span: mitem.span });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ use rustc_span::Span;
|
||||
use std::env;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn expand_option_env<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
@ -54,7 +56,7 @@ pub fn expand_env<'cx>(
|
||||
) -> Box<dyn base::MacResult + 'cx> {
|
||||
let mut exprs = match get_exprs_from_tts(cx, tts) {
|
||||
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
|
||||
cx.span_err(sp, "env! takes 1 or 2 arguments");
|
||||
cx.emit_err(errors::EnvTakesArgs { span: sp });
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
None => return DummyResult::any(sp),
|
||||
@ -78,18 +80,12 @@ pub fn expand_env<'cx>(
|
||||
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
|
||||
let e = match value {
|
||||
None => {
|
||||
let (msg, help) = match custom_msg {
|
||||
None => (
|
||||
format!("environment variable `{var}` not defined at compile time"),
|
||||
Some(help_for_missing_env_var(var.as_str())),
|
||||
),
|
||||
Some(s) => (s.to_string(), None),
|
||||
};
|
||||
let mut diag = cx.struct_span_err(sp, &msg);
|
||||
if let Some(help) = help {
|
||||
diag.help(help);
|
||||
}
|
||||
diag.emit();
|
||||
cx.emit_err(errors::EnvNotDefined {
|
||||
span: sp,
|
||||
msg: custom_msg,
|
||||
var,
|
||||
help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
|
||||
});
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
Some(value) => cx.expr_str(sp, value),
|
||||
@ -97,15 +93,13 @@ pub fn expand_env<'cx>(
|
||||
MacEager::expr(e)
|
||||
}
|
||||
|
||||
fn help_for_missing_env_var(var: &str) -> String {
|
||||
fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp {
|
||||
if var.starts_with("CARGO_")
|
||||
|| var.starts_with("DEP_")
|
||||
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
|
||||
{
|
||||
format!(
|
||||
"Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead"
|
||||
)
|
||||
errors::EnvNotDefinedHelp::CargoVar
|
||||
} else {
|
||||
format!("Use `std::env::var(\"{var}\")` to read the variable at run time")
|
||||
errors::EnvNotDefinedHelp::Other
|
||||
}
|
||||
}
|
||||
|
553
compiler/rustc_builtin_macros/src/errors.rs
Normal file
553
compiler/rustc_builtin_macros/src/errors.rs
Normal file
@ -0,0 +1,553 @@
|
||||
use rustc_errors::{
|
||||
AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_requires_cfg_pattern)]
|
||||
pub(crate) struct RequiresCfgPattern {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_expected_one_cfg_pattern)]
|
||||
pub(crate) struct OneCfgPattern {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_alloc_error_must_be_fn)]
|
||||
pub(crate) struct AllocErrorMustBeFn {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_requires_boolean)]
|
||||
pub(crate) struct AssertRequiresBoolean {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_requires_expression)]
|
||||
pub(crate) struct AssertRequiresExpression {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) token: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_missing_comma)]
|
||||
pub(crate) struct AssertMissingComma {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[suggestion(code = ", ", applicability = "maybe-incorrect", style = "short")]
|
||||
pub(crate) comma: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum CfgAccessibleInvalid {
|
||||
#[diag(builtin_macros_cfg_accessible_unspecified_path)]
|
||||
UnspecifiedPath(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_multiple_paths)]
|
||||
MultiplePaths(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_literal_path)]
|
||||
LiteralPath(#[primary_span] Span),
|
||||
#[diag(builtin_macros_cfg_accessible_has_args)]
|
||||
HasArguments(#[primary_span] Span),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_cfg_accessible_indeterminate)]
|
||||
pub(crate) struct CfgAccessibleIndeterminate {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_missing_literal)]
|
||||
#[note]
|
||||
pub(crate) struct ConcatMissingLiteral {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytestr)]
|
||||
pub(crate) struct ConcatBytestr {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_invalid)]
|
||||
pub(crate) struct ConcatBytesInvalid {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) lit_kind: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: Option<ConcatBytesInvalidSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ConcatBytesInvalidSuggestion {
|
||||
#[suggestion(
|
||||
builtin_macros_byte_char,
|
||||
code = "b{snippet}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
CharLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_byte_str,
|
||||
code = "b{snippet}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
StrLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_number_array,
|
||||
code = "[{snippet}]",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
IntLit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
snippet: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_oob)]
|
||||
pub(crate) struct ConcatBytesOob {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_non_u8)]
|
||||
pub(crate) struct ConcatBytesNonU8 {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_missing_literal)]
|
||||
#[note]
|
||||
pub(crate) struct ConcatBytesMissingLiteral {
|
||||
#[primary_span]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_array)]
|
||||
pub(crate) struct ConcatBytesArray {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[note]
|
||||
#[help]
|
||||
pub(crate) bytestr: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_bytes_bad_repeat)]
|
||||
pub(crate) struct ConcatBytesBadRepeat {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_missing_args)]
|
||||
pub(crate) struct ConcatIdentsMissingArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_missing_comma)]
|
||||
pub(crate) struct ConcatIdentsMissingComma {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_concat_idents_ident_args)]
|
||||
pub(crate) struct ConcatIdentsIdentArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_bad_derive_target, code = "E0774")]
|
||||
pub(crate) struct BadDeriveTarget {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_label2)]
|
||||
pub(crate) item: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_unexpected_lit, code = "E0777")]
|
||||
pub(crate) struct BadDeriveLit {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub help: BadDeriveLitHelp,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum BadDeriveLitHelp {
|
||||
#[help(builtin_macros_str_lit)]
|
||||
StrLit { sym: Symbol },
|
||||
#[help(builtin_macros_other)]
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_path_args_list)]
|
||||
pub(crate) struct DerivePathArgsList {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_path_args_value)]
|
||||
pub(crate) struct DerivePathArgsValue {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_no_default_variant)]
|
||||
#[help]
|
||||
pub(crate) struct NoDefaultVariant {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) suggs: Vec<NoDefaultVariantSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
builtin_macros_suggestion,
|
||||
code = "#[default] {ident}",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct NoDefaultVariantSugg {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_multiple_defaults)]
|
||||
#[note]
|
||||
pub(crate) struct MultipleDefaults {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) first: Span,
|
||||
#[label(builtin_macros_additional)]
|
||||
pub additional: Vec<Span>,
|
||||
#[subdiagnostic]
|
||||
pub suggs: Vec<MultipleDefaultsSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct MultipleDefaultsSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_unit_default)]
|
||||
#[help]
|
||||
pub(crate) struct NonUnitDefault {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_exhaustive_default)]
|
||||
#[help]
|
||||
pub(crate) struct NonExhaustiveDefault {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) non_exhaustive: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_multiple_default_attrs)]
|
||||
#[note]
|
||||
pub(crate) struct MultipleDefaultAttrs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label]
|
||||
pub(crate) first: Span,
|
||||
#[label(builtin_macros_label_again)]
|
||||
pub(crate) first_rest: Span,
|
||||
#[help]
|
||||
pub(crate) rest: MultiSpan,
|
||||
pub(crate) only_one: bool,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: MultipleDefaultAttrsSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_help,
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct MultipleDefaultAttrsSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_default_arg)]
|
||||
pub(crate) struct DefaultHasArg {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "#[default]", style = "hidden", applicability = "maybe-incorrect")]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_macro_call)]
|
||||
pub(crate) struct DeriveMacroCall {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_cannot_derive_union)]
|
||||
pub(crate) struct DeriveUnion {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_env_takes_args)]
|
||||
pub(crate) struct EnvTakesArgs {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
//#[derive(Diagnostic)]
|
||||
//#[diag(builtin_macros_env_not_defined)]
|
||||
pub(crate) struct EnvNotDefined {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) msg: Option<Symbol>,
|
||||
pub(crate) var: Symbol,
|
||||
pub(crate) help: Option<EnvNotDefinedHelp>,
|
||||
}
|
||||
|
||||
// Hand-written implementation to support custom user messages
|
||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &'a rustc_errors::Handler,
|
||||
) -> rustc_errors::DiagnosticBuilder<'a, G> {
|
||||
let mut diag = if let Some(msg) = self.msg {
|
||||
handler.struct_diagnostic(msg.as_str())
|
||||
} else {
|
||||
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
|
||||
};
|
||||
diag.set_arg("var", self.var);
|
||||
diag.set_span(self.span);
|
||||
if let Some(help) = self.help {
|
||||
diag.subdiagnostic(help);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum EnvNotDefinedHelp {
|
||||
#[help(builtin_macros_cargo)]
|
||||
CargoVar,
|
||||
#[help(builtin_macros_other)]
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_requires_string)]
|
||||
pub(crate) struct FormatRequiresString {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_duplicate_arg)]
|
||||
pub(crate) struct FormatDuplicateArg {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_label1)]
|
||||
pub(crate) prev: Span,
|
||||
#[label(builtin_macros_label2)]
|
||||
pub(crate) duplicate: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_positional_after_named)]
|
||||
pub(crate) struct PositionalAfterNamed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[label(builtin_macros_named_args)]
|
||||
pub(crate) args: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_string_invalid)]
|
||||
pub(crate) struct InvalidFormatString {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) desc: String,
|
||||
pub(crate) label1: String,
|
||||
#[subdiagnostic]
|
||||
pub(crate) note_: Option<InvalidFormatStringNote>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) label_: Option<InvalidFormatStringLabel>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg_: Option<InvalidFormatStringSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(builtin_macros_note)]
|
||||
pub(crate) struct InvalidFormatStringNote {
|
||||
pub(crate) note: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(builtin_macros_second_label)]
|
||||
pub(crate) struct InvalidFormatStringLabel {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) label: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_sugg,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidFormatStringSuggestion {
|
||||
#[suggestion_part(code = "{len}")]
|
||||
pub(crate) captured: Span,
|
||||
pub(crate) len: String,
|
||||
#[suggestion_part(code = ", {arg}")]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) arg: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_no_arg_named)]
|
||||
#[note]
|
||||
#[note(builtin_macros_note2)]
|
||||
pub(crate) struct FormatNoArgNamed {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unknown_trait)]
|
||||
#[note]
|
||||
pub(crate) struct FormatUnknownTrait<'a> {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ty: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub(crate) suggs: Vec<FormatUnknownTraitSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
builtin_macros_suggestion,
|
||||
code = "{fmt}",
|
||||
style = "tool-only",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub struct FormatUnknownTraitSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub fmt: &'static str,
|
||||
pub trait_name: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unused_arg)]
|
||||
pub(crate) struct FormatUnusedArg {
|
||||
#[primary_span]
|
||||
#[label(builtin_macros_format_unused_arg)]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) named: bool,
|
||||
}
|
||||
|
||||
// Allow the singular form to be a subdiagnostic of the multiple-unused
|
||||
// form of diagnostic.
|
||||
impl AddToDiagnostic for FormatUnusedArg {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut rustc_errors::Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
diag.set_arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
diag.span_label(self.span, msg);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_unused_args)]
|
||||
pub(crate) struct FormatUnusedArgs {
|
||||
#[primary_span]
|
||||
pub(crate) unused: Vec<Span>,
|
||||
#[label]
|
||||
pub(crate) fmt: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) unused_labels: Vec<FormatUnusedArg>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_format_pos_mismatch)]
|
||||
pub(crate) struct FormatPositionalMismatch {
|
||||
#[primary_span]
|
||||
pub(crate) span: MultiSpan,
|
||||
pub(crate) n: usize,
|
||||
pub(crate) desc: String,
|
||||
#[subdiagnostic]
|
||||
pub(crate) highlight: SingleLabelManySpans,
|
||||
}
|
@ -7,7 +7,7 @@ use rustc_ast::{
|
||||
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
|
||||
use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
@ -36,6 +36,8 @@ enum PositionUsedAs {
|
||||
}
|
||||
use PositionUsedAs::*;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
struct MacroInput {
|
||||
fmtstr: P<Expr>,
|
||||
args: FormatArguments,
|
||||
@ -66,7 +68,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
let mut p = ecx.new_parser_from_tts(tts);
|
||||
|
||||
if p.token == token::Eof {
|
||||
return Err(ecx.struct_span_err(sp, "requires at least a format string argument"));
|
||||
return Err(ecx.create_err(errors::FormatRequiresString { span: sp }));
|
||||
}
|
||||
|
||||
let first_token = &p.token;
|
||||
@ -121,13 +123,12 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
p.expect(&token::Eq)?;
|
||||
let expr = p.parse_expr()?;
|
||||
if let Some((_, prev)) = args.by_name(ident.name) {
|
||||
ecx.struct_span_err(
|
||||
ident.span,
|
||||
&format!("duplicate argument named `{}`", ident),
|
||||
)
|
||||
.span_label(prev.kind.ident().unwrap().span, "previously here")
|
||||
.span_label(ident.span, "duplicate argument")
|
||||
.emit();
|
||||
ecx.emit_err(errors::FormatDuplicateArg {
|
||||
span: ident.span,
|
||||
prev: prev.kind.ident().unwrap().span,
|
||||
duplicate: ident.span,
|
||||
ident,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr });
|
||||
@ -135,20 +136,21 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||
_ => {
|
||||
let expr = p.parse_expr()?;
|
||||
if !args.named_args().is_empty() {
|
||||
let mut err = ecx.struct_span_err(
|
||||
expr.span,
|
||||
"positional arguments cannot follow named arguments",
|
||||
);
|
||||
err.span_label(
|
||||
expr.span,
|
||||
"positional arguments must be before named arguments",
|
||||
);
|
||||
for arg in args.named_args() {
|
||||
if let Some(name) = arg.kind.ident() {
|
||||
err.span_label(name.span.to(arg.expr.span), "named argument");
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
ecx.emit_err(errors::PositionalAfterNamed {
|
||||
span: expr.span,
|
||||
args: args
|
||||
.named_args()
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
if let Some(ident) = a.kind.ident() {
|
||||
Some((a, ident))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|(arg, n)| n.span.to(arg.expr.span))
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
|
||||
}
|
||||
@ -234,13 +236,19 @@ fn make_format_args(
|
||||
// argument span here.
|
||||
fmt_span
|
||||
};
|
||||
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
|
||||
e.span_label(sp, err.label + " in format string");
|
||||
let mut e = errors::InvalidFormatString {
|
||||
span: sp,
|
||||
note_: None,
|
||||
label_: None,
|
||||
sugg_: None,
|
||||
desc: err.description,
|
||||
label1: err.label,
|
||||
};
|
||||
if let Some(note) = err.note {
|
||||
e.note(¬e);
|
||||
e.note_ = Some(errors::InvalidFormatStringNote { note });
|
||||
}
|
||||
if let Some((label, span)) = err.secondary_label && is_source_literal {
|
||||
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
|
||||
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
|
||||
}
|
||||
if err.should_be_replaced_with_positional_argument {
|
||||
let captured_arg_span =
|
||||
@ -250,17 +258,15 @@ fn make_format_args(
|
||||
Some(arg) => arg.expr.span,
|
||||
None => fmt_span,
|
||||
};
|
||||
e.multipart_suggestion_verbose(
|
||||
"consider using a positional formatting argument instead",
|
||||
vec![
|
||||
(captured_arg_span, args.unnamed_args().len().to_string()),
|
||||
(span.shrink_to_hi(), format!(", {}", arg)),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
|
||||
captured: captured_arg_span,
|
||||
len: args.unnamed_args().len().to_string(),
|
||||
span: span.shrink_to_hi(),
|
||||
arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
e.emit();
|
||||
ecx.emit_err(e);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
@ -318,10 +324,7 @@ fn make_format_args(
|
||||
} else {
|
||||
// For the moment capturing variables from format strings expanded from macros is
|
||||
// disabled (see RFC #2795)
|
||||
ecx.struct_span_err(span, &format!("there is no argument named `{name}`"))
|
||||
.note(format!("did you intend to capture a variable `{name}` from the surrounding scope?"))
|
||||
.note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro")
|
||||
.emit();
|
||||
ecx.emit_err(errors::FormatNoArgNamed { span, name });
|
||||
DummyResult::raw_expr(span, true)
|
||||
};
|
||||
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
|
||||
@ -475,12 +478,8 @@ fn make_format_args(
|
||||
.enumerate()
|
||||
.filter(|&(_, used)| !used)
|
||||
.map(|(i, _)| {
|
||||
let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind {
|
||||
"named argument never used"
|
||||
} else {
|
||||
"argument never used"
|
||||
};
|
||||
(args.explicit_args()[i].expr.span, msg)
|
||||
let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_));
|
||||
(args.explicit_args()[i].expr.span, named)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -531,22 +530,8 @@ fn invalid_placeholder_type_error(
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
|
||||
let mut err =
|
||||
ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty));
|
||||
err.note(
|
||||
"the only appropriate formatting traits are:\n\
|
||||
- ``, which uses the `Display` trait\n\
|
||||
- `?`, which uses the `Debug` trait\n\
|
||||
- `e`, which uses the `LowerExp` trait\n\
|
||||
- `E`, which uses the `UpperExp` trait\n\
|
||||
- `o`, which uses the `Octal` trait\n\
|
||||
- `p`, which uses the `Pointer` trait\n\
|
||||
- `b`, which uses the `Binary` trait\n\
|
||||
- `x`, which uses the `LowerHex` trait\n\
|
||||
- `X`, which uses the `UpperHex` trait",
|
||||
);
|
||||
if let Some(sp) = sp {
|
||||
for (fmt, name) in &[
|
||||
let suggs = if let Some(sp) = sp {
|
||||
[
|
||||
("", "Display"),
|
||||
("?", "Debug"),
|
||||
("e", "LowerExp"),
|
||||
@ -556,40 +541,38 @@ fn invalid_placeholder_type_error(
|
||||
("b", "Binary"),
|
||||
("x", "LowerHex"),
|
||||
("X", "UpperHex"),
|
||||
] {
|
||||
err.tool_only_span_suggestion(
|
||||
sp,
|
||||
&format!("use the `{}` trait", name),
|
||||
*fmt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name })
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
|
||||
}
|
||||
|
||||
fn report_missing_placeholders(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
unused: Vec<(Span, &str)>,
|
||||
unused: Vec<(Span, bool)>,
|
||||
detect_foreign_fmt: bool,
|
||||
str_style: Option<usize>,
|
||||
fmt_str: &str,
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let mut diag = if let &[(span, msg)] = &unused[..] {
|
||||
let mut diag = ecx.struct_span_err(span, msg);
|
||||
diag.span_label(span, msg);
|
||||
diag
|
||||
let mut diag = if let &[(span, named)] = &unused[..] {
|
||||
//let mut diag = ecx.struct_span_err(span, msg);
|
||||
//diag.span_label(span, msg);
|
||||
//diag
|
||||
ecx.create_err(errors::FormatUnusedArg { span, named })
|
||||
} else {
|
||||
let mut diag = ecx.struct_span_err(
|
||||
unused.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
|
||||
"multiple unused formatting arguments",
|
||||
);
|
||||
diag.span_label(fmt_span, "multiple missing formatting specifiers");
|
||||
for &(span, msg) in &unused {
|
||||
diag.span_label(span, msg);
|
||||
}
|
||||
diag
|
||||
let unused_labels =
|
||||
unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect();
|
||||
let unused_spans = unused.iter().map(|&(span, _)| span).collect();
|
||||
ecx.create_err(errors::FormatUnusedArgs {
|
||||
fmt: fmt_span,
|
||||
unused: unused_spans,
|
||||
unused_labels,
|
||||
})
|
||||
};
|
||||
|
||||
// Used to ensure we only report translations for *one* kind of foreign format.
|
||||
@ -768,18 +751,16 @@ fn report_invalid_references(
|
||||
} else {
|
||||
MultiSpan::from_spans(spans)
|
||||
};
|
||||
e = ecx.struct_span_err(
|
||||
e = ecx.create_err(errors::FormatPositionalMismatch {
|
||||
span,
|
||||
&format!(
|
||||
"{} positional argument{} in format string, but {}",
|
||||
num_placeholders,
|
||||
pluralize!(num_placeholders),
|
||||
num_args_desc,
|
||||
),
|
||||
);
|
||||
for arg in args.explicit_args() {
|
||||
e.span_label(arg.expr.span, "");
|
||||
}
|
||||
n: num_placeholders,
|
||||
desc: num_args_desc,
|
||||
highlight: SingleLabelManySpans {
|
||||
spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(),
|
||||
label: "",
|
||||
kind: rustc_errors::LabelKind::Label,
|
||||
},
|
||||
});
|
||||
// Point out `{:.*}` placeholders: those take an extra argument.
|
||||
let mut has_precision_star = false;
|
||||
for piece in template {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(is_sorted)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_quote)]
|
||||
#![recursion_limit = "256"]
|
||||
@ -39,6 +40,7 @@ mod derive;
|
||||
mod deriving;
|
||||
mod edition_panic;
|
||||
mod env;
|
||||
mod errors;
|
||||
mod format;
|
||||
mod format_foreign;
|
||||
mod global_allocator;
|
||||
|
@ -880,6 +880,7 @@ impl Diagnostic {
|
||||
///
|
||||
/// This is intended to be used for suggestions that are *very* obvious in what the changes
|
||||
/// need to be from the message, but we still want other tools to be able to apply them.
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn tool_only_span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::{fluent_generated as fluent, AddToDiagnostic};
|
||||
use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust;
|
||||
@ -6,6 +6,7 @@ use rustc_hir as hir;
|
||||
use rustc_lint_defs::Level;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::TargetDataLayoutErrors;
|
||||
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
|
||||
use rustc_type_ir as type_ir;
|
||||
@ -276,3 +277,26 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility struct used to apply a single label while highlighting multiple spans
|
||||
pub struct SingleLabelManySpans {
|
||||
pub spans: Vec<Span>,
|
||||
pub label: &'static str,
|
||||
pub kind: LabelKind,
|
||||
}
|
||||
impl AddToDiagnostic for SingleLabelManySpans {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut crate::Diagnostic, _: F) {
|
||||
match self.kind {
|
||||
LabelKind::Note => diag.span_note(self.spans, self.label),
|
||||
LabelKind::Label => diag.span_labels(self.spans, self.label),
|
||||
LabelKind::Help => diag.span_help(self.spans, self.label),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of label to attach when using [`SingleLabelManySpans`]
|
||||
pub enum LabelKind {
|
||||
Note,
|
||||
Label,
|
||||
Help,
|
||||
}
|
||||
|
@ -383,7 +383,9 @@ pub use diagnostic::{
|
||||
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
|
||||
};
|
||||
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
|
||||
pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList};
|
||||
pub use diagnostic_impls::{
|
||||
DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
|
||||
};
|
||||
use std::backtrace::Backtrace;
|
||||
|
||||
/// A handler deals with errors and other compiler output.
|
||||
|
@ -392,14 +392,16 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
}
|
||||
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
||||
let inner = info.ty.inner_type();
|
||||
if type_matches_path(inner, &["rustc_span", "Span"]) {
|
||||
if type_matches_path(inner, &["rustc_span", "Span"])
|
||||
|| type_matches_path(inner, &["rustc_span", "MultiSpan"])
|
||||
{
|
||||
Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
|
||||
} else if type_is_unit(inner)
|
||||
|| (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner))
|
||||
{
|
||||
Ok(self.add_subdiagnostic(&fn_ident, slug))
|
||||
} else {
|
||||
report_type_error(attr, "`Span`, `bool` or `()`")?
|
||||
report_type_error(attr, "`Span`, `MultiSpan`, `bool` or `()`")?
|
||||
}
|
||||
}
|
||||
SubdiagnosticKind::Suggestion {
|
||||
|
@ -518,7 +518,7 @@ struct BoolField {
|
||||
#[help]
|
||||
foo: bool,
|
||||
#[help(no_crate_help)]
|
||||
//~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()`
|
||||
//~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type
|
||||
// only allow plain 'bool' fields
|
||||
bar: Option<bool>,
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ error: invalid applicability
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
|
||||
| ^^^^^^^^
|
||||
|
||||
error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()`
|
||||
error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
|
||||
--> $DIR/diagnostic-derive.rs:520:5
|
||||
|
|
||||
LL | #[help(no_crate_help)]
|
||||
|
@ -1 +1 @@
|
||||
fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments
|
||||
fn main() { env!(); } //~ ERROR: `env!()` takes 1 or 2 arguments
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: env! takes 1 or 2 arguments
|
||||
error: `env!()` takes 1 or 2 arguments
|
||||
--> $DIR/extenv-no-args.rs:1:13
|
||||
|
|
||||
LL | fn main() { env!(); }
|
||||
|
@ -1 +1 @@
|
||||
fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments
|
||||
fn main() { env!("one", "two", "three"); } //~ ERROR: `env!()` takes 1 or 2 arguments
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: env! takes 1 or 2 arguments
|
||||
error: `env!()` takes 1 or 2 arguments
|
||||
--> $DIR/extenv-too-many-args.rs:1:13
|
||||
|
|
||||
LL | fn main() { env!("one", "two", "three"); }
|
||||
|
@ -4,7 +4,7 @@ error: environment variable `NON_EXISTENT` not defined at compile time
|
||||
LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time
|
||||
= help: use `std::env::var("NON_EXISTENT")` to read the variable at run time
|
||||
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![feature(concat_idents)]
|
||||
|
||||
fn main() {
|
||||
let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments
|
||||
let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: concat_idents! takes 1 or more arguments
|
||||
error: `concat_idents!()` takes 1 or more arguments
|
||||
--> $DIR/issue-50403.rs:4:13
|
||||
|
|
||||
LL | let x = concat_idents!();
|
||||
|
@ -4,7 +4,7 @@ error: expected a byte literal
|
||||
LL | concat_bytes!(pie);
|
||||
| ^^^
|
||||
|
|
||||
= note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
error: expected a byte literal
|
||||
--> $DIR/concat-bytes-error.rs:5:19
|
||||
@ -12,7 +12,7 @@ error: expected a byte literal
|
||||
LL | concat_bytes!(pie, pie);
|
||||
| ^^^ ^^^
|
||||
|
|
||||
= note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
error: cannot concatenate string literals
|
||||
--> $DIR/concat-bytes-error.rs:6:19
|
||||
@ -98,7 +98,7 @@ error: expected a byte literal
|
||||
LL | -33,
|
||||
| ^^^
|
||||
|
|
||||
= note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
error: cannot concatenate doubly nested array
|
||||
--> $DIR/concat-bytes-error.rs:35:9
|
||||
@ -151,7 +151,7 @@ error: expected a byte literal
|
||||
LL | concat_bytes!([pie; 2]);
|
||||
| ^^^
|
||||
|
|
||||
= note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
= note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
error: cannot concatenate float literals
|
||||
--> $DIR/concat-bytes-error.rs:46:20
|
||||
|
@ -3,36 +3,48 @@ error: the `#[default]` attribute may only be used on unit enum variants
|
||||
|
|
||||
LL | #[default]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: the `#[default]` attribute may only be used on unit enum variants
|
||||
--> $DIR/macros-nonfatal-errors.rs:18:36
|
||||
|
|
||||
LL | struct DefaultInnerAttrTupleStruct(#[default] ());
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: the `#[default]` attribute may only be used on unit enum variants
|
||||
--> $DIR/macros-nonfatal-errors.rs:22:1
|
||||
|
|
||||
LL | #[default]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: the `#[default]` attribute may only be used on unit enum variants
|
||||
--> $DIR/macros-nonfatal-errors.rs:26:1
|
||||
|
|
||||
LL | #[default]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: the `#[default]` attribute may only be used on unit enum variants
|
||||
--> $DIR/macros-nonfatal-errors.rs:36:11
|
||||
|
|
||||
LL | Foo = #[default] 0,
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: the `#[default]` attribute may only be used on unit enum variants
|
||||
--> $DIR/macros-nonfatal-errors.rs:37:14
|
||||
|
|
||||
LL | Bar([u8; #[default] 1]),
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: no default declared
|
||||
--> $DIR/macros-nonfatal-errors.rs:42:10
|
||||
@ -132,7 +144,7 @@ error: asm template must be a string literal
|
||||
LL | asm!(invalid);
|
||||
| ^^^^^^^
|
||||
|
||||
error: concat_idents! requires ident args
|
||||
error: `concat_idents!()` requires ident args
|
||||
--> $DIR/macros-nonfatal-errors.rs:101:5
|
||||
|
|
||||
LL | concat_idents!("not", "idents");
|
||||
@ -150,7 +162,7 @@ error: expected string literal
|
||||
LL | env!(invalid);
|
||||
| ^^^^^^^
|
||||
|
||||
error: env! takes 1 or 2 arguments
|
||||
error: `env!()` takes 1 or 2 arguments
|
||||
--> $DIR/macros-nonfatal-errors.rs:105:5
|
||||
|
|
||||
LL | env!(foo, abr, baz);
|
||||
@ -162,7 +174,7 @@ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at co
|
||||
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
|
||||
= help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
|
||||
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: format argument must be a string literal
|
||||
|
Loading…
Reference in New Issue
Block a user