steven_wu created this revision. This is basically reverting r261774 with a tweak for clang-cl. UNIX standard states: When c99 encounters a compilation error that causes an object file not to be created, it shall write a diagnostic to standard error and continue to compile other source code operands, but it shall not perform the link phase and it shall return a non-zero exit status
The same goes for c89 or cc. And they are all alias or shims pointing to clang on Darwin. The original commit was intended for CUDA so the error message doesn't get emit twice for both host and device. It seems that the clang driver has been changed to model the CUDA dependency differently. Now the driver behaves the same without this commit. rdar://problem/32223263 https://reviews.llvm.org/D39502 Files: lib/Driver/Compilation.cpp test/Driver/output-file-cleanup.c Index: test/Driver/output-file-cleanup.c =================================================================== --- test/Driver/output-file-cleanup.c +++ test/Driver/output-file-cleanup.c @@ -53,6 +53,6 @@ // RUN: not %clang -S %t-dir/1.c %t-dir/2.c %t-dir/3.c %t-dir/4.c %t-dir/5.c // RUN: test -f %t-dir/1.s // RUN: test ! -f %t-dir/2.s -// RUN: test ! -f %t-dir/3.s +// RUN: test -f %t-dir/3.s // RUN: test ! -f %t-dir/4.s -// RUN: test ! -f %t-dir/5.s +// RUN: test -f %t-dir/5.s Index: lib/Driver/Compilation.cpp =================================================================== --- lib/Driver/Compilation.cpp +++ lib/Driver/Compilation.cpp @@ -182,16 +182,42 @@ return ExecutionFailed ? 1 : Res; } -void Compilation::ExecuteJobs( - const JobList &Jobs, - SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const { +typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; + +static bool ActionFailed(const Action *A, + const FailingCommandList &FailingCommands) { + + if (FailingCommands.empty()) + return false; + + for (FailingCommandList::const_iterator CI = FailingCommands.begin(), + CE = FailingCommands.end(); CI != CE; ++CI) + if (A == &(CI->second->getSource())) + return true; + + for (const Action *AI : A->inputs()) + if (ActionFailed(AI, FailingCommands)) + return true; + + return false; +} + +static bool InputsOk(const Command &C, + const FailingCommandList &FailingCommands) { + return !ActionFailed(&C.getSource(), FailingCommands); +} + +void Compilation::ExecuteJobs(const JobList &Jobs, + FailingCommandList &FailingCommands) const { for (const auto &Job : Jobs) { + if (!InputsOk(Job, FailingCommands)) + continue; const Command *FailingCommand = nullptr; if (int Res = ExecuteCommand(Job, FailingCommand)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); - // Bail as soon as one command fails, so we don't output duplicate error - // messages if we die on e.g. the same file. - return; + // Bail on error in cl mode. + if (TheDriver.IsCLMode()) + return; } } }
Index: test/Driver/output-file-cleanup.c =================================================================== --- test/Driver/output-file-cleanup.c +++ test/Driver/output-file-cleanup.c @@ -53,6 +53,6 @@ // RUN: not %clang -S %t-dir/1.c %t-dir/2.c %t-dir/3.c %t-dir/4.c %t-dir/5.c // RUN: test -f %t-dir/1.s // RUN: test ! -f %t-dir/2.s -// RUN: test ! -f %t-dir/3.s +// RUN: test -f %t-dir/3.s // RUN: test ! -f %t-dir/4.s -// RUN: test ! -f %t-dir/5.s +// RUN: test -f %t-dir/5.s Index: lib/Driver/Compilation.cpp =================================================================== --- lib/Driver/Compilation.cpp +++ lib/Driver/Compilation.cpp @@ -182,16 +182,42 @@ return ExecutionFailed ? 1 : Res; } -void Compilation::ExecuteJobs( - const JobList &Jobs, - SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const { +typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList; + +static bool ActionFailed(const Action *A, + const FailingCommandList &FailingCommands) { + + if (FailingCommands.empty()) + return false; + + for (FailingCommandList::const_iterator CI = FailingCommands.begin(), + CE = FailingCommands.end(); CI != CE; ++CI) + if (A == &(CI->second->getSource())) + return true; + + for (const Action *AI : A->inputs()) + if (ActionFailed(AI, FailingCommands)) + return true; + + return false; +} + +static bool InputsOk(const Command &C, + const FailingCommandList &FailingCommands) { + return !ActionFailed(&C.getSource(), FailingCommands); +} + +void Compilation::ExecuteJobs(const JobList &Jobs, + FailingCommandList &FailingCommands) const { for (const auto &Job : Jobs) { + if (!InputsOk(Job, FailingCommands)) + continue; const Command *FailingCommand = nullptr; if (int Res = ExecuteCommand(Job, FailingCommand)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); - // Bail as soon as one command fails, so we don't output duplicate error - // messages if we die on e.g. the same file. - return; + // Bail on error in cl mode. + if (TheDriver.IsCLMode()) + return; } } }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits