head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.11
	netbsd-11-0-RC3:1.1.1.11
	netbsd-11-0-RC2:1.1.1.11
	netbsd-11-0-RC1:1.1.1.11
	perseant-exfatfs-base-20250801:1.1.1.11
	netbsd-11:1.1.1.11.0.10
	netbsd-11-base:1.1.1.11
	netbsd-10-1-RELEASE:1.1.1.11
	perseant-exfatfs-base-20240630:1.1.1.11
	perseant-exfatfs:1.1.1.11.0.8
	perseant-exfatfs-base:1.1.1.11
	netbsd-8-3-RELEASE:1.1.1.8
	netbsd-9-4-RELEASE:1.1.1.10
	netbsd-10-0-RELEASE:1.1.1.11
	netbsd-10-0-RC6:1.1.1.11
	netbsd-10-0-RC5:1.1.1.11
	netbsd-10-0-RC4:1.1.1.11
	netbsd-10-0-RC3:1.1.1.11
	netbsd-10-0-RC2:1.1.1.11
	netbsd-10-0-RC1:1.1.1.11
	netbsd-10:1.1.1.11.0.6
	netbsd-10-base:1.1.1.11
	netbsd-9-3-RELEASE:1.1.1.10
	cjep_sun2x:1.1.1.11.0.4
	cjep_sun2x-base:1.1.1.11
	cjep_staticlib_x-base1:1.1.1.11
	netbsd-9-2-RELEASE:1.1.1.10
	cjep_staticlib_x:1.1.1.11.0.2
	cjep_staticlib_x-base:1.1.1.11
	netbsd-9-1-RELEASE:1.1.1.10
	phil-wifi-20200421:1.1.1.11
	phil-wifi-20200411:1.1.1.11
	phil-wifi-20200406:1.1.1.11
	netbsd-8-2-RELEASE:1.1.1.8
	netbsd-9-0-RELEASE:1.1.1.10
	netbsd-9-0-RC2:1.1.1.10
	netbsd-9-0-RC1:1.1.1.10
	netbsd-9:1.1.1.10.0.2
	netbsd-9-base:1.1.1.10
	phil-wifi-20190609:1.1.1.10
	netbsd-8-1-RELEASE:1.1.1.8
	netbsd-8-1-RC1:1.1.1.8
	pgoyette-compat-merge-20190127:1.1.1.9.2.1
	pgoyette-compat-20190127:1.1.1.10
	pgoyette-compat-20190118:1.1.1.10
	pgoyette-compat-1226:1.1.1.10
	pgoyette-compat-1126:1.1.1.10
	pgoyette-compat-1020:1.1.1.10
	pgoyette-compat-0930:1.1.1.10
	pgoyette-compat-0906:1.1.1.10
	netbsd-7-2-RELEASE:1.1.1.5.2.1
	pgoyette-compat-0728:1.1.1.10
	clang-337282:1.1.1.10
	netbsd-8-0-RELEASE:1.1.1.8
	phil-wifi:1.1.1.9.0.4
	phil-wifi-base:1.1.1.9
	pgoyette-compat-0625:1.1.1.9
	netbsd-8-0-RC2:1.1.1.8
	pgoyette-compat-0521:1.1.1.9
	pgoyette-compat-0502:1.1.1.9
	pgoyette-compat-0422:1.1.1.9
	netbsd-8-0-RC1:1.1.1.8
	pgoyette-compat-0415:1.1.1.9
	pgoyette-compat-0407:1.1.1.9
	pgoyette-compat-0330:1.1.1.9
	pgoyette-compat-0322:1.1.1.9
	pgoyette-compat-0315:1.1.1.9
	netbsd-7-1-2-RELEASE:1.1.1.5.2.1
	pgoyette-compat:1.1.1.9.0.2
	pgoyette-compat-base:1.1.1.9
	netbsd-7-1-1-RELEASE:1.1.1.5.2.1
	clang-319952:1.1.1.9
	matt-nb8-mediatek:1.1.1.8.0.10
	matt-nb8-mediatek-base:1.1.1.8
	clang-309604:1.1.1.9
	perseant-stdc-iso10646:1.1.1.8.0.8
	perseant-stdc-iso10646-base:1.1.1.8
	netbsd-8:1.1.1.8.0.6
	netbsd-8-base:1.1.1.8
	prg-localcount2-base3:1.1.1.8
	prg-localcount2-base2:1.1.1.8
	prg-localcount2-base1:1.1.1.8
	prg-localcount2:1.1.1.8.0.4
	prg-localcount2-base:1.1.1.8
	pgoyette-localcount-20170426:1.1.1.8
	bouyer-socketcan-base1:1.1.1.8
	pgoyette-localcount-20170320:1.1.1.8
	netbsd-7-1:1.1.1.5.2.1.0.6
	netbsd-7-1-RELEASE:1.1.1.5.2.1
	netbsd-7-1-RC2:1.1.1.5.2.1
	clang-294123:1.1.1.8
	netbsd-7-nhusb-base-20170116:1.1.1.5.2.1
	bouyer-socketcan:1.1.1.8.0.2
	bouyer-socketcan-base:1.1.1.8
	clang-291444:1.1.1.8
	pgoyette-localcount-20170107:1.1.1.7
	netbsd-7-1-RC1:1.1.1.5.2.1
	pgoyette-localcount-20161104:1.1.1.7
	netbsd-7-0-2-RELEASE:1.1.1.5.2.1
	localcount-20160914:1.1.1.7
	netbsd-7-nhusb:1.1.1.5.2.1.0.4
	netbsd-7-nhusb-base:1.1.1.5.2.1
	clang-280599:1.1.1.7
	pgoyette-localcount-20160806:1.1.1.7
	pgoyette-localcount-20160726:1.1.1.7
	pgoyette-localcount:1.1.1.7.0.2
	pgoyette-localcount-base:1.1.1.7
	netbsd-7-0-1-RELEASE:1.1.1.5.2.1
	clang-261930:1.1.1.7
	netbsd-7-0:1.1.1.5.2.1.0.2
	netbsd-7-0-RELEASE:1.1.1.5.2.1
	netbsd-7-0-RC3:1.1.1.5.2.1
	netbsd-7-0-RC2:1.1.1.5.2.1
	netbsd-7-0-RC1:1.1.1.5.2.1
	clang-237755:1.1.1.6
	clang-232565:1.1.1.6
	clang-227398:1.1.1.6
	tls-maxphys-base:1.1.1.5
	tls-maxphys:1.1.1.5.0.4
	netbsd-7:1.1.1.5.0.2
	netbsd-7-base:1.1.1.5
	clang-215315:1.1.1.5
	clang-209886:1.1.1.4
	yamt-pagecache:1.1.1.3.0.4
	yamt-pagecache-base9:1.1.1.3
	tls-earlyentropy:1.1.1.3.0.2
	tls-earlyentropy-base:1.1.1.4
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.3
	riastradh-drm2-base3:1.1.1.3
	clang-202566:1.1.1.3
	clang-201163:1.1.1.2
	clang-199312:1.1.1.2
	clang-198450:1.1.1.2
	clang-196603:1.1.1.1
	clang-195771:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2013.11.28.14.14.52;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	ow8OybrawrB1f3fx;

1.1.1.1
date	2013.11.28.14.14.52;	author joerg;	state Exp;
branches;
next	1.1.1.2;
commitid	ow8OybrawrB1f3fx;

1.1.1.2
date	2014.01.05.15.39.28;	author joerg;	state Exp;
branches;
next	1.1.1.3;
commitid	wh3aCSIWykURqWjx;

1.1.1.3
date	2014.03.04.19.54.54;	author joerg;	state Exp;
branches
	1.1.1.3.2.1
	1.1.1.3.4.1;
next	1.1.1.4;
commitid	29z1hJonZISIXprx;

1.1.1.4
date	2014.05.30.18.14.41;	author joerg;	state Exp;
branches;
next	1.1.1.5;
commitid	8q0kdlBlCn09GACx;

1.1.1.5
date	2014.08.10.17.08.34;	author joerg;	state Exp;
branches
	1.1.1.5.2.1
	1.1.1.5.4.1;
next	1.1.1.6;
commitid	N85tXAN6Ex9VZPLx;

1.1.1.6
date	2015.01.29.19.57.30;	author joerg;	state Exp;
branches;
next	1.1.1.7;
commitid	mlISSizlPKvepX7y;

1.1.1.7
date	2016.02.27.22.12.04;	author joerg;	state Exp;
branches
	1.1.1.7.2.1;
next	1.1.1.8;
commitid	tIimz3oDlh1NpBWy;

1.1.1.8
date	2017.01.11.10.33.42;	author joerg;	state Exp;
branches;
next	1.1.1.9;
commitid	CNnUNfII1jgNmxBz;

1.1.1.9
date	2017.08.01.19.34.59;	author joerg;	state Exp;
branches
	1.1.1.9.2.1
	1.1.1.9.4.1;
next	1.1.1.10;
commitid	pMuDy65V0VicSx1A;

1.1.1.10
date	2018.07.17.18.31.13;	author joerg;	state Exp;
branches;
next	1.1.1.11;
commitid	wDzL46ALjrCZgwKA;

1.1.1.11
date	2019.11.13.22.19.22;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.3.2.1
date	2014.08.10.07.08.08;	author tls;	state Exp;
branches;
next	;
commitid	t01A1TLTYxkpGMLx;

1.1.1.3.4.1
date	2014.03.04.19.54.54;	author yamt;	state dead;
branches;
next	1.1.1.3.4.2;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.3.4.2
date	2014.05.22.16.18.27;	author yamt;	state Exp;
branches;
next	;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.5.2.1
date	2015.06.04.20.04.28;	author snj;	state Exp;
branches;
next	;
commitid	yRnjq9fueSo6n9oy;

1.1.1.5.4.1
date	2014.08.10.17.08.34;	author tls;	state dead;
branches;
next	1.1.1.5.4.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.5.4.2
date	2014.08.19.23.47.27;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.7.2.1
date	2017.03.20.06.52.37;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.9.2.1
date	2018.07.28.04.33.18;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.9.4.1
date	2019.06.10.21.45.22;	author christos;	state Exp;
branches;
next	1.1.1.9.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.9.4.2
date	2020.04.13.07.46.33;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@//===--- Compilation.cpp - Compilation Task Implementation ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Compilation.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <errno.h>
#include <sys/stat.h>

using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;

Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
                         InputArgList *_Args, DerivedArgList *_TranslatedArgs)
  : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
    TranslatedArgs(_TranslatedArgs), Redirects(0) {
}

Compilation::~Compilation() {
  delete TranslatedArgs;
  delete Args;

  // Free any derived arg lists.
  for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
                      DerivedArgList*>::iterator it = TCArgs.begin(),
         ie = TCArgs.end(); it != ie; ++it)
    if (it->second != TranslatedArgs)
      delete it->second;

  // Free the actions, if built.
  for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
       it != ie; ++it)
    delete *it;

  // Free redirections of stdout/stderr.
  if (Redirects) {
    delete Redirects[1];
    delete Redirects[2];
    delete [] Redirects;
  }
}

const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
                                                       const char *BoundArch) {
  if (!TC)
    TC = &DefaultToolChain;

  DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
  if (!Entry) {
    Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch);
    if (!Entry)
      Entry = TranslatedArgs;
  }

  return *Entry;
}

bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
  std::string P(File);

  // FIXME: Why are we trying to remove files that we have not created? For
  // example we should only try to remove a temporary assembly file if
  // "clang -cc1" succeed in writing it. Was this a workaround for when
  // clang was writing directly to a .s file and sometimes leaving it behind
  // during a failure?

  // FIXME: If this is necessary, we can still try to split
  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
  // duplicated stat from is_regular_file.

  // Don't try to remove files which we don't have write access to (but may be
  // able to remove), or non-regular files. Underlying tools may have
  // intentionally not overwritten them.
  if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
    return true;

  if (llvm::error_code EC = llvm::sys::fs::remove(File)) {
    // Failure is only failure if the file exists and is "regular". We checked
    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
    // so we don't need to check again.
    
    if (IssueErrors)
      getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
        << EC.message();
    return false;
  }
  return true;
}

bool Compilation::CleanupFileList(const ArgStringList &Files,
                                  bool IssueErrors) const {
  bool Success = true;
  for (ArgStringList::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it)
    Success &= CleanupFile(*it, IssueErrors);
  return Success;
}

bool Compilation::CleanupFileMap(const ArgStringMap &Files,
                                 const JobAction *JA,
                                 bool IssueErrors) const {
  bool Success = true;
  for (ArgStringMap::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it) {

    // If specified, only delete the files associated with the JobAction.
    // Otherwise, delete all files in the map.
    if (JA && it->first != JA)
      continue;
    Success &= CleanupFile(it->second, IssueErrors);
  }
  return Success;
}

int Compilation::ExecuteCommand(const Command &C,
                                const Command *&FailingCommand) const {
  if ((getDriver().CCPrintOptions ||
       getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
    raw_ostream *OS = &llvm::errs();

    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
    // output stream.
    if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
      std::string Error;
      OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
                                    llvm::sys::fs::F_Append);
      if (!Error.empty()) {
        getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
          << Error;
        FailingCommand = &C;
        delete OS;
        return 1;
      }
    }

    if (getDriver().CCPrintOptions)
      *OS << "[Logging clang options]";

    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);

    if (OS != &llvm::errs())
      delete OS;
  }

  std::string Error;
  bool ExecutionFailed;
  int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
  if (!Error.empty()) {
    assert(Res && "Error string set with 0 result code!");
    getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
  }

  if (Res)
    FailingCommand = &C;

  return ExecutionFailed ? 1 : Res;
}

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 (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
    if (ActionFailed(*AI, FailingCommands))
      return true;

  return false;
}

static bool InputsOk(const Command &C,
                     const FailingCommandList &FailingCommands) {
  return !ActionFailed(&C.getSource(), FailingCommands);
}

void Compilation::ExecuteJob(const Job &J,
                             FailingCommandList &FailingCommands) const {
  if (const Command *C = dyn_cast<Command>(&J)) {
    if (!InputsOk(*C, FailingCommands))
      return;
    const Command *FailingCommand = 0;
    if (int Res = ExecuteCommand(*C, FailingCommand))
      FailingCommands.push_back(std::make_pair(Res, FailingCommand));
  } else {
    const JobList *Jobs = cast<JobList>(&J);
    for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
         it != ie; ++it)
      ExecuteJob(**it, FailingCommands);
  }
}

void Compilation::initCompilationForDiagnostics() {
  // Free actions and jobs.
  DeleteContainerPointers(Actions);
  Jobs.clear();

  // Clear temporary/results file lists.
  TempFiles.clear();
  ResultFiles.clear();
  FailureResultFiles.clear();

  // Remove any user specified output.  Claim any unclaimed arguments, so as
  // to avoid emitting warnings about unused args.
  OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
                                options::OPT_MMD };
  for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
    if (TranslatedArgs->hasArg(OutputOpts[i]))
      TranslatedArgs->eraseArg(OutputOpts[i]);
  }
  TranslatedArgs->ClaimAllArgs();

  // Redirect stdout/stderr to /dev/null.
  Redirects = new const StringRef*[3]();
  Redirects[0] = 0;
  Redirects[1] = new const StringRef();
  Redirects[2] = new const StringRef();
}

StringRef Compilation::getSysRoot() const {
  return getDriver().SysRoot;
}
@


1.1.1.1
log
@Import Clang 3.4rc1 r195771.
@
text
@@


1.1.1.2
log
@Import clang 3.5svn r198450.
@
text
@d73 2
@


1.1.1.3
log
@Import Clang 3.5svn r202566.
@
text
@d138 1
a138 2
                                    llvm::sys::fs::F_Append |
                                        llvm::sys::fs::F_Text);
@


1.1.1.3.2.1
log
@Rebase.
@
text
@d30 1
a30 1
    TranslatedArgs(_TranslatedArgs), Redirects(nullptr) {
d202 1
a202 1
    const Command *FailingCommand = nullptr;
d235 1
a235 1
  Redirects[0] = nullptr;
@


1.1.1.4
log
@Import Clang 3.5svn r209886.
@
text
@d30 1
a30 1
    TranslatedArgs(_TranslatedArgs), Redirects(nullptr) {
d202 1
a202 1
    const Command *FailingCommand = nullptr;
d235 1
a235 1
  Redirects[0] = nullptr;
@


1.1.1.5
log
@Import clang 3.6svn r215315.
@
text
@d20 2
d29 3
a31 3
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
      TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
      ForDiagnostics(false) {}
d89 1
a89 1
  if (std::error_code EC = llvm::sys::fs::remove(File)) {
a213 2
  ForDiagnostics = true;

@


1.1.1.5.2.1
log
@Update LLVM to 3.6.1, requested by joerg in ticket 824.
@
text
@d91 1
a91 1

d134 2
a135 2
      std::error_code EC;
      OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC,
d138 1
a138 1
      if (EC) {
d140 1
a140 1
            << EC.message();
d205 3
a207 2
    for (const auto &Job : *Jobs)
      ExecuteJob(Job, FailingCommands);
d236 2
a237 2
  Redirects[1] = new StringRef();
  Redirects[2] = new StringRef();
@


1.1.1.6
log
@Import Clang 3.6RC1 r227398.
@
text
@d91 1
a91 1

d134 2
a135 2
      std::error_code EC;
      OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, EC,
d138 1
a138 1
      if (EC) {
d140 1
a140 1
            << EC.message();
d205 3
a207 2
    for (const auto &Job : *Jobs)
      ExecuteJob(Job, FailingCommands);
d236 2
a237 2
  Redirects[1] = new StringRef();
  Redirects[2] = new StringRef();
@


1.1.1.7
log
@Import Clang 3.8.0rc3 r261930.
@
text
@d27 2
a28 3
    : TheDriver(D), DefaultToolChain(_DefaultToolChain),
      CudaHostToolChain(&DefaultToolChain), CudaDeviceToolChain(nullptr),
      Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
d42 5
d195 5
a199 5
void Compilation::ExecuteJobs(const JobList &Jobs,
                              FailingCommandList &FailingCommands) const {
  for (const auto &Job : Jobs) {
    if (!InputsOk(Job, FailingCommands))
      continue;
d201 1
a201 1
    if (int Res = ExecuteCommand(Job, FailingCommand))
d203 4
d214 1
a214 2
  Actions.clear();
  AllActions.clear();
@


1.1.1.7.2.1
log
@Sync with HEAD
@
text
@d27 2
a28 1
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
d30 1
a30 5
      ForDiagnostics(false) {
  // The offloading host toolchain is the default tool chain.
  OrderedOffloadingToolchains.insert(
      std::make_pair(Action::OFK_Host, &DefaultToolChain));
}
d37 5
a41 3
  for (auto Arg : TCArgs)
    if (Arg.second != TranslatedArgs)
      delete Arg.second;
a44 1
    delete Redirects[0];
d51 2
a52 3
const DerivedArgList &
Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
                                 Action::OffloadKind DeviceOffloadKind) {
d56 1
a56 1
  DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
d58 1
a58 1
    Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
d166 27
a192 3
void Compilation::ExecuteJobs(
    const JobList &Jobs,
    SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const {
d194 2
d197 1
a197 1
    if (int Res = ExecuteCommand(Job, FailingCommand)) {
a198 4
      // 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;
    }
a234 4

void Compilation::Redirect(const StringRef** Redirects) {
  this->Redirects = Redirects;
}
@


1.1.1.8
log
@Import Clang pre-4.0.0 r291444.
@
text
@d27 2
a28 1
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
d30 1
a30 5
      ForDiagnostics(false) {
  // The offloading host toolchain is the default tool chain.
  OrderedOffloadingToolchains.insert(
      std::make_pair(Action::OFK_Host, &DefaultToolChain));
}
d37 5
a41 3
  for (auto Arg : TCArgs)
    if (Arg.second != TranslatedArgs)
      delete Arg.second;
a44 1
    delete Redirects[0];
d51 2
a52 3
const DerivedArgList &
Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
                                 Action::OffloadKind DeviceOffloadKind) {
d56 1
a56 1
  DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
d58 1
a58 1
    Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
d166 27
a192 3
void Compilation::ExecuteJobs(
    const JobList &Jobs,
    SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) const {
d194 2
d197 1
a197 1
    if (int Res = ExecuteCommand(Job, FailingCommand)) {
a198 4
      // 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;
    }
a234 4

void Compilation::Redirect(const StringRef** Redirects) {
  this->Redirects = Redirects;
}
@


1.1.1.9
log
@Import clang r309604 from branches/release_50
@
text
@d26 1
a26 2
                         InputArgList *_Args, DerivedArgList *_TranslatedArgs,
                         bool ContainsError)
d29 1
a29 1
      ForDiagnostics(false), ContainsError(ContainsError) {
@


1.1.1.9.4.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
//===- Compilation.cpp - Compilation Task Implementation ------------------===//
a10 1
#include "clang/Basic/LLVM.h"
a13 1
#include "clang/Driver/Job.h"
a15 2
#include "clang/Driver/Util.h"
#include "llvm/ADT/None.h"
a16 2
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
a17 2
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/Option.h"
a19 4
#include <cassert>
#include <string>
#include <system_error>
#include <utility>
d21 1
a22 1
using namespace driver;
d28 4
a31 3
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
  // The offloading host toolchain is the default toolchain.
a36 5
  // Remove temporary files. This must be done before arguments are freed, as
  // the file names might be derived from the input arguments.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d44 8
d62 3
a64 25
    SmallVector<Arg *, 4> AllocatedArgs;
    DerivedArgList *OpenMPArgs = nullptr;
    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
    if (DeviceOffloadKind == Action::OFK_OpenMP) {
      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
      OpenMPArgs = TC->TranslateOpenMPTargetArgs(
          *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
    }

    if (!OpenMPArgs) {
      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = TranslatedArgs;
    } else {
      Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = OpenMPArgs;
      else
        delete OpenMPArgs;
    }

    // Add allocated arguments to the final DAL.
    for (auto ArgPtr : AllocatedArgs)
      Entry->AddSynthesizedArg(ArgPtr);
d93 1
a93 1
      getDriver().Diag(diag::err_drv_unable_to_remove_file)
d103 3
a105 2
  for (const auto &File: Files)
    Success &= CleanupFile(File, IssueErrors);
d113 3
a115 1
  for (const auto &File : Files) {
d118 1
a118 1
    if (JA && File.first != JA)
d120 1
a120 1
    Success &= CleanupFile(File.second, IssueErrors);
d139 1
a139 1
        getDriver().Diag(diag::err_drv_cc_print_options_failure)
d161 1
a161 1
    getDriver().Diag(diag::err_drv_command_failure) << Error;
d170 3
a172 35
using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;

static bool ActionFailed(const Action *A,
                         const FailingCommandList &FailingCommands) {
  if (FailingCommands.empty())
    return false;

  // CUDA/HIP can have the same input source code compiled multiple times so do
  // not compiled again if there are already failures. It is OK to abort the
  // CUDA pipeline on errors.
  if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
    return true;

  for (const auto &CI : FailingCommands)
    if (A == &(CI.second->getSource()))
      return true;

  for (const auto *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 {
  // According to UNIX standard, driver need to continue compiling all the
  // inputs on the command line even one of them failed.
  // In all but CLMode, execute all the jobs unless the necessary inputs for the
  // job is missing due to previous failures.
a173 2
    if (!InputsOk(Job, FailingCommands))
      continue;
d177 3
a179 3
      // Bail as soon as one command fails in cl driver mode.
      if (TheDriver.IsCLMode())
        return;
a191 4
  // Remove temporary files.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d208 4
a211 4
  Redirects = {None, {""}, {""}};

  // Temporary files added by diagnostics should be kept.
  ForceKeepTempFiles = true;
d218 1
a218 1
void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
@


1.1.1.9.4.2
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.9.2.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
//===- Compilation.cpp - Compilation Task Implementation ------------------===//
a10 1
#include "clang/Basic/LLVM.h"
a13 1
#include "clang/Driver/Job.h"
a15 2
#include "clang/Driver/Util.h"
#include "llvm/ADT/None.h"
a16 2
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
a17 2
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/Option.h"
a19 4
#include <cassert>
#include <string>
#include <system_error>
#include <utility>
d21 1
a22 1
using namespace driver;
d28 4
a31 3
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
  // The offloading host toolchain is the default toolchain.
a36 5
  // Remove temporary files. This must be done before arguments are freed, as
  // the file names might be derived from the input arguments.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d44 8
d62 3
a64 25
    SmallVector<Arg *, 4> AllocatedArgs;
    DerivedArgList *OpenMPArgs = nullptr;
    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
    if (DeviceOffloadKind == Action::OFK_OpenMP) {
      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
      OpenMPArgs = TC->TranslateOpenMPTargetArgs(
          *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
    }

    if (!OpenMPArgs) {
      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = TranslatedArgs;
    } else {
      Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = OpenMPArgs;
      else
        delete OpenMPArgs;
    }

    // Add allocated arguments to the final DAL.
    for (auto ArgPtr : AllocatedArgs)
      Entry->AddSynthesizedArg(ArgPtr);
d93 1
a93 1
      getDriver().Diag(diag::err_drv_unable_to_remove_file)
d103 3
a105 2
  for (const auto &File: Files)
    Success &= CleanupFile(File, IssueErrors);
d113 3
a115 1
  for (const auto &File : Files) {
d118 1
a118 1
    if (JA && File.first != JA)
d120 1
a120 1
    Success &= CleanupFile(File.second, IssueErrors);
d139 1
a139 1
        getDriver().Diag(diag::err_drv_cc_print_options_failure)
d161 1
a161 1
    getDriver().Diag(diag::err_drv_command_failure) << Error;
d170 3
a172 35
using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;

static bool ActionFailed(const Action *A,
                         const FailingCommandList &FailingCommands) {
  if (FailingCommands.empty())
    return false;

  // CUDA/HIP can have the same input source code compiled multiple times so do
  // not compiled again if there are already failures. It is OK to abort the
  // CUDA pipeline on errors.
  if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
    return true;

  for (const auto &CI : FailingCommands)
    if (A == &(CI.second->getSource()))
      return true;

  for (const auto *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 {
  // According to UNIX standard, driver need to continue compiling all the
  // inputs on the command line even one of them failed.
  // In all but CLMode, execute all the jobs unless the necessary inputs for the
  // job is missing due to previous failures.
a173 2
    if (!InputsOk(Job, FailingCommands))
      continue;
d177 3
a179 3
      // Bail as soon as one command fails in cl driver mode.
      if (TheDriver.IsCLMode())
        return;
a191 4
  // Remove temporary files.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d208 4
a211 4
  Redirects = {None, {""}, {""}};

  // Temporary files added by diagnostics should be kept.
  ForceKeepTempFiles = true;
d218 1
a218 1
void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
@


1.1.1.10
log
@Import clang r337282 from trunk
@
text
@d1 1
a1 1
//===- Compilation.cpp - Compilation Task Implementation ------------------===//
a10 1
#include "clang/Basic/LLVM.h"
a13 1
#include "clang/Driver/Job.h"
a15 2
#include "clang/Driver/Util.h"
#include "llvm/ADT/None.h"
a16 2
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
a17 2
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/Option.h"
a19 4
#include <cassert>
#include <string>
#include <system_error>
#include <utility>
d21 1
a22 1
using namespace driver;
d28 4
a31 3
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
  // The offloading host toolchain is the default toolchain.
a36 5
  // Remove temporary files. This must be done before arguments are freed, as
  // the file names might be derived from the input arguments.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d44 8
d62 3
a64 25
    SmallVector<Arg *, 4> AllocatedArgs;
    DerivedArgList *OpenMPArgs = nullptr;
    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
    if (DeviceOffloadKind == Action::OFK_OpenMP) {
      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
      OpenMPArgs = TC->TranslateOpenMPTargetArgs(
          *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
    }

    if (!OpenMPArgs) {
      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = TranslatedArgs;
    } else {
      Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
      if (!Entry)
        Entry = OpenMPArgs;
      else
        delete OpenMPArgs;
    }

    // Add allocated arguments to the final DAL.
    for (auto ArgPtr : AllocatedArgs)
      Entry->AddSynthesizedArg(ArgPtr);
d93 1
a93 1
      getDriver().Diag(diag::err_drv_unable_to_remove_file)
d103 3
a105 2
  for (const auto &File: Files)
    Success &= CleanupFile(File, IssueErrors);
d113 3
a115 1
  for (const auto &File : Files) {
d118 1
a118 1
    if (JA && File.first != JA)
d120 1
a120 1
    Success &= CleanupFile(File.second, IssueErrors);
d139 1
a139 1
        getDriver().Diag(diag::err_drv_cc_print_options_failure)
d161 1
a161 1
    getDriver().Diag(diag::err_drv_command_failure) << Error;
d170 3
a172 35
using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;

static bool ActionFailed(const Action *A,
                         const FailingCommandList &FailingCommands) {
  if (FailingCommands.empty())
    return false;

  // CUDA/HIP can have the same input source code compiled multiple times so do
  // not compiled again if there are already failures. It is OK to abort the
  // CUDA pipeline on errors.
  if (A->isOffloading(Action::OFK_Cuda) || A->isOffloading(Action::OFK_HIP))
    return true;

  for (const auto &CI : FailingCommands)
    if (A == &(CI.second->getSource()))
      return true;

  for (const auto *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 {
  // According to UNIX standard, driver need to continue compiling all the
  // inputs on the command line even one of them failed.
  // In all but CLMode, execute all the jobs unless the necessary inputs for the
  // job is missing due to previous failures.
a173 2
    if (!InputsOk(Job, FailingCommands))
      continue;
d177 3
a179 3
      // Bail as soon as one command fails in cl driver mode.
      if (TheDriver.IsCLMode())
        return;
a191 4
  // Remove temporary files.
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
    CleanupFileList(TempFiles);

d208 4
a211 4
  Redirects = {None, {""}, {""}};

  // Temporary files added by diagnostics should be kept.
  ForceKeepTempFiles = true;
d218 1
a218 1
void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
@


1.1.1.11
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.5.4.1
log
@file Compilation.cpp was added on branch tls-maxphys on 2014-08-19 23:47:27 +0000
@
text
@d1 242
@


1.1.1.5.4.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 242
//===--- Compilation.cpp - Compilation Task Implementation ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Compilation.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;

Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
                         InputArgList *_Args, DerivedArgList *_TranslatedArgs)
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
      TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
      ForDiagnostics(false) {}

Compilation::~Compilation() {
  delete TranslatedArgs;
  delete Args;

  // Free any derived arg lists.
  for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
                      DerivedArgList*>::iterator it = TCArgs.begin(),
         ie = TCArgs.end(); it != ie; ++it)
    if (it->second != TranslatedArgs)
      delete it->second;

  // Free the actions, if built.
  for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
       it != ie; ++it)
    delete *it;

  // Free redirections of stdout/stderr.
  if (Redirects) {
    delete Redirects[1];
    delete Redirects[2];
    delete [] Redirects;
  }
}

const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
                                                       const char *BoundArch) {
  if (!TC)
    TC = &DefaultToolChain;

  DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
  if (!Entry) {
    Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch);
    if (!Entry)
      Entry = TranslatedArgs;
  }

  return *Entry;
}

bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
  // FIXME: Why are we trying to remove files that we have not created? For
  // example we should only try to remove a temporary assembly file if
  // "clang -cc1" succeed in writing it. Was this a workaround for when
  // clang was writing directly to a .s file and sometimes leaving it behind
  // during a failure?

  // FIXME: If this is necessary, we can still try to split
  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
  // duplicated stat from is_regular_file.

  // Don't try to remove files which we don't have write access to (but may be
  // able to remove), or non-regular files. Underlying tools may have
  // intentionally not overwritten them.
  if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
    return true;

  if (std::error_code EC = llvm::sys::fs::remove(File)) {
    // Failure is only failure if the file exists and is "regular". We checked
    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
    // so we don't need to check again.
    
    if (IssueErrors)
      getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
        << EC.message();
    return false;
  }
  return true;
}

bool Compilation::CleanupFileList(const ArgStringList &Files,
                                  bool IssueErrors) const {
  bool Success = true;
  for (ArgStringList::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it)
    Success &= CleanupFile(*it, IssueErrors);
  return Success;
}

bool Compilation::CleanupFileMap(const ArgStringMap &Files,
                                 const JobAction *JA,
                                 bool IssueErrors) const {
  bool Success = true;
  for (ArgStringMap::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it) {

    // If specified, only delete the files associated with the JobAction.
    // Otherwise, delete all files in the map.
    if (JA && it->first != JA)
      continue;
    Success &= CleanupFile(it->second, IssueErrors);
  }
  return Success;
}

int Compilation::ExecuteCommand(const Command &C,
                                const Command *&FailingCommand) const {
  if ((getDriver().CCPrintOptions ||
       getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
    raw_ostream *OS = &llvm::errs();

    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
    // output stream.
    if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
      std::string Error;
      OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
                                    llvm::sys::fs::F_Append |
                                        llvm::sys::fs::F_Text);
      if (!Error.empty()) {
        getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
          << Error;
        FailingCommand = &C;
        delete OS;
        return 1;
      }
    }

    if (getDriver().CCPrintOptions)
      *OS << "[Logging clang options]";

    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);

    if (OS != &llvm::errs())
      delete OS;
  }

  std::string Error;
  bool ExecutionFailed;
  int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
  if (!Error.empty()) {
    assert(Res && "Error string set with 0 result code!");
    getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
  }

  if (Res)
    FailingCommand = &C;

  return ExecutionFailed ? 1 : Res;
}

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 (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
    if (ActionFailed(*AI, FailingCommands))
      return true;

  return false;
}

static bool InputsOk(const Command &C,
                     const FailingCommandList &FailingCommands) {
  return !ActionFailed(&C.getSource(), FailingCommands);
}

void Compilation::ExecuteJob(const Job &J,
                             FailingCommandList &FailingCommands) const {
  if (const Command *C = dyn_cast<Command>(&J)) {
    if (!InputsOk(*C, FailingCommands))
      return;
    const Command *FailingCommand = nullptr;
    if (int Res = ExecuteCommand(*C, FailingCommand))
      FailingCommands.push_back(std::make_pair(Res, FailingCommand));
  } else {
    const JobList *Jobs = cast<JobList>(&J);
    for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
         it != ie; ++it)
      ExecuteJob(**it, FailingCommands);
  }
}

void Compilation::initCompilationForDiagnostics() {
  ForDiagnostics = true;

  // Free actions and jobs.
  DeleteContainerPointers(Actions);
  Jobs.clear();

  // Clear temporary/results file lists.
  TempFiles.clear();
  ResultFiles.clear();
  FailureResultFiles.clear();

  // Remove any user specified output.  Claim any unclaimed arguments, so as
  // to avoid emitting warnings about unused args.
  OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
                                options::OPT_MMD };
  for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
    if (TranslatedArgs->hasArg(OutputOpts[i]))
      TranslatedArgs->eraseArg(OutputOpts[i]);
  }
  TranslatedArgs->ClaimAllArgs();

  // Redirect stdout/stderr to /dev/null.
  Redirects = new const StringRef*[3]();
  Redirects[0] = nullptr;
  Redirects[1] = new const StringRef();
  Redirects[2] = new const StringRef();
}

StringRef Compilation::getSysRoot() const {
  return getDriver().SysRoot;
}
@


1.1.1.3.4.1
log
@file Compilation.cpp was added on branch yamt-pagecache on 2014-05-22 16:18:27 +0000
@
text
@d1 242
@


1.1.1.3.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 242
//===--- Compilation.cpp - Compilation Task Implementation ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Compilation.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <errno.h>
#include <sys/stat.h>

using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;

Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
                         InputArgList *_Args, DerivedArgList *_TranslatedArgs)
  : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
    TranslatedArgs(_TranslatedArgs), Redirects(0) {
}

Compilation::~Compilation() {
  delete TranslatedArgs;
  delete Args;

  // Free any derived arg lists.
  for (llvm::DenseMap<std::pair<const ToolChain*, const char*>,
                      DerivedArgList*>::iterator it = TCArgs.begin(),
         ie = TCArgs.end(); it != ie; ++it)
    if (it->second != TranslatedArgs)
      delete it->second;

  // Free the actions, if built.
  for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
       it != ie; ++it)
    delete *it;

  // Free redirections of stdout/stderr.
  if (Redirects) {
    delete Redirects[1];
    delete Redirects[2];
    delete [] Redirects;
  }
}

const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
                                                       const char *BoundArch) {
  if (!TC)
    TC = &DefaultToolChain;

  DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)];
  if (!Entry) {
    Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch);
    if (!Entry)
      Entry = TranslatedArgs;
  }

  return *Entry;
}

bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
  // FIXME: Why are we trying to remove files that we have not created? For
  // example we should only try to remove a temporary assembly file if
  // "clang -cc1" succeed in writing it. Was this a workaround for when
  // clang was writing directly to a .s file and sometimes leaving it behind
  // during a failure?

  // FIXME: If this is necessary, we can still try to split
  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
  // duplicated stat from is_regular_file.

  // Don't try to remove files which we don't have write access to (but may be
  // able to remove), or non-regular files. Underlying tools may have
  // intentionally not overwritten them.
  if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
    return true;

  if (llvm::error_code EC = llvm::sys::fs::remove(File)) {
    // Failure is only failure if the file exists and is "regular". We checked
    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
    // so we don't need to check again.
    
    if (IssueErrors)
      getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
        << EC.message();
    return false;
  }
  return true;
}

bool Compilation::CleanupFileList(const ArgStringList &Files,
                                  bool IssueErrors) const {
  bool Success = true;
  for (ArgStringList::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it)
    Success &= CleanupFile(*it, IssueErrors);
  return Success;
}

bool Compilation::CleanupFileMap(const ArgStringMap &Files,
                                 const JobAction *JA,
                                 bool IssueErrors) const {
  bool Success = true;
  for (ArgStringMap::const_iterator
         it = Files.begin(), ie = Files.end(); it != ie; ++it) {

    // If specified, only delete the files associated with the JobAction.
    // Otherwise, delete all files in the map.
    if (JA && it->first != JA)
      continue;
    Success &= CleanupFile(it->second, IssueErrors);
  }
  return Success;
}

int Compilation::ExecuteCommand(const Command &C,
                                const Command *&FailingCommand) const {
  if ((getDriver().CCPrintOptions ||
       getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
    raw_ostream *OS = &llvm::errs();

    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
    // output stream.
    if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
      std::string Error;
      OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
                                    llvm::sys::fs::F_Append |
                                        llvm::sys::fs::F_Text);
      if (!Error.empty()) {
        getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
          << Error;
        FailingCommand = &C;
        delete OS;
        return 1;
      }
    }

    if (getDriver().CCPrintOptions)
      *OS << "[Logging clang options]";

    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);

    if (OS != &llvm::errs())
      delete OS;
  }

  std::string Error;
  bool ExecutionFailed;
  int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
  if (!Error.empty()) {
    assert(Res && "Error string set with 0 result code!");
    getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
  }

  if (Res)
    FailingCommand = &C;

  return ExecutionFailed ? 1 : Res;
}

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 (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
    if (ActionFailed(*AI, FailingCommands))
      return true;

  return false;
}

static bool InputsOk(const Command &C,
                     const FailingCommandList &FailingCommands) {
  return !ActionFailed(&C.getSource(), FailingCommands);
}

void Compilation::ExecuteJob(const Job &J,
                             FailingCommandList &FailingCommands) const {
  if (const Command *C = dyn_cast<Command>(&J)) {
    if (!InputsOk(*C, FailingCommands))
      return;
    const Command *FailingCommand = 0;
    if (int Res = ExecuteCommand(*C, FailingCommand))
      FailingCommands.push_back(std::make_pair(Res, FailingCommand));
  } else {
    const JobList *Jobs = cast<JobList>(&J);
    for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
         it != ie; ++it)
      ExecuteJob(**it, FailingCommands);
  }
}

void Compilation::initCompilationForDiagnostics() {
  // Free actions and jobs.
  DeleteContainerPointers(Actions);
  Jobs.clear();

  // Clear temporary/results file lists.
  TempFiles.clear();
  ResultFiles.clear();
  FailureResultFiles.clear();

  // Remove any user specified output.  Claim any unclaimed arguments, so as
  // to avoid emitting warnings about unused args.
  OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
                                options::OPT_MMD };
  for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
    if (TranslatedArgs->hasArg(OutputOpts[i]))
      TranslatedArgs->eraseArg(OutputOpts[i]);
  }
  TranslatedArgs->ClaimAllArgs();

  // Redirect stdout/stderr to /dev/null.
  Redirects = new const StringRef*[3]();
  Redirects[0] = 0;
  Redirects[1] = new const StringRef();
  Redirects[2] = new const StringRef();
}

StringRef Compilation::getSysRoot() const {
  return getDriver().SysRoot;
}
@


