Skip to content

Commit 784930e

Browse files
committed
Introduce the #[diagnostic] attribute namespace
1 parent 125516a commit 784930e

File tree

12 files changed

+135
-11
lines changed

12 files changed

+135
-11
lines changed

compiler/rustc_hir/src/def.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ impl<Id> Res<Id> {
630630
| Res::SelfTyParam { .. }
631631
| Res::SelfTyAlias { .. }
632632
| Res::SelfCtor(..)
633-
| Res::ToolMod
633+
| Res::ToolMod { .. }
634634
| Res::NonMacroAttr(..)
635635
| Res::Err => None,
636636
}
@@ -652,7 +652,7 @@ impl<Id> Res<Id> {
652652
Res::PrimTy(..) => "builtin type",
653653
Res::Local(..) => "local variable",
654654
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type",
655-
Res::ToolMod => "tool module",
655+
Res::ToolMod { .. } => "tool module",
656656
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
657657
Res::Err => "unresolved item",
658658
}
@@ -720,9 +720,10 @@ impl<Id> Res<Id> {
720720
pub fn ns(&self) -> Option<Namespace> {
721721
match self {
722722
Res::Def(kind, ..) => kind.ns(),
723-
Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => {
724-
Some(Namespace::TypeNS)
725-
}
723+
Res::PrimTy(..)
724+
| Res::SelfTyParam { .. }
725+
| Res::SelfTyAlias { .. }
726+
| Res::ToolMod { .. } => Some(Namespace::TypeNS),
726727
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
727728
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
728729
Res::Err => None,

compiler/rustc_lint/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ impl LintStore {
404404
// FIXME: rustc and rustdoc are considered tools for lints, but not for attributes.
405405
if tool_name != sym::rustc
406406
&& tool_name != sym::rustdoc
407+
&& tool_name != sym::diagnostic
407408
&& !registered_tools.contains(&Ident::with_dummy_span(tool_name))
408409
{
409410
return CheckLintNameResult::NoTool;

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3398,6 +3398,7 @@ declare_lint_pass! {
33983398
UNFULFILLED_LINT_EXPECTATIONS,
33993399
UNINHABITED_STATIC,
34003400
UNKNOWN_CRATE_TYPES,
3401+
UNKNOWN_DIAGNOSTIC_ATTRIBUTE,
34013402
UNKNOWN_LINTS,
34023403
UNREACHABLE_CODE,
34033404
UNREACHABLE_PATTERNS,
@@ -4251,3 +4252,26 @@ declare_lint! {
42514252
Warn,
42524253
"\"invalid_parameter\" isn't a valid argument for `#[macro_export]`",
42534254
}
4255+
4256+
declare_lint! {
4257+
/// The `unknown_diagnostic_attribute` lint detects unrecognized diagnostic attributes.
4258+
///
4259+
/// ### Example
4260+
///
4261+
/// ```rust
4262+
/// #[diagnostic::does_not_exist]
4263+
/// struct Foo;
4264+
/// ```
4265+
///
4266+
/// {{produces}}
4267+
///
4268+
/// ### Explanation
4269+
///
4270+
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
4271+
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
4272+
/// consider if you are using an old version of the compiler, and the attribute
4273+
/// is only available in a newer version.
4274+
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTE,
4275+
Warn,
4276+
"unrecognized diagnostic attribute"
4277+
}

compiler/rustc_passes/src/dead.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
110110
Res::Def(_, def_id) => self.check_def_id(def_id),
111111
Res::SelfTyParam { trait_: t } => self.check_def_id(t),
112112
Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i),
113-
Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
113+
Res::ToolMod { .. } | Res::NonMacroAttr(..) | Res::Err => {}
114114
}
115115
}
116116

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
956956
_,
957957
)
958958
| Res::PrimTy(..)
959-
| Res::ToolMod => self.r.define(parent, ident, TypeNS, (res, vis, span, expansion)),
959+
| Res::ToolMod { .. } => {
960+
self.r.define(parent, ident, TypeNS, (res, vis, span, expansion))
961+
}
960962
Res::Def(
961963
DefKind::Fn
962964
| DefKind::AssocFn

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14041404
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
14051405
format!("a derive macro: `#[derive({})]`", ident)
14061406
}
1407-
Res::ToolMod => {
1407+
Res::ToolMod { .. } => {
14081408
// Don't confuse the user with tool modules.
14091409
continue;
14101410
}
@@ -1505,7 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
15051505
if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
15061506
// These already contain the "built-in" prefix or look bad with it.
15071507
let add_built_in =
1508-
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1508+
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod { .. });
15091509
let (built_in, from) = if from_prelude {
15101510
("", " from prelude")
15111511
} else if b.is_extern_crate()

compiler/rustc_resolve/src/macros.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
2121
use rustc_middle::middle::stability;
2222
use rustc_middle::ty::RegisteredTools;
2323
use rustc_middle::ty::TyCtxt;
24-
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
24+
use rustc_session::lint::builtin::{
25+
LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTE,
26+
};
2527
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
2628
use rustc_session::lint::BuiltinLintDiagnostics;
2729
use rustc_session::parse::feature_err;
@@ -137,10 +139,11 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
137139
}
138140
}
139141
}
140-
// We implicitly add `rustfmt` and `clippy` to known tools,
142+
// We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
141143
// but it's not an error to register them explicitly.
142144
let predefined_tools = [sym::clippy, sym::rustfmt];
143145
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
146+
registered_tools.insert(Ident::with_dummy_span(sym::diagnostic));
144147
registered_tools
145148
}
146149

@@ -493,6 +496,27 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
493496
Err(Determinacy::Undetermined) => return Err(Indeterminate),
494497
};
495498

499+
if kind == MacroKind::Attr
500+
&& !path.segments.is_empty()
501+
&& path.segments[0].ident.as_str() == "diagnostic"
502+
{
503+
if path.segments.len() != 2 {
504+
self.tcx
505+
.sess
506+
.span_err(path.span, "Diagnostic attributes requires a path with 2 segments");
507+
self.tcx
508+
.sess
509+
.span_err(path.span, "Diagnostic attributes requires a path with 2 segments");
510+
} else {
511+
self.tcx.sess.parse_sess.buffer_lint(
512+
UNKNOWN_DIAGNOSTIC_ATTRIBUTE,
513+
path.segments[1].span(),
514+
node_id,
515+
"Unknown diagnostic attribute",
516+
);
517+
}
518+
}
519+
496520
// Report errors for the resolved macro.
497521
for segment in &path.segments {
498522
if let Some(args) = &segment.args {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
mod diagnostic {}
4+
5+
macro_rules! diagnostic{
6+
() => {}
7+
}
8+
9+
#[allow(non_upper_case_globals)]
10+
const diagnostic: () = ();
11+
12+
fn main() {
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// check-pass
2+
#[diagnostic::non_existing_attribute]
3+
//~^WARN Unknown diagnostic attribute
4+
pub trait Bar {
5+
}
6+
7+
#[diagnostic::non_existing_attribute(with_option = "foo")]
8+
//~^WARN Unknown diagnostic attribute
9+
struct Foo;
10+
11+
fn main() {
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
warning: Unknown diagnostic attribute
2+
--> $DIR/non_existing_attributes_accepted.rs:2:15
3+
|
4+
LL | #[diagnostic::non_existing_attribute]
5+
| ^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(unknown_diagnostic_attribute)]` on by default
8+
9+
warning: Unknown diagnostic attribute
10+
--> $DIR/non_existing_attributes_accepted.rs:7:15
11+
|
12+
LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
13+
| ^^^^^^^^^^^^^^^^^^^^^^
14+
15+
warning: 2 warnings emitted
16+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// check-fail
2+
3+
#[diagnostic]
4+
//~^ERROR Diagnostic attributes requires a path with 2 segments
5+
//~|ERROR Diagnostic attributes requires a path with 2 segments
6+
//~|ERROR cannot find attribute `diagnostic` in this scope
7+
pub struct Bar;
8+
9+
10+
fn main() {
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Diagnostic attributes requires a path with 2 segments
2+
--> $DIR/requires_path.rs:3:3
3+
|
4+
LL | #[diagnostic]
5+
| ^^^^^^^^^^
6+
7+
error: Diagnostic attributes requires a path with 2 segments
8+
--> $DIR/requires_path.rs:3:3
9+
|
10+
LL | #[diagnostic]
11+
| ^^^^^^^^^^
12+
13+
error: cannot find attribute `diagnostic` in this scope
14+
--> $DIR/requires_path.rs:3:3
15+
|
16+
LL | #[diagnostic]
17+
| ^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)