Diagnostic args are still args if they're documented
This commit is contained in:
parent
ad6b20bf52
commit
2b9279f313
4 changed files with 97 additions and 8 deletions
|
@ -4,17 +4,16 @@ use crate::diagnostics::error::{
|
||||||
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
use crate::diagnostics::utils::{
|
||||||
build_field_mapping, is_doc_comment, new_code_ident,
|
build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
|
||||||
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
|
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
|
||||||
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap,
|
||||||
|
HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
|
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
|
||||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||||
|
|
||||||
use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
|
|
||||||
|
|
||||||
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
|
||||||
pub(crate) struct SubdiagnosticDeriveBuilder {
|
pub(crate) struct SubdiagnosticDeriveBuilder {
|
||||||
diag: syn::Ident,
|
diag: syn::Ident,
|
||||||
|
@ -212,7 +211,6 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||||
/// Generates the code for a field with no attributes.
|
/// Generates the code for a field with no attributes.
|
||||||
fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
|
fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
|
||||||
let ast = binding.ast();
|
let ast = binding.ast();
|
||||||
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
|
|
||||||
|
|
||||||
let diag = &self.parent.diag;
|
let diag = &self.parent.diag;
|
||||||
let ident = ast.ident.as_ref().unwrap();
|
let ident = ast.ident.as_ref().unwrap();
|
||||||
|
@ -580,7 +578,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||||
.variant
|
.variant
|
||||||
.bindings()
|
.bindings()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|binding| binding.ast().attrs.is_empty())
|
.filter(|binding| should_generate_set_arg(binding.ast()))
|
||||||
.map(|binding| self.generate_field_set_arg(binding))
|
.map(|binding| self.generate_field_set_arg(binding))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -851,7 +851,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
||||||
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
||||||
/// call (like `span_label`).
|
/// call (like `span_label`).
|
||||||
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
|
||||||
field.attrs.is_empty()
|
// Perhaps this should be an exhaustive list...
|
||||||
|
field.attrs.iter().all(|attr| is_doc_comment(attr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// check-fail
|
||||||
|
// Tests that a doc comment will not preclude a field from being considered a diagnostic argument
|
||||||
|
|
||||||
|
// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
|
||||||
|
// changing the output of this test. Since Subdiagnostic is strictly internal to the compiler
|
||||||
|
// the test is just ignored on stable and beta:
|
||||||
|
// ignore-stage1
|
||||||
|
// ignore-beta
|
||||||
|
// ignore-stable
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
extern crate rustc_errors;
|
||||||
|
extern crate rustc_fluent_macro;
|
||||||
|
extern crate rustc_macros;
|
||||||
|
extern crate rustc_session;
|
||||||
|
extern crate rustc_span;
|
||||||
|
|
||||||
|
use rustc_errors::{Applicability, DiagnosticMessage, SubdiagnosticMessage};
|
||||||
|
use rustc_fluent_macro::fluent_messages;
|
||||||
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
fluent_messages! { "./example.ftl" }
|
||||||
|
|
||||||
|
struct NotIntoDiagnosticArg;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
//~^ ERROR the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
#[diag(no_crate_example)]
|
||||||
|
struct Test {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
/// A doc comment
|
||||||
|
arg: NotIntoDiagnosticArg,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
//~^ ERROR the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
#[label(no_crate_example)]
|
||||||
|
struct SubTest {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
/// A doc comment
|
||||||
|
arg: NotIntoDiagnosticArg,
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
--> $DIR/diagnostic-derive-doc-comment-field.rs:29:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Diagnostic)]
|
||||||
|
| ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
||||||
|
= help: the following other types implement trait `IntoDiagnosticArg`:
|
||||||
|
&'a T
|
||||||
|
&'a std::path::Path
|
||||||
|
&'a str
|
||||||
|
&rustc_target::spec::TargetTriple
|
||||||
|
Box<(dyn std::error::Error + 'static)>
|
||||||
|
CString
|
||||||
|
CguReuse
|
||||||
|
Cow<'a, str>
|
||||||
|
and 42 others
|
||||||
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:747:5
|
||||||
|
= note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied
|
||||||
|
--> $DIR/diagnostic-derive-doc-comment-field.rs:39:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Subdiagnostic)]
|
||||||
|
| ^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
||||||
|
= help: the following other types implement trait `IntoDiagnosticArg`:
|
||||||
|
&'a T
|
||||||
|
&'a std::path::Path
|
||||||
|
&'a str
|
||||||
|
&rustc_target::spec::TargetTriple
|
||||||
|
Box<(dyn std::error::Error + 'static)>
|
||||||
|
CString
|
||||||
|
CguReuse
|
||||||
|
Cow<'a, str>
|
||||||
|
and 42 others
|
||||||
|
note: required by a bound in `Diagnostic::set_arg`
|
||||||
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:964:5
|
||||||
|
= note: this error originates in the derive macro `Subdiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue