<div dir="ltr">Hi Richard,<div><br></div><div>This commit has caused an infinite loop in one of our internal libclang based tooling tests. It keeps repeating the following frames:</div><div><br></div><div><div>    frame #33528: 0x0000000109db2edf libclang.dylib`clang::DiagnosticsEngine::ReportDelayed(this=0x000000011c002c00) at Diagnostic.cpp:149</div><div>    frame #33529: 0x0000000109db5a36 libclang.dylib`clang::DiagnosticsEngine::EmitCurrentDiagnostic(this=0x000000011c002c00, Force=false) at Diagnostic.cpp:428</div><div>    frame #33530: 0x000000010a33f93c libclang.dylib`clang::DiagnosticBuilder::Emit(this=0x0000700008d4bfd8) at Diagnostic.h:1013</div><div>    frame #33531: 0x000000010a33f8e5 libclang.dylib`clang::DiagnosticBuilder::~DiagnosticBuilder(this=0x0000700008d4bfd8) at Diagnostic.h:1036</div><div>    frame #33532: 0x000000010a335015 libclang.dylib`clang::DiagnosticBuilder::~DiagnosticBuilder(this=0x0000700008d4bfd8) at Diagnostic.h:1035</div></div><div><br></div><div>It doesn't really look like a regression though, it seems that this has just uncovered a bug in Clang: DiagnosticsEngine::ReportDelayed is clearing DelayedDiagID *after* reporting the issue which causes the infinite recursion, when it should clear it before. Is that right? I will commit a fix for this now.</div><div><br></div><div>Alex</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On 3 May 2017 at 01:28, Richard Smith via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Tue May  2 19:28:49 2017<br>
New Revision: 301992<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=301992&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=301992&view=rev</a><br>
Log:<br>
[modules] Round-trip -Werror flag through explicit module build.<br>
<br>
The intent for an explicit module build is that the diagnostics produced within<br>
the module are those that were configured when the module was built, not those<br>
that are enabled within a user of the module. This includes diagnostics that<br>
don't actually show up until the module is used (for instance, diagnostics<br>
produced during template instantiation and weird cases like -Wpadded).<br>
<br>
We serialized and restored the diagnostic state for individual warning groups,<br>
but previously did not track the state for flags like -Werror and -Weverything,<br>
which are implemented as separate bits rather than as part of the diagnostics<br>
mapping information.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/<wbr>Diagnostic.h<br>
    cfe/trunk/include/clang/Basic/<wbr>DiagnosticIDs.h<br>
    cfe/trunk/lib/Basic/<wbr>Diagnostic.cpp<br>
    cfe/trunk/lib/Basic/<wbr>DiagnosticIDs.cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTReader.cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
    cfe/trunk/test/Index/keep-<wbr>going.cpp<br>
    cfe/trunk/test/Modules/diag-<wbr>flags.cpp<br>
    cfe/trunk/tools/libclang/<wbr>CIndex.cpp<br>
    cfe/trunk/unittests/Basic/<wbr>DiagnosticTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>Diagnostic.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/Diagnostic.h?rev=<wbr>301992&r1=301991&r2=301992&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>Diagnostic.h (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>Diagnostic.h Tue May  2 19:28:49 2017<br>
@@ -178,12 +178,7 @@ public:<br>
<br>
 private:<br>
   unsigned char AllExtensionsSilenced; // Used by __extension__<br>
-  bool IgnoreAllWarnings;        // Ignore all warnings: -w<br>
-  bool WarningsAsErrors;         // Treat warnings like errors.<br>
-  bool EnableAllWarnings;        // Enable all warnings.<br>
-  bool ErrorsAsFatal;            // Treat errors like fatal errors.<br>
-  bool FatalsAsError;             // Treat fatal errors like errors.<br>
-  bool SuppressSystemWarnings;   // Suppress warnings in system headers.<br>
+  bool SuppressAfterFatalError;  // Suppress diagnostics after a fatal error?<br>
   bool SuppressAllDiagnostics;   // Suppress all diagnostics.<br>
   bool ElideType;                // Elide common types of templates.<br>
   bool PrintTemplateTree;        // Print a tree when comparing templates.<br>
@@ -194,7 +189,6 @@ private:<br>
                                    // 0 -> no limit.<br>
   unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation<br>
                                     // backtrace stack, 0 -> no limit.<br>
-  diag::Severity ExtBehavior;       // Map extensions to warnings or errors?<br>
   IntrusiveRefCntPtr<<wbr>DiagnosticIDs> Diags;<br>
   IntrusiveRefCntPtr<<wbr>DiagnosticOptions> DiagOpts;<br>
   DiagnosticConsumer *Client;<br>
@@ -216,6 +210,19 @@ private:<br>
     llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;<br>
<br>
   public:<br>
+    // "Global" configuration state that can actually vary between modules.<br>
+    unsigned IgnoreAllWarnings : 1;      // Ignore all warnings: -w<br>
+    unsigned EnableAllWarnings : 1;      // Enable all warnings.<br>
+    unsigned WarningsAsErrors : 1;       // Treat warnings like errors.<br>
+    unsigned ErrorsAsFatal : 1;          // Treat errors like fatal errors.<br>
+    unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers.<br>
+    diag::Severity ExtBehavior : 4;     // Map extensions to warnings or errors?<br>
+<br>
+    DiagState()<br>
+        : IgnoreAllWarnings(false), EnableAllWarnings(false),<br>
+          WarningsAsErrors(false), ErrorsAsFatal(false),<br>
+          SuppressSystemWarnings(false), ExtBehavior(diag::Severity::<wbr>Ignored) {}<br>
+<br>
     typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator;<br>
     typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_<wbr>iterator<br>
     const_iterator;<br>
@@ -493,33 +500,47 @@ public:<br>
   /// \brief When set to true, any unmapped warnings are ignored.<br>
   ///<br>
   /// If this and WarningsAsErrors are both set, then this one wins.<br>
-  void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }<br>
-  bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }<br>
+  void setIgnoreAllWarnings(bool Val) {<br>
+    GetCurDiagState()-><wbr>IgnoreAllWarnings = Val;<br>
+  }<br>
+  bool getIgnoreAllWarnings() const {<br>
+    return GetCurDiagState()-><wbr>IgnoreAllWarnings;<br>
+  }<br>
<br>
   /// \brief When set to true, any unmapped ignored warnings are no longer<br>
   /// ignored.<br>
   ///<br>
   /// If this and IgnoreAllWarnings are both set, then that one wins.<br>
-  void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }<br>
-  bool getEnableAllWarnings() const { return EnableAllWarnings; }<br>
+  void setEnableAllWarnings(bool Val) {<br>
+    GetCurDiagState()-><wbr>EnableAllWarnings = Val;<br>
+  }<br>
+  bool getEnableAllWarnings() const {<br>
+    return GetCurDiagState()-><wbr>EnableAllWarnings;<br>
+  }<br>
<br>
   /// \brief When set to true, any warnings reported are issued as errors.<br>
-  void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }<br>
-  bool getWarningsAsErrors() const { return WarningsAsErrors; }<br>
+  void setWarningsAsErrors(bool Val) {<br>
+    GetCurDiagState()-><wbr>WarningsAsErrors = Val;<br>
+  }<br>
+  bool getWarningsAsErrors() const {<br>
+    return GetCurDiagState()-><wbr>WarningsAsErrors;<br>
+  }<br>
<br>
   /// \brief When set to true, any error reported is made a fatal error.<br>
-  void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }<br>
-  bool getErrorsAsFatal() const { return ErrorsAsFatal; }<br>
+  void setErrorsAsFatal(bool Val) { GetCurDiagState()-><wbr>ErrorsAsFatal = Val; }<br>
+  bool getErrorsAsFatal() const { return GetCurDiagState()-><wbr>ErrorsAsFatal; }<br>
<br>
-  /// \brief When set to true, any fatal error reported is made an error.<br>
-  ///<br>
-  /// This setting takes precedence over the setErrorsAsFatal setting above.<br>
-  void setFatalsAsError(bool Val) { FatalsAsError = Val; }<br>
-  bool getFatalsAsError() const { return FatalsAsError; }<br>
+  /// \brief When set to true (the default), suppress further diagnostics after<br>
+  /// a fatal error.<br>
+  void setSuppressAfterFatalError(<wbr>bool Val) { SuppressAfterFatalError = Val; }<br>
<br>
   /// \brief When set to true mask warnings that come from system headers.<br>
-  void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }<br>
-  bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }<br>
+  void setSuppressSystemWarnings(bool Val) {<br>
+    GetCurDiagState()-><wbr>SuppressSystemWarnings = Val;<br>
+  }<br>
+  bool getSuppressSystemWarnings() const {<br>
+    return GetCurDiagState()-><wbr>SuppressSystemWarnings;<br>
+  }<br>
<br>
   /// \brief Suppress all diagnostics, to silence the front end when we<br>
   /// know that we don't want any more diagnostics to be passed along to the<br>
@@ -571,11 +592,15 @@ public:<br>
   }<br>
<br>
   /// \brief Controls whether otherwise-unmapped extension diagnostics are<br>
-  /// mapped onto ignore/warning/error.<br>
+  /// mapped onto ignore/warning/error.<br>
   ///<br>
   /// This corresponds to the GCC -pedantic and -pedantic-errors option.<br>
-  void setExtensionHandlingBehavior(<wbr>diag::Severity H) { ExtBehavior = H; }<br>
-  diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; }<br>
+  void setExtensionHandlingBehavior(<wbr>diag::Severity H) {<br>
+    GetCurDiagState()->ExtBehavior = H;<br>
+  }<br>
+  diag::Severity getExtensionHandlingBehavior() const {<br>
+    return GetCurDiagState()-><wbr>ExtBehavior;<br>
+  }<br>
<br>
   /// \brief Counter bumped when an __extension__  block is/ encountered.<br>
   ///<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticIDs.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticIDs.h?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/DiagnosticIDs.h?<wbr>rev=301992&r1=301991&r2=<wbr>301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticIDs.h (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticIDs.h Tue May  2 19:28:49 2017<br>
@@ -122,15 +122,21 @@ public:<br>
   bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }<br>
   void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }<br>
<br>
-  /// Serialize the bits that aren't based on context.<br>
-  unsigned serializeBits() const {<br>
-    return (WasUpgradedFromWarning << 3) | Severity;<br>
+  /// Serialize this mapping as a raw integer.<br>
+  unsigned serialize() const {<br>
+    return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |<br>
+           (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;<br>
   }<br>
-  static diag::Severity deserializeSeverity(unsigned Bits) {<br>
-    return (diag::Severity)(Bits & 0x7);<br>
-  }<br>
-  static bool deserializeUpgradedFromWarning<wbr>(unsigned Bits) {<br>
-    return Bits >> 3;<br>
+  /// Deserialize a mapping.<br>
+  static DiagnosticMapping deserialize(unsigned Bits) {<br>
+    DiagnosticMapping Result;<br>
+    Result.IsUser = (Bits >> 7) & 1;<br>
+    Result.IsPragma = (Bits >> 6) & 1;<br>
+    Result.HasNoWarningAsError = (Bits >> 5) & 1;<br>
+    Result.HasNoErrorAsFatal = (Bits >> 4) & 1;<br>
+    Result.WasUpgradedFromWarning = (Bits >> 3) & 1;<br>
+    Result.Severity = Bits & 0x7;<br>
+    return Result;<br>
   }<br>
 };<br>
<br>
<br>
Modified: cfe/trunk/lib/Basic/<wbr>Diagnostic.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Basic/<wbr>Diagnostic.cpp?rev=301992&r1=<wbr>301991&r2=301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Basic/<wbr>Diagnostic.cpp (original)<br>
+++ cfe/trunk/lib/Basic/<wbr>Diagnostic.cpp Tue May  2 19:28:49 2017<br>
@@ -67,18 +67,12 @@ DiagnosticsEngine::<wbr>DiagnosticsEngine(Int<br>
   ArgToStringCookie = nullptr;<br>
<br>
   AllExtensionsSilenced = 0;<br>
-  IgnoreAllWarnings = false;<br>
-  WarningsAsErrors = false;<br>
-  EnableAllWarnings = false;<br>
-  ErrorsAsFatal = false;<br>
-  FatalsAsError = false;<br>
-  SuppressSystemWarnings = false;<br>
+  SuppressAfterFatalError = true;<br>
   SuppressAllDiagnostics = false;<br>
   ElideType = true;<br>
   PrintTemplateTree = false;<br>
   ShowColors = false;<br>
   ShowOverloads = Ovl_All;<br>
-  ExtBehavior = diag::Severity::Ignored;<br>
<br>
   ErrorLimit = 0;<br>
   TemplateBacktraceLimit = 0;<br>
@@ -343,8 +337,8 @@ bool DiagnosticsEngine::<wbr>setDiagnosticGro<br>
     return setSeverityForGroup(diag::<wbr>Flavor::WarningOrError, Group,<br>
                                diag::Severity::Fatal);<br>
<br>
-  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and<br>
-  // potentially downgrade anything already mapped to be an error.<br>
+  // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,<br>
+  // and potentially downgrade anything already mapped to be a fatal error.<br>
<br>
   // Get the diagnostics in this group.<br>
   SmallVector<diag::kind, 8> GroupDiags;<br>
<br>
Modified: cfe/trunk/lib/Basic/<wbr>DiagnosticIDs.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticIDs.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Basic/<wbr>DiagnosticIDs.cpp?rev=301992&<wbr>r1=301991&r2=301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Basic/<wbr>DiagnosticIDs.cpp (original)<br>
+++ cfe/trunk/lib/Basic/<wbr>DiagnosticIDs.cpp Tue May  2 19:28:49 2017<br>
@@ -420,7 +420,7 @@ DiagnosticIDs::<wbr>getDiagnosticSeverity(uns<br>
     Result = Mapping.getSeverity();<br>
<br>
   // Upgrade ignored diagnostics if -Weverything is enabled.<br>
-  if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&<br>
+  if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&<br>
       !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)<br>
     Result = diag::Severity::Warning;<br>
<br>
@@ -435,7 +435,7 @@ DiagnosticIDs::<wbr>getDiagnosticSeverity(uns<br>
   // For extension diagnostics that haven't been explicitly mapped, check if we<br>
   // should upgrade the diagnostic.<br>
   if (IsExtensionDiag && !Mapping.isUser())<br>
-    Result = std::max(Result, Diag.ExtBehavior);<br>
+    Result = std::max(Result, State->ExtBehavior);<br>
<br>
   // At this point, ignored errors can no longer be upgraded.<br>
   if (Result == diag::Severity::Ignored)<br>
@@ -443,28 +443,24 @@ DiagnosticIDs::<wbr>getDiagnosticSeverity(uns<br>
<br>
   // Honor -w, which is lower in priority than pedantic-errors, but higher than<br>
   // -Werror.<br>
-  if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)<br>
+  // FIXME: Under GCC, this also suppresses warnings that have been mapped to<br>
+  // errors by -W flags and #pragma diagnostic.<br>
+  if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)<br>
     return diag::Severity::Ignored;<br>
<br>
   // If -Werror is enabled, map warnings to errors unless explicitly disabled.<br>
   if (Result == diag::Severity::Warning) {<br>
-    if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError()<wbr>)<br>
+    if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError()<wbr>)<br>
       Result = diag::Severity::Error;<br>
   }<br>
<br>
   // If -Wfatal-errors is enabled, map errors to fatal unless explicity<br>
   // disabled.<br>
   if (Result == diag::Severity::Error) {<br>
-    if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())<br>
+    if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())<br>
       Result = diag::Severity::Fatal;<br>
   }<br>
<br>
-  // If explicitly requested, map fatal errors to errors.<br>
-  if (Result == diag::Severity::Fatal) {<br>
-      if (Diag.FatalsAsError)<br>
-        Result = diag::Severity::Error;<br>
-  }<br>
-<br>
   // Custom diagnostics always are emitted in system headers.<br>
   bool ShowInSystemHeader =<br>
       !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)-><wbr>WarnShowInSystemHeader;<br>
@@ -472,7 +468,7 @@ DiagnosticIDs::<wbr>getDiagnosticSeverity(uns<br>
   // If we are in a system header, we ignore it. We look at the diagnostic class<br>
   // because we also want to ignore extensions and warnings in -Werror and<br>
   // -pedantic-errors modes, which *map* warnings/extensions to errors.<br>
-  if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&<br>
+  if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&<br>
       Diag.getSourceManager().<wbr>isInSystemHeader(<br>
           Diag.getSourceManager().<wbr>getExpansionLoc(Loc)))<br>
     return diag::Severity::Ignored;<br>
@@ -632,7 +628,7 @@ bool DiagnosticIDs::ProcessDiag(<wbr>Diagnost<br>
<br>
   // If a fatal error has already been emitted, silence all subsequent<br>
   // diagnostics.<br>
-  if (Diag.FatalErrorOccurred) {<br>
+  if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {<br>
     if (DiagLevel >= DiagnosticIDs::Error &&<br>
         Diag.Client-><wbr>IncludeInDiagnosticCounts()) {<br>
       ++Diag.NumErrors;<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTReader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTReader.cpp?<wbr>rev=301992&r1=301991&r2=<wbr>301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTReader.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTReader.cpp Tue May  2 19:28:49 2017<br>
@@ -5531,14 +5531,8 @@ void ASTReader::<wbr>ReadPragmaDiagnosticMapp<br>
              "Invalid data, not enough diag/map pairs");<br>
       while (Size--) {<br>
         unsigned DiagID = Record[Idx++];<br>
-        unsigned SeverityAndUpgradedFromWarning = Record[Idx++];<br>
-        bool WasUpgradedFromWarning =<br>
-            DiagnosticMapping::<wbr>deserializeUpgradedFromWarning<wbr>(<br>
-                SeverityAndUpgradedFromWarning<wbr>);<br>
         DiagnosticMapping NewMapping =<br>
-            Diag.makeUserMapping(<wbr>DiagnosticMapping::<wbr>deserializeSeverity(<br>
-                                     SeverityAndUpgradedFromWarning<wbr>),<br>
-                                 Loc);<br>
+            DiagnosticMapping::<wbr>deserialize(Record[Idx++]);<br>
         if (!NewMapping.isPragma() && !IncludeNonPragmaStates)<br>
           continue;<br>
<br>
@@ -5547,14 +5541,12 @@ void ASTReader::<wbr>ReadPragmaDiagnosticMapp<br>
         // If this mapping was specified as a warning but the severity was<br>
         // upgraded due to diagnostic settings, simulate the current diagnostic<br>
         // settings (and use a warning).<br>
-        if (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) {<br>
-          Mapping = Diag.makeUserMapping(diag::<wbr>Severity::Warning, Loc);<br>
-          continue;<br>
+        if (NewMapping.<wbr>wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) {<br>
+          NewMapping.setSeverity(diag::<wbr>Severity::Warning);<br>
+          NewMapping.<wbr>setUpgradedFromWarning(false);<br>
         }<br>
<br>
-        // Use the deserialized mapping verbatim.<br>
         Mapping = NewMapping;<br>
-        Mapping.<wbr>setUpgradedFromWarning(<wbr>WasUpgradedFromWarning);<br>
       }<br>
       return NewState;<br>
     };<br>
@@ -5569,22 +5561,36 @@ void ASTReader::<wbr>ReadPragmaDiagnosticMapp<br>
       DiagStates.push_back(<wbr>FirstState);<br>
<br>
       // Skip the initial diagnostic state from the serialized module.<br>
-      assert(Record[0] == 0 &&<br>
+      assert(Record[1] == 0 &&<br>
              "Invalid data, unexpected backref in initial state");<br>
-      Idx = 2 + Record[1] * 2;<br>
+      Idx = 3 + Record[2] * 2;<br>
       assert(Idx < Record.size() &&<br>
              "Invalid data, not enough state change pairs in initial state");<br>
+    } else if (F.isModule()) {<br>
+      // For an explicit module, preserve the flags from the module build<br>
+      // command line (-w, -Weverything, -Werror, ...) along with any explicit<br>
+      // -Wblah flags.<br>
+      unsigned Flags = Record[Idx++];<br>
+      DiagState Initial;<br>
+      Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;<br>
+      Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;<br>
+      Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;<br>
+      Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;<br>
+      Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;<br>
+      Initial.ExtBehavior = (diag::Severity)Flags;<br>
+      FirstState = ReadDiagState(Initial, SourceLocation(), true);<br>
+<br>
+      // Set up the root buffer of the module to start with the initial<br>
+      // diagnostic state of the module itself, to cover files that contain no<br>
+      // explicit transitions (for which we did not serialize anything).<br>
+      Diag.DiagStatesByLoc.Files[F.<wbr>OriginalSourceFileID]<br>
+          .StateTransitions.push_back({<wbr>FirstState, 0});<br>
     } else {<br>
-      FirstState = ReadDiagState(<br>
-          F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.<wbr>CurDiagState,<br>
-          SourceLocation(), F.isModule());<br>
-<br>
-      // For an explicit module, set up the root buffer of the module to start<br>
-      // with the initial diagnostic state of the module itself, to cover files<br>
-      // that contain no explicit transitions.<br>
-      if (F.isModule())<br>
-        Diag.DiagStatesByLoc.Files[F.<wbr>OriginalSourceFileID]<br>
-            .StateTransitions.push_back({<wbr>FirstState, 0});<br>
+      // For prefix ASTs, start with whatever the user configured on the<br>
+      // command line.<br>
+      Idx++; // Skip flags.<br>
+      FirstState = ReadDiagState(*Diag.<wbr>DiagStatesByLoc.CurDiagState,<br>
+                                 SourceLocation(), false);<br>
     }<br>
<br>
     // Read the state transitions.<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriter.cpp?<wbr>rev=301992&r1=301991&r2=<wbr>301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp Tue May  2 19:28:49 2017<br>
@@ -2868,8 +2868,26 @@ void ASTWriter::<wbr>WritePragmaDiagnosticMap<br>
   unsigned CurrID = 0;<br>
   RecordData Record;<br>
<br>
+  auto EncodeDiagStateFlags =<br>
+      [](const DiagnosticsEngine::DiagState *DS) -> unsigned {<br>
+    unsigned Result = (unsigned)DS->ExtBehavior;<br>
+    for (unsigned Val :<br>
+         {DS->IgnoreAllWarnings, DS->EnableAllWarnings, DS->WarningsAsErrors,<br>
+          DS->ErrorsAsFatal, DS->SuppressSystemWarnings})<br>
+      Result = (Result << 1) | Val;<br>
+    return Result;<br>
+  };<br>
+<br>
+  unsigned Flags = EncodeDiagStateFlags(Diag.<wbr>DiagStatesByLoc.<wbr>FirstDiagState);<br>
+  Record.push_back(Flags);<br>
+<br>
   auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,<br>
                           bool IncludeNonPragmaStates) {<br>
+    // Ensure that the diagnostic state wasn't modified since it was created.<br>
+    // We will not correctly round-trip this information otherwise.<br>
+    assert(Flags == EncodeDiagStateFlags(State) &&<br>
+           "diag state flags vary in single AST file");<br>
+<br>
     unsigned &DiagStateID = DiagStateIDMap[State];<br>
     Record.push_back(DiagStateID);<br>
<br>
@@ -2882,7 +2900,7 @@ void ASTWriter::<wbr>WritePragmaDiagnosticMap<br>
       for (const auto &I : *State) {<br>
         if (I.second.isPragma() || IncludeNonPragmaStates) {<br>
           Record.push_back(I.first);<br>
-          Record.push_back(I.second.<wbr>serializeBits());<br>
+          Record.push_back(I.second.<wbr>serialize());<br>
         }<br>
       }<br>
       // Update the placeholder.<br>
<br>
Modified: cfe/trunk/test/Index/keep-<wbr>going.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/keep-going.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/Index/<wbr>keep-going.cpp?rev=301992&r1=<wbr>301991&r2=301992&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Index/keep-<wbr>going.cpp (original)<br>
+++ cfe/trunk/test/Index/keep-<wbr>going.cpp Tue May  2 19:28:49 2017<br>
@@ -25,5 +25,5 @@ class C : public A<float> { };<br>
 // CHECK: C++ base class specifier=A<float>:4:7 [access=public isVirtual=false] [type=A<float>] [typekind=Unexposed] [templateargs/1= [type=float] [typekind=Float]] [canonicaltype=A<float>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=float] [typekind=Float]] [isPOD=0] [nbFields=1]<br>
 // CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0]<br>
<br>
-// CHECK-DIAG: keep-going.cpp:1:10: error: 'missing1.h' file not found<br>
-// CHECK-DIAG: keep-going.cpp:8:10: error: 'missing2.h' file not found<br>
+// CHECK-DIAG: keep-going.cpp:1:10: fatal error: 'missing1.h' file not found<br>
+// CHECK-DIAG: keep-going.cpp:8:10: fatal error: 'missing2.h' file not found<br>
<br>
Modified: cfe/trunk/test/Modules/diag-<wbr>flags.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/diag-flags.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/diag-flags.cpp?rev=<wbr>301992&r1=301991&r2=301992&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Modules/diag-<wbr>flags.cpp (original)<br>
+++ cfe/trunk/test/Modules/diag-<wbr>flags.cpp Tue May  2 19:28:49 2017<br>
@@ -1,20 +1,42 @@<br>
 // RUN: rm -rf %t<br>
 //<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DIMPLICIT_FLAG -Werror=padded<br>
-//<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/explicit.pcm -Werror=string-plus-int -Wpadded<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm<br>
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DEXPLICIT_FLAG -fmodule-file=%t/explicit.pcm -Werror=padded<br>
+// For an implicit module, all that matters are the warning flags in the user.<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -Wpadded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -Wpadded -Werror<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -Werror=padded<br>
+//<br>
+// For an explicit module, all that matters are the warning flags in the module build.<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/nodiag.pcm<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -fmodule-file=%t/nodiag.pcm -Wpadded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -fmodule-file=%t/nodiag.pcm -Werror -Wpadded<br>
+//<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/warning.pcm -Wpadded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm -Werror=padded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm -Werror<br>
+//<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/werror-no-error.pcm -Werror -Wpadded -Wno-error=padded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-<wbr>error.pcm<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-<wbr>error.pcm -Wno-padded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-<wbr>error.pcm -Werror=padded<br>
+//<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/error.pcm -Werror=padded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/error.pcm -Wno-padded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/error.pcm -Wno-error=padded<br>
+//<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/werror.pcm -Werror -Wpadded<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/werror.pcm -Wno-error<br>
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/werror.pcm -Wno-padded<br>
<br>
 import diag_flags;<br>
<br>
 // Diagnostic flags from the module user make no difference to diagnostics<br>
 // emitted within the module when using an explicitly-loaded module.<br>
-#ifdef IMPLICIT_FLAG<br>
+#if ERROR<br>
 // expected-error@diag_flags.h:14 {{padding struct}}<br>
-#elif defined(EXPLICIT_FLAG)<br>
+#elif WARNING<br>
 // expected-warning@diag_flags.h:<wbr>14 {{padding struct}}<br>
 #else<br>
 // expected-no-diagnostics<br>
<br>
Modified: cfe/trunk/tools/libclang/<wbr>CIndex.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/tools/<wbr>libclang/CIndex.cpp?rev=<wbr>301992&r1=301991&r2=301992&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/libclang/<wbr>CIndex.cpp (original)<br>
+++ cfe/trunk/tools/libclang/<wbr>CIndex.cpp Tue May  2 19:28:49 2017<br>
@@ -3313,7 +3313,7 @@ clang_parseTranslationUnit_<wbr>Impl(CXIndex<br>
     Diags(CompilerInstance::<wbr>createDiagnostics(new DiagnosticOptions));<br>
<br>
   if (options & CXTranslationUnit_KeepGoing)<br>
-    Diags->setFatalsAsError(true);<br>
+    Diags-><wbr>setSuppressAfterFatalError(<wbr>false);<br>
<br>
   // Recover resources if we crash before exiting this function.<br>
   llvm::<wbr>CrashRecoveryContextCleanupReg<wbr>istrar<DiagnosticsEngine,<br>
<br>
Modified: cfe/trunk/unittests/Basic/<wbr>DiagnosticTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/DiagnosticTest.cpp?rev=301992&r1=301991&r2=301992&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/unittests/<wbr>Basic/DiagnosticTest.cpp?rev=<wbr>301992&r1=301991&r2=301992&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/unittests/Basic/<wbr>DiagnosticTest.cpp (original)<br>
+++ cfe/trunk/unittests/Basic/<wbr>DiagnosticTest.cpp Tue May  2 19:28:49 2017<br>
@@ -46,27 +46,30 @@ TEST(DiagnosticTest, suppressAndTrap) {<br>
   EXPECT_FALSE(Diags.<wbr>hasUnrecoverableErrorOccurred(<wbr>));<br>
 }<br>
<br>
-// Check that FatalsAsErrors works as intended<br>
-TEST(DiagnosticTest, fatalsAsErrors) {<br>
-  DiagnosticsEngine Diags(new DiagnosticIDs(),<br>
-                          new DiagnosticOptions,<br>
-                          new IgnoringDiagConsumer());<br>
-  Diags.setFatalsAsError(true);<br>
-<br>
-  // Diag that would set UncompilableErrorOccurred and ErrorOccurred.<br>
-  Diags.Report(diag::err_target_<wbr>unknown_triple) << "unknown";<br>
-<br>
-  // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.<br>
-  Diags.Report(diag::err_cannot_<wbr>open_file) << "file" << "error";<br>
-<br>
-  // Diag that would set FatalErrorOccurred<br>
-  // (via non-note following a fatal error).<br>
-  Diags.Report(diag::warn_mt_<wbr>message) << "warning";<br>
-<br>
-  EXPECT_TRUE(Diags.<wbr>hasErrorOccurred());<br>
-  EXPECT_FALSE(Diags.<wbr>hasFatalErrorOccurred());<br>
-  EXPECT_TRUE(Diags.<wbr>hasUncompilableErrorOccurred()<wbr>);<br>
-  EXPECT_TRUE(Diags.<wbr>hasUnrecoverableErrorOccurred(<wbr>));<br>
+// Check that SuppressAfterFatalError works as intended<br>
+TEST(DiagnosticTest, suppressAfterFatalError) {<br>
+  for (unsigned Suppress = 0; Suppress != 2; ++Suppress) {<br>
+    DiagnosticsEngine Diags(new DiagnosticIDs(),<br>
+                            new DiagnosticOptions,<br>
+                            new IgnoringDiagConsumer());<br>
+    Diags.<wbr>setSuppressAfterFatalError(<wbr>Suppress);<br>
+<br>
+    // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.<br>
+    Diags.Report(diag::err_cannot_<wbr>open_file) << "file" << "error";<br>
+<br>
+    // Diag that would set FatalErrorOccurred<br>
+    // (via non-note following a fatal error).<br>
+    Diags.Report(diag::warn_mt_<wbr>message) << "warning";<br>
+<br>
+    EXPECT_TRUE(Diags.<wbr>hasErrorOccurred());<br>
+    EXPECT_TRUE(Diags.<wbr>hasFatalErrorOccurred());<br>
+    EXPECT_TRUE(Diags.<wbr>hasUncompilableErrorOccurred()<wbr>);<br>
+    EXPECT_TRUE(Diags.<wbr>hasUnrecoverableErrorOccurred(<wbr>));<br>
+<br>
+    // The warning should be emitted and counted only if we're not suppressing<br>
+    // after fatal errors.<br>
+    EXPECT_EQ(Diags.<wbr>getNumWarnings(), Suppress ? 0u : 1u);<br>
+  }<br>
 }<br>
<br>
 }<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>