Browse Source

[Driver] Actually report errors during parsing instead of stopping when there's an error somewhere.

This is a more principled version of r303756. That change was both very
brittle about the state of the Diags object going into the driver and
also broke tooling in funny ways.

In particular it prevented tools from capturing diagnostics properly and
made the compilation database logic fail to provide arguments to the
tool, falling back to scanning directories for JSON files.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306822 91177308-0d34-0410-b5e6-96231b3b80d8
Benjamin Kramer 8 years ago
parent
commit
f5f1f63df1

+ 7 - 1
include/clang/Driver/Compilation.h

@@ -105,10 +105,13 @@ class Compilation {
   /// Whether we're compiling for diagnostic purposes.
   /// Whether we're compiling for diagnostic purposes.
   bool ForDiagnostics;
   bool ForDiagnostics;
 
 
+  /// Whether an error during the parsing of the input args.
+  bool ContainsError;
+
 public:
 public:
   Compilation(const Driver &D, const ToolChain &DefaultToolChain,
   Compilation(const Driver &D, const ToolChain &DefaultToolChain,
               llvm::opt::InputArgList *Args,
               llvm::opt::InputArgList *Args,
-              llvm::opt::DerivedArgList *TranslatedArgs);
+              llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError);
   ~Compilation();
   ~Compilation();
 
 
   const Driver &getDriver() const { return TheDriver; }
   const Driver &getDriver() const { return TheDriver; }
@@ -275,6 +278,9 @@ public:
   /// Return true if we're compiling for diagnostics.
   /// Return true if we're compiling for diagnostics.
   bool isForDiagnostics() const { return ForDiagnostics; }
   bool isForDiagnostics() const { return ForDiagnostics; }
 
 
+  /// Return whether an error during the parsing of the input args.
+  bool containsError() const { return ContainsError; }
+
   /// Redirect - Redirect output of this compilation. Can only be done once.
   /// Redirect - Redirect output of this compilation. Can only be done once.
   ///
   ///
   /// \param Redirects - array of pointers to paths. The array
   /// \param Redirects - array of pointers to paths. The array

+ 2 - 1
include/clang/Driver/Driver.h

@@ -341,7 +341,8 @@ public:
 
 
   /// ParseArgStrings - Parse the given list of strings into an
   /// ParseArgStrings - Parse the given list of strings into an
   /// ArgList.
   /// ArgList.
-  llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args);
+  llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args,
+                                          bool &ContainsError);
 
 
   /// BuildInputs - Construct the list of inputs and their types from 
   /// BuildInputs - Construct the list of inputs and their types from 
   /// the given arguments.
   /// the given arguments.

+ 3 - 2
lib/Driver/Compilation.cpp

@@ -23,10 +23,11 @@ using namespace clang;
 using namespace llvm::opt;
 using namespace llvm::opt;
 
 
 Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
 Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
-                         InputArgList *_Args, DerivedArgList *_TranslatedArgs)
+                         InputArgList *_Args, DerivedArgList *_TranslatedArgs,
+                         bool ContainsError)
     : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
     : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
       Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
       Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
-      ForDiagnostics(false) {
+      ForDiagnostics(false), ContainsError(ContainsError) {
   // The offloading host toolchain is the default tool chain.
   // The offloading host toolchain is the default tool chain.
   OrderedOffloadingToolchains.insert(
   OrderedOffloadingToolchains.insert(
       std::make_pair(Action::OFK_Host, &DefaultToolChain));
       std::make_pair(Action::OFK_Host, &DefaultToolChain));

+ 29 - 13
lib/Driver/Driver.cpp

@@ -153,8 +153,10 @@ void Driver::setDriverModeFromOption(StringRef Opt) {
     Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
     Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
 }
 }
 
 
-InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
+InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
+                                     bool &ContainsError) {
   llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
   llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+  ContainsError = false;
 
 
   unsigned IncludedFlagsBitmask;
   unsigned IncludedFlagsBitmask;
   unsigned ExcludedFlagsBitmask;
   unsigned ExcludedFlagsBitmask;
@@ -167,27 +169,41 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
                           IncludedFlagsBitmask, ExcludedFlagsBitmask);
                           IncludedFlagsBitmask, ExcludedFlagsBitmask);
 
 
   // Check for missing argument error.
   // Check for missing argument error.
-  if (MissingArgCount)
-    Diag(clang::diag::err_drv_missing_argument)
+  if (MissingArgCount) {
+    Diag(diag::err_drv_missing_argument)
         << Args.getArgString(MissingArgIndex) << MissingArgCount;
         << Args.getArgString(MissingArgIndex) << MissingArgCount;
+    ContainsError |=
+        Diags.getDiagnosticLevel(diag::err_drv_missing_argument,
+                                 SourceLocation()) > DiagnosticsEngine::Warning;
+  }
 
 
   // Check for unsupported options.
   // Check for unsupported options.
   for (const Arg *A : Args) {
   for (const Arg *A : Args) {
     if (A->getOption().hasFlag(options::Unsupported)) {
     if (A->getOption().hasFlag(options::Unsupported)) {
-      Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(Args);
+      Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
+      ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt,
+                                                SourceLocation()) >
+                       DiagnosticsEngine::Warning;
       continue;
       continue;
     }
     }
 
 
     // Warn about -mcpu= without an argument.
     // Warn about -mcpu= without an argument.
     if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) {
     if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) {
-      Diag(clang::diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+      Diag(diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+      ContainsError |= Diags.getDiagnosticLevel(
+                           diag::warn_drv_empty_joined_argument,
+                           SourceLocation()) > DiagnosticsEngine::Warning;
     }
     }
   }
   }
 
 
-  for (const Arg *A : Args.filtered(options::OPT_UNKNOWN))
-    Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl :
-                              diag::err_drv_unknown_argument)
-      << A->getAsString(Args);
+  for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) {
+    auto ID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+                         : diag::err_drv_unknown_argument;
+
+    Diags.Report(ID) << A->getAsString(Args);
+    ContainsError |= Diags.getDiagnosticLevel(ID, SourceLocation()) >
+                     DiagnosticsEngine::Warning;
+  }
 
 
   return Args;
   return Args;
 }
 }
@@ -600,9 +616,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
   // FIXME: This stuff needs to go into the Compilation, not the driver.
   // FIXME: This stuff needs to go into the Compilation, not the driver.
   bool CCCPrintPhases;
   bool CCCPrintPhases;
 
 
-  InputArgList Args = ParseArgStrings(ArgList.slice(1));
-  if (Diags.hasErrorOccurred())
-    return nullptr;
+  bool ContainsError;
+  InputArgList Args = ParseArgStrings(ArgList.slice(1), ContainsError);
 
 
   // Silence driver warnings if requested
   // Silence driver warnings if requested
   Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
   Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
@@ -692,7 +707,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
       *UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs));
       *UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs));
 
 
   // The compilation takes ownership of Args.
   // The compilation takes ownership of Args.
-  Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs);
+  Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
+                                   ContainsError);
 
 
   if (!HandleImmediateArgs(*C))
   if (!HandleImmediateArgs(*C))
     return C;
     return C;

+ 1 - 1
tools/driver/driver.cpp

@@ -462,7 +462,7 @@ int main(int argc_, const char **argv_) {
 
 
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
   int Res = 1;
   int Res = 1;
-  if (C.get()) {
+  if (C && !C->containsError()) {
     SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
     SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
     Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
     Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
 
 

+ 11 - 0
unittests/Driver/ToolChainTest.cpp

@@ -152,5 +152,16 @@ TEST(ToolChainTest, DefaultDriverMode) {
   EXPECT_TRUE(CXXDriver.CCCIsCXX());
   EXPECT_TRUE(CXXDriver.CCCIsCXX());
   EXPECT_TRUE(CLDriver.IsCLMode());
   EXPECT_TRUE(CLDriver.IsCLMode());
 }
 }
+TEST(ToolChainTest, InvalidArgument) {
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  struct TestDiagnosticConsumer : public DiagnosticConsumer {};
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
+  std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+      {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
+  EXPECT_TRUE(C);
+  EXPECT_TRUE(C->containsError());
+}
 
 
 } // end anonymous namespace.
 } // end anonymous namespace.