Permit {This} in diagnostic attribute format literals

This commit is contained in:
mejrs
2026-04-23 21:59:41 +02:00
parent acb65f36a0
commit c2916be8d7
23 changed files with 368 additions and 204 deletions
@@ -6,7 +6,6 @@
Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue,
OnUnimplementedCondition, Piece, Predicate,
};
use rustc_hir::lints::FormatWarning;
use rustc_macros::Diagnostic;
use rustc_parse_format::{
Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
@@ -19,9 +18,8 @@
use crate::context::{AcceptContext, Stage};
use crate::errors::{
DisallowedPlaceholder, DisallowedPositionalArgument, IgnoredDiagnosticOption,
InvalidFormatSpecifier, MalFormedDiagnosticAttributeLint, MissingOptionsForDiagnosticAttribute,
NonMetaItemDiagnosticAttribute, WrappedParserError,
FormatWarning, IgnoredDiagnosticOption, MalFormedDiagnosticAttributeLint,
MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError,
};
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
@@ -88,6 +86,29 @@ fn allowed_options(&self) -> &'static str {
Self::DiagnosticOnUnmatchArgs => DEFAULT,
}
}
fn allowed_format_arguments(&self) -> &'static str {
match self {
Self::RustcOnUnimplemented => {
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented> for allowed format arguments"
}
Self::DiagnosticOnUnimplemented => {
"only `Self` and generics of the trait are allowed as a format argument"
}
Self::DiagnosticOnConst => {
"only `Self` and generics of the implementation are allowed as a format argument"
}
Self::DiagnosticOnMove => {
"only `This`, `Self` and generics of the type are allowed as a format argument"
}
Self::DiagnosticOnUnknown => {
"only `This` is allowed as a format argument, referring to the failed import"
}
Self::DiagnosticOnUnmatchArgs => {
"only `This` is allowed as a format argument, referring to the macro's name"
}
}
}
}
fn merge_directives<S: Stage>(
@@ -257,22 +278,13 @@ fn parse_directive_items<'p, S: Stage>(
match parse_format_string(input.name, snippet, input.span, mode) {
Ok((f, warnings)) => {
for warning in warnings {
let (FormatWarning::InvalidSpecifier { span, .. }
| FormatWarning::PositionalArgument { span, .. }
| FormatWarning::DisallowedPlaceholder { span }) = warning;
let (FormatWarning::InvalidSpecifier { span }
| FormatWarning::PositionalArgument { span }
| FormatWarning::IndexedArgument { span }
| FormatWarning::DisallowedPlaceholder { span, .. }) = warning;
cx.emit_dyn_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
move |dcx, level| match warning {
FormatWarning::PositionalArgument { .. } => {
DisallowedPositionalArgument.into_diag(dcx, level)
}
FormatWarning::InvalidSpecifier { .. } => {
InvalidFormatSpecifier.into_diag(dcx, level)
}
FormatWarning::DisallowedPlaceholder { .. } => {
DisallowedPlaceholder.into_diag(dcx, level)
}
},
move |dcx, level| warning.into_diag(dcx, level),
span,
);
}
@@ -422,38 +434,74 @@ fn parse_arg(
is_source_literal: bool,
) -> FormatArg {
let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
if matches!(mode, Mode::DiagnosticOnUnknown) {
warnings.push(FormatWarning::DisallowedPlaceholder { span });
return FormatArg::AsIs(sym::empty_braces);
}
match arg.position {
// Something like "hello {name}"
Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
// Only `#[rustc_on_unimplemented]` can use these
(Mode::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
(Mode::RustcOnUnimplemented { .. } | Mode::DiagnosticOnUnmatchArgs, sym::This) => {
FormatArg::This
(Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext,
// Like `{This}`, but sugared.
// FIXME(mejrs) maybe rename/rework this or something
// if we want to apply this to other attrs?
(Mode::RustcOnUnimplemented, sym::Trait) => FormatArg::Trait,
// Some diagnostic attributes can use `{This}` to refer to the annotated item.
// For those that don't, we continue and maybe use it as a generic parameter.
//
// FIXME(mejrs) `DiagnosticOnUnimplemented` is intentionally not here;
// that requires lang approval which is best kept for a standalone PR.
(
Mode::RustcOnUnimplemented
| Mode::DiagnosticOnUnknown
| Mode::DiagnosticOnMove
| Mode::DiagnosticOnUnmatchArgs,
sym::This,
) => FormatArg::This,
// `{Self}`; the self type.
// - For trait declaration attributes that's the type that does not implement it.
// - for trait impl attributes, the implemented for type.
// - For ADT attributes, that's the type (which will be identical to `{This}`)
// - For everything else it doesn't make sense.
(
Mode::RustcOnUnimplemented
| Mode::DiagnosticOnUnimplemented
| Mode::DiagnosticOnMove
| Mode::DiagnosticOnConst,
kw::SelfUpper,
) => FormatArg::SelfUpper,
// Generic parameters.
// FIXME(mejrs) unfortunately, all the "special" symbols above might fall through,
// but at this time we are not aware of what generic parameters the trait actually has.
// If we find `ItemContext` or something we have to assume that's a generic parameter.
// We lint against that in `check_attr.rs` though.
(
Mode::RustcOnUnimplemented
| Mode::DiagnosticOnUnimplemented
| Mode::DiagnosticOnMove
| Mode::DiagnosticOnConst,
generic_param,
) => FormatArg::GenericParam { generic_param, span },
// Generics are explicitly not allowed, we print those back as is.
(Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchArgs, as_is) => {
warnings.push(FormatWarning::DisallowedPlaceholder {
span,
attr: mode.as_str(),
allowed: mode.allowed_format_arguments(),
});
return FormatArg::AsIs(Symbol::intern(&format!("{{{as_is}}}")));
}
(Mode::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
// Any attribute can use these
(_, kw::SelfUpper) => FormatArg::SelfUpper,
(_, generic_param) => FormatArg::GenericParam { generic_param, span },
},
// `{:1}` and `{}` are ignored
Position::ArgumentIs(idx) => {
warnings.push(FormatWarning::PositionalArgument {
span,
help: format!("use `{{{idx}}}` to print a number in braces"),
});
warnings.push(FormatWarning::IndexedArgument { span });
FormatArg::AsIs(Symbol::intern(&format!("{{{idx}}}")))
}
Position::ArgumentImplicitlyIs(_) => {
warnings.push(FormatWarning::PositionalArgument {
span,
help: String::from("use `{{}}` to print empty braces"),
});
warnings.push(FormatWarning::PositionalArgument { span });
FormatArg::AsIs(sym::empty_braces)
}
}
@@ -473,7 +521,7 @@ fn warn_on_format_spec(
.as_ref()
.map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
.unwrap_or(input_span);
warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
warnings.push(FormatWarning::InvalidSpecifier { span })
}
}
+31 -17
View File
@@ -357,23 +357,6 @@ pub(crate) struct MalFormedDiagnosticAttributeLint {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("positional format arguments are not allowed here")]
#[help(
"only named format arguments with the name of one of the generic types are allowed in this context"
)]
pub(crate) struct DisallowedPositionalArgument;
#[derive(Diagnostic)]
#[diag("format arguments are not allowed here")]
#[help("consider removing this format argument")]
pub(crate) struct DisallowedPlaceholder;
#[derive(Diagnostic)]
#[diag("invalid format specifier")]
#[help("no format specifier are supported in this position")]
pub(crate) struct InvalidFormatSpecifier;
#[derive(Diagnostic)]
#[diag("{$description}")]
pub(crate) struct WrappedParserError<'a> {
@@ -407,3 +390,34 @@ pub(crate) struct MissingOptionsForDiagnosticAttribute {
"only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma"
)]
pub(crate) struct NonMetaItemDiagnosticAttribute;
#[derive(Diagnostic, Clone, Copy)]
pub(crate) enum FormatWarning {
#[diag("positional arguments are not permitted in diagnostic attributes")]
#[help("you can print empty braces by escaping them")]
PositionalArgument {
#[label("remove this format argument")]
span: Span,
},
#[diag("indexed format arguments are not permitted in diagnostic attributes")]
IndexedArgument {
#[label("remove this format argument")]
span: Span,
},
#[diag("format specifiers are not permitted in diagnostic attributes")]
InvalidSpecifier {
#[label("remove this format specifier")]
span: Span,
},
#[diag("this format argument is not allowed in `#[{$attr}]`")]
#[note("{$allowed}")]
DisallowedPlaceholder {
#[label("remove this format argument")]
span: Span,
attr: &'static str,
allowed: &'static str,
},
}
+1 -1
View File
@@ -1,8 +1,8 @@
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::MultiSpan;
use rustc_errors::{Diag, DiagCtxtHandle, Level};
pub use rustc_lint_defs::AttributeLintKind;
use rustc_lint_defs::LintId;
pub use rustc_lint_defs::{AttributeLintKind, FormatWarning};
use crate::HirId;
-7
View File
@@ -658,13 +658,6 @@ pub enum AttributeLintKind {
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
}
#[derive(Debug, Clone, HashStable_Generic)]
pub enum FormatWarning {
PositionalArgument { span: Span, help: String },
InvalidSpecifier { name: String, span: Span },
DisallowedPlaceholder { span: Span },
}
pub type RegisteredTools = FxIndexSet<Ident>;
/// Declares a static item of type `&'static Lint`.
+1 -17
View File
@@ -201,9 +201,6 @@ fn check_attributes(
},
Attribute::Parsed(AttributeKind::OnUnimplemented{directive,..}) => {self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())},
Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)},
Attribute::Parsed(AttributeKind::OnUnmatchArgs { directive, .. }) => {
self.check_diagnostic_on_unmatch_args(hir_id, directive.as_deref())
},
Attribute::Parsed(AttributeKind::OnMove { directive , .. }) => {
self.check_diagnostic_on_move(hir_id, directive.as_deref())
},
@@ -256,6 +253,7 @@ fn check_attributes(
| AttributeKind::NoMangle(..)
| AttributeKind::NoStd { .. }
| AttributeKind::OnUnknown { .. }
| AttributeKind::OnUnmatchArgs { .. }
| AttributeKind::Optimize(..)
| AttributeKind::PanicRuntime
| AttributeKind::PatchableFunctionEntry { .. }
@@ -562,20 +560,6 @@ fn check_diagnostic_on_const(
// ...whose generics would that be, anyway? The traits' or the impls'?
}
/// Checks use of generic formatting parameters in `#[diagnostic::on_unmatch_args]`.
fn check_diagnostic_on_unmatch_args(&self, hir_id: HirId, directive: Option<&Directive>) {
if let Some(directive) = directive {
directive.visit_params(&mut |argument_name, span| {
self.tcx.emit_node_span_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
hir_id,
span,
errors::OnUnmatchArgsMalformedFormatLiterals { name: argument_name },
)
});
}
}
/// Checks use of generic formatting parameters in `#[diagnostic::on_move]`
fn check_diagnostic_on_move(&self, hir_id: HirId, directive: Option<&Directive>) {
if let Some(directive) = directive {
-7
View File
@@ -1303,10 +1303,3 @@ pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr {
pub(crate) struct OnMoveMalformedFormatLiterals {
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag("unknown parameter `{$name}`")]
#[help(r#"use {"`{This}`"} to refer to the macro name"#)]
pub(crate) struct OnUnmatchArgsMalformedFormatLiterals {
pub name: Symbol,
}
+8 -1
View File
@@ -2,6 +2,7 @@
use std::mem;
use itertools::Itertools;
use rustc_ast::{Item, NodeId};
use rustc_attr_parsing::AttributeParser;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
@@ -879,8 +880,14 @@ fn throw_unresolved_import_error(
let (message, label, notes) =
// Feature gating for `on_unknown_attr` happens initialization of the field
if let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive) {
let this = errors.iter().map(|(_import, err)| {
// Is this unwrap_or reachable?
err.segment.unwrap_or(kw::Underscore)
}).join(", ");
let args = FormatArgs {
this: paths.join(", "),
this,
// Unused
this_sugared: String::new(),
// Unused
@@ -4,7 +4,6 @@
use rustc_hir::attrs::diagnostic::{ConditionOptions, CustomDiagnostic, FormatArgs};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::find_attr;
pub use rustc_hir::lints::FormatWarning;
use rustc_middle::ty::print::PrintTraitRefExt;
use rustc_middle::ty::{self, GenericParamDef, GenericParamDefKind};
use rustc_span::Symbol;
@@ -31,17 +31,17 @@ pub trait MultiLine4 {}
#[diagnostic::on_unimplemented(message = "here is a big \
multiline string \
{Self:+}")]
//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals]
//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
pub trait MultiLineFmt {}
#[diagnostic::on_unimplemented(message = "here is a big \
multiline string {Self:X}")]
//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals]
//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
pub trait MultiLineFmt2 {}
#[diagnostic::on_unimplemented(message = "here is a big \
multiline string {Self:#}")]
//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals]
//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
pub trait MultiLineFmt3 {}
@@ -51,5 +51,5 @@ pub trait MultiLineFmt3 {}
\
\
multiline string {Self:?}")]
//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals]
//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
pub trait MultiLineFmt4 {}
@@ -36,37 +36,29 @@ LL | multiline string {unknown}")]
|
= help: expect either a generic argument name or `{Self}` as format argument
error: invalid format specifier
error: format specifiers are not permitted in diagnostic attributes
--> $DIR/multiline_spans.rs:33:47
|
LL | ... {Self:+}")]
| ^^
|
= help: no format specifier are supported in this position
| ^^ remove this format specifier
error: invalid format specifier
error: format specifiers are not permitted in diagnostic attributes
--> $DIR/multiline_spans.rs:38:64
|
LL | ... multiline string {Self:X}")]
| ^^
|
= help: no format specifier are supported in this position
| ^^ remove this format specifier
error: invalid format specifier
error: format specifiers are not permitted in diagnostic attributes
--> $DIR/multiline_spans.rs:43:27
|
LL | multiline string {Self:#}")]
| ^^
|
= help: no format specifier are supported in this position
| ^^ remove this format specifier
error: invalid format specifier
error: format specifiers are not permitted in diagnostic attributes
--> $DIR/multiline_spans.rs:53:27
|
LL | multiline string {Self:?}")]
| ^^
|
= help: no format specifier are supported in this position
| ^^ remove this format specifier
error: aborting due to 8 previous errors
@@ -1,3 +1,4 @@
//@ dont-require-annotations: NOTE
#![feature(diagnostic_on_move)]
#[diagnostic::on_move(
@@ -10,6 +11,7 @@
#[diagnostic::on_move(
message="Foo for {X}",
label="Bar for {X}",
note = "This is `{This}`",
)]
struct MyType<X> {
_x: X,
@@ -21,12 +23,15 @@ fn takes_mytype<X>(_: MyType<X>) {}
fn main() {
let foo = Foo;
//~^ NOTE Bar for Foo
takes_foo(foo);
let bar = foo;
//~^ERROR Foo for Foo
let mytype = MyType { _x: 0 };
//~^ NOTE Bar for i32
takes_mytype(mytype);
let baz = mytype;
//~^ERROR Foo for i32
//~|NOTE This is `MyType`
}
@@ -1,22 +1,23 @@
error[E0382]: Foo for Foo
--> $DIR/on_move_with_format.rs:25:15
--> $DIR/on_move_with_format.rs:28:15
|
LL | let foo = Foo;
| --- Bar for Foo
LL |
LL | takes_foo(foo);
| --- value moved here
LL | let bar = foo;
| ^^^ value used here after move
|
note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary
--> $DIR/on_move_with_format.rs:18:17
--> $DIR/on_move_with_format.rs:20:17
|
LL | fn takes_foo(_: Foo) {}
| --------- ^^^ this parameter takes ownership of the value
| |
| in this function
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/on_move_with_format.rs:8:1
--> $DIR/on_move_with_format.rs:9:1
|
LL | struct Foo;
| ^^^^^^^^^^ consider implementing `Clone` for this type
@@ -25,24 +26,26 @@ LL | takes_foo(foo);
| --- you could clone this value
error[E0382]: Foo for i32
--> $DIR/on_move_with_format.rs:30:15
--> $DIR/on_move_with_format.rs:34:15
|
LL | let mytype = MyType { _x: 0 };
| ------ Bar for i32
LL |
LL | takes_mytype(mytype);
| ------ value moved here
LL | let baz = mytype;
| ^^^^^^ value used here after move
|
= note: This is `MyType`
note: consider changing this parameter type in function `takes_mytype` to borrow instead if owning the value isn't necessary
--> $DIR/on_move_with_format.rs:20:23
--> $DIR/on_move_with_format.rs:22:23
|
LL | fn takes_mytype<X>(_: MyType<X>) {}
| ------------ ^^^^^^^^^ this parameter takes ownership of the value
| |
| in this function
note: if `MyType<i32>` implemented `Clone`, you could clone the value
--> $DIR/on_move_with_format.rs:14:1
--> $DIR/on_move_with_format.rs:16:1
|
LL | struct MyType<X> {
| ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
@@ -4,24 +4,24 @@
trait ImportantTrait1 {}
#[diagnostic::on_unimplemented(message = "Test {}")]
//~^WARN positional format arguments are not allowed here
//~^WARN positional arguments are not permitted in diagnostic attributes
trait ImportantTrait2 {}
#[diagnostic::on_unimplemented(message = "Test {1:}")]
//~^WARN positional format arguments are not allowed here
//~|WARN invalid format specifier [malformed_diagnostic_format_literals]
//~^WARN indexed format arguments are not permitted in diagnostic attributes
//~|WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
trait ImportantTrait3 {}
#[diagnostic::on_unimplemented(message = "Test {Self:123}")]
//~^WARN invalid format specifier
//~^WARN format specifiers are not permitted in diagnostic attributes
trait ImportantTrait4 {}
#[diagnostic::on_unimplemented(message = "Test {Self:!}")]
//~^WARN invalid format specifier [malformed_diagnostic_format_literals]
//~^WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
trait ImportantTrait5 {}
#[diagnostic::on_unimplemented(message = "Test {Self:}")]
//~^WARN invalid format specifier [malformed_diagnostic_format_literals]
//~^WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals]
trait ImportantTrait6 {}
@@ -8,53 +8,43 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
|
= note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: positional format arguments are not allowed here
warning: positional arguments are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:6:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {}")]
| ^
| ^ remove this format argument
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
= help: you can print empty braces by escaping them
warning: invalid format specifier
warning: format specifiers are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:10:50
|
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
| ^
|
= help: no format specifier are supported in this position
| ^ remove this format specifier
warning: positional format arguments are not allowed here
warning: indexed format arguments are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:10:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
| ^
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
| ^ remove this format argument
warning: invalid format specifier
warning: format specifiers are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:15:53
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
| ^^^^
|
= help: no format specifier are supported in this position
| ^^^^ remove this format specifier
warning: invalid format specifier
warning: format specifiers are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:19:53
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
| ^^
|
= help: no format specifier are supported in this position
| ^^ remove this format specifier
warning: invalid format specifier
warning: format specifiers are not permitted in diagnostic attributes
--> $DIR/broken_format.rs:23:53
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")]
| ^
|
= help: no format specifier are supported in this position
| ^ remove this format specifier
error[E0277]: {{Test } thing
--> $DIR/broken_format.rs:36:13
@@ -1,32 +1,35 @@
#![feature(diagnostic_on_unknown)]
#[diagnostic::on_unknown(message = "foo {}")]
//~^ WARN: format arguments are not allowed here
//~^ WARN: positional arguments are not permitted in diagnostic attributes
use std::does_not_exist;
//~^ ERROR: foo {}
#[diagnostic::on_unknown(message = "foo {A}")]
//~^ WARN: format arguments are not allowed here
//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
use std::does_not_exist2;
//~^ ERROR: foo {}
//~^ ERROR: foo {A}
#[diagnostic::on_unknown(label = "foo {}")]
//~^ WARN: format arguments are not allowed here
//~^ WARN: positional arguments are not permitted in diagnostic attributes
use std::does_not_exist3;
//~^ ERROR: unresolved import `std::does_not_exist3`
#[diagnostic::on_unknown(label = "foo {A}")]
//~^ WARN: format arguments are not allowed here
//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
use std::does_not_exist4;
//~^ ERROR: unresolved import `std::does_not_exist4`
#[diagnostic::on_unknown(note = "foo {}")]
//~^ WARN: format arguments are not allowed here
//~^ WARN: positional arguments are not permitted in diagnostic attributes
use std::does_not_exist5;
//~^ ERROR: unresolved import `std::does_not_exist5`
#[diagnostic::on_unknown(note = "foo {A}")]
//~^ WARN: format arguments are not allowed here
#[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")]
//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]`
use std::does_not_exist6;
//~^ ERROR: unresolved import `std::does_not_exist6`
@@ -6,7 +6,7 @@ LL | use std::does_not_exist;
|
= note: unresolved import `std::does_not_exist`
error[E0432]: foo {}
error[E0432]: foo {A}
--> $DIR/incorrect_format_string.rs:10:5
|
LL | use std::does_not_exist2;
@@ -24,7 +24,7 @@ error[E0432]: unresolved import `std::does_not_exist4`
--> $DIR/incorrect_format_string.rs:20:5
|
LL | use std::does_not_exist4;
| ^^^^^^^^^^^^^^^^^^^^ foo {}
| ^^^^^^^^^^^^^^^^^^^^ foo {A}
error[E0432]: unresolved import `std::does_not_exist5`
--> $DIR/incorrect_format_string.rs:25:5
@@ -35,62 +35,86 @@ LL | use std::does_not_exist5;
= note: foo {}
error[E0432]: unresolved import `std::does_not_exist6`
--> $DIR/incorrect_format_string.rs:30:5
--> $DIR/incorrect_format_string.rs:33:5
|
LL | use std::does_not_exist6;
| ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist6` in the root
|
= note: foo {}
= note: foo {Self} {ItemContext} {Trait} {A}
warning: format arguments are not allowed here
warning: positional arguments are not permitted in diagnostic attributes
--> $DIR/incorrect_format_string.rs:3:42
|
LL | #[diagnostic::on_unknown(message = "foo {}")]
| ^
| ^ remove this format argument
|
= help: consider removing this format argument
= help: you can print empty braces by escaping them
= note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: format arguments are not allowed here
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:8:42
|
LL | #[diagnostic::on_unknown(message = "foo {A}")]
| ^
| ^ remove this format argument
|
= help: consider removing this format argument
= note: only `This` is allowed as a format argument, referring to the failed import
warning: format arguments are not allowed here
warning: positional arguments are not permitted in diagnostic attributes
--> $DIR/incorrect_format_string.rs:13:40
|
LL | #[diagnostic::on_unknown(label = "foo {}")]
| ^
| ^ remove this format argument
|
= help: consider removing this format argument
= help: you can print empty braces by escaping them
warning: format arguments are not allowed here
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:18:40
|
LL | #[diagnostic::on_unknown(label = "foo {A}")]
| ^
| ^ remove this format argument
|
= help: consider removing this format argument
= note: only `This` is allowed as a format argument, referring to the failed import
warning: format arguments are not allowed here
warning: positional arguments are not permitted in diagnostic attributes
--> $DIR/incorrect_format_string.rs:23:39
|
LL | #[diagnostic::on_unknown(note = "foo {}")]
| ^
| ^ remove this format argument
|
= help: consider removing this format argument
= help: you can print empty braces by escaping them
warning: format arguments are not allowed here
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:28:39
|
LL | #[diagnostic::on_unknown(note = "foo {A}")]
| ^
LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")]
| ^^^^ remove this format argument
|
= help: consider removing this format argument
= note: only `This` is allowed as a format argument, referring to the failed import
error: aborting due to 6 previous errors; 6 warnings emitted
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:28:46
|
LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")]
| ^^^^^^^^^^^ remove this format argument
|
= note: only `This` is allowed as a format argument, referring to the failed import
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:28:60
|
LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")]
| ^^^^^ remove this format argument
|
= note: only `This` is allowed as a format argument, referring to the failed import
warning: this format argument is not allowed in `#[diagnostic::on_unknown]`
--> $DIR/incorrect_format_string.rs:28:68
|
LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")]
| ^ remove this format argument
|
= note: only `This` is allowed as a format argument, referring to the failed import
error: aborting due to 6 previous errors; 9 warnings emitted
For more information about this error, try `rustc --explain E0432`.
@@ -0,0 +1,45 @@
#![feature(diagnostic_on_unknown)]
#![crate_type = "lib"]
pub mod foo {}
#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")]
use foo::Foo;
//~^ERROR unresolved import `foo::Foo`
//~|NOTE the name of this item is a single ident: `Foo`
//~|NOTE no `Foo` in `foo`
#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")]
use foo::foo::Foo;
//~^ERROR unresolved import `foo::foo`
//~|NOTE the name of this item is a single ident: `foo`
//~|NOTE could not find `foo` in `foo`
#[diagnostic::on_unknown(note = "the name of this item is two idents: `{This}`")]
use foo::{Bar, Foo};
//~^ERROR unresolved imports `foo::Bar`, `foo::Foo`
//~|NOTE the name of this item is two idents: `Bar, Foo`
//~|NOTE no `Foo` in `foo`
//~|NOTE no `Bar` in `foo`
#[diagnostic::on_unknown(note = "the name of this item is many idents: `{This}`")]
use foo::{
Foo,
//~^ERROR unresolved imports `foo::Foo`, `foo::bar`
//~|NOTE the name of this item is many idents: `Foo, bar`
//~|NOTE no `Foo` in `foo`
bar::{Baz, Biz},
//~^NOTE could not find `bar` in `foo`
};
#[diagnostic::on_unknown(note = "the name of this is: `{This}`")]
pub use doesnt_exist::*;
//~^ERROR unresolved import `doesnt_exist`
//~|NOTE use of unresolved module or unlinked crate `doesnt_exist`
//~|NOTE the name of this is: `doesnt_exist`
#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")]
use foo::Foo as DoNotUseForThisParam;
//~^ERROR unresolved import `foo::Foo`
//~|NOTE the name of this item is a single ident: `Foo`
//~|NOTE no `Foo` in `foo`
@@ -0,0 +1,60 @@
error[E0432]: unresolved import `foo::Foo`
--> $DIR/this_format_argument.rs:7:5
|
LL | use foo::Foo;
| ^^^^^^^^ no `Foo` in `foo`
|
= note: the name of this item is a single ident: `Foo`
error[E0432]: unresolved import `foo::foo`
--> $DIR/this_format_argument.rs:13:10
|
LL | use foo::foo::Foo;
| ^^^ could not find `foo` in `foo`
|
= note: the name of this item is a single ident: `foo`
error[E0432]: unresolved imports `foo::Bar`, `foo::Foo`
--> $DIR/this_format_argument.rs:19:11
|
LL | use foo::{Bar, Foo};
| ^^^ ^^^ no `Foo` in `foo`
| |
| no `Bar` in `foo`
|
= note: the name of this item is two idents: `Bar, Foo`
error[E0432]: unresolved imports `foo::Foo`, `foo::bar`
--> $DIR/this_format_argument.rs:27:5
|
LL | Foo,
| ^^^ no `Foo` in `foo`
...
LL | bar::{Baz, Biz},
| ^^^ could not find `bar` in `foo`
|
= note: the name of this item is many idents: `Foo, bar`
error[E0432]: unresolved import `doesnt_exist`
--> $DIR/this_format_argument.rs:36:9
|
LL | pub use doesnt_exist::*;
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `doesnt_exist`
|
= note: the name of this is: `doesnt_exist`
help: you might be missing a crate named `doesnt_exist`, add it to your project and import it in your code
|
LL + extern crate doesnt_exist;
|
error[E0432]: unresolved import `foo::Foo`
--> $DIR/this_format_argument.rs:42:5
|
LL | use foo::Foo as DoNotUseForThisParam;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `Foo` in `foo`
|
= note: the name of this item is a single ident: `Foo`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0432`.
@@ -7,7 +7,7 @@ pub mod foo {
message = "first message",
label = "first label",
note = "custom note",
note = "custom note 2"
note = "custom note 2",
)]
use foo::Foo;
//~^ERROR first message
@@ -3,7 +3,10 @@
#[diagnostic::on_unmatch_args(
message = "{T}! is missing arguments",
//~^ WARN unknown parameter `T`
//~^ WARN this format argument is not allowed in `#[diagnostic::on_unmatch_args]`
//~| NOTE only `This` is allowed as a format argument
//~| NOTE remove this format argument
//~| NOTE `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
)]
macro_rules! pair {
($ty:ty, $value:expr) => {};
@@ -1,10 +1,10 @@
warning: unknown parameter `T`
warning: this format argument is not allowed in `#[diagnostic::on_unmatch_args]`
--> $DIR/report_warning_on_invalid_formats.rs:5:17
|
LL | message = "{T}! is missing arguments",
| ^
| ^ remove this format argument
|
= help: use `{This}` to refer to the macro name
= note: only `This` is allowed as a format argument, referring to the macro's name
= note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: 1 warning emitted
+2 -1
View File
@@ -23,7 +23,8 @@ trait NoContent {}
trait ParameterNotPresent<A, B> {}
#[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{}>`")]
//~^ WARN positional format arguments are not allowed here
//~^ WARN positional arguments are not permitted in diagnostic attributes
//~| NOTE remove this format argument
trait NoPositionalArgs<A, B> {}
#[rustc_on_unimplemented(lorem = "")]
+21 -21
View File
@@ -1,59 +1,59 @@
error[E0232]: invalid flag in `on`-clause
--> $DIR/bad-annotation.rs:45:44
--> $DIR/bad-annotation.rs:46:44
|
LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))]
| ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `desugared`
error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]`
--> $DIR/bad-annotation.rs:50:26
--> $DIR/bad-annotation.rs:51:26
|
LL | #[rustc_on_unimplemented(on(), message = "y")]
| ^^^^ empty `on`-clause here
error[E0232]: literals inside `on`-clauses are not supported
--> $DIR/bad-annotation.rs:70:29
--> $DIR/bad-annotation.rs:71:29
|
LL | #[rustc_on_unimplemented(on("y", message = "y"))]
| ^^^ unexpected literal here
error[E0232]: literals inside `on`-clauses are not supported
--> $DIR/bad-annotation.rs:75:29
--> $DIR/bad-annotation.rs:76:29
|
LL | #[rustc_on_unimplemented(on(42, message = "y"))]
| ^^ unexpected literal here
error[E0232]: expected a single predicate in `not(..)`
--> $DIR/bad-annotation.rs:80:32
--> $DIR/bad-annotation.rs:81:32
|
LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))]
| ^^^^^^ unexpected quantity of predicates here
error[E0232]: expected a single predicate in `not(..)`
--> $DIR/bad-annotation.rs:85:32
--> $DIR/bad-annotation.rs:86:32
|
LL | #[rustc_on_unimplemented(on(not(), message = "y"))]
| ^^ unexpected quantity of predicates here
error[E0232]: expected an identifier inside this `on`-clause
--> $DIR/bad-annotation.rs:90:29
--> $DIR/bad-annotation.rs:91:29
|
LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))]
| ^^^^^^^^^^^ expected an identifier here, not `thing::What`
error[E0232]: expected an identifier inside this `on`-clause
--> $DIR/bad-annotation.rs:95:29
--> $DIR/bad-annotation.rs:96:29
|
LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))]
| ^^^^^^^^^^^ expected an identifier here, not `thing::What`
error[E0232]: this predicate is invalid
--> $DIR/bad-annotation.rs:100:29
--> $DIR/bad-annotation.rs:101:29
|
LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))]
| ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa`
error[E0232]: invalid flag in `on`-clause
--> $DIR/bad-annotation.rs:105:29
--> $DIR/bad-annotation.rs:106:29
|
LL | #[rustc_on_unimplemented(on(something, message = "y"))]
| ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something`
@@ -67,13 +67,13 @@ LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with para
= note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: there is no parameter `_Self` on trait `InvalidName`
--> $DIR/bad-annotation.rs:110:29
--> $DIR/bad-annotation.rs:111:29
|
LL | #[rustc_on_unimplemented(on(_Self = "y", message = "y"))]
| ^^^^^^^^^^^
warning: there is no parameter `abc` on trait `InvalidName2`
--> $DIR/bad-annotation.rs:114:29
--> $DIR/bad-annotation.rs:115:29
|
LL | #[rustc_on_unimplemented(on(abc = "y", message = "y"))]
| ^^^^^^^^^
@@ -87,16 +87,16 @@ LL | #[rustc_on_unimplemented]
= help: see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: positional format arguments are not allowed here
warning: positional arguments are not permitted in diagnostic attributes
--> $DIR/bad-annotation.rs:25:90
|
LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{}>`")]
| ^
| ^ remove this format argument
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
= help: you can print empty braces by escaping them
warning: malformed `rustc_on_unimplemented` attribute
--> $DIR/bad-annotation.rs:29:26
--> $DIR/bad-annotation.rs:30:26
|
LL | #[rustc_on_unimplemented(lorem = "")]
| ^^^^^^^^^^ invalid option found here
@@ -104,7 +104,7 @@ LL | #[rustc_on_unimplemented(lorem = "")]
= help: see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>
warning: malformed `rustc_on_unimplemented` attribute
--> $DIR/bad-annotation.rs:34:26
--> $DIR/bad-annotation.rs:35:26
|
LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))]
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -112,7 +112,7 @@ LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))]
= help: see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>
warning: `message` is ignored due to previous definition of `message`
--> $DIR/bad-annotation.rs:39:41
--> $DIR/bad-annotation.rs:40:41
|
LL | #[rustc_on_unimplemented(message = "x", message = "y")]
| ------------- ^^^^^^^^^^^^^ `message` is later redundantly declared here
@@ -120,7 +120,7 @@ LL | #[rustc_on_unimplemented(message = "x", message = "y")]
| `message` is first declared here
warning: malformed `rustc_on_unimplemented` attribute
--> $DIR/bad-annotation.rs:55:26
--> $DIR/bad-annotation.rs:56:26
|
LL | #[rustc_on_unimplemented(on = "x", message = "y")]
| ^^^^^^^^ invalid option found here
@@ -128,7 +128,7 @@ LL | #[rustc_on_unimplemented(on = "x", message = "y")]
= help: see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>
warning: malformed `rustc_on_unimplemented` attribute
--> $DIR/bad-annotation.rs:60:26
--> $DIR/bad-annotation.rs:61:26
|
LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")]
| ^^^^^^^^^^^^^^ invalid option found here
@@ -136,7 +136,7 @@ LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")]
= help: see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>
warning: malformed `rustc_on_unimplemented` attribute
--> $DIR/bad-annotation.rs:65:46
--> $DIR/bad-annotation.rs:66:46
|
LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here