DiagnosticIDs.cpp revision 218887
1//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file implements the Diagnostic IDs-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/ASTDiagnostic.h"
15#include "clang/Analysis/AnalysisDiagnostic.h"
16#include "clang/Basic/DiagnosticIDs.h"
17#include "clang/Basic/SourceManager.h"
18#include "clang/Driver/DriverDiagnostic.h"
19#include "clang/Frontend/FrontendDiagnostic.h"
20#include "clang/Lex/LexDiagnostic.h"
21#include "clang/Parse/ParseDiagnostic.h"
22#include "clang/Sema/SemaDiagnostic.h"
23
24#include <map>
25using namespace clang;
26
27//===----------------------------------------------------------------------===//
28// Builtin Diagnostic information
29//===----------------------------------------------------------------------===//
30
31namespace {
32
33// Diagnostic classes.
34enum {
35  CLASS_NOTE       = 0x01,
36  CLASS_WARNING    = 0x02,
37  CLASS_EXTENSION  = 0x03,
38  CLASS_ERROR      = 0x04
39};
40
41struct StaticDiagInfoRec {
42  unsigned short DiagID;
43  unsigned Mapping : 3;
44  unsigned Class : 3;
45  unsigned SFINAE : 1;
46  unsigned AccessControl : 1;
47  unsigned Category : 5;
48
49  const char *Description;
50  const char *OptionGroup;
51
52  bool operator<(const StaticDiagInfoRec &RHS) const {
53    return DiagID < RHS.DiagID;
54  }
55};
56
57}
58
59static const StaticDiagInfoRec StaticDiagInfo[] = {
60#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY)    \
61  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP },
62#include "clang/Basic/DiagnosticCommonKinds.inc"
63#include "clang/Basic/DiagnosticDriverKinds.inc"
64#include "clang/Basic/DiagnosticFrontendKinds.inc"
65#include "clang/Basic/DiagnosticLexKinds.inc"
66#include "clang/Basic/DiagnosticParseKinds.inc"
67#include "clang/Basic/DiagnosticASTKinds.inc"
68#include "clang/Basic/DiagnosticSemaKinds.inc"
69#include "clang/Basic/DiagnosticAnalysisKinds.inc"
70  { 0, 0, 0, 0, 0, 0, 0, 0}
71};
72#undef DIAG
73
74/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
75/// or null if the ID is invalid.
76static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
77  unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
78
79  // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
80#ifndef NDEBUG
81  static bool IsFirst = true;
82  if (IsFirst) {
83    for (unsigned i = 1; i != NumDiagEntries; ++i) {
84      assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
85             "Diag ID conflict, the enums at the start of clang::diag (in "
86             "DiagnosticIDs.h) probably need to be increased");
87
88      assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
89             "Improperly sorted diag info");
90    }
91    IsFirst = false;
92  }
93#endif
94
95  // Search the diagnostic table with a binary search.
96  StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 };
97
98  const StaticDiagInfoRec *Found =
99    std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
100  if (Found == StaticDiagInfo + NumDiagEntries ||
101      Found->DiagID != DiagID)
102    return 0;
103
104  return Found;
105}
106
107static unsigned GetDefaultDiagMapping(unsigned DiagID) {
108  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
109    return Info->Mapping;
110  return diag::MAP_FATAL;
111}
112
113/// getWarningOptionForDiag - Return the lowest-level warning option that
114/// enables the specified diagnostic.  If there is no -Wfoo flag that controls
115/// the diagnostic, this returns null.
116const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
117  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
118    return Info->OptionGroup;
119  return 0;
120}
121
122/// getWarningOptionForDiag - Return the category number that a specified
123/// DiagID belongs to, or 0 if no category.
124unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
125  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
126    return Info->Category;
127  return 0;
128}
129
130/// getCategoryNameFromID - Given a category ID, return the name of the
131/// category, an empty string if CategoryID is zero, or null if CategoryID is
132/// invalid.
133const char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
134  // Second the table of options, sorted by name for fast binary lookup.
135  static const char *CategoryNameTable[] = {
136#define GET_CATEGORY_TABLE
137#define CATEGORY(X) X,
138#include "clang/Basic/DiagnosticGroups.inc"
139#undef GET_CATEGORY_TABLE
140    "<<END>>"
141  };
142  static const size_t CategoryNameTableSize =
143    sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
144
145  if (CategoryID >= CategoryNameTableSize) return 0;
146  return CategoryNameTable[CategoryID];
147}
148
149
150
151DiagnosticIDs::SFINAEResponse
152DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
153  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
154    if (Info->AccessControl)
155      return SFINAE_AccessControl;
156
157    if (!Info->SFINAE)
158      return SFINAE_Report;
159
160    if (Info->Class == CLASS_ERROR)
161      return SFINAE_SubstitutionFailure;
162
163    // Suppress notes, warnings, and extensions;
164    return SFINAE_Suppress;
165  }
166
167  return SFINAE_Report;
168}
169
170/// getDiagClass - Return the class field of the diagnostic.
171///
172static unsigned getBuiltinDiagClass(unsigned DiagID) {
173  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
174    return Info->Class;
175  return ~0U;
176}
177
178//===----------------------------------------------------------------------===//
179// Custom Diagnostic information
180//===----------------------------------------------------------------------===//
181
182namespace clang {
183  namespace diag {
184    class CustomDiagInfo {
185      typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
186      std::vector<DiagDesc> DiagInfo;
187      std::map<DiagDesc, unsigned> DiagIDs;
188    public:
189
190      /// getDescription - Return the description of the specified custom
191      /// diagnostic.
192      const char *getDescription(unsigned DiagID) const {
193        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
194               "Invalid diagnosic ID");
195        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
196      }
197
198      /// getLevel - Return the level of the specified custom diagnostic.
199      DiagnosticIDs::Level getLevel(unsigned DiagID) const {
200        assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
201               "Invalid diagnosic ID");
202        return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
203      }
204
205      unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message,
206                                 DiagnosticIDs &Diags) {
207        DiagDesc D(L, Message);
208        // Check to see if it already exists.
209        std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
210        if (I != DiagIDs.end() && I->first == D)
211          return I->second;
212
213        // If not, assign a new ID.
214        unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
215        DiagIDs.insert(std::make_pair(D, ID));
216        DiagInfo.push_back(D);
217        return ID;
218      }
219    };
220
221  } // end diag namespace
222} // end clang namespace
223
224
225//===----------------------------------------------------------------------===//
226// Common Diagnostic implementation
227//===----------------------------------------------------------------------===//
228
229DiagnosticIDs::DiagnosticIDs() {
230  CustomDiagInfo = 0;
231}
232
233DiagnosticIDs::~DiagnosticIDs() {
234  delete CustomDiagInfo;
235}
236
237/// getCustomDiagID - Return an ID for a diagnostic with the specified message
238/// and level.  If this is the first request for this diagnosic, it is
239/// registered and created, otherwise the existing ID is returned.
240unsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) {
241  if (CustomDiagInfo == 0)
242    CustomDiagInfo = new diag::CustomDiagInfo();
243  return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
244}
245
246
247/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
248/// level of the specified diagnostic ID is a Warning or Extension.
249/// This only works on builtin diagnostics, not custom ones, and is not legal to
250/// call on NOTEs.
251bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
252  return DiagID < diag::DIAG_UPPER_LIMIT &&
253         getBuiltinDiagClass(DiagID) != CLASS_ERROR;
254}
255
256/// \brief Determine whether the given built-in diagnostic ID is a
257/// Note.
258bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
259  return DiagID < diag::DIAG_UPPER_LIMIT &&
260    getBuiltinDiagClass(DiagID) == CLASS_NOTE;
261}
262
263/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
264/// ID is for an extension of some sort.  This also returns EnabledByDefault,
265/// which is set to indicate whether the diagnostic is ignored by default (in
266/// which case -pedantic enables it) or treated as a warning/error by default.
267///
268bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
269                                        bool &EnabledByDefault) {
270  if (DiagID >= diag::DIAG_UPPER_LIMIT ||
271      getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
272    return false;
273
274  EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
275  return true;
276}
277
278/// getDescription - Given a diagnostic ID, return a description of the
279/// issue.
280const char *DiagnosticIDs::getDescription(unsigned DiagID) const {
281  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
282    return Info->Description;
283  return CustomDiagInfo->getDescription(DiagID);
284}
285
286/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
287/// object, classify the specified diagnostic ID into a Level, consumable by
288/// the DiagnosticClient.
289DiagnosticIDs::Level
290DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
291                                  const Diagnostic &Diag) const {
292  // Handle custom diagnostics, which cannot be mapped.
293  if (DiagID >= diag::DIAG_UPPER_LIMIT)
294    return CustomDiagInfo->getLevel(DiagID);
295
296  unsigned DiagClass = getBuiltinDiagClass(DiagID);
297  assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
298  return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
299}
300
301/// \brief Based on the way the client configured the Diagnostic
302/// object, classify the specified diagnostic ID into a Level, consumable by
303/// the DiagnosticClient.
304///
305/// \param Loc The source location we are interested in finding out the
306/// diagnostic state. Can be null in order to query the latest state.
307DiagnosticIDs::Level
308DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
309                                  SourceLocation Loc,
310                                  const Diagnostic &Diag) const {
311  // Specific non-error diagnostics may be mapped to various levels from ignored
312  // to error.  Errors can only be mapped to fatal.
313  DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
314
315  Diagnostic::DiagStatePointsTy::iterator
316    Pos = Diag.GetDiagStatePointForLoc(Loc);
317  Diagnostic::DiagState *State = Pos->State;
318
319  // Get the mapping information, if unset, compute it lazily.
320  unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
321                                                       State);
322  if (MappingInfo == 0) {
323    MappingInfo = GetDefaultDiagMapping(DiagID);
324    Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
325  }
326
327  switch (MappingInfo & 7) {
328  default: assert(0 && "Unknown mapping!");
329  case diag::MAP_IGNORE:
330    // Ignore this, unless this is an extension diagnostic and we're mapping
331    // them onto warnings or errors.
332    if (!isBuiltinExtensionDiag(DiagID) ||  // Not an extension
333        Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored
334        (MappingInfo & 8) != 0)             // User explicitly mapped it.
335      return DiagnosticIDs::Ignored;
336    Result = DiagnosticIDs::Warning;
337    if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error;
338    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
339      Result = DiagnosticIDs::Fatal;
340    break;
341  case diag::MAP_ERROR:
342    Result = DiagnosticIDs::Error;
343    if (Diag.ErrorsAsFatal)
344      Result = DiagnosticIDs::Fatal;
345    break;
346  case diag::MAP_FATAL:
347    Result = DiagnosticIDs::Fatal;
348    break;
349  case diag::MAP_WARNING:
350    // If warnings are globally mapped to ignore or error, do it.
351    if (Diag.IgnoreAllWarnings)
352      return DiagnosticIDs::Ignored;
353
354    Result = DiagnosticIDs::Warning;
355
356    // If this is an extension diagnostic and we're in -pedantic-error mode, and
357    // if the user didn't explicitly map it, upgrade to an error.
358    if (Diag.ExtBehavior == Diagnostic::Ext_Error &&
359        (MappingInfo & 8) == 0 &&
360        isBuiltinExtensionDiag(DiagID))
361      Result = DiagnosticIDs::Error;
362
363    if (Diag.WarningsAsErrors)
364      Result = DiagnosticIDs::Error;
365    if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
366      Result = DiagnosticIDs::Fatal;
367    break;
368
369  case diag::MAP_WARNING_NO_WERROR:
370    // Diagnostics specified with -Wno-error=foo should be set to warnings, but
371    // not be adjusted by -Werror or -pedantic-errors.
372    Result = DiagnosticIDs::Warning;
373
374    // If warnings are globally mapped to ignore or error, do it.
375    if (Diag.IgnoreAllWarnings)
376      return DiagnosticIDs::Ignored;
377
378    break;
379
380  case diag::MAP_ERROR_NO_WFATAL:
381    // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
382    // unaffected by -Wfatal-errors.
383    Result = DiagnosticIDs::Error;
384    break;
385  }
386
387  // Okay, we're about to return this as a "diagnostic to emit" one last check:
388  // if this is any sort of extension warning, and if we're in an __extension__
389  // block, silence it.
390  if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
391    return DiagnosticIDs::Ignored;
392
393  return Result;
394}
395
396struct WarningOption {
397  const char  *Name;
398  const short *Members;
399  const short *SubGroups;
400};
401
402#define GET_DIAG_ARRAYS
403#include "clang/Basic/DiagnosticGroups.inc"
404#undef GET_DIAG_ARRAYS
405
406// Second the table of options, sorted by name for fast binary lookup.
407static const WarningOption OptionTable[] = {
408#define GET_DIAG_TABLE
409#include "clang/Basic/DiagnosticGroups.inc"
410#undef GET_DIAG_TABLE
411};
412static const size_t OptionTableSize =
413sizeof(OptionTable) / sizeof(OptionTable[0]);
414
415static bool WarningOptionCompare(const WarningOption &LHS,
416                                 const WarningOption &RHS) {
417  return strcmp(LHS.Name, RHS.Name) < 0;
418}
419
420static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
421                            SourceLocation Loc, Diagnostic &Diag) {
422  // Option exists, poke all the members of its diagnostic set.
423  if (const short *Member = Group->Members) {
424    for (; *Member != -1; ++Member)
425      Diag.setDiagnosticMapping(*Member, Mapping, Loc);
426  }
427
428  // Enable/disable all subgroups along with this one.
429  if (const short *SubGroups = Group->SubGroups) {
430    for (; *SubGroups != (short)-1; ++SubGroups)
431      MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
432  }
433}
434
435/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
436/// "unknown-pragmas" to have the specified mapping.  This returns true and
437/// ignores the request if "Group" was unknown, false otherwise.
438bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
439                                           diag::Mapping Map,
440                                           SourceLocation Loc,
441                                           Diagnostic &Diag) const {
442  assert((Loc.isValid() ||
443          Diag.DiagStatePoints.empty() ||
444          Diag.DiagStatePoints.back().Loc.isInvalid()) &&
445         "Loc should be invalid only when the mapping comes from command-line");
446  assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
447          Diag.DiagStatePoints.back().Loc.isInvalid() ||
448          !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
449                                            Diag.DiagStatePoints.back().Loc)) &&
450         "Source location of new mapping is before the previous one!");
451
452  WarningOption Key = { Group, 0, 0 };
453  const WarningOption *Found =
454  std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
455                   WarningOptionCompare);
456  if (Found == OptionTable + OptionTableSize ||
457      strcmp(Found->Name, Group) != 0)
458    return true;  // Option not found.
459
460  MapGroupMembers(Found, Map, Loc, Diag);
461  return false;
462}
463
464/// ProcessDiag - This is the method used to report a diagnostic that is
465/// finally fully formed.
466bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
467  DiagnosticInfo Info(&Diag);
468
469  if (Diag.SuppressAllDiagnostics)
470    return false;
471
472  assert(Diag.getClient() && "DiagnosticClient not set!");
473
474  // Figure out the diagnostic level of this message.
475  DiagnosticIDs::Level DiagLevel;
476  unsigned DiagID = Info.getID();
477
478  // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
479  // in a system header.
480  bool ShouldEmitInSystemHeader;
481
482  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
483    // Handle custom diagnostics, which cannot be mapped.
484    DiagLevel = CustomDiagInfo->getLevel(DiagID);
485
486    // Custom diagnostics always are emitted in system headers.
487    ShouldEmitInSystemHeader = true;
488  } else {
489    // Get the class of the diagnostic.  If this is a NOTE, map it onto whatever
490    // the diagnostic level was for the previous diagnostic so that it is
491    // filtered the same as the previous diagnostic.
492    unsigned DiagClass = getBuiltinDiagClass(DiagID);
493    if (DiagClass == CLASS_NOTE) {
494      DiagLevel = DiagnosticIDs::Note;
495      ShouldEmitInSystemHeader = false;  // extra consideration is needed
496    } else {
497      // If this is not an error and we are in a system header, we ignore it.
498      // Check the original Diag ID here, because we also want to ignore
499      // extensions and warnings in -Werror and -pedantic-errors modes, which
500      // *map* warnings/extensions to errors.
501      ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
502
503      DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
504                                     Diag);
505    }
506  }
507
508  if (DiagLevel != DiagnosticIDs::Note) {
509    // Record that a fatal error occurred only when we see a second
510    // non-note diagnostic. This allows notes to be attached to the
511    // fatal error, but suppresses any diagnostics that follow those
512    // notes.
513    if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
514      Diag.FatalErrorOccurred = true;
515
516    Diag.LastDiagLevel = DiagLevel;
517  }
518
519  // If a fatal error has already been emitted, silence all subsequent
520  // diagnostics.
521  if (Diag.FatalErrorOccurred) {
522    if (DiagLevel >= DiagnosticIDs::Error &&
523        Diag.Client->IncludeInDiagnosticCounts()) {
524      ++Diag.NumErrors;
525      ++Diag.NumErrorsSuppressed;
526    }
527
528    return false;
529  }
530
531  // If the client doesn't care about this message, don't issue it.  If this is
532  // a note and the last real diagnostic was ignored, ignore it too.
533  if (DiagLevel == DiagnosticIDs::Ignored ||
534      (DiagLevel == DiagnosticIDs::Note &&
535       Diag.LastDiagLevel == DiagnosticIDs::Ignored))
536    return false;
537
538  // If this diagnostic is in a system header and is not a clang error, suppress
539  // it.
540  if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
541      Info.getLocation().isValid() &&
542      Diag.getSourceManager().isInSystemHeader(
543          Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) &&
544      (DiagLevel != DiagnosticIDs::Note ||
545       Diag.LastDiagLevel == DiagnosticIDs::Ignored)) {
546    Diag.LastDiagLevel = DiagnosticIDs::Ignored;
547    return false;
548  }
549
550  if (DiagLevel >= DiagnosticIDs::Error) {
551    if (Diag.Client->IncludeInDiagnosticCounts()) {
552      Diag.ErrorOccurred = true;
553      ++Diag.NumErrors;
554    }
555
556    // If we've emitted a lot of errors, emit a fatal error after it to stop a
557    // flood of bogus errors.
558    if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit &&
559        DiagLevel == DiagnosticIDs::Error)
560      Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
561  }
562
563  // If we have any Fix-Its, make sure that all of the Fix-Its point into
564  // source locations that aren't macro instantiations. If any point into
565  // macro instantiations, remove all of the Fix-Its.
566  for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
567    const FixItHint &FixIt = Diag.FixItHints[I];
568    if (FixIt.RemoveRange.isInvalid() ||
569        FixIt.RemoveRange.getBegin().isMacroID() ||
570        FixIt.RemoveRange.getEnd().isMacroID()) {
571      Diag.NumFixItHints = 0;
572      break;
573    }
574  }
575
576  // Finally, report it.
577  Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info);
578  if (Diag.Client->IncludeInDiagnosticCounts()) {
579    if (DiagLevel == DiagnosticIDs::Warning)
580      ++Diag.NumWarnings;
581  }
582
583  Diag.CurDiagID = ~0U;
584
585  return true;
586}
587