1
1
use crate :: snippet:: Style ;
2
2
use crate :: {
3
- CodeSuggestion , DiagnosticBuilder , DiagnosticMessage , EmissionGuarantee , ErrCode , Level ,
4
- MultiSpan , SubdiagnosticMessage , Substitution , SubstitutionPart , SuggestionStyle ,
3
+ CodeSuggestion , DiagCtxt , DiagnosticMessage , ErrCode , ErrorGuaranteed , ExplicitBug , Level ,
4
+ MultiSpan , StashKey , SubdiagnosticMessage , Substitution , SubstitutionPart , SuggestionStyle ,
5
5
} ;
6
6
use rustc_data_structures:: fx:: FxIndexMap ;
7
7
use rustc_error_messages:: fluent_value_from_str_list_sep_by_and;
8
8
use rustc_error_messages:: FluentValue ;
9
9
use rustc_lint_defs:: { Applicability , LintExpectationId } ;
10
+ use rustc_span:: source_map:: Spanned ;
10
11
use rustc_span:: symbol:: Symbol ;
11
12
use rustc_span:: { Span , DUMMY_SP } ;
12
13
use std:: borrow:: Cow ;
13
14
use std:: fmt:: { self , Debug } ;
14
15
use std:: hash:: { Hash , Hasher } ;
16
+ use std:: marker:: PhantomData ;
15
17
use std:: ops:: { Deref , DerefMut } ;
16
- use std:: panic:: Location ;
18
+ use std:: panic;
19
+ use std:: thread:: panicking;
17
20
18
21
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
19
22
/// `.disable_suggestions()` was called on the `Diagnostic`.
@@ -40,6 +43,86 @@ pub enum DiagnosticArgValue {
40
43
StrListSepByAnd ( Vec < Cow < ' static , str > > ) ,
41
44
}
42
45
46
+ /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
47
+ /// (or "proof") token that the emission happened.
48
+ pub trait EmissionGuarantee : Sized {
49
+ /// This exists so that bugs and fatal errors can both result in `!` (an
50
+ /// abort) when emitted, but have different aborting behaviour.
51
+ type EmitResult = Self ;
52
+
53
+ /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each
54
+ /// `impl` of `EmissionGuarantee`, to make it impossible to create a value
55
+ /// of `Self::EmitResult` without actually performing the emission.
56
+ #[ track_caller]
57
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult ;
58
+ }
59
+
60
+ impl EmissionGuarantee for ErrorGuaranteed {
61
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult {
62
+ db. emit_producing_error_guaranteed ( )
63
+ }
64
+ }
65
+
66
+ impl EmissionGuarantee for ( ) {
67
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult {
68
+ db. emit_producing_nothing ( ) ;
69
+ }
70
+ }
71
+
72
+ /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
73
+ /// bug diagnostics.
74
+ #[ derive( Copy , Clone ) ]
75
+ pub struct BugAbort ;
76
+
77
+ impl EmissionGuarantee for BugAbort {
78
+ type EmitResult = !;
79
+
80
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult {
81
+ db. emit_producing_nothing ( ) ;
82
+ panic:: panic_any ( ExplicitBug ) ;
83
+ }
84
+ }
85
+
86
+ /// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
87
+ /// fatal diagnostics.
88
+ #[ derive( Copy , Clone ) ]
89
+ pub struct FatalAbort ;
90
+
91
+ impl EmissionGuarantee for FatalAbort {
92
+ type EmitResult = !;
93
+
94
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult {
95
+ db. emit_producing_nothing ( ) ;
96
+ crate :: FatalError . raise ( )
97
+ }
98
+ }
99
+
100
+ impl EmissionGuarantee for rustc_span:: fatal_error:: FatalError {
101
+ fn emit_producing_guarantee ( db : DiagnosticBuilder < ' _ , Self > ) -> Self :: EmitResult {
102
+ db. emit_producing_nothing ( ) ;
103
+ rustc_span:: fatal_error:: FatalError
104
+ }
105
+ }
106
+
107
+ /// Trait implemented by error types. This is rarely implemented manually. Instead, use
108
+ /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
109
+ #[ rustc_diagnostic_item = "IntoDiagnostic" ]
110
+ pub trait IntoDiagnostic < ' a , G : EmissionGuarantee = ErrorGuaranteed > {
111
+ /// Write out as a diagnostic out of `DiagCtxt`.
112
+ #[ must_use]
113
+ fn into_diagnostic ( self , dcx : & ' a DiagCtxt , level : Level ) -> DiagnosticBuilder < ' a , G > ;
114
+ }
115
+
116
+ impl < ' a , T , G > IntoDiagnostic < ' a , G > for Spanned < T >
117
+ where
118
+ T : IntoDiagnostic < ' a , G > ,
119
+ G : EmissionGuarantee ,
120
+ {
121
+ fn into_diagnostic ( self , dcx : & ' a DiagCtxt , level : Level ) -> DiagnosticBuilder < ' a , G > {
122
+ self . node . into_diagnostic ( dcx, level) . with_span ( self . span )
123
+ }
124
+ }
125
+
43
126
/// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic`
44
127
/// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type
45
128
/// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*`
@@ -98,36 +181,6 @@ pub trait DecorateLint<'a, G: EmissionGuarantee> {
98
181
fn msg ( & self ) -> DiagnosticMessage ;
99
182
}
100
183
101
- /// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps
102
- /// this type, is used for most operations, and should be used instead whenever
103
- /// possible. This type should only be used when `DiagnosticBuilder`'s lifetime
104
- /// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`.
105
- #[ must_use]
106
- #[ derive( Clone , Debug , Encodable , Decodable ) ]
107
- pub struct Diagnostic {
108
- // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
109
- // outside of what methods in this crate themselves allow.
110
- pub ( crate ) level : Level ,
111
-
112
- pub messages : Vec < ( DiagnosticMessage , Style ) > ,
113
- pub code : Option < ErrCode > ,
114
- pub span : MultiSpan ,
115
- pub children : Vec < SubDiagnostic > ,
116
- pub suggestions : Result < Vec < CodeSuggestion > , SuggestionsDisabled > ,
117
- args : FxIndexMap < DiagnosticArgName , DiagnosticArgValue > ,
118
-
119
- /// This is not used for highlighting or rendering any error message. Rather, it can be used
120
- /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
121
- /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
122
- pub sort_span : Span ,
123
-
124
- pub is_lint : Option < IsLint > ,
125
-
126
- /// With `-Ztrack_diagnostics` enabled,
127
- /// we print where in rustc this error was emitted.
128
- pub ( crate ) emitted_at : DiagnosticLocation ,
129
- }
130
-
131
184
#[ derive( Clone , Debug , Encodable , Decodable ) ]
132
185
pub struct DiagnosticLocation {
133
186
file : Cow < ' static , str > ,
@@ -138,7 +191,7 @@ pub struct DiagnosticLocation {
138
191
impl DiagnosticLocation {
139
192
#[ track_caller]
140
193
fn caller ( ) -> Self {
141
- let loc = Location :: caller ( ) ;
194
+ let loc = panic :: Location :: caller ( ) ;
142
195
DiagnosticLocation { file : loc. file ( ) . into ( ) , line : loc. line ( ) , col : loc. column ( ) }
143
196
}
144
197
}
@@ -157,15 +210,6 @@ pub struct IsLint {
157
210
has_future_breakage : bool ,
158
211
}
159
212
160
- /// A "sub"-diagnostic attached to a parent diagnostic.
161
- /// For example, a note attached to an error.
162
- #[ derive( Clone , Debug , PartialEq , Hash , Encodable , Decodable ) ]
163
- pub struct SubDiagnostic {
164
- pub level : Level ,
165
- pub messages : Vec < ( DiagnosticMessage , Style ) > ,
166
- pub span : MultiSpan ,
167
- }
168
-
169
213
#[ derive( Debug , PartialEq , Eq ) ]
170
214
pub struct DiagnosticStyledString ( pub Vec < StringPart > ) ;
171
215
@@ -215,6 +259,36 @@ impl StringPart {
215
259
}
216
260
}
217
261
262
+ /// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps
263
+ /// this type, is used for most operations, and should be used instead whenever
264
+ /// possible. This type should only be used when `DiagnosticBuilder`'s lifetime
265
+ /// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`.
266
+ #[ must_use]
267
+ #[ derive( Clone , Debug , Encodable , Decodable ) ]
268
+ pub struct Diagnostic {
269
+ // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
270
+ // outside of what methods in this crate themselves allow.
271
+ pub ( crate ) level : Level ,
272
+
273
+ pub messages : Vec < ( DiagnosticMessage , Style ) > ,
274
+ pub code : Option < ErrCode > ,
275
+ pub span : MultiSpan ,
276
+ pub children : Vec < SubDiagnostic > ,
277
+ pub suggestions : Result < Vec < CodeSuggestion > , SuggestionsDisabled > ,
278
+ args : FxIndexMap < DiagnosticArgName , DiagnosticArgValue > ,
279
+
280
+ /// This is not used for highlighting or rendering any error message. Rather, it can be used
281
+ /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
282
+ /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
283
+ pub sort_span : Span ,
284
+
285
+ pub is_lint : Option < IsLint > ,
286
+
287
+ /// With `-Ztrack_diagnostics` enabled,
288
+ /// we print where in rustc this error was emitted.
289
+ pub ( crate ) emitted_at : DiagnosticLocation ,
290
+ }
291
+
218
292
impl Diagnostic {
219
293
#[ track_caller]
220
294
pub fn new < M : Into < DiagnosticMessage > > ( level : Level , message : M ) -> Self {
@@ -336,6 +410,118 @@ impl Diagnostic {
336
410
pub fn replace_args ( & mut self , args : FxIndexMap < DiagnosticArgName , DiagnosticArgValue > ) {
337
411
self . args = args;
338
412
}
413
+
414
+ /// Fields used for Hash, and PartialEq trait.
415
+ fn keys (
416
+ & self ,
417
+ ) -> (
418
+ & Level ,
419
+ & [ ( DiagnosticMessage , Style ) ] ,
420
+ & Option < ErrCode > ,
421
+ & MultiSpan ,
422
+ & [ SubDiagnostic ] ,
423
+ & Result < Vec < CodeSuggestion > , SuggestionsDisabled > ,
424
+ Vec < ( & DiagnosticArgName , & DiagnosticArgValue ) > ,
425
+ & Option < IsLint > ,
426
+ ) {
427
+ (
428
+ & self . level ,
429
+ & self . messages ,
430
+ & self . code ,
431
+ & self . span ,
432
+ & self . children ,
433
+ & self . suggestions ,
434
+ self . args ( ) . collect ( ) ,
435
+ // omit self.sort_span
436
+ & self . is_lint ,
437
+ // omit self.emitted_at
438
+ )
439
+ }
440
+ }
441
+
442
+ impl Hash for Diagnostic {
443
+ fn hash < H > ( & self , state : & mut H )
444
+ where
445
+ H : Hasher ,
446
+ {
447
+ self . keys ( ) . hash ( state) ;
448
+ }
449
+ }
450
+
451
+ impl PartialEq for Diagnostic {
452
+ fn eq ( & self , other : & Self ) -> bool {
453
+ self . keys ( ) == other. keys ( )
454
+ }
455
+ }
456
+
457
+ /// A "sub"-diagnostic attached to a parent diagnostic.
458
+ /// For example, a note attached to an error.
459
+ #[ derive( Clone , Debug , PartialEq , Hash , Encodable , Decodable ) ]
460
+ pub struct SubDiagnostic {
461
+ pub level : Level ,
462
+ pub messages : Vec < ( DiagnosticMessage , Style ) > ,
463
+ pub span : MultiSpan ,
464
+ }
465
+
466
+ /// Used for emitting structured error messages and other diagnostic information.
467
+ /// Wraps a `Diagnostic`, adding some useful things.
468
+ /// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
469
+ /// that it has been emitted or cancelled.
470
+ /// - The `EmissionGuarantee`, which determines the type returned from `emit`.
471
+ ///
472
+ /// Each constructed `DiagnosticBuilder` must be consumed by a function such as
473
+ /// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a
474
+ /// `DiagnosticBuilder` is dropped without being consumed by one of these
475
+ /// functions.
476
+ ///
477
+ /// If there is some state in a downstream crate you would like to
478
+ /// access in the methods of `DiagnosticBuilder` here, consider
479
+ /// extending `DiagCtxtFlags`.
480
+ #[ must_use]
481
+ pub struct DiagnosticBuilder < ' a , G : EmissionGuarantee = ErrorGuaranteed > {
482
+ pub dcx : & ' a DiagCtxt ,
483
+
484
+ /// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is
485
+ /// consumed via `emit`, `cancel`, etc. At that point it is consumed and
486
+ /// replaced with `None`. Then `drop` checks that it is `None`; if not, it
487
+ /// panics because a diagnostic was built but not used.
488
+ ///
489
+ /// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is
490
+ /// often used as a return value, especially within the frequently-used
491
+ /// `PResult` type. In theory, return value optimization (RVO) should avoid
492
+ /// unnecessary copying. In practice, it does not (at the time of writing).
493
+ diag : Option < Box < Diagnostic > > ,
494
+
495
+ _marker : PhantomData < G > ,
496
+ }
497
+
498
+ // Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted
499
+ // twice, which would be bad.
500
+ impl < G > !Clone for DiagnosticBuilder < ' _ , G > { }
501
+
502
+ rustc_data_structures:: static_assert_size!(
503
+ DiagnosticBuilder <' _, ( ) >,
504
+ 2 * std:: mem:: size_of:: <usize >( )
505
+ ) ;
506
+
507
+ impl < G : EmissionGuarantee > Deref for DiagnosticBuilder < ' _ , G > {
508
+ type Target = Diagnostic ;
509
+
510
+ fn deref ( & self ) -> & Diagnostic {
511
+ self . diag . as_ref ( ) . unwrap ( )
512
+ }
513
+ }
514
+
515
+ impl < G : EmissionGuarantee > DerefMut for DiagnosticBuilder < ' _ , G > {
516
+ fn deref_mut ( & mut self ) -> & mut Diagnostic {
517
+ self . diag . as_mut ( ) . unwrap ( )
518
+ }
519
+ }
520
+
521
+ impl < G : EmissionGuarantee > Debug for DiagnosticBuilder < ' _ , G > {
522
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
523
+ self . diag . fmt ( f)
524
+ }
339
525
}
340
526
341
527
/// `DiagnosticBuilder` impls many `&mut self -> &mut Self` methods. Each one
@@ -382,6 +568,20 @@ macro_rules! with_fn {
382
568
}
383
569
384
570
impl < ' a , G : EmissionGuarantee > DiagnosticBuilder < ' a , G > {
571
+ #[ rustc_lint_diagnostics]
572
+ #[ track_caller]
573
+ pub fn new < M : Into < DiagnosticMessage > > ( dcx : & ' a DiagCtxt , level : Level , message : M ) -> Self {
574
+ Self :: new_diagnostic ( dcx, Diagnostic :: new ( level, message) )
575
+ }
576
+
577
+ /// Creates a new `DiagnosticBuilder` with an already constructed
578
+ /// diagnostic.
579
+ #[ track_caller]
580
+ pub ( crate ) fn new_diagnostic ( dcx : & ' a DiagCtxt , diag : Diagnostic ) -> Self {
581
+ debug ! ( "Created new diagnostic" ) ;
582
+ Self { dcx, diag : Some ( Box :: new ( diag) ) , _marker : PhantomData }
583
+ }
584
+
385
585
/// Delay emission of this diagnostic as a bug.
386
586
///
387
587
/// This can be useful in contexts where an error indicates a bug but
@@ -1040,48 +1240,112 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
1040
1240
let sub = SubDiagnostic { level, messages, span } ;
1041
1241
self . children . push ( sub) ;
1042
1242
}
1043
- }
1044
1243
1045
- impl Diagnostic {
1046
- /// Fields used for Hash, and PartialEq trait
1047
- fn keys (
1048
- & self ,
1049
- ) -> (
1050
- & Level ,
1051
- & [ ( DiagnosticMessage , Style ) ] ,
1052
- & Option < ErrCode > ,
1053
- & MultiSpan ,
1054
- & [ SubDiagnostic ] ,
1055
- & Result < Vec < CodeSuggestion > , SuggestionsDisabled > ,
1056
- Vec < ( & DiagnosticArgName , & DiagnosticArgValue ) > ,
1057
- & Option < IsLint > ,
1058
- ) {
1059
- (
1060
- & self . level ,
1061
- & self . messages ,
1062
- & self . code ,
1063
- & self . span ,
1064
- & self . children ,
1065
- & self . suggestions ,
1066
- self . args ( ) . collect ( ) ,
1067
- // omit self.sort_span
1068
- & self . is_lint ,
1069
- // omit self.emitted_at
1070
- )
1244
+ /// Takes the diagnostic. For use by methods that consume the
1245
+ /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the
1246
+ /// only code that will be run on `self`.
1247
+ fn take_diag ( & mut self ) -> Diagnostic {
1248
+ Box :: into_inner ( self . diag . take ( ) . unwrap ( ) )
1071
1249
}
1072
- }
1073
1250
1074
- impl Hash for Diagnostic {
1075
- fn hash < H > ( & self , state : & mut H )
1076
- where
1077
- H : Hasher ,
1078
- {
1079
- self . keys ( ) . hash ( state) ;
1251
+ /// Most `emit_producing_guarantee` functions use this as a starting point.
1252
+ fn emit_producing_nothing ( mut self ) {
1253
+ let diag = self . take_diag ( ) ;
1254
+ self . dcx . emit_diagnostic ( diag) ;
1255
+ }
1256
+
1257
+ /// `ErrorGuaranteed::emit_producing_guarantee` uses this.
1258
+ fn emit_producing_error_guaranteed ( mut self ) -> ErrorGuaranteed {
1259
+ let diag = self . take_diag ( ) ;
1260
+
1261
+ // The only error levels that produce `ErrorGuaranteed` are
1262
+ // `Error` and `DelayedBug`. But `DelayedBug` should never occur here
1263
+ // because delayed bugs have their level changed to `Bug` when they are
1264
+ // actually printed, so they produce an ICE.
1265
+ //
1266
+ // (Also, even though `level` isn't `pub`, the whole `Diagnostic` could
1267
+ // be overwritten with a new one thanks to `DerefMut`. So this assert
1268
+ // protects against that, too.)
1269
+ assert ! (
1270
+ matches!( diag. level, Level :: Error | Level :: DelayedBug ) ,
1271
+ "invalid diagnostic level ({:?})" ,
1272
+ diag. level,
1273
+ ) ;
1274
+
1275
+ let guar = self . dcx . emit_diagnostic ( diag) ;
1276
+ guar. unwrap ( )
1277
+ }
1278
+
1279
+ /// Emit and consume the diagnostic.
1280
+ #[ track_caller]
1281
+ pub fn emit ( self ) -> G :: EmitResult {
1282
+ G :: emit_producing_guarantee ( self )
1283
+ }
1284
+
1285
+ /// Emit the diagnostic unless `delay` is true,
1286
+ /// in which case the emission will be delayed as a bug.
1287
+ ///
1288
+ /// See `emit` and `delay_as_bug` for details.
1289
+ #[ track_caller]
1290
+ pub fn emit_unless ( mut self , delay : bool ) -> G :: EmitResult {
1291
+ if delay {
1292
+ self . downgrade_to_delayed_bug ( ) ;
1293
+ }
1294
+ self . emit ( )
1295
+ }
1296
+
1297
+ /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
1298
+ /// cancelled or it will panic when dropped).
1299
+ pub fn cancel ( mut self ) {
1300
+ self . diag = None ;
1301
+ drop ( self ) ;
1302
+ }
1303
+
1304
+ /// Stashes diagnostic for possible later improvement in a different,
1305
+ /// later stage of the compiler. The diagnostic can be accessed with
1306
+ /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
1307
+ pub fn stash ( mut self , span : Span , key : StashKey ) {
1308
+ self . dcx . stash_diagnostic ( span, key, self . take_diag ( ) ) ;
1309
+ }
1310
+
1311
+ /// Delay emission of this diagnostic as a bug.
1312
+ ///
1313
+ /// This can be useful in contexts where an error indicates a bug but
1314
+ /// typically this only happens when other compilation errors have already
1315
+ /// happened. In those cases this can be used to defer emission of this
1316
+ /// diagnostic as a bug in the compiler only if no other errors have been
1317
+ /// emitted.
1318
+ ///
1319
+ /// In the meantime, though, callsites are required to deal with the "bug"
1320
+ /// locally in whichever way makes the most sense.
1321
+ #[ track_caller]
1322
+ pub fn delay_as_bug ( mut self ) -> G :: EmitResult {
1323
+ self . downgrade_to_delayed_bug ( ) ;
1324
+ self . emit ( )
1080
1325
}
1081
1326
}
1082
1327
1083
- impl PartialEq for Diagnostic {
1084
- fn eq ( & self , other : & Self ) -> bool {
1085
- self . keys ( ) == other. keys ( )
1328
+ /// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted,
1329
+ /// cancelled, etc.) or we emit a bug.
1330
+ impl < G : EmissionGuarantee > Drop for DiagnosticBuilder < ' _ , G > {
1331
+ fn drop ( & mut self ) {
1332
+ match self . diag . take ( ) {
1333
+ Some ( diag) if !panicking ( ) => {
1334
+ self . dcx . emit_diagnostic ( Diagnostic :: new (
1335
+ Level :: Bug ,
1336
+ DiagnosticMessage :: from ( "the following error was constructed but not emitted" ) ,
1337
+ ) ) ;
1338
+ self . dcx . emit_diagnostic ( * diag) ;
1339
+ panic ! ( "error was constructed but not emitted" ) ;
1340
+ }
1341
+ _ => { }
1342
+ }
1086
1343
}
1087
1344
}
1345
+
1346
+ #[ macro_export]
1347
+ macro_rules! struct_span_code_err {
1348
+ ( $dcx: expr, $span: expr, $code: expr, $( $message: tt) * ) => ( {
1349
+ $dcx. struct_span_err( $span, format!( $( $message) * ) ) . with_code( $code)
1350
+ } )
1351
+ }
0 commit comments