Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|this, cx, args| {
if !cx.features().diagnostic_on_const() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl OnMoveParser {
mode: Mode,
) {
if !cx.features().diagnostic_on_move() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl OnUnknownParser {
mode: Mode,
) {
if !cx.features().diagnostic_on_unknown() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
let span = cx.attr_span;
Expand Down
26 changes: 15 additions & 11 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1521,20 +1521,24 @@ pub(crate) struct RedundantImportVisibility {
#[diag("unknown diagnostic attribute")]
pub(crate) struct UnknownDiagnosticAttribute {
#[subdiagnostic]
pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
pub help: Option<UnknownDiagnosticAttributeHelp>,
}

#[derive(Subdiagnostic)]
#[suggestion(
"an attribute with a similar name exists",
style = "verbose",
code = "{typo_name}",
applicability = "machine-applicable"
)]
pub(crate) struct UnknownDiagnosticAttributeTypoSugg {
#[primary_span]
pub span: Span,
pub typo_name: Symbol,
pub(crate) enum UnknownDiagnosticAttributeHelp {
#[suggestion(
"an attribute with a similar name exists",
style = "verbose",
code = "{typo_name}",
applicability = "machine-applicable"
)]
Typo {
#[primary_span]
span: Span,
typo_name: Symbol,
},
#[help("add `#![feature({$feature})]` to the crate attributes to enable")]
UseFeature { feature: Symbol },
}

// FIXME: Make this properly translatable.
Expand Down
53 changes: 37 additions & 16 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,34 +712,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
}

let diagnostic_attributes: &[(Symbol, bool)] = &[
(sym::on_unimplemented, true),
(sym::do_not_recommend, true),
(sym::on_move, true),
(sym::on_const, self.tcx.features().diagnostic_on_const()),
(sym::on_unknown, self.tcx.features().diagnostic_on_unknown()),
const DIAGNOSTIC_ATTRIBUTES: &[(Symbol, Option<Symbol>)] = &[
(sym::on_unimplemented, None),
(sym::do_not_recommend, None),
(sym::on_move, Some(sym::diagnostic_on_move)),
(sym::on_const, Some(sym::diagnostic_on_const)),
(sym::on_unknown, Some(sym::diagnostic_on_unknown)),
];

if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
&& let [namespace, attribute, ..] = &*path.segments
&& namespace.ident.name == sym::diagnostic
&& !diagnostic_attributes
.iter()
.any(|(attr, stable)| *stable && attribute.ident.name == *attr)
&& !DIAGNOSTIC_ATTRIBUTES.iter().any(|(attr, feature)| {
attribute.ident.name == *attr
&& feature.is_none_or(|f| self.tcx.features().enabled(f))
})
{
let name = attribute.ident.name;
let span = attribute.span();
let candidates = diagnostic_attributes
.iter()
.filter_map(|(sym, stable)| stable.then_some(*sym))
.collect::<Vec<_>>();
let typo = find_best_match_for_name(&candidates, attribute.ident.name, Some(5))
.map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name });

let help = 'help: {
if self.tcx.sess.is_nightly_build() {
for (attr, feature) in DIAGNOSTIC_ATTRIBUTES {
if let Some(feature) = *feature
&& *attr == name
{
break 'help Some(errors::UnknownDiagnosticAttributeHelp::UseFeature {
feature,
});
}
}
}

let candidates = DIAGNOSTIC_ATTRIBUTES
.iter()
.filter_map(|(attr, feature)| {
feature.is_none_or(|f| self.tcx.features().enabled(f)).then_some(*attr)
})
.collect::<Vec<_>>();

find_best_match_for_name(&candidates, name, None).map(|typo_name| {
errors::UnknownDiagnosticAttributeHelp::Typo { span, typo_name }
})
};

self.tcx.sess.psess.buffer_lint(
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
span,
node_id,
errors::UnknownDiagnosticAttribute { typo },
errors::UnknownDiagnosticAttribute { help },
);
}

Expand Down
5 changes: 2 additions & 3 deletions tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
//! gate, but the fact that not adding the feature gate will cause the
//! diagnostic to not emit the custom diagnostic message
//!
#[diagnostic::on_move(
message = "Foo"
)]
#[diagnostic::on_move(message = "Foo")]
//~^ WARN unknown diagnostic attribute
Comment thread
mejrs marked this conversation as resolved.
#[derive(Debug)]
struct Foo;

Expand Down
17 changes: 13 additions & 4 deletions tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
warning: unknown diagnostic attribute
--> $DIR/feature-gate-diagnostic-on-move.rs:5:15
|
LL | #[diagnostic::on_move(message = "Foo")]
| ^^^^^^^
|
= help: add `#![feature(diagnostic_on_move)]` to the crate attributes to enable
= note: `#[warn(unknown_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default

error[E0382]: use of moved value: `foo`
--> $DIR/feature-gate-diagnostic-on-move.rs:16:15
--> $DIR/feature-gate-diagnostic-on-move.rs:15:15
|
LL | let foo = Foo;
| --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
Expand All @@ -9,21 +18,21 @@ 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/feature-gate-diagnostic-on-move.rs:11:17
--> $DIR/feature-gate-diagnostic-on-move.rs:10: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/feature-gate-diagnostic-on-move.rs:9:1
--> $DIR/feature-gate-diagnostic-on-move.rs:8:1
|
LL | struct Foo;
| ^^^^^^^^^^ consider implementing `Clone` for this type
...
LL | takes_foo(foo);
| --- you could clone this value

error: aborting due to 1 previous error
error: aborting due to 1 previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0382`.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ error: unknown diagnostic attribute
LL | #[diagnostic::on_unknown(message = "Tada")]
| ^^^^^^^^^^
|
= help: add `#![feature(diagnostic_on_unknown)]` to the crate attributes to enable
note: the lint level is defined here
--> $DIR/feature-gate-diagnostic-on-unknown.rs:1:9
|
Expand Down
Loading