]> granicus.if.org Git - clang/commitdiff
[modules] Round-trip -Werror flag through explicit module build.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 3 May 2017 00:28:49 +0000 (00:28 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 3 May 2017 00:28:49 +0000 (00:28 +0000)
The intent for an explicit module build is that the diagnostics produced within
the module are those that were configured when the module was built, not those
that are enabled within a user of the module. This includes diagnostics that
don't actually show up until the module is used (for instance, diagnostics
produced during template instantiation and weird cases like -Wpadded).

We serialized and restored the diagnostic state for individual warning groups,
but previously did not track the state for flags like -Werror and -Weverything,
which are implemented as separate bits rather than as part of the diagnostics
mapping information.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301992 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Diagnostic.h
include/clang/Basic/DiagnosticIDs.h
lib/Basic/Diagnostic.cpp
lib/Basic/DiagnosticIDs.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Index/keep-going.cpp
test/Modules/diag-flags.cpp
tools/libclang/CIndex.cpp
unittests/Basic/DiagnosticTest.cpp

index a8e11bcb892783fdc2f37b1f7e5de6d24565f314..610273015ca445b7246207ef140d645e15fdf356 100644 (file)
@@ -178,12 +178,7 @@ public:
 
 private:
   unsigned char AllExtensionsSilenced; // Used by __extension__
-  bool IgnoreAllWarnings;        // Ignore all warnings: -w
-  bool WarningsAsErrors;         // Treat warnings like errors.
-  bool EnableAllWarnings;        // Enable all warnings.
-  bool ErrorsAsFatal;            // Treat errors like fatal errors.
-  bool FatalsAsError;             // Treat fatal errors like errors.
-  bool SuppressSystemWarnings;   // Suppress warnings in system headers.
+  bool SuppressAfterFatalError;  // Suppress diagnostics after a fatal error?
   bool SuppressAllDiagnostics;   // Suppress all diagnostics.
   bool ElideType;                // Elide common types of templates.
   bool PrintTemplateTree;        // Print a tree when comparing templates.
@@ -194,7 +189,6 @@ private:
                                    // 0 -> no limit.
   unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation
                                     // backtrace stack, 0 -> no limit.
-  diag::Severity ExtBehavior;       // Map extensions to warnings or errors?
   IntrusiveRefCntPtr<DiagnosticIDs> Diags;
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticConsumer *Client;
@@ -216,6 +210,19 @@ private:
     llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
 
   public:
+    // "Global" configuration state that can actually vary between modules.
+    unsigned IgnoreAllWarnings : 1;      // Ignore all warnings: -w
+    unsigned EnableAllWarnings : 1;      // Enable all warnings.
+    unsigned WarningsAsErrors : 1;       // Treat warnings like errors.
+    unsigned ErrorsAsFatal : 1;          // Treat errors like fatal errors.
+    unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers.
+    diag::Severity ExtBehavior : 4;     // Map extensions to warnings or errors?
+
+    DiagState()
+        : IgnoreAllWarnings(false), EnableAllWarnings(false),
+          WarningsAsErrors(false), ErrorsAsFatal(false),
+          SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {}
+
     typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator;
     typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator
     const_iterator;
@@ -493,33 +500,47 @@ public:
   /// \brief When set to true, any unmapped warnings are ignored.
   ///
   /// If this and WarningsAsErrors are both set, then this one wins.
-  void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
-  bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
+  void setIgnoreAllWarnings(bool Val) {
+    GetCurDiagState()->IgnoreAllWarnings = Val;
+  }
+  bool getIgnoreAllWarnings() const {
+    return GetCurDiagState()->IgnoreAllWarnings;
+  }
 
   /// \brief When set to true, any unmapped ignored warnings are no longer
   /// ignored.
   ///
   /// If this and IgnoreAllWarnings are both set, then that one wins.
-  void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
-  bool getEnableAllWarnings() const { return EnableAllWarnings; }
+  void setEnableAllWarnings(bool Val) {
+    GetCurDiagState()->EnableAllWarnings = Val;
+  }
+  bool getEnableAllWarnings() const {
+    return GetCurDiagState()->EnableAllWarnings;
+  }
 
   /// \brief When set to true, any warnings reported are issued as errors.
-  void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
-  bool getWarningsAsErrors() const { return WarningsAsErrors; }
+  void setWarningsAsErrors(bool Val) {
+    GetCurDiagState()->WarningsAsErrors = Val;
+  }
+  bool getWarningsAsErrors() const {
+    return GetCurDiagState()->WarningsAsErrors;
+  }
 
   /// \brief When set to true, any error reported is made a fatal error.
-  void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }
-  bool getErrorsAsFatal() const { return ErrorsAsFatal; }
+  void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
+  bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
 
-  /// \brief When set to true, any fatal error reported is made an error.
-  ///
-  /// This setting takes precedence over the setErrorsAsFatal setting above.
-  void setFatalsAsError(bool Val) { FatalsAsError = Val; }
-  bool getFatalsAsError() const { return FatalsAsError; }
+  /// \brief When set to true (the default), suppress further diagnostics after
+  /// a fatal error.
+  void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; }
 
   /// \brief When set to true mask warnings that come from system headers.
-  void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
-  bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
+  void setSuppressSystemWarnings(bool Val) {
+    GetCurDiagState()->SuppressSystemWarnings = Val;
+  }
+  bool getSuppressSystemWarnings() const {
+    return GetCurDiagState()->SuppressSystemWarnings;
+  }
 
   /// \brief Suppress all diagnostics, to silence the front end when we 
   /// know that we don't want any more diagnostics to be passed along to the
@@ -571,11 +592,15 @@ public:
   }
 
   /// \brief Controls whether otherwise-unmapped extension diagnostics are
-  /// mapped onto ignore/warning/error. 
+  /// mapped onto ignore/warning/error.
   ///
   /// This corresponds to the GCC -pedantic and -pedantic-errors option.
-  void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; }
-  diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; }
+  void setExtensionHandlingBehavior(diag::Severity H) {
+    GetCurDiagState()->ExtBehavior = H;
+  }
+  diag::Severity getExtensionHandlingBehavior() const {
+    return GetCurDiagState()->ExtBehavior;
+  }
 
   /// \brief Counter bumped when an __extension__  block is/ encountered.
   ///
index f5f70cb5e7d3c05698b01c7290201a04f8861e94..7646e33d2366e364ccdf0e40dbfb3a62cae1f9df 100644 (file)
@@ -122,15 +122,21 @@ public:
   bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
   void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
 
-  /// Serialize the bits that aren't based on context.
-  unsigned serializeBits() const {
-    return (WasUpgradedFromWarning << 3) | Severity;
+  /// Serialize this mapping as a raw integer.
+  unsigned serialize() const {
+    return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |
+           (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;
   }
-  static diag::Severity deserializeSeverity(unsigned Bits) {
-    return (diag::Severity)(Bits & 0x7);
-  }
-  static bool deserializeUpgradedFromWarning(unsigned Bits) {
-    return Bits >> 3;
+  /// Deserialize a mapping.
+  static DiagnosticMapping deserialize(unsigned Bits) {
+    DiagnosticMapping Result;
+    Result.IsUser = (Bits >> 7) & 1;
+    Result.IsPragma = (Bits >> 6) & 1;
+    Result.HasNoWarningAsError = (Bits >> 5) & 1;
+    Result.HasNoErrorAsFatal = (Bits >> 4) & 1;
+    Result.WasUpgradedFromWarning = (Bits >> 3) & 1;
+    Result.Severity = Bits & 0x7;
+    return Result;
   }
 };
 
index 350d5477751c629e868dfb29b0cc6b5fdf705eb7..6bdef78c074f7fb4337590a156121689bfeb1af0 100644 (file)
@@ -67,18 +67,12 @@ DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
   ArgToStringCookie = nullptr;
 
   AllExtensionsSilenced = 0;
-  IgnoreAllWarnings = false;
-  WarningsAsErrors = false;
-  EnableAllWarnings = false;
-  ErrorsAsFatal = false;
-  FatalsAsError = false;
-  SuppressSystemWarnings = false;
+  SuppressAfterFatalError = true;
   SuppressAllDiagnostics = false;
   ElideType = true;
   PrintTemplateTree = false;
   ShowColors = false;
   ShowOverloads = Ovl_All;
-  ExtBehavior = diag::Severity::Ignored;
 
   ErrorLimit = 0;
   TemplateBacktraceLimit = 0;
@@ -343,8 +337,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
     return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
                                diag::Severity::Fatal);
 
-  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
-  // potentially downgrade anything already mapped to be an error.
+  // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
+  // and potentially downgrade anything already mapped to be a fatal error.
 
   // Get the diagnostics in this group.
   SmallVector<diag::kind, 8> GroupDiags;
index e0580af45b50689fbe88f324650a725e6fbbfbed..2852b40026c2bed66f4b140c58c3d6e28282a7db 100644 (file)
@@ -420,7 +420,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
     Result = Mapping.getSeverity();
 
   // Upgrade ignored diagnostics if -Weverything is enabled.
-  if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
+  if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
       !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
     Result = diag::Severity::Warning;
 
@@ -435,7 +435,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
   // For extension diagnostics that haven't been explicitly mapped, check if we
   // should upgrade the diagnostic.
   if (IsExtensionDiag && !Mapping.isUser())
-    Result = std::max(Result, Diag.ExtBehavior);
+    Result = std::max(Result, State->ExtBehavior);
 
   // At this point, ignored errors can no longer be upgraded.
   if (Result == diag::Severity::Ignored)
@@ -443,28 +443,24 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
 
   // Honor -w, which is lower in priority than pedantic-errors, but higher than
   // -Werror.
-  if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)
+  // FIXME: Under GCC, this also suppresses warnings that have been mapped to
+  // errors by -W flags and #pragma diagnostic.
+  if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)
     return diag::Severity::Ignored;
 
   // If -Werror is enabled, map warnings to errors unless explicitly disabled.
   if (Result == diag::Severity::Warning) {
-    if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError())
+    if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
       Result = diag::Severity::Error;
   }
 
   // If -Wfatal-errors is enabled, map errors to fatal unless explicity
   // disabled.
   if (Result == diag::Severity::Error) {
-    if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
+    if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
       Result = diag::Severity::Fatal;
   }
 
-  // If explicitly requested, map fatal errors to errors.
-  if (Result == diag::Severity::Fatal) {
-      if (Diag.FatalsAsError)
-        Result = diag::Severity::Error;
-  }
-
   // Custom diagnostics always are emitted in system headers.
   bool ShowInSystemHeader =
       !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
@@ -472,7 +468,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
   // If we are in a system header, we ignore it. We look at the diagnostic class
   // because we also want to ignore extensions and warnings in -Werror and
   // -pedantic-errors modes, which *map* warnings/extensions to errors.
-  if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
+  if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
       Diag.getSourceManager().isInSystemHeader(
           Diag.getSourceManager().getExpansionLoc(Loc)))
     return diag::Severity::Ignored;
@@ -632,7 +628,7 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
 
   // If a fatal error has already been emitted, silence all subsequent
   // diagnostics.
-  if (Diag.FatalErrorOccurred) {
+  if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {
     if (DiagLevel >= DiagnosticIDs::Error &&
         Diag.Client->IncludeInDiagnosticCounts()) {
       ++Diag.NumErrors;
index 01129a9415e3ff7d39cdc2fe497771da785cad49..61b5a822c55200d9fad5ee0b81c835c8ce47eedd 100644 (file)
@@ -5531,14 +5531,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
              "Invalid data, not enough diag/map pairs");
       while (Size--) {
         unsigned DiagID = Record[Idx++];
-        unsigned SeverityAndUpgradedFromWarning = Record[Idx++];
-        bool WasUpgradedFromWarning =
-            DiagnosticMapping::deserializeUpgradedFromWarning(
-                SeverityAndUpgradedFromWarning);
         DiagnosticMapping NewMapping =
-            Diag.makeUserMapping(DiagnosticMapping::deserializeSeverity(
-                                     SeverityAndUpgradedFromWarning),
-                                 Loc);
+            DiagnosticMapping::deserialize(Record[Idx++]);
         if (!NewMapping.isPragma() && !IncludeNonPragmaStates)
           continue;
 
@@ -5547,14 +5541,12 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
         // If this mapping was specified as a warning but the severity was
         // upgraded due to diagnostic settings, simulate the current diagnostic
         // settings (and use a warning).
-        if (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) {
-          Mapping = Diag.makeUserMapping(diag::Severity::Warning, Loc);
-          continue;
+        if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) {
+          NewMapping.setSeverity(diag::Severity::Warning);
+          NewMapping.setUpgradedFromWarning(false);
         }
 
-        // Use the deserialized mapping verbatim.
         Mapping = NewMapping;
-        Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
       }
       return NewState;
     };
@@ -5569,22 +5561,36 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
       DiagStates.push_back(FirstState);
 
       // Skip the initial diagnostic state from the serialized module.
-      assert(Record[0] == 0 &&
+      assert(Record[1] == 0 &&
              "Invalid data, unexpected backref in initial state");
-      Idx = 2 + Record[1] * 2;
+      Idx = 3 + Record[2] * 2;
       assert(Idx < Record.size() &&
              "Invalid data, not enough state change pairs in initial state");
+    } else if (F.isModule()) {
+      // For an explicit module, preserve the flags from the module build
+      // command line (-w, -Weverything, -Werror, ...) along with any explicit
+      // -Wblah flags.
+      unsigned Flags = Record[Idx++];
+      DiagState Initial;
+      Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
+      Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
+      Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
+      Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;
+      Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;
+      Initial.ExtBehavior = (diag::Severity)Flags;
+      FirstState = ReadDiagState(Initial, SourceLocation(), true);
+
+      // Set up the root buffer of the module to start with the initial
+      // diagnostic state of the module itself, to cover files that contain no
+      // explicit transitions (for which we did not serialize anything).
+      Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
+          .StateTransitions.push_back({FirstState, 0});
     } else {
-      FirstState = ReadDiagState(
-          F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState,
-          SourceLocation(), F.isModule());
-
-      // For an explicit module, set up the root buffer of the module to start
-      // with the initial diagnostic state of the module itself, to cover files
-      // that contain no explicit transitions.
-      if (F.isModule())
-        Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
-            .StateTransitions.push_back({FirstState, 0});
+      // For prefix ASTs, start with whatever the user configured on the
+      // command line.
+      Idx++; // Skip flags.
+      FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState,
+                                 SourceLocation(), false);
     }
 
     // Read the state transitions.
index 80bf65666ececb79239f9198dc9b4fb75c949dfa..69cdc37665c6c3874f4ea966c0c124309074409e 100644 (file)
@@ -2868,8 +2868,26 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
   unsigned CurrID = 0;
   RecordData Record;
 
+  auto EncodeDiagStateFlags =
+      [](const DiagnosticsEngine::DiagState *DS) -> unsigned {
+    unsigned Result = (unsigned)DS->ExtBehavior;
+    for (unsigned Val :
+         {DS->IgnoreAllWarnings, DS->EnableAllWarnings, DS->WarningsAsErrors,
+          DS->ErrorsAsFatal, DS->SuppressSystemWarnings})
+      Result = (Result << 1) | Val;
+    return Result;
+  };
+
+  unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState);
+  Record.push_back(Flags);
+
   auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
                           bool IncludeNonPragmaStates) {
+    // Ensure that the diagnostic state wasn't modified since it was created.
+    // We will not correctly round-trip this information otherwise.
+    assert(Flags == EncodeDiagStateFlags(State) &&
+           "diag state flags vary in single AST file");
+
     unsigned &DiagStateID = DiagStateIDMap[State];
     Record.push_back(DiagStateID);
   
@@ -2882,7 +2900,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
       for (const auto &I : *State) {
         if (I.second.isPragma() || IncludeNonPragmaStates) {
           Record.push_back(I.first);
-          Record.push_back(I.second.serializeBits());
+          Record.push_back(I.second.serialize());
         }
       }
       // Update the placeholder.
index 82987c6cf133ccd9464a49e641b45670f460defc..dbfcad32d3d28fb12e77895af8a926faf246041a 100644 (file)
@@ -25,5 +25,5 @@ class C : public A<float> { };
 // 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]
 // CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0]
 
-// CHECK-DIAG: keep-going.cpp:1:10: error: 'missing1.h' file not found
-// CHECK-DIAG: keep-going.cpp:8:10: error: 'missing2.h' file not found
+// CHECK-DIAG: keep-going.cpp:1:10: fatal error: 'missing1.h' file not found
+// CHECK-DIAG: keep-going.cpp:8:10: fatal error: 'missing2.h' file not found
index adbbd08ac8dce9f299c8a8b4c2d4bd22e5cb7f93..31d2fe4439b8d1b4c56fcef79aab18714244fc45 100644 (file)
@@ -1,20 +1,42 @@
 // RUN: rm -rf %t
 //
-// 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
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts
-// 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
+// For an implicit module, all that matters are the warning flags in the user.
+// 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
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -Wpadded
+// 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
+// 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
 //
-// 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
-// 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
-// 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
+// For an explicit module, all that matters are the warning flags in the module build.
+// 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
+// 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
+// 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
+//
+// 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
+// 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
+// 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
+// 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
+//
+// 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
+// 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-error.pcm
+// 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-error.pcm -Wno-padded
+// 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-error.pcm -Werror=padded
+//
+// 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
+// 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
+// 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
+//
+// 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
+// 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
+// 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
 
 import diag_flags;
 
 // Diagnostic flags from the module user make no difference to diagnostics
 // emitted within the module when using an explicitly-loaded module.
-#ifdef IMPLICIT_FLAG
+#if ERROR
 // expected-error@diag_flags.h:14 {{padding struct}}
-#elif defined(EXPLICIT_FLAG)
+#elif WARNING
 // expected-warning@diag_flags.h:14 {{padding struct}}
 #else
 // expected-no-diagnostics
index 86f1047dee93861a016da62975e05c1b0b0285d5..c251d83e2097688400bf92dd3c5dd6caab85ffe8 100644 (file)
@@ -3313,7 +3313,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
     Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
 
   if (options & CXTranslationUnit_KeepGoing)
-    Diags->setFatalsAsError(true);
+    Diags->setSuppressAfterFatalError(false);
 
   // Recover resources if we crash before exiting this function.
   llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
index 4ffa0837bd6e76ce5160a7c8f35700cedea6e82c..0111b172472b8bfc3c7998ab8f90ec08f68263e1 100644 (file)
@@ -46,27 +46,30 @@ TEST(DiagnosticTest, suppressAndTrap) {
   EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
 }
 
-// Check that FatalsAsErrors works as intended
-TEST(DiagnosticTest, fatalsAsErrors) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(),
-                          new DiagnosticOptions,
-                          new IgnoringDiagConsumer());
-  Diags.setFatalsAsError(true);
+// Check that SuppressAfterFatalError works as intended
+TEST(DiagnosticTest, suppressAfterFatalError) {
+  for (unsigned Suppress = 0; Suppress != 2; ++Suppress) {
+    DiagnosticsEngine Diags(new DiagnosticIDs(),
+                            new DiagnosticOptions,
+                            new IgnoringDiagConsumer());
+    Diags.setSuppressAfterFatalError(Suppress);
 
-  // Diag that would set UncompilableErrorOccurred and ErrorOccurred.
-  Diags.Report(diag::err_target_unknown_triple) << "unknown";
+    // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
+    Diags.Report(diag::err_cannot_open_file) << "file" << "error";
 
-  // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
-  Diags.Report(diag::err_cannot_open_file) << "file" << "error";
+    // Diag that would set FatalErrorOccurred
+    // (via non-note following a fatal error).
+    Diags.Report(diag::warn_mt_message) << "warning";
 
-  // Diag that would set FatalErrorOccurred
-  // (via non-note following a fatal error).
-  Diags.Report(diag::warn_mt_message) << "warning";
+    EXPECT_TRUE(Diags.hasErrorOccurred());
+    EXPECT_TRUE(Diags.hasFatalErrorOccurred());
+    EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
+    EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
 
-  EXPECT_TRUE(Diags.hasErrorOccurred());
-  EXPECT_FALSE(Diags.hasFatalErrorOccurred());
-  EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
-  EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
+    // The warning should be emitted and counted only if we're not suppressing
+    // after fatal errors.
+    EXPECT_EQ(Diags.getNumWarnings(), Suppress ? 0u : 1u);
+  }
 }
 
 }