@@ -18,30 +18,15 @@ use syn::{
1818} ;
1919use synstructure:: { BindingInfo , Structure } ;
2020
21- /// What kind of diagnostic is being derived - an error, a warning or a lint?
22- #[ derive( Copy , Clone ) ]
21+ /// What kind of diagnostic is being derived - a fatal/error/ warning or a lint?
22+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
2323pub ( crate ) enum DiagnosticDeriveKind {
24- /// `#[error(..)]`
25- Error ,
26- /// `#[warn(..)]`
27- Warn ,
28- /// `#[lint(..)]`
29- Lint ,
30- }
31-
32- impl DiagnosticDeriveKind {
33- /// Returns human-readable string corresponding to the kind.
34- pub fn descr ( & self ) -> & ' static str {
35- match self {
36- DiagnosticDeriveKind :: Error => "error" ,
37- DiagnosticDeriveKind :: Warn => "warning" ,
38- DiagnosticDeriveKind :: Lint => "lint" ,
39- }
40- }
24+ SessionDiagnostic ,
25+ LintDiagnostic ,
4126}
4227
4328/// Tracks persistent information required for building up individual calls to diagnostic methods
44- /// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and
29+ /// for generated diagnostic derives - both `SessionDiagnostic` for fatal/ errors/warnings and
4530/// `LintDiagnostic` for lints.
4631pub ( crate ) struct DiagnosticDeriveBuilder {
4732 /// The identifier to use for the generated `DiagnosticBuilder` instance.
@@ -51,8 +36,8 @@ pub(crate) struct DiagnosticDeriveBuilder {
5136 /// derive builder.
5237 pub fields : HashMap < String , TokenStream > ,
5338
54- /// Kind of diagnostic requested via the struct attribute .
55- pub kind : Option < ( DiagnosticDeriveKind , proc_macro :: Span ) > ,
39+ /// Kind of diagnostic that should be derived .
40+ pub kind : DiagnosticDeriveKind ,
5641 /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
5742 /// has the actual diagnostic message.
5843 pub slug : Option < ( Path , proc_macro:: Span ) > ,
@@ -143,7 +128,7 @@ impl DiagnosticDeriveBuilder {
143128 }
144129
145130 /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
146- /// attributes like `#[error (..)`, such as the diagnostic kind and slug . Generates
131+ /// attributes like `#[diag (..)] `, such as the slug and error code . Generates
147132 /// diagnostic builder calls for setting error code and creating note/help messages.
148133 fn generate_structure_code_for_attr (
149134 & mut self ,
@@ -156,15 +141,15 @@ impl DiagnosticDeriveBuilder {
156141 let name = name. as_str ( ) ;
157142 let meta = attr. parse_meta ( ) ?;
158143
159- let is_help_note_or_warn = matches ! ( name, "help " | "note " | "warn_ " ) ;
144+ let is_diag = matches ! ( name, "error " | "warning " | "lint" | "diag ") ;
160145
161146 let nested = match meta {
162- // Most attributes are lists, like `#[error(..)]`/`#[warning (..)]` for most cases or
147+ // Most attributes are lists, like `#[diag (..)]` for most cases or
163148 // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
164149 Meta :: List ( MetaList { ref nested, .. } ) => nested,
165150 // Subdiagnostics without spans can be applied to the type too, and these are just
166- // paths: `#[help]` and `#[note ]`
167- Meta :: Path ( _) if is_help_note_or_warn => {
151+ // paths: `#[help]`, `#[note]` and `#[warn_ ]`
152+ Meta :: Path ( _) if !is_diag => {
168153 let fn_name = if name == "warn_" {
169154 Ident :: new ( "warn" , attr. span ( ) )
170155 } else {
@@ -178,23 +163,32 @@ impl DiagnosticDeriveBuilder {
178163 // Check the kind before doing any further processing so that there aren't misleading
179164 // "no kind specified" errors if there are failures later.
180165 match name {
181- "error" => self . kind . set_once ( ( DiagnosticDeriveKind :: Error , span) ) ,
182- "warning" => self . kind . set_once ( ( DiagnosticDeriveKind :: Warn , span) ) ,
183- "lint" => self . kind . set_once ( ( DiagnosticDeriveKind :: Lint , span) ) ,
184- "help" | "note" | "warn_" => ( ) ,
166+ "error" | "warning" => {
167+ if self . kind == DiagnosticDeriveKind :: LintDiagnostic {
168+ span_err ( span, "only `#[lint(..)]` is supported" )
169+ . help ( "use the `#[lint(...)]` attribute to create a lint" )
170+ . emit ( ) ;
171+ }
172+ }
173+ "lint" => {
174+ if self . kind == DiagnosticDeriveKind :: SessionDiagnostic {
175+ span_err ( span, "only `#[error(..)]` and `#[warning(..)]` are supported" )
176+ . help ( "use the `#[error(...)]` attribute to create a error" )
177+ . emit ( ) ;
178+ }
179+ }
180+ "diag" | "help" | "note" | "warn_" => ( ) ,
185181 _ => throw_invalid_attr ! ( attr, & meta, |diag| {
186- diag. help(
187- "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes" ,
188- )
182+ diag. help( "only `diag`, `help`, `note` and `warn_` are valid attributes" )
189183 } ) ,
190184 }
191185
192- // First nested element should always be the path, e.g. `#[error (typeck::invalid)]` or
186+ // First nested element should always be the path, e.g. `#[diag (typeck::invalid)]` or
193187 // `#[help(typeck::another_help)]`.
194188 let mut nested_iter = nested. into_iter ( ) ;
195189 if let Some ( nested_attr) = nested_iter. next ( ) {
196190 // Report an error if there are any other list items after the path.
197- if is_help_note_or_warn && nested_iter. next ( ) . is_some ( ) {
191+ if !is_diag && nested_iter. next ( ) . is_some ( ) {
198192 throw_invalid_nested_attr ! ( attr, & nested_attr, |diag| {
199193 diag. help(
200194 "`help`, `note` and `warn_` struct attributes can only have one argument" ,
@@ -203,16 +197,16 @@ impl DiagnosticDeriveBuilder {
203197 }
204198
205199 match nested_attr {
206- NestedMeta :: Meta ( Meta :: Path ( path) ) if is_help_note_or_warn => {
207- let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
208- return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: #path) ; } ) ;
209- }
210200 NestedMeta :: Meta ( Meta :: Path ( path) ) => {
211- self . slug . set_once ( ( path. clone ( ) , span) ) ;
201+ if is_diag {
202+ self . slug . set_once ( ( path. clone ( ) , span) ) ;
203+ } else {
204+ let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
205+ return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: #path) ; } ) ;
206+ }
212207 }
213208 NestedMeta :: Meta ( meta @ Meta :: NameValue ( _) )
214- if !is_help_note_or_warn
215- && meta. path ( ) . segments . last ( ) . unwrap ( ) . ident == "code" =>
209+ if is_diag && meta. path ( ) . segments . last ( ) . unwrap ( ) . ident == "code" =>
216210 {
217211 // don't error for valid follow-up attributes
218212 }
@@ -347,6 +341,7 @@ impl DiagnosticDeriveBuilder {
347341 }
348342 "primary_span" => {
349343 report_error_if_not_applied_to_span ( attr, & info) ?;
344+
350345 Ok ( quote ! {
351346 #diag. set_span( #binding) ;
352347 } )
0 commit comments