@@ -339,22 +339,25 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
339339}
340340
341341declare_tool_lint ! {
342- /// The `untranslatable_diagnostic` lint detects diagnostics created
343- /// without using translatable Fluent strings.
342+ /// The `untranslatable_diagnostic` lint detects messages passed to functions annotated with
343+ /// `#[rustc_lint_diagnostics]` without using translatable Fluent strings.
344344 ///
345- /// More details on translatable diagnostics can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
345+ /// More details on translatable diagnostics can be found
346+ /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
346347 pub rustc:: UNTRANSLATABLE_DIAGNOSTIC ,
347348 Deny ,
348349 "prevent creation of diagnostics which cannot be translated" ,
349350 report_in_external_macro: true
350351}
351352
352353declare_tool_lint ! {
353- /// The `diagnostic_outside_of_impl` lint detects diagnostics created manually,
354- /// and inside an `IntoDiagnostic`/`AddToDiagnostic` implementation,
355- /// or a `#[derive(Diagnostic)]`/`#[derive(Subdiagnostic)]` expansion.
354+ /// The `diagnostic_outside_of_impl` lint detects calls to functions annotated with
355+ /// `#[rustc_lint_diagnostics]` that are outside a `IntoDiagnostic`, `AddToDiagnostic`, or
356+ /// `DecorateLint` impl, or a `#[derive(Diagnostic)]`, `#[derive(Subdiagnostic)]`,
357+ /// `#[derive(DecorateLint)]` expansion.
356358 ///
357- /// More details on diagnostics implementations can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
359+ /// More details on diagnostics implementations can be found
360+ /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
358361 pub rustc:: DIAGNOSTIC_OUTSIDE_OF_IMPL ,
359362 Deny ,
360363 "prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls" ,
@@ -369,10 +372,15 @@ declare_tool_lint! {
369372 report_in_external_macro: true
370373}
371374
372- declare_lint_pass ! ( Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC , DIAGNOSTIC_OUTSIDE_OF_IMPL , UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL ] ) ;
375+ declare_lint_pass ! ( Diagnostics => [
376+ UNTRANSLATABLE_DIAGNOSTIC ,
377+ DIAGNOSTIC_OUTSIDE_OF_IMPL ,
378+ UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL
379+ ] ) ;
373380
374381impl LateLintPass < ' _ > for Diagnostics {
375382 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
383+ // Return early if it's not a call to a function marked with `#[rustc_lint_diagnostics]`.
376384 let Some ( ( span, def_id, args) ) = typeck_results_of_method_fn ( cx, expr) else { return } ;
377385 debug ! ( ?span, ?def_id, ?args) ;
378386 let has_attr = ty:: Instance :: resolve ( cx. tcx , cx. param_env , def_id, args)
@@ -383,12 +391,19 @@ impl LateLintPass<'_> for Diagnostics {
383391 return ;
384392 }
385393
394+ // Calls to `#[rustc_lint_diagnostics]`-marked functions should only occur:
395+ // - inside an impl of `IntoDiagnostic`, `AddToDiagnostic`, or `DecorateLint`, or
396+ // - inside a function that is itself marked with `#[rustc_lint_diagnostics]`.
397+ //
398+ // Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
386399 let mut found_parent_with_attr = false ;
387400 let mut found_impl = false ;
388401 for ( hir_id, parent) in cx. tcx . hir ( ) . parent_iter ( expr. hir_id ) {
389- if let Some ( owner_did) = hir_id. as_owner ( ) {
390- found_parent_with_attr = found_parent_with_attr
391- || cx. tcx . has_attr ( owner_did, sym:: rustc_lint_diagnostics) ;
402+ if let Some ( owner_did) = hir_id. as_owner ( )
403+ && cx. tcx . has_attr ( owner_did, sym:: rustc_lint_diagnostics)
404+ {
405+ found_parent_with_attr = true ;
406+ break ;
392407 }
393408
394409 debug ! ( ?parent) ;
@@ -407,6 +422,10 @@ impl LateLintPass<'_> for Diagnostics {
407422 cx. emit_span_lint ( DIAGNOSTIC_OUTSIDE_OF_IMPL , span, DiagOutOfImpl ) ;
408423 }
409424
425+ // Calls to `#[rustc_lint_diagnostics]`-marked functions should only be passed
426+ // `DiagnosticMessage` or `SubdiagnosticMessage` arguments, unless they are inside a
427+ // function that is itself marked with `#[rustc_lint_diagnostics]`. Otherwise, emit an
428+ // `UNTRANSLATABLE_DIAGNOSTIC` lint.
410429 let mut found_diagnostic_message = false ;
411430 for ty in args. types ( ) {
412431 debug ! ( ?ty) ;
@@ -506,7 +525,7 @@ declare_tool_lint! {
506525 report_in_external_macro: true
507526}
508527
509- declare_lint_pass ! ( BadOptAccess => [ BAD_OPT_ACCESS ] ) ;
528+ declare_lint_pass ! ( BadOptAccess => [ BAD_OPT_ACCESS ] ) ;
510529
511530impl LateLintPass < ' _ > for BadOptAccess {
512531 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
0 commit comments