summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp41
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp1083
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp357
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp679
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp196
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp532
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp313
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp36
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp563
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp154
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp131
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp68
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp108
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp330
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp2
28 files changed, 2919 insertions, 1801 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
index d8118cb..7dc475e 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
@@ -34,10 +34,11 @@ namespace {
typedef RecursiveASTVisitor<ASTPrinter> base;
public:
- ASTPrinter(std::unique_ptr<raw_ostream> Out = nullptr, bool Dump = false,
- StringRef FilterString = "", bool DumpLookups = false)
- : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), Dump(Dump),
- FilterString(FilterString), DumpLookups(DumpLookups) {}
+ enum Kind { DumpFull, Dump, Print, None };
+ ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, StringRef FilterString,
+ bool DumpLookups = false)
+ : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
+ OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {}
void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
@@ -55,7 +56,7 @@ namespace {
bool ShowColors = Out.has_colors();
if (ShowColors)
Out.changeColor(raw_ostream::BLUE);
- Out << ((Dump || DumpLookups) ? "Dumping " : "Printing ") << getName(D)
+ Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D)
<< ":\n";
if (ShowColors)
Out.resetColor();
@@ -80,22 +81,30 @@ namespace {
if (DumpLookups) {
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
if (DC == DC->getPrimaryContext())
- DC->dumpLookups(Out, Dump);
+ DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull);
else
Out << "Lookup map is in primary DeclContext "
<< DC->getPrimaryContext() << "\n";
} else
Out << "Not a DeclContext\n";
- } else if (Dump)
- D->dump(Out);
- else
+ } else if (OutputKind == Print)
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ else if (OutputKind != None)
+ D->dump(Out, OutputKind == DumpFull);
}
raw_ostream &Out;
std::unique_ptr<raw_ostream> OwnedOut;
- bool Dump;
+
+ /// How to output individual declarations.
+ Kind OutputKind;
+
+ /// Which declarations or DeclContexts to display.
std::string FilterString;
+
+ /// Whether the primary output is lookup results or declarations. Individual
+ /// results will be output with a format determined by OutputKind. This is
+ /// incompatible with OutputKind == Print.
bool DumpLookups;
};
@@ -125,16 +134,20 @@ namespace {
std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
- return llvm::make_unique<ASTPrinter>(std::move(Out), /*Dump=*/false,
+ return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
FilterString);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString,
bool DumpDecls,
+ bool Deserialize,
bool DumpLookups) {
- assert((DumpDecls || DumpLookups) && "nothing to dump");
- return llvm::make_unique<ASTPrinter>(nullptr, DumpDecls, FilterString,
- DumpLookups);
+ assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
+ return llvm::make_unique<ASTPrinter>(nullptr,
+ Deserialize ? ASTPrinter::DumpFull :
+ DumpDecls ? ASTPrinter::Dump :
+ ASTPrinter::None,
+ FilterString, DumpLookups);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
index 51064da..354527d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
@@ -21,14 +21,13 @@ ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return AdaptedAction->CreateASTConsumer(CI, InFile);
}
-bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI) {
// FIXME: This is a hack. We need a better way to communicate the
// AST file, compiler instance, and file name than member variables
// of FrontendAction.
AdaptedAction->setCurrentInput(getCurrentInput(), takeCurrentASTUnit());
AdaptedAction->setCompilerInstance(&CI);
- return AdaptedAction->BeginSourceFileAction(CI, Filename);
+ return AdaptedAction->BeginSourceFileAction(CI);
}
void ASTMergeAction::ExecuteAction() {
@@ -45,9 +44,9 @@ void ASTMergeAction::ExecuteAction() {
new ForwardingDiagnosticConsumer(
*CI.getDiagnostics().getClient()),
/*ShouldOwnClient=*/true));
- std::unique_ptr<ASTUnit> Unit =
- ASTUnit::LoadFromASTFile(ASTFiles[I], CI.getPCHContainerReader(),
- Diags, CI.getFileSystemOpts(), false);
+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+ ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), false);
if (!Unit)
continue;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
index d892996..1094e6d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/VirtualFileSystem.h"
@@ -78,106 +79,83 @@ namespace {
}
}
};
-
- struct OnDiskData {
- /// \brief The file in which the precompiled preamble is stored.
- std::string PreambleFile;
-
- /// \brief Temporary files that should be removed when the ASTUnit is
- /// destroyed.
- SmallVector<std::string, 4> TemporaryFiles;
-
- /// \brief Erase temporary files.
- void CleanTemporaryFiles();
-
- /// \brief Erase the preamble file.
- void CleanPreambleFile();
-
- /// \brief Erase temporary files and the preamble file.
- void Cleanup();
- };
-}
-
-static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
- static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
- return M;
-}
-
-static void cleanupOnDiskMapAtExit();
-typedef llvm::DenseMap<const ASTUnit *,
- std::unique_ptr<OnDiskData>> OnDiskDataMap;
-static OnDiskDataMap &getOnDiskDataMap() {
- static OnDiskDataMap M;
- static bool hasRegisteredAtExit = false;
- if (!hasRegisteredAtExit) {
- hasRegisteredAtExit = true;
- atexit(cleanupOnDiskMapAtExit);
+ template <class T>
+ std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
+ if (!Val)
+ return nullptr;
+ return std::move(*Val);
}
- return M;
-}
-static void cleanupOnDiskMapAtExit() {
- // Use the mutex because there can be an alive thread destroying an ASTUnit.
- llvm::MutexGuard Guard(getOnDiskMutex());
- for (const auto &I : getOnDiskDataMap()) {
- // We don't worry about freeing the memory associated with OnDiskDataMap.
- // All we care about is erasing stale files.
- I.second->Cleanup();
+ template <class T>
+ bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
}
-}
-static OnDiskData &getOnDiskData(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- auto &D = M[AU];
- if (!D)
- D = llvm::make_unique<OnDiskData>();
- return *D;
-}
-
-static void erasePreambleFile(const ASTUnit *AU) {
- getOnDiskData(AU).CleanPreambleFile();
-}
+/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file
+/// and file-to-buffer remappings inside \p Invocation.
+static std::unique_ptr<llvm::MemoryBuffer>
+getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
+ vfs::FileSystem *VFS,
+ StringRef FilePath) {
+ const auto &PreprocessorOpts = Invocation.getPreprocessorOpts();
-static void removeOnDiskEntry(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- OnDiskDataMap::iterator I = M.find(AU);
- if (I != M.end()) {
- I->second->Cleanup();
- M.erase(I);
- }
-}
-
-static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
- getOnDiskData(AU).PreambleFile = preambleFile;
-}
+ // Try to determine if the main file has been remapped, either from the
+ // command line (to another file) or directly through the compiler
+ // invocation (to a memory buffer).
+ llvm::MemoryBuffer *Buffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
+ auto FileStatus = VFS->status(FilePath);
+ if (FileStatus) {
+ llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID();
-static const std::string &getPreambleFile(const ASTUnit *AU) {
- return getOnDiskData(AU).PreambleFile;
-}
+ // Check whether there is a file-file remapping of the main file
+ for (const auto &RF : PreprocessorOpts.RemappedFiles) {
+ std::string MPath(RF.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping. Try to load the resulting, remapped source.
+ BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
+ if (!BufferOwner)
+ return nullptr;
+ }
+ }
+ }
-void OnDiskData::CleanTemporaryFiles() {
- for (StringRef File : TemporaryFiles)
- llvm::sys::fs::remove(File);
- TemporaryFiles.clear();
-}
+ // Check whether there is a file-buffer remapping. It supercedes the
+ // file-file remapping.
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ std::string MPath(RB.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping.
+ BufferOwner.reset();
+ Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
+ }
+ }
+ }
+ }
-void OnDiskData::CleanPreambleFile() {
- if (!PreambleFile.empty()) {
- llvm::sys::fs::remove(PreambleFile);
- PreambleFile.clear();
+ // If the main source file was not remapped, load it now.
+ if (!Buffer && !BufferOwner) {
+ BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath));
+ if (!BufferOwner)
+ return nullptr;
}
-}
-void OnDiskData::Cleanup() {
- CleanTemporaryFiles();
- CleanPreambleFile();
+ if (BufferOwner)
+ return BufferOwner;
+ if (!Buffer)
+ return nullptr;
+ return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
+}
}
struct ASTUnit::ASTWriterData {
@@ -185,21 +163,14 @@ struct ASTUnit::ASTWriterData {
llvm::BitstreamWriter Stream;
ASTWriter Writer;
- ASTWriterData() : Stream(Buffer), Writer(Stream, { }) { }
+ ASTWriterData(MemoryBufferCache &PCMCache)
+ : Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {}
};
void ASTUnit::clearFileLevelDecls() {
llvm::DeleteContainerSeconds(FileDecls);
}
-void ASTUnit::CleanTemporaryFiles() {
- getOnDiskData(this).CleanTemporaryFiles();
-}
-
-void ASTUnit::addTemporaryFile(StringRef TempFile) {
- getOnDiskData(this).TemporaryFiles.push_back(TempFile);
-}
-
/// \brief After failing to build a precompiled preamble (due to
/// errors in the source that occurs in the preamble), the number of
/// reparses during which we'll skip even trying to precompile the
@@ -238,9 +209,6 @@ ASTUnit::~ASTUnit() {
clearFileLevelDecls();
- // Clean up the temporary files and the preamble file.
- removeOnDiskEntry(this);
-
// Free the buffers associated with remapped files. We are required to
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
@@ -490,7 +458,9 @@ namespace {
/// a Preprocessor.
class ASTInfoCollector : public ASTReaderListener {
Preprocessor &PP;
- ASTContext &Context;
+ ASTContext *Context;
+ HeaderSearchOptions &HSOpts;
+ PreprocessorOptions &PPOpts;
LangOptions &LangOpt;
std::shared_ptr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
@@ -498,11 +468,14 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
- ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
+ ASTInfoCollector(Preprocessor &PP, ASTContext *Context,
+ HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts,
+ LangOptions &LangOpt,
std::shared_ptr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts),
- Target(Target), Counter(Counter), InitializedLanguage(false) {}
+ : PP(PP), Context(Context), HSOpts(HSOpts), PPOpts(PPOpts),
+ LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target),
+ Counter(Counter), InitializedLanguage(false) {}
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
bool AllowCompatibleDifferences) override {
@@ -516,6 +489,20 @@ public:
return false;
}
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ bool Complain) override {
+ this->HSOpts = HSOpts;
+ return false;
+ }
+
+ virtual bool
+ ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
+ std::string &SuggestedPredefines) override {
+ this->PPOpts = PPOpts;
+ return false;
+ }
+
bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
bool AllowCompatibleDifferences) override {
// If we've already initialized the target, don't do it again.
@@ -549,28 +536,39 @@ private:
// Initialize the preprocessor.
PP.Initialize(*Target);
+ if (!Context)
+ return;
+
// Initialize the ASTContext
- Context.InitBuiltinTypes(*Target);
+ Context->InitBuiltinTypes(*Target);
// We didn't have access to the comment options when the ASTContext was
// constructed, so register them now.
- Context.getCommentCommandTraits().registerCommentOptions(
+ Context->getCommentCommandTraits().registerCommentOptions(
LangOpt.CommentOpts);
}
};
/// \brief Diagnostic consumer that saves each diagnostic it is given.
class StoredDiagnosticConsumer : public DiagnosticConsumer {
- SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags;
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
+ const LangOptions *LangOpts;
SourceManager *SourceMgr;
public:
- explicit StoredDiagnosticConsumer(
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : StoredDiags(StoredDiags), SourceMgr(nullptr) {}
+ StoredDiagnosticConsumer(
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
+ LangOpts(nullptr), SourceMgr(nullptr) {
+ assert((StoredDiags || StandaloneDiags) &&
+ "No output collections were passed to StoredDiagnosticConsumer.");
+ }
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP = nullptr) override {
+ this->LangOpts = &LangOpts;
if (PP)
SourceMgr = &PP->getSourceManager();
}
@@ -589,8 +587,9 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr)
{
if (RequestCapture || Diags.getClient() == nullptr) {
OwningPreviousClient = Diags.takeClient();
@@ -607,16 +606,39 @@ public:
} // anonymous namespace
+static ASTUnit::StandaloneDiagnostic
+makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag);
+
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info) {
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(Level, Info);
// Only record the diagnostic if it's part of the source manager we know
// about. This effectively drops diagnostics from modules we're building.
// FIXME: In the long run, ee don't want to drop source managers from modules.
- if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr)
- StoredDiags.emplace_back(Level, Info);
+ if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) {
+ StoredDiagnostic *ResultDiag = nullptr;
+ if (StoredDiags) {
+ StoredDiags->emplace_back(Level, Info);
+ ResultDiag = &StoredDiags->back();
+ }
+
+ if (StandaloneDiags) {
+ llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None;
+ if (!ResultDiag) {
+ StoredDiag.emplace(Level, Info);
+ ResultDiag = StoredDiag.getPointer();
+ }
+ StandaloneDiags->push_back(
+ makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
+ }
+ }
+}
+
+IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
+ return Reader;
}
ASTMutationListener *ASTUnit::getASTMutationListener() {
@@ -647,12 +669,12 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
if (CaptureDiagnostics)
- Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
+ Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr));
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo,
bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles,
bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors,
@@ -668,6 +690,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+ AST->LangOpts = std::make_shared<LangOptions>();
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
@@ -677,18 +700,18 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
+ AST->PCMCache = new MemoryBufferCache;
AST->HSOpts = std::make_shared<HeaderSearchOptions>();
AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat();
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
AST->getSourceManager(),
AST->getDiagnostics(),
- AST->ASTFileLangOpts,
+ AST->getLangOpts(),
/*Target=*/nullptr));
-
- auto PPOpts = std::make_shared<PreprocessorOptions>();
+ AST->PPOpts = std::make_shared<PreprocessorOptions>();
for (const auto &RemappedFile : RemappedFiles)
- PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
+ AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
// Gather Info for preprocessor construction later on.
@@ -696,35 +719,36 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
unsigned Counter;
AST->PP = std::make_shared<Preprocessor>(
- std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts,
- AST->getSourceManager(), HeaderInfo, *AST,
+ AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts,
+ AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader,
/*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
- AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(),
- PP.getIdentifierTable(), PP.getSelectorTable(),
- PP.getBuiltinInfo());
- ASTContext &Context = *AST->Ctx;
+ if (ToLoad >= LoadASTOnly)
+ AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(),
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo());
bool disableValid = false;
if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
disableValid = true;
- AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { },
+ AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { },
/*isysroot=*/"",
/*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors);
AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
- *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target,
- Counter));
+ *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
+ AST->TargetOpts, AST->Target, Counter));
// Attach the AST reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
// AST file as needed.
// We need the external source to be set up before we read the AST, because
// eagerly-deserialized declarations may use it.
- Context.setExternalSource(AST->Reader);
+ if (AST->Ctx)
+ AST->Ctx->setExternalSource(AST->Reader);
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
@@ -746,21 +770,29 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
PP.setCounterValue(Counter);
// Create an AST consumer, even though it isn't used.
- AST->Consumer.reset(new ASTConsumer);
-
+ if (ToLoad >= LoadASTOnly)
+ AST->Consumer.reset(new ASTConsumer);
+
// Create a semantic analysis object and tell the AST reader about it.
- AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
- AST->TheSema->Initialize();
- AST->Reader->InitializeSema(*AST->TheSema);
+ if (ToLoad >= LoadEverything) {
+ AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer));
+ AST->TheSema->Initialize();
+ AST->Reader->InitializeSema(*AST->TheSema);
+ }
// Tell the diagnostic client that we have started a source file.
- AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP);
+ AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
return AST;
}
namespace {
+/// \brief Add the given macro to the hash of all top-level entities.
+void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+}
+
/// \brief Preprocessor callback class that updates a hash value with the names
/// of all macros that have been defined by the translation unit.
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
@@ -771,7 +803,7 @@ public:
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
- Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
};
@@ -897,45 +929,27 @@ public:
}
};
-class PrecompilePreambleAction : public ASTFrontendAction {
- ASTUnit &Unit;
- bool HasEmittedPreamblePCH;
-
+class ASTUnitPreambleCallbacks : public PreambleCallbacks {
public:
- explicit PrecompilePreambleAction(ASTUnit &Unit)
- : Unit(Unit), HasEmittedPreamblePCH(false) {}
+ unsigned getHash() const { return Hash; }
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
- bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
- void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
- bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
-
- bool hasCodeCompletionSupport() const override { return false; }
- bool hasASTFileSupport() const override { return false; }
- TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
-};
+ std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
-class PrecompilePreambleConsumer : public PCHGenerator {
- ASTUnit &Unit;
- unsigned &Hash;
- std::vector<Decl *> TopLevelDecls;
- PrecompilePreambleAction *Action;
- std::unique_ptr<raw_ostream> Out;
+ std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
+ return std::move(TopLevelDeclIDs);
+ }
-public:
- PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action,
- const Preprocessor &PP, StringRef isysroot,
- std::unique_ptr<raw_ostream> Out)
- : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
- ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
- /*AllowASTWithErrors=*/true),
- Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action),
- Out(std::move(Out)) {
- Hash = 0;
+ void AfterPCHEmitted(ASTWriter &Writer) override {
+ TopLevelDeclIDs.reserve(TopLevelDecls.size());
+ for (Decl *D : TopLevelDecls) {
+ // Invalid top-level decls may not have been serialized.
+ if (D->isInvalidDecl())
+ continue;
+ TopLevelDeclIDs.push_back(Writer.getDeclID(D));
+ }
}
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ void HandleTopLevelDecl(DeclGroupRef DG) override {
for (Decl *D : DG) {
// FIXME: Currently ObjC method declarations are incorrectly being
// reported as top-level declarations, even though their DeclContext
@@ -946,59 +960,22 @@ public:
AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
- return true;
}
- void HandleTranslationUnit(ASTContext &Ctx) override {
- PCHGenerator::HandleTranslationUnit(Ctx);
- if (hasEmittedPCH()) {
- // Write the generated bitstream to "Out".
- *Out << getPCH();
- // Make sure it hits disk now.
- Out->flush();
- // Free the buffer.
- llvm::SmallVector<char, 0> Empty;
- getPCH() = std::move(Empty);
-
- // Translate the top-level declarations we captured during
- // parsing into declaration IDs in the precompiled
- // preamble. This will allow us to deserialize those top-level
- // declarations when requested.
- for (Decl *D : TopLevelDecls) {
- // Invalid top-level decls may not have been serialized.
- if (D->isInvalidDecl())
- continue;
- Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D));
- }
-
- Action->setHasEmittedPreamblePCH();
- }
+ void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
+
+private:
+ unsigned Hash = 0;
+ std::vector<Decl *> TopLevelDecls;
+ std::vector<serialization::DeclID> TopLevelDeclIDs;
+ llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
};
} // anonymous namespace
-std::unique_ptr<ASTConsumer>
-PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- std::string Sysroot;
- std::string OutputFile;
- std::unique_ptr<raw_ostream> OS =
- GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
- OutputFile);
- if (!OS)
- return nullptr;
-
- if (!CI.getFrontendOpts().RelocatablePCH)
- Sysroot.clear();
-
- CI.getPreprocessor().addPPCallbacks(
- llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
- Unit.getCurrentTopLevelHashValue()));
- return llvm::make_unique<PrecompilePreambleConsumer>(
- Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS));
-}
-
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
return StoredDiag.getLocation().isValid();
}
@@ -1034,15 +1011,20 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
- SavedMainFileBuffer.reset();
-
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
// Create the compiler instance to use for building the AST.
std::unique_ptr<CompilerInstance> Clang(
new CompilerInstance(std::move(PCHContainerOps)));
+ if (FileMgr && VFS) {
+ assert(VFS == FileMgr->getVirtualFileSystem() &&
+ "VFS passed to Parse and VFS in FileMgr are different");
+ } else if (VFS) {
+ Clang->setVirtualFileSystem(VFS);
+ }
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1069,9 +1051,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1081,18 +1065,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
Clang->createFileManager();
FileMgr = &Clang->getFileManager();
}
- SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
- UserFilesAreVolatile);
- TheSema.reset();
- Ctx = nullptr;
- PP = nullptr;
- Reader = nullptr;
- // Clear out old caches and data.
- TopLevelDecls.clear();
- clearFileLevelDecls();
- CleanTemporaryFiles();
+ ResetForParse();
+ SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
+ UserFilesAreVolatile);
if (!OverrideMainBuffer) {
checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDeclsInPreamble.clear();
@@ -1106,15 +1083,9 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
// The stored diagnostic has the old source manager in it; update
// the locations to refer into the new source manager. Since we've
@@ -1140,6 +1111,8 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
if (SavedMainFileBuffer)
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
PreambleDiagnostics, StoredDiagnostics);
+ else
+ PreambleSrcLocCache.clear();
if (!Act->Execute())
goto error;
@@ -1165,111 +1138,6 @@ error:
return true;
}
-/// \brief Simple function to retrieve a path for a preamble precompiled header.
-static std::string GetPreamblePCHPath() {
- // FIXME: This is a hack so that we can override the preamble file during
- // crash-recovery testing, which is the only case where the preamble files
- // are not necessarily cleaned up.
- const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
- if (TmpFile)
- return TmpFile;
-
- SmallString<128> Path;
- llvm::sys::fs::createTemporaryFile("preamble", "pch", Path);
-
- return Path.str();
-}
-
-/// \brief Compute the preamble for the main file, providing the source buffer
-/// that corresponds to the main file along with a pair (bytes, start-of-line)
-/// that describes the preamble.
-ASTUnit::ComputedPreamble
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
- FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
-
- // Try to determine if the main file has been remapped, either from the
- // command line (to another file) or directly through the compiler invocation
- // (to a memory buffer).
- llvm::MemoryBuffer *Buffer = nullptr;
- std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
- std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
- llvm::sys::fs::UniqueID MainFileID;
- if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
- // Check whether there is a file-file remapping of the main file
- for (const auto &RF : PreprocessorOpts.RemappedFiles) {
- std::string MPath(RF.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping. Try to load the resulting, remapped source.
- BufferOwner = getBufferForFile(RF.second);
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
- }
- }
-
- // Check whether there is a file-buffer remapping. It supercedes the
- // file-file remapping.
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- std::string MPath(RB.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping.
- BufferOwner.reset();
- Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
- }
- }
- }
- }
-
- // If the main source file was not remapped, load it now.
- if (!Buffer && !BufferOwner) {
- BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile());
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
-
- if (!Buffer)
- Buffer = BufferOwner.get();
- auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(),
- *Invocation.getLangOpts(), MaxLines);
- return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first,
- Pre.second);
-}
-
-ASTUnit::PreambleFileHash
-ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
- PreambleFileHash Result;
- Result.Size = Size;
- Result.ModTime = ModTime;
- memset(Result.MD5, 0, sizeof(Result.MD5));
- return Result;
-}
-
-ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer(
- const llvm::MemoryBuffer *Buffer) {
- PreambleFileHash Result;
- Result.Size = Buffer->getBufferSize();
- Result.ModTime = 0;
-
- llvm::MD5 MD5Ctx;
- MD5Ctx.update(Buffer->getBuffer().data());
- MD5Ctx.final(Result.MD5);
-
- return Result;
-}
-
-namespace clang {
-bool operator==(const ASTUnit::PreambleFileHash &LHS,
- const ASTUnit::PreambleFileHash &RHS) {
- return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
- memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5)) == 0;
-}
-} // namespace clang
-
static std::pair<unsigned, unsigned>
makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -1338,135 +1206,44 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts,
std::unique_ptr<llvm::MemoryBuffer>
ASTUnit::getMainBufferWithPrecompiledPreamble(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
+ const CompilerInvocation &PreambleInvocationIn,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
unsigned MaxLines) {
- auto PreambleInvocation =
- std::make_shared<CompilerInvocation>(PreambleInvocationIn);
- FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts
- = PreambleInvocation->getPreprocessorOpts();
-
- ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines);
-
- if (!NewPreamble.Size) {
- // We couldn't find a preamble in the main source. Clear out the current
- // preamble, if we have one. It's obviously no good any more.
- Preamble.clear();
- erasePreambleFile(this);
-
- // The next time we actually see a preamble, precompile it.
- PreambleRebuildCounter = 1;
+ auto MainFilePath =
+ PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
+ std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
+ getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
+ MainFilePath);
+ if (!MainFileBuffer)
return nullptr;
- }
-
- if (!Preamble.empty()) {
- // We've previously computed a preamble. Check whether we have the same
- // preamble now that we did before, and that there's enough space in
- // the main-file buffer within the precompiled preamble to fit the
- // new main file.
- if (Preamble.size() == NewPreamble.Size &&
- PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine &&
- memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Size) == 0) {
- // The preamble has not changed. We may be able to re-use the precompiled
- // preamble.
-
- // Check that none of the files used by the preamble have changed.
- bool AnyFileChanged = false;
-
- // First, make a record of those files that have been overridden via
- // remapping or unsaved_files.
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
- for (const auto &R : PreprocessorOpts.RemappedFiles) {
- if (AnyFileChanged)
- break;
-
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(R.second, Status)) {
- // If we can't stat the file we're remapping to, assume that something
- // horrible happened.
- AnyFileChanged = true;
- break;
- }
- OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
- Status.getSize(),
- llvm::sys::toTimeT(Status.getLastModificationTime()));
- }
+ PreambleBounds Bounds =
+ ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(),
+ MainFileBuffer.get(), MaxLines);
+ if (!Bounds.Size)
+ return nullptr;
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- if (AnyFileChanged)
- break;
+ if (Preamble) {
+ if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
+ VFS.get())) {
+ // Okay! We can re-use the precompiled preamble.
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(RB.first, Status)) {
- AnyFileChanged = true;
- break;
- }
+ // Set the state of the diagnostic object to mimic its state
+ // after parsing the preamble.
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocationIn.getDiagnosticOpts());
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- OverriddenFiles[Status.getUniqueID()] =
- PreambleFileHash::createForMemoryBuffer(RB.second);
- }
-
- // Check whether anything has changed.
- for (llvm::StringMap<PreambleFileHash>::iterator
- F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
- !AnyFileChanged && F != FEnd;
- ++F) {
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
- // If we can't stat the file, assume that something horrible happened.
- AnyFileChanged = true;
- break;
- }
-
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden
- = OverriddenFiles.find(Status.getUniqueID());
- if (Overridden != OverriddenFiles.end()) {
- // This file was remapped; check whether the newly-mapped file
- // matches up with the previous mapping.
- if (Overridden->second != F->second)
- AnyFileChanged = true;
- continue;
- }
-
- // The file was not remapped; check whether it has changed on disk.
- if (Status.getSize() != uint64_t(F->second.Size) ||
- llvm::sys::toTimeT(Status.getLastModificationTime()) !=
- F->second.ModTime)
- AnyFileChanged = true;
- }
-
- if (!AnyFileChanged) {
- // Okay! We can re-use the precompiled preamble.
-
- // Set the state of the diagnostic object to mimic its state
- // after parsing the preamble.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(),
- PreambleInvocation->getDiagnosticOpts());
- getDiagnostics().setNumWarnings(NumWarningsInPreamble);
-
- return llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile());
- }
+ PreambleRebuildCounter = 1;
+ return MainFileBuffer;
+ } else {
+ Preamble.reset();
+ PreambleDiagnostics.clear();
+ TopLevelDeclsInPreamble.clear();
+ PreambleRebuildCounter = 1;
}
-
- // If we aren't allowed to rebuild the precompiled preamble, just
- // return now.
- if (!AllowRebuild)
- return nullptr;
-
- // We can't reuse the previously-computed preamble. Build a new one.
- Preamble.clear();
- PreambleDiagnostics.clear();
- erasePreambleFile(this);
- PreambleRebuildCounter = 1;
- } else if (!AllowRebuild) {
- // We aren't allowed to rebuild the precompiled preamble; just
- // return now.
- return nullptr;
}
// If the preamble rebuild counter > 1, it's because we previously
@@ -1477,162 +1254,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
return nullptr;
}
- // Create a temporary file for the precompiled preamble. In rare
- // circumstances, this can fail.
- std::string PreamblePCHPath = GetPreamblePCHPath();
- if (PreamblePCHPath.empty()) {
- // Try again next time.
- PreambleRebuildCounter = 1;
- return nullptr;
- }
-
- // We did not previously compute a preamble, or it can't be reused anyway.
- SimpleTimer PreambleTimer(WantTiming);
- PreambleTimer.setOutput("Precompiling preamble");
-
- // Save the preamble text for later; we'll need to compare against it for
- // subsequent reparses.
- StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
- Preamble.assign(FileMgr->getFile(MainFilename),
- NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Buffer->getBufferStart() + NewPreamble.Size);
- PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine;
-
- PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename);
-
- // Remap the main source file to the preamble buffer.
- StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
- PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get());
-
- // Tell the compiler invocation to generate a temporary precompiled header.
- FrontendOpts.ProgramAction = frontend::GeneratePCH;
- // FIXME: Generate the precompiled header into memory?
- FrontendOpts.OutputFile = PreamblePCHPath;
- PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
- PreprocessorOpts.PrecompiledPreambleBytes.second = false;
-
- // Create the compiler instance to use for building the precompiled preamble.
- std::unique_ptr<CompilerInstance> Clang(
- new CompilerInstance(std::move(PCHContainerOps)));
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
- CICleanup(Clang.get());
-
- Clang->setInvocation(std::move(PreambleInvocation));
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
-
- // Set up diagnostics, capturing all of the diagnostics produced.
- Clang->setDiagnostics(&getDiagnostics());
-
- // Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(
- Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget()) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Inform the target of the language options.
- //
- // FIXME: We shouldn't need to do this, the target should be immutable once
- // created. This complexity should be lifted elsewhere.
- Clang->getTarget().adjust(Clang->getLangOpts());
-
- assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
- "Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
- "FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not support here!");
-
- // Clear out old caches and data.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
- TopLevelDecls.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleDiagnostics.clear();
-
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
- if (!VFS)
+ assert(!Preamble && "No Preamble should be stored at that point");
+ // If we aren't allowed to rebuild the precompiled preamble, just
+ // return now.
+ if (!AllowRebuild)
return nullptr;
- // Create a file manager object to provide access to and cache the filesystem.
- Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
-
- // Create the source manager.
- Clang->setSourceManager(new SourceManager(getDiagnostics(),
- Clang->getFileManager()));
-
- auto PreambleDepCollector = std::make_shared<DependencyCollector>();
- Clang->addDependencyCollector(PreambleDepCollector);
-
- std::unique_ptr<PrecompilePreambleAction> Act;
- Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
+ SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone;
+ SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
+ ASTUnitPreambleCallbacks Callbacks;
+ {
+ llvm::Optional<CaptureDroppedDiagnostics> Capture;
+ if (CaptureDiagnostics)
+ Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags,
+ &NewPreambleDiagsStandalone);
+
+ // We did not previously compute a preamble, or it can't be reused anyway.
+ SimpleTimer PreambleTimer(WantTiming);
+ PreambleTimer.setOutput("Precompiling preamble");
+
+ llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
+ PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
+ PCHContainerOps, Callbacks);
+ if (NewPreamble) {
+ Preamble = std::move(*NewPreamble);
+ PreambleRebuildCounter = 1;
+ } else {
+ switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
+ case BuildPreambleError::CouldntCreateTempFile:
+ case BuildPreambleError::PreambleIsEmpty:
+ // Try again next time.
+ PreambleRebuildCounter = 1;
+ return nullptr;
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ case BuildPreambleError::BeginSourceFileFailed:
+ case BuildPreambleError::CouldntEmitPCH:
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ // These erros are more likely to repeat, retry after some period.
+ PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+ return nullptr;
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+ }
}
-
- Act->Execute();
-
- // Transfer any diagnostics generated when parsing the preamble into the set
- // of preamble diagnostics.
- for (stored_diag_iterator I = stored_diag_afterDriver_begin(),
- E = stored_diag_end();
- I != E; ++I)
- PreambleDiagnostics.push_back(
- makeStandaloneDiagnostic(Clang->getLangOpts(), *I));
- Act->EndSourceFile();
+ assert(Preamble && "Preamble wasn't built");
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
+ TopLevelDecls.clear();
+ TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
+ PreambleTopLevelHashValue = Callbacks.getHash();
- if (!Act->hasEmittedPreamblePCH()) {
- // The preamble PCH failed (e.g. there was a module loading fatal error),
- // so no precompiled header was generated. Forget that we even tried.
- // FIXME: Should we leave a note for ourselves to try again?
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Keep track of the preamble we precompiled.
- setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
-
- // Keep track of all of the files that the source manager knows about,
- // so we can verify whether they have changed or not.
- FilesInPreamble.clear();
- SourceManager &SourceMgr = Clang->getSourceManager();
- for (auto &Filename : PreambleDepCollector->getDependencies()) {
- const FileEntry *File = Clang->getFileManager().getFile(Filename);
- if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
- continue;
- if (time_t ModTime = File->getModificationTime()) {
- FilesInPreamble[File->getName()] = PreambleFileHash::createForFile(
- File->getSize(), ModTime);
- } else {
- llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
- FilesInPreamble[File->getName()] =
- PreambleFileHash::createForMemoryBuffer(Buffer);
- }
- }
- PreambleRebuildCounter = 1;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
+ checkAndRemoveNonDriverDiags(NewPreambleDiags);
+ StoredDiagnostics = std::move(NewPreambleDiags);
+ PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
// If the hash of top-level entities differs from the hash of the top-level
// entities the last time we rebuilt the preamble, clear out the completion
@@ -1642,11 +1318,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
- return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(),
- MainFilename);
+ return MainFileBuffer;
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+ assert(Preamble && "Should only be called when preamble was built");
+
std::vector<Decl *> Resolved;
Resolved.reserve(TopLevelDeclsInPreamble.size());
ExternalASTSource &Source = *getASTContext().getExternalSource();
@@ -1723,6 +1400,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
UserFilesAreVolatile);
+ AST->PCMCache = new MemoryBufferCache;
return AST;
}
@@ -1802,10 +1480,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
// Configure the various subsystems.
AST->TheSema.reset();
@@ -1872,30 +1552,36 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
bool ASTUnit::LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- unsigned PrecompilePreambleAfterNParses) {
+ unsigned PrecompilePreambleAfterNParses,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
-
+
+ assert(VFS && "VFS is null");
+
// We'll manage file buffers ourselves.
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Invocation->getFrontendOpts().DisableFree = false;
+ getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (PrecompilePreambleAfterNParses > 0) {
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
}
-
+
SimpleTimer ParsingTimer(WantTiming);
ParsingTimer.setOutput("Parsing " + getMainFileName());
-
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
MemBufferCleanup(OverrideMainBuffer.get());
- return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
@@ -1929,7 +1615,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
DiagCleanup(Diags.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses))
+ PrecompilePreambleAfterNParses,
+ AST->FileMgr->getVirtualFileSystem()))
return nullptr;
return AST;
}
@@ -1943,8 +1630,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
- bool UserFilesAreVolatile, bool ForSerialization,
- llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
+ bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
+ llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -1953,11 +1641,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
{
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
- StoredDiagnostics);
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+ &StoredDiagnostics, nullptr);
CI = clang::createInvocationFromCommandLine(
- llvm::makeArrayRef(ArgBegin, ArgEnd), Diags);
+ llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS);
if (!CI)
return nullptr;
}
@@ -1970,6 +1658,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
+ PPOpts.GeneratePreamble = PrecompilePreambleAfterNParses != 0;
+ PPOpts.SingleFileParseMode = SingleFileParse;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -1985,11 +1675,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->FileSystemOpts = CI->getFileSystemOpts();
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ VFS = vfs::getRealFileSystem();
+ VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
if (!VFS)
return nullptr;
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
+ AST->PCMCache = new MemoryBufferCache;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
@@ -2001,7 +1693,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
if (ForSerialization)
- AST->WriterData.reset(new ASTWriterData());
+ AST->WriterData.reset(new ASTWriterData(*AST->PCMCache));
// Zero out now to ease cleanup during crash recovery.
CI = nullptr;
Diags = nullptr;
@@ -2011,7 +1703,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ASTUnitCleanup(AST.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses)) {
+ PrecompilePreambleAfterNParses,
+ VFS)) {
// Some error occurred, if caller wants to examine diagnostics, pass it the
// ASTUnit.
if (ErrAST) {
@@ -2025,10 +1718,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
}
bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArrayRef<RemappedFile> RemappedFiles) {
+ ArrayRef<RemappedFile> RemappedFiles,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
+ if (!VFS) {
+ assert(FileMgr && "FileMgr is null on Reparse call");
+ VFS = FileMgr->getVirtualFileSystem();
+ }
+
clearFileLevelDecls();
SimpleTimer ParsingTimer(WantTiming);
@@ -2048,9 +1747,10 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
+ if (Preamble || PreambleRebuildCounter > 0)
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+
// Clear out the diagnostics state.
FileMgr.reset();
@@ -2061,7 +1761,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// Parse the sources
bool Result =
- Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
// If we're caching global code-completion results, and the top-level
// declarations have changed, clear out the code-completion cache.
@@ -2076,6 +1776,19 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
return Result;
}
+void ASTUnit::ResetForParse() {
+ SavedMainFileBuffer.reset();
+
+ SourceMgr.reset();
+ TheSema.reset();
+ Ctx.reset();
+ PP.reset();
+ Reader.reset();
+
+ TopLevelDecls.clear();
+ clearFileLevelDecls();
+}
+
//----------------------------------------------------------------------------//
// Code completion
//----------------------------------------------------------------------------//
@@ -2368,7 +2081,7 @@ void ASTUnit::CodeComplete(
Clang->setDiagnostics(&Diag);
CaptureDroppedDiagnostics Capture(true,
Clang->getDiagnostics(),
- StoredDiagnostics);
+ &StoredDiagnostics, nullptr);
ProcessWarningOptions(Diag, Inv.getDiagnosticOpts());
// Create the target instance.
@@ -2387,11 +2100,12 @@ void ASTUnit::CodeComplete(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
-
// Use the source and file managers that we were given.
Clang->setFileManager(&FileMgr);
@@ -2416,17 +2130,21 @@ void ASTUnit::CodeComplete(
// point is within the main file, after the end of the precompiled
// preamble.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty()) {
+ if (Preamble) {
std::string CompleteFilePath(File);
- llvm::sys::fs::UniqueID CompleteFileID;
- if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) {
+ auto VFS = FileMgr.getVirtualFileSystem();
+ auto CompleteFileStatus = VFS->status(CompleteFilePath);
+ if (CompleteFileStatus) {
+ llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
+
std::string MainPath(OriginalSourceFile);
- llvm::sys::fs::UniqueID MainID;
- if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
+ auto MainStatus = VFS->status(MainPath);
+ if (MainStatus) {
+ llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
if (CompleteFileID == MainID && Line > 1)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
- PCHContainerOps, Inv, false, Line - 1);
+ PCHContainerOps, Inv, VFS, false, Line - 1);
}
}
}
@@ -2434,14 +2152,8 @@ void ASTUnit::CodeComplete(
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
-
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
OwnedBuffers.push_back(OverrideMainBuffer.release());
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -2516,7 +2228,8 @@ bool ASTUnit::serialize(raw_ostream &OS) {
SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
- ASTWriter Writer(Stream, { });
+ MemoryBufferCache PCMCache;
+ ASTWriter Writer(Stream, Buffer, PCMCache, {});
return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
}
@@ -2531,9 +2244,9 @@ void ASTUnit::TranslateStoredDiagnostics(
// remap all the locations to the new view. This includes the diag location,
// any associated source ranges, and the source ranges of associated fix-its.
// FIXME: There should be a cleaner way to do this.
-
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
+
for (const StandaloneDiagnostic &SD : Diags) {
// Rebuild the StoredDiagnostic.
if (SD.Filename.empty())
@@ -2541,8 +2254,16 @@ void ASTUnit::TranslateStoredDiagnostics(
const FileEntry *FE = FileMgr.getFile(SD.Filename);
if (!FE)
continue;
- FileID FID = SrcMgr.translateFile(FE);
- SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ SourceLocation FileLoc;
+ auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
+ if (ItFileID == PreambleSrcLocCache.end()) {
+ FileID FID = SrcMgr.translateFile(FE);
+ FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ PreambleSrcLocCache[SD.Filename] = FileLoc;
+ } else {
+ FileLoc = ItFileID->getValue();
+ }
+
if (FileLoc.isInvalid())
continue;
SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
@@ -2679,11 +2400,11 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
- if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
+ if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc
= SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
return FileLoc.getLocWithOffset(Offs);
@@ -2700,12 +2421,12 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
- Offs < Preamble.size()) {
+ Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
return FileLoc.getLocWithOffset(Offs);
}
@@ -2823,18 +2544,32 @@ const FileEntry *ASTUnit::getPCHFile() {
}
bool ASTUnit::isModuleFile() {
- return isMainFileAST() && ASTFileLangOpts.isCompilingModule();
+ return isMainFileAST() && getLangOpts().isCompilingModule();
}
-void ASTUnit::PreambleData::countLines() const {
- NumLines = 0;
- if (empty())
- return;
+InputKind ASTUnit::getInputKind() const {
+ auto &LangOpts = getLangOpts();
+
+ InputKind::Language Lang;
+ if (LangOpts.OpenCL)
+ Lang = InputKind::OpenCL;
+ else if (LangOpts.CUDA)
+ Lang = InputKind::CUDA;
+ else if (LangOpts.RenderScript)
+ Lang = InputKind::RenderScript;
+ else if (LangOpts.CPlusPlus)
+ Lang = LangOpts.ObjC1 ? InputKind::ObjCXX : InputKind::CXX;
+ else
+ Lang = LangOpts.ObjC1 ? InputKind::ObjC : InputKind::C;
+
+ InputKind::Format Fmt = InputKind::Source;
+ if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap)
+ Fmt = InputKind::ModuleMap;
- NumLines = std::count(Buffer.begin(), Buffer.end(), '\n');
+ // We don't know if input was preprocessed. Assume not.
+ bool PP = false;
- if (Buffer.back() != '\n')
- ++NumLines;
+ return InputKind(Lang, Fmt, PP);
}
#ifndef NDEBUG
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
index b984c2e..534c758 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile,
ASTDeserializationListener *deserialListener = nullptr) {
Preprocessor &PP = CI.getPreprocessor();
std::unique_ptr<ASTReader> Reader;
- Reader.reset(new ASTReader(PP, CI.getASTContext(),
+ Reader.reset(new ASTReader(PP, &CI.getASTContext(),
CI.getPCHContainerReader(),
/*Extensions=*/{ },
/*isysroot=*/"", /*DisableValidation=*/true));
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
index afcaa6e..bb6a665 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
@@ -11,8 +11,10 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
@@ -55,12 +57,15 @@ using namespace clang;
CompilerInstance::CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool BuildingModule)
- : ModuleLoader(BuildingModule), Invocation(new CompilerInvocation()),
- ModuleManager(nullptr),
- ThePCHContainerOperations(std::move(PCHContainerOps)),
- BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
- ModuleBuildFailed(false) {}
+ MemoryBufferCache *SharedPCMCache)
+ : ModuleLoader(/* BuildingModule = */ SharedPCMCache),
+ Invocation(new CompilerInvocation()),
+ PCMCache(SharedPCMCache ? SharedPCMCache : new MemoryBufferCache),
+ ThePCHContainerOperations(std::move(PCHContainerOps)) {
+ // Don't allow this to invalidate buffers in use by others.
+ if (SharedPCMCache)
+ getPCMCache().finalizeCurrentBuffers();
+}
CompilerInstance::~CompilerInstance() {
assert(OutputFiles.empty() && "Still output files in flight?");
@@ -131,6 +136,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
return ModuleManager;
}
void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) {
+ assert(PCMCache.get() == &Reader->getModuleManager().getPCMCache() &&
+ "Expected ASTReader to use the same PCM cache");
ModuleManager = std::move(Reader);
}
@@ -373,7 +380,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
getDiagnostics(), getLangOpts(), &getTarget());
PP = std::make_shared<Preprocessor>(
Invocation->getPreprocessorOptsPtr(), getDiagnostics(), getLangOpts(),
- getSourceManager(), *HeaderInfo, *this, PTHMgr,
+ getSourceManager(), getPCMCache(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true, TUKind);
PP->Initialize(getTarget(), getAuxTarget());
@@ -491,6 +498,8 @@ void CompilerInstance::createPCHExternalASTSource(
AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(),
getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
+ TheDependencyFileGenerator.get(),
+ DependencyCollectors,
DeserializationListener,
OwnDeserializationListener, Preamble,
getFrontendOpts().UseGlobalModuleIndex);
@@ -501,12 +510,14 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex) {
HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader(
- PP, Context, PCHContainerRdr, Extensions,
+ PP, &Context, PCHContainerRdr, Extensions,
Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation,
AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false,
HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex));
@@ -518,6 +529,12 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener),
/*TakeOwnership=*/OwnDeserializationListener);
+
+ if (DependencyFile)
+ DependencyFile->AttachToASTReader(*Reader);
+ for (auto &Listener : DependencyCollectors)
+ Listener->attachToASTReader(*Reader);
+
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
: serialization::MK_PCH,
@@ -651,6 +668,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
llvm::sys::fs::remove(OF.Filename);
}
OutputFiles.clear();
+ if (DeleteBuiltModules) {
+ for (auto &Module : BuiltModules)
+ llvm::sys::fs::remove(Module.second);
+ BuiltModules.clear();
+ }
NonSeekStream.reset();
}
@@ -803,8 +825,11 @@ bool CompilerInstance::InitializeSourceManager(
const FrontendInputFile &Input, DiagnosticsEngine &Diags,
FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS,
DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) {
- SrcMgr::CharacteristicKind
- Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+ SrcMgr::CharacteristicKind Kind =
+ Input.getKind().getFormat() == InputKind::ModuleMap
+ ? Input.isSystem() ? SrcMgr::C_System_ModuleMap
+ : SrcMgr::C_User_ModuleMap
+ : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
if (Input.isBuffer()) {
SourceMgr.setMainFileID(SourceMgr.createFileID(
@@ -842,7 +867,8 @@ bool CompilerInstance::InitializeSourceManager(
/*SearchPath=*/nullptr,
/*RelativePath=*/nullptr,
/*RequestingModule=*/nullptr,
- /*SuggestedModule=*/nullptr, /*SkipCache=*/true);
+ /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr,
+ /*SkipCache=*/true);
// Also add the header to /showIncludes output.
if (File)
DepOpts.ShowIncludesPretendHeader = File->getName();
@@ -910,8 +936,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (!hasTarget())
return false;
- // Create TargetInfo for the other side of CUDA compilation.
- if (getLangOpts().CUDA && !getFrontendOpts().AuxTriple.empty()) {
+ // Create TargetInfo for the other side of CUDA and OpenMP compilation.
+ if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) &&
+ !getFrontendOpts().AuxTriple.empty()) {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = getFrontendOpts().AuxTriple;
TO->HostTriple = getTarget().getTriple().str();
@@ -999,26 +1026,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
/// \brief Determine the appropriate source input kind based on language
/// options.
-static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
+static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) {
if (LangOpts.OpenCL)
- return IK_OpenCL;
+ return InputKind::OpenCL;
if (LangOpts.CUDA)
- return IK_CUDA;
+ return InputKind::CUDA;
if (LangOpts.ObjC1)
- return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC;
- return LangOpts.CPlusPlus? IK_CXX : IK_C;
+ return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC;
+ return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C;
}
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance. Returns true if the module
/// was built without errors.
-static bool compileModuleImpl(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
- ModuleMap &ModMap
- = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-
+static bool
+compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
+ StringRef ModuleName, FrontendInputFile Input,
+ StringRef OriginalModuleMapFile, StringRef ModuleFileName,
+ llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
+ [](CompilerInstance &) {},
+ llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
+ [](CompilerInstance &) {}) {
// Construct a compiler invocation for creating this module.
auto Invocation =
std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1032,7 +1060,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
// Remove any macro definitions that are explicitly ignored by the module.
// They aren't supposed to affect how the module is built anyway.
- const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
+ HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
PPOpts.Macros.erase(
std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(),
[&HSOpts](const std::pair<std::string, bool> &def) {
@@ -1043,7 +1071,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
PPOpts.Macros.end());
// Note the name of the module we're building.
- Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
+ Invocation->getLangOpts()->CurrentModule = ModuleName;
// Make sure that the failed-module structure has been allocated in
// the importing instance, and propagate the pointer to the newly-created
@@ -1063,8 +1091,10 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
FrontendOpts.DisableFree = false;
FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.BuildingImplicitModule = true;
- FrontendOpts.Inputs.clear();
- InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
+ FrontendOpts.OriginalModuleMap = OriginalModuleMapFile;
+ // Force implicitly-built modules to hash the content of the module file.
+ HSOpts.ModulesHashContent = true;
+ FrontendOpts.Inputs = {Input};
// Don't free the remapped file buffers; they are owned by our caller.
PPOpts.RetainRemappedFileBuffers = true;
@@ -1074,9 +1104,11 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
Invocation->getModuleHash() && "Module hash mismatch!");
// Construct a compiler instance that will be used to actually create the
- // module.
+ // module. Since we're sharing a PCMCache,
+ // CompilerInstance::CompilerInstance is responsible for finalizing the
+ // buffers to prevent use-after-frees.
CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(),
- /*BuildingModule=*/true);
+ &ImportingInstance.getPreprocessor().getPCMCache());
auto &Inv = *Invocation;
Instance.setInvocation(std::move(Invocation));
@@ -1093,7 +1125,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
SourceManager &SourceMgr = Instance.getSourceManager();
SourceMgr.setModuleBuildStack(
ImportingInstance.getSourceManager().getModuleBuildStack());
- SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ SourceMgr.pushModuleBuildStack(ModuleName,
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
// If we're collecting module dependencies, we need to share a collector
@@ -1102,47 +1134,28 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
Inv.getDependencyOutputOpts() = DependencyOutputOptions();
- // Get or create the module map that we'll use to build this module.
- std::string InferredModuleMapContent;
- if (const FileEntry *ModuleMapFile =
- ModMap.getContainingModuleMapFile(Module)) {
- // Use the module map where this module resides.
- FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK);
- } else {
- SmallString<128> FakeModuleMapFile(Module->Directory->getName());
- llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
- FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK);
-
- llvm::raw_string_ostream OS(InferredModuleMapContent);
- Module->print(OS);
- OS.flush();
-
- std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
- llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- ModuleMapFile = Instance.getFileManager().getVirtualFile(
- FakeModuleMapFile, InferredModuleMapContent.size(), 0);
- SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
- }
-
- // Construct a module-generating action. Passing through the module map is
- // safe because the FileManager is shared between the compiler instances.
- GenerateModuleFromModuleMapAction CreateModuleAction(
- ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
-
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build)
- << Module->Name << ModuleFileName;
+ << ModuleName << ModuleFileName;
+
+ PreBuildStep(Instance);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
llvm::CrashRecoveryContext CRC;
- CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
- ThreadStackSize);
+ CRC.RunSafelyOnThread(
+ [&]() {
+ GenerateModuleFromModuleMapAction Action;
+ Instance.ExecuteAction(Action);
+ },
+ ThreadStackSize);
+
+ PostBuildStep(Instance);
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build_done)
- << Module->Name;
+ << ModuleName;
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
@@ -1150,13 +1163,66 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
// doesn't make sense for all clients, so clean this up manually.
Instance.clearOutputFiles(/*EraseFiles=*/true);
+ return !Instance.getDiagnostics().hasErrorOccurred();
+}
+
+/// \brief Compile a module file for the given module, using the options
+/// provided by the importing compiler instance. Returns true if the module
+/// was built without errors.
+static bool compileModuleImpl(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
+ InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
+ InputKind::ModuleMap);
+
+ // Get or create the module map that we'll use to build this module.
+ ModuleMap &ModMap
+ = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool Result;
+ if (const FileEntry *ModuleMapFile =
+ ModMap.getContainingModuleMapFile(Module)) {
+ // Use the module map where this module resides.
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName);
+ } else {
+ // FIXME: We only need to fake up an input file here as a way of
+ // transporting the module's directory to the module map parser. We should
+ // be able to do that more directly, and parse from a memory buffer without
+ // inventing this file.
+ SmallString<128> FakeModuleMapFile(Module->Directory->getName());
+ llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
+
+ std::string InferredModuleMapContent;
+ llvm::raw_string_ostream OS(InferredModuleMapContent);
+ Module->print(OS);
+ OS.flush();
+
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName,
+ [&](CompilerInstance &Instance) {
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ FakeModuleMapFile, InferredModuleMapContent.size(), 0);
+ Instance.getSourceManager().overrideFileContents(
+ ModuleMapFile, std::move(ModuleMapBuffer));
+ });
+ }
+
// We've rebuilt a module. If we're allowed to generate or update the global
// module index, record that fact in the importing compiler instance.
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
ImportingInstance.setBuildGlobalModuleIndex(true);
}
- return !Instance.getDiagnostics().hasErrorOccurred();
+ return Result;
}
static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
@@ -1180,10 +1246,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
case llvm::LockFileManager::LFS_Error:
- Diags.Report(ModuleNameLoc, diag::err_module_lock_failure)
+ // PCMCache takes care of correctness and locks are only necessary for
+ // performance. Fallback to building the module in case of any lock
+ // related errors.
+ Diags.Report(ModuleNameLoc, diag::remark_module_lock_failure)
<< Module->Name << Locked.getErrorMessage();
- return false;
-
+ // Clear out any potential leftover.
+ Locked.unsafeRemoveLockFile();
+ // FALLTHROUGH
case llvm::LockFileManager::LFS_Owned:
// We're responsible for building the module ourselves.
if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module,
@@ -1203,11 +1273,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
case llvm::LockFileManager::Res_OwnerDied:
continue; // try again to get the lock.
case llvm::LockFileManager::Res_Timeout:
- Diags.Report(ModuleNameLoc, diag::err_module_lock_timeout)
+ // Since PCMCache takes care of correctness, we try waiting for another
+ // process to complete the build so clang does not do it done twice. If
+ // case of timeout, build it ourselves.
+ Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout)
<< Module->Name;
// Clear the lock file so that future invokations can make progress.
Locked.unsafeRemoveLockFile();
- return false;
+ continue;
}
break;
}
@@ -1400,7 +1473,7 @@ void CompilerInstance::createModuleManager() {
"Reading modules",
*FrontendTimerGroup);
ModuleManager = new ASTReader(
- getPreprocessor(), getASTContext(), getPCHContainerReader(),
+ getPreprocessor(), &getASTContext(), getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation,
/*AllowASTWithCompilerErrors=*/false,
@@ -1555,24 +1628,36 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
PP->getHeaderSearchInfo().getHeaderSearchOpts();
std::string ModuleFileName;
- bool LoadFromPrebuiltModulePath = false;
- // We try to load the module from the prebuilt module paths. If not
- // successful, we then try to find it in the module cache.
- if (!HSOpts.PrebuiltModulePaths.empty()) {
- // Load the module from the prebuilt module path.
+ enum ModuleSource {
+ ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma
+ } Source = ModuleNotFound;
+
+ // Check to see if the module has been built as part of this compilation
+ // via a module build pragma.
+ auto BuiltModuleIt = BuiltModules.find(ModuleName);
+ if (BuiltModuleIt != BuiltModules.end()) {
+ ModuleFileName = BuiltModuleIt->second;
+ Source = ModuleBuildPragma;
+ }
+
+ // Try to load the module from the prebuilt module path.
+ if (Source == ModuleNotFound && !HSOpts.PrebuiltModulePaths.empty()) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(
ModuleName, "", /*UsePrebuiltPath*/ true);
if (!ModuleFileName.empty())
- LoadFromPrebuiltModulePath = true;
+ Source = PrebuiltModulePath;
}
- if (!LoadFromPrebuiltModulePath && Module) {
- // Load the module from the module cache.
+
+ // Try to load the module from the module cache.
+ if (Source == ModuleNotFound && Module) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- } else if (!LoadFromPrebuiltModulePath) {
+ Source = ModuleCache;
+ }
+
+ if (Source == ModuleNotFound) {
// We can't find a module, error out here.
getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
ModuleBuildFailed = true;
return ModuleLoadResult();
}
@@ -1600,20 +1685,20 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
*FrontendTimerGroup);
llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
- // Try to load the module file. If we are trying to load from the prebuilt
- // module path, we don't have the module map files and don't know how to
- // rebuild modules.
- unsigned ARRFlags = LoadFromPrebuiltModulePath ?
- ASTReader::ARR_ConfigurationMismatch :
- ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ // Try to load the module file. If we are not trying to load from the
+ // module cache, we don't know how to rebuild modules.
+ unsigned ARRFlags = Source == ModuleCache ?
+ ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing :
+ ASTReader::ARR_ConfigurationMismatch;
switch (ModuleManager->ReadAST(ModuleFileName,
- LoadFromPrebuiltModulePath ?
- serialization::MK_PrebuiltModule :
- serialization::MK_ImplicitModule,
- ImportLoc,
- ARRFlags)) {
+ Source == PrebuiltModulePath
+ ? serialization::MK_PrebuiltModule
+ : Source == ModuleBuildPragma
+ ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success: {
- if (LoadFromPrebuiltModulePath && !Module) {
+ if (Source != ModuleCache && !Module) {
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
if (!Module || !Module->getASTFile() ||
FileMgr->getFile(ModuleFileName) != Module->getASTFile()) {
@@ -1631,10 +1716,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::OutOfDate:
case ASTReader::Missing: {
- if (LoadFromPrebuiltModulePath) {
- // We can't rebuild the module without a module map. Since ReadAST
- // already produces diagnostics for these two cases, we simply
- // error out here.
+ if (Source != ModuleCache) {
+ // We don't know the desired configuration for this module and don't
+ // necessarily even have a module map. Since ReadAST already produces
+ // diagnostics for these two cases, we simply error out here.
ModuleBuildFailed = true;
KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
@@ -1691,11 +1776,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
case ASTReader::ConfigurationMismatch:
- if (LoadFromPrebuiltModulePath)
+ if (Source == PrebuiltModulePath)
+ // FIXME: We shouldn't be setting HadFatalFailure below if we only
+ // produce a warning here!
getDiagnostics().Report(SourceLocation(),
diag::warn_module_config_mismatch)
<< ModuleFileName;
// Fall through to error out.
+ LLVM_FALLTHROUGH;
case ASTReader::VersionMismatch:
case ASTReader::HadErrors:
ModuleLoader::HadFatalFailure = true;
@@ -1719,7 +1807,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// If we never found the module, fail.
if (!Module)
return ModuleLoadResult();
-
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
if (Path.size() > 1) {
@@ -1792,20 +1880,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Check whether this module is available.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first
- << SourceRange(Path.front().second, Path.back().second);
- }
+ if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(),
+ getDiagnostics(), Module)) {
+ getDiagnostics().Report(ImportLoc, diag::note_module_import_here)
+ << SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
return ModuleLoadResult();
@@ -1826,6 +1904,59 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return LastModuleImportResult;
}
+void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
+ StringRef ModuleName,
+ StringRef Source) {
+ // Avoid creating filenames with special characters.
+ SmallString<128> CleanModuleName(ModuleName);
+ for (auto &C : CleanModuleName)
+ if (!isAlphanumeric(C))
+ C = '_';
+
+ // FIXME: Using a randomized filename here means that our intermediate .pcm
+ // output is nondeterministic (as .pcm files refer to each other by name).
+ // Can this affect the output in any way?
+ SmallString<128> ModuleFileName;
+ if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
+ CleanModuleName, "pcm", ModuleFileName)) {
+ getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
+ << ModuleFileName << EC.message();
+ return;
+ }
+ std::string ModuleMapFileName = (CleanModuleName + ".map").str();
+
+ FrontendInputFile Input(
+ ModuleMapFileName,
+ InputKind(getLanguageFromOptions(*Invocation->getLangOpts()),
+ InputKind::ModuleMap, /*Preprocessed*/true));
+
+ std::string NullTerminatedSource(Source.str());
+
+ auto PreBuildStep = [&](CompilerInstance &Other) {
+ // Create a virtual file containing our desired source.
+ // FIXME: We shouldn't need to do this.
+ const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile(
+ ModuleMapFileName, NullTerminatedSource.size(), 0);
+ Other.getSourceManager().overrideFileContents(
+ ModuleMapFile,
+ llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str()));
+
+ Other.BuiltModules = std::move(BuiltModules);
+ Other.DeleteBuiltModules = false;
+ };
+
+ auto PostBuildStep = [this](CompilerInstance &Other) {
+ BuiltModules = std::move(Other.BuiltModules);
+ };
+
+ // Build the module, inheriting any modules that we've built locally.
+ if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
+ ModuleFileName, PreBuildStep, PostBuildStep)) {
+ BuiltModules[ModuleName] = ModuleFileName.str();
+ llvm::sys::RemoveFileOnSignal(ModuleFileName);
+ }
+}
+
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
index 36f6b0a..0d0869c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -81,7 +81,7 @@ using namespace llvm::opt;
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
unsigned DefaultOpt = 0;
- if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
+ if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = 2;
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -330,6 +330,17 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) {
return "default";
}
+static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) {
+ if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) {
+ StringRef Value = A->getValue();
+ if (Value == "static" || Value == "pic" || Value == "ropi" ||
+ Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic")
+ return Value;
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value;
+ }
+ return "pic";
+}
+
/// \brief Create a new Regex instance out of the string value in \p RpassArg.
/// It returns a pointer to the newly generated Regex instance.
static std::shared_ptr<llvm::Regex>
@@ -465,6 +476,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager,
/* Default */ false);
+ Opts.DebugPassManager =
+ Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager,
+ /* Default */ false);
+
if (Arg *A = Args.getLastArg(OPT_fveclib)) {
StringRef Name = A->getValue();
if (Name == "Accelerate")
@@ -505,8 +520,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags);
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.EmitCodeView = Args.hasArg(OPT_gcodeview);
+ Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
+ Opts.EnableSplitDwarf = Args.hasArg(OPT_enable_split_dwarf);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
@@ -521,6 +538,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
+ Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
@@ -544,6 +562,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as);
Opts.Autolink = !Args.hasArg(OPT_fno_autolink);
Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ);
+ Opts.DebugInfoForProfiling = Args.hasFlag(
+ OPT_fdebug_info_for_profiling, OPT_fno_debug_info_for_profiling, false);
setPGOInstrumentor(Opts, Args, Diags);
Opts.InstrProfileOutput =
@@ -553,6 +573,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (!Opts.ProfileInstrumentUsePath.empty())
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
+ if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
+
+ StringRef Ver = A->getValue();
+ std::pair<StringRef, StringRef> VerParts = Ver.split('.');
+ unsigned Major, Minor = 0;
+
+ // Check the version number is valid: either 3.x (0 <= x <= 9) or
+ // y or y.0 (4 <= y <= current version).
+ if (!VerParts.first.startswith("0") &&
+ !VerParts.first.getAsInteger(10, Major) &&
+ 3 <= Major && Major <= CLANG_VERSION_MAJOR &&
+ (Major == 3 ? VerParts.second.size() == 1 &&
+ !VerParts.second.getAsInteger(10, Minor)
+ : VerParts.first.size() == Ver.size() ||
+ VerParts.second == "0")) {
+ // Got a valid version number.
+ if (Major == 3 && Minor <= 8)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8);
+ else if (Major <= 4)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
+ } else if (Ver != "latest") {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+
Opts.CoverageMapping =
Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
@@ -570,7 +617,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
- Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
+ Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) ||
Args.hasArg(OPT_cl_finite_math_only) ||
@@ -580,7 +629,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_finite_math_only) ||
Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoSignedZeros = (Args.hasArg(OPT_fno_signed_zeros) ||
- Args.hasArg(OPT_cl_no_signed_zeros));
+ Args.hasArg(OPT_cl_no_signed_zeros) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero);
Opts.CorrectlyRoundedDivSqrt =
Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt);
@@ -608,7 +659,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
- Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.RelocationModel = getRelocModel(Args, Diags);
Opts.ThreadModel = Args.getLastArgValue(OPT_mthread_model, "posix");
if (Opts.ThreadModel != "posix" && Opts.ThreadModel != "single")
Diags.Report(diag::err_drv_invalid_value)
@@ -629,18 +680,25 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables);
Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
- const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ);
- Opts.EmitSummaryIndex = A && A->containsValue("thin");
+ Opts.EmitSummaryIndex = false;
+ if (Arg *A = Args.getLastArg(OPT_flto_EQ)) {
+ StringRef S = A->getValue();
+ if (S == "thin")
+ Opts.EmitSummaryIndex = true;
+ else if (S != "full")
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+ Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false);
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
- if (IK != IK_LLVM_IR)
+ if (IK.getLanguage() != InputKind::LLVM_IR)
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-x ir";
Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ);
}
+ Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ);
Opts.MSVolatile = Args.hasArg(OPT_fms_volatile);
- Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive);
Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops);
Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp);
@@ -709,21 +767,43 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument);
Opts.XRayInstructionThreshold =
- getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags);
+ getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.CallFEntry = Args.hasArg(OPT_mfentry);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
- Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU);
+ } else {
+ auto DCT = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ Opts.setCompressDebugSections(DCT);
+ }
+ }
+
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) {
- unsigned LinkFlags = llvm::Linker::Flags::None;
- if (A->getOption().matches(OPT_mlink_cuda_bitcode))
- LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded |
- llvm::Linker::Flags::InternalizeLinkedSymbols;
- Opts.LinkBitcodeFiles.push_back(std::make_pair(LinkFlags, A->getValue()));
+ CodeGenOptions::BitcodeFileToLink F;
+ F.Filename = A->getValue();
+ if (A->getOption().matches(OPT_mlink_cuda_bitcode)) {
+ F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded;
+ // When linking CUDA bitcode, propagate function attributes so that
+ // e.g. libdevice gets fast-math attrs if we're building with fast-math.
+ F.PropagateAttrs = true;
+ F.Internalize = true;
+ }
+ Opts.LinkBitcodeFiles.push_back(F);
}
Opts.SanitizeCoverageType =
getLastArgIntValue(Args, OPT_fsanitize_coverage_type, 0, Diags);
@@ -738,6 +818,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeCoverageTracePC = Args.hasArg(OPT_fsanitize_coverage_trace_pc);
Opts.SanitizeCoverageTracePCGuard =
Args.hasArg(OPT_fsanitize_coverage_trace_pc_guard);
+ Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune);
+ Opts.SanitizeCoverageInline8bitCounters =
+ Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters);
Opts.SanitizeMemoryTrackOrigins =
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeMemoryUseAfterDtor =
@@ -749,6 +832,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressUseAfterScope =
A->getOption().getID() == OPT_fsanitize_address_use_after_scope;
}
+ Opts.SanitizeAddressGlobalsDeadStripping =
+ Args.hasArg(OPT_fsanitize_address_globals_dead_stripping);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -801,18 +886,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
- if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue();
- if (Val == "fast")
- Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
- else if (Val == "on")
- Opts.setFPContractMode(CodeGenOptions::FPC_On);
- else if (Val == "off")
- Opts.setFPContractMode(CodeGenOptions::FPC_Off);
- else
- Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
- }
-
if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
StringRef Val = A->getValue();
if (Val == "ieee")
@@ -862,14 +935,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DiagnosticsWithHotness =
Args.hasArg(options::OPT_fdiagnostics_show_hotness);
- if (Opts.DiagnosticsWithHotness &&
- Opts.getProfileUse() == CodeGenOptions::ProfileNone)
- Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo);
+ bool UsingSampleProfile = !Opts.SampleProfileFile.empty();
+ bool UsingProfile = UsingSampleProfile ||
+ (Opts.getProfileUse() != CodeGenOptions::ProfileNone);
+
+ if (Opts.DiagnosticsWithHotness && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-show-hotness";
+
+ Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value(
+ Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0);
+ if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-hotness-threshold=";
// If the user requested to use a sample profile for PGO, then the
// backend will need to track source location information so the profile
// can be incorporated into the IR.
- if (!Opts.SampleProfileFile.empty())
+ if (UsingSampleProfile)
NeedLocTracking = true;
// If the user requested a flag that requires source locations available in
@@ -1068,6 +1151,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.SpellCheckingLimit = getLastArgIntValue(
Args, OPT_fspell_checking_limit,
DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
+ Opts.SnippetLineLimit = getLastArgIntValue(
+ Args, OPT_fcaret_diagnostics_max_lines,
+ DiagnosticOptions::DefaultSnippetLineLimit, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -1123,6 +1209,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_ast_list:
Opts.ProgramAction = frontend::ASTDeclList; break;
case OPT_ast_dump:
+ case OPT_ast_dump_all:
case OPT_ast_dump_lookups:
Opts.ProgramAction = frontend::ASTDump; break;
case OPT_ast_print:
@@ -1241,6 +1328,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump);
+ Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
@@ -1329,44 +1417,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
<< "ARC migration" << "ObjC migration";
}
- InputKind DashX = IK_None;
+ InputKind DashX(InputKind::Unknown);
if (const Arg *A = Args.getLastArg(OPT_x)) {
- DashX = llvm::StringSwitch<InputKind>(A->getValue())
- .Case("c", IK_C)
- .Case("cl", IK_OpenCL)
- .Case("cuda", IK_CUDA)
- .Case("c++", IK_CXX)
- .Case("c++-module", IK_CXX)
- .Case("objective-c", IK_ObjC)
- .Case("objective-c++", IK_ObjCXX)
- .Case("cpp-output", IK_PreprocessedC)
- .Case("assembler-with-cpp", IK_Asm)
- .Case("c++-cpp-output", IK_PreprocessedCXX)
- .Case("c++-module-cpp-output", IK_PreprocessedCXX)
- .Case("cuda-cpp-output", IK_PreprocessedCuda)
- .Case("objective-c-cpp-output", IK_PreprocessedObjC)
- .Case("objc-cpp-output", IK_PreprocessedObjC)
- .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
- .Case("objc++-cpp-output", IK_PreprocessedObjCXX)
- .Case("c-header", IK_C)
- .Case("cl-header", IK_OpenCL)
- .Case("objective-c-header", IK_ObjC)
- .Case("c++-header", IK_CXX)
- .Case("objective-c++-header", IK_ObjCXX)
- .Cases("ast", "pcm", IK_AST)
- .Case("ir", IK_LLVM_IR)
- .Case("renderscript", IK_RenderScript)
- .Default(IK_None);
- if (DashX == IK_None)
+ StringRef XValue = A->getValue();
+
+ // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'.
+ // FIXME: Supporting '<lang>-header-cpp-output' would be useful.
+ bool Preprocessed = XValue.consume_back("-cpp-output");
+ bool ModuleMap = XValue.consume_back("-module-map");
+ IsHeaderFile =
+ !Preprocessed && !ModuleMap && XValue.consume_back("-header");
+
+ // Principal languages.
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("c", InputKind::C)
+ .Case("cl", InputKind::OpenCL)
+ .Case("cuda", InputKind::CUDA)
+ .Case("c++", InputKind::CXX)
+ .Case("objective-c", InputKind::ObjC)
+ .Case("objective-c++", InputKind::ObjCXX)
+ .Case("renderscript", InputKind::RenderScript)
+ .Default(InputKind::Unknown);
+
+ // "objc[++]-cpp-output" is an acceptable synonym for
+ // "objective-c[++]-cpp-output".
+ if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("objc", InputKind::ObjC)
+ .Case("objc++", InputKind::ObjCXX)
+ .Default(InputKind::Unknown);
+
+ // Some special cases cannot be combined with suffixes.
+ if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("cpp-output", InputKind(InputKind::C).getPreprocessed())
+ .Case("assembler-with-cpp", InputKind::Asm)
+ .Cases("ast", "pcm",
+ InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("ir", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
+
+ if (DashX.isUnknown())
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
- IsHeaderFile = llvm::StringSwitch<bool>(A->getValue())
- .Case("c-header", true)
- .Case("cl-header", true)
- .Case("objective-c-header", true)
- .Case("c++-header", true)
- .Case("objective-c++-header", true)
- .Default(false);
+
+ if (Preprocessed)
+ DashX = DashX.getPreprocessed();
+ if (ModuleMap)
+ DashX = DashX.withFormat(InputKind::ModuleMap);
}
// '-' is the default input if none is given.
@@ -1376,13 +1474,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Inputs.push_back("-");
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
InputKind IK = DashX;
- if (IK == IK_None) {
+ if (IK.isUnknown()) {
IK = FrontendOptions::getInputKindForExtension(
StringRef(Inputs[i]).rsplit('.').second);
+ // FIXME: Warn on this?
+ if (IK.isUnknown())
+ IK = InputKind::C;
// FIXME: Remove this hack.
if (i == 0)
DashX = IK;
}
+
+ // The -emit-module action implicitly takes a module map.
+ if (Opts.ProgramAction == frontend::GenerateModule &&
+ IK.getFormat() == InputKind::Source)
+ IK = IK.withFormat(InputKind::ModuleMap);
+
Opts.Inputs.emplace_back(std::move(Inputs[i]), IK);
}
@@ -1407,7 +1514,8 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
return P.str();
}
-static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
+static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
+ const std::string &WorkingDir) {
using namespace options;
Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
@@ -1417,11 +1525,23 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
- Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
+
+ // Canonicalize -fmodules-cache-path before storing it.
+ SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path));
+ if (!(P.empty() || llvm::sys::path::is_absolute(P))) {
+ if (WorkingDir.empty())
+ llvm::sys::fs::make_absolute(P);
+ else
+ llvm::sys::fs::make_absolute(WorkingDir, P);
+ }
+ llvm::sys::path::remove_dots(P);
+ Opts.ModuleCachePath = P.str();
+
Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path);
for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path))
Opts.AddPrebuiltModulePath(A->getValue());
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
+ Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content);
Opts.ModulesValidateDiagnosticOptions =
!Args.hasArg(OPT_fmodules_disable_diagnostic_validation);
Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps);
@@ -1495,6 +1615,9 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
!A->getOption().matches(OPT_iwithsysroot));
for (const Arg *A : Args.filtered(OPT_iframework))
Opts.AddPath(A->getValue(), frontend::System, true, true);
+ for (const Arg *A : Args.filtered(OPT_iframeworkwithsysroot))
+ Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true,
+ /*IgnoreSysRoot=*/false);
// Add the paths for the various language specific isystem flags.
for (const Arg *A : Args.filtered(OPT_c_isystem))
@@ -1525,13 +1648,6 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.AddVFSOverlayFile(A->getValue());
}
-static bool isOpenCL(LangStandard::Kind LangStd) {
- return LangStd == LangStandard::lang_opencl ||
- LangStd == LangStandard::lang_opencl11 ||
- LangStd == LangStandard::lang_opencl12 ||
- LangStd == LangStandard::lang_opencl20;
-}
-
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
const llvm::Triple &T,
PreprocessorOptions &PPOpts,
@@ -1539,49 +1655,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
- if (IK == IK_Asm) {
+ //
+ // FIXME: Perhaps a better model would be for a single source file to have
+ // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std)
+ // simultaneously active?
+ if (IK.getLanguage() == InputKind::Asm) {
Opts.AsmPreprocessor = 1;
- } else if (IK == IK_ObjC ||
- IK == IK_ObjCXX ||
- IK == IK_PreprocessedObjC ||
- IK == IK_PreprocessedObjCXX) {
+ } else if (IK.isObjectiveC()) {
Opts.ObjC1 = Opts.ObjC2 = 1;
}
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
- switch (IK) {
- case IK_None:
- case IK_AST:
- case IK_LLVM_IR:
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
llvm_unreachable("Invalid input kind!");
- case IK_OpenCL:
- LangStd = LangStandard::lang_opencl;
+ case InputKind::OpenCL:
+ LangStd = LangStandard::lang_opencl10;
break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
+ case InputKind::CUDA:
LangStd = LangStandard::lang_cuda;
break;
- case IK_Asm:
- case IK_C:
- case IK_PreprocessedC:
+ case InputKind::Asm:
+ case InputKind::C:
// The PS4 uses C99 as the default C standard.
if (T.isPS4())
LangStd = LangStandard::lang_gnu99;
else
LangStd = LangStandard::lang_gnu11;
break;
- case IK_ObjC:
- case IK_PreprocessedObjC:
+ case InputKind::ObjC:
LangStd = LangStandard::lang_gnu11;
break;
- case IK_CXX:
- case IK_PreprocessedCXX:
- case IK_ObjCXX:
- case IK_PreprocessedObjCXX:
- LangStd = LangStandard::lang_gnucxx98;
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
+ // The PS4 uses C++11 as the default C++ standard.
+ if (T.isPS4())
+ LangStd = LangStandard::lang_gnucxx11;
+ else
+ LangStd = LangStandard::lang_gnucxx98;
break;
- case IK_RenderScript:
+ case InputKind::RenderScript:
LangStd = LangStandard::lang_c99;
break;
}
@@ -1595,15 +1710,16 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus1z = Std.isCPlusPlus1z();
+ Opts.CPlusPlus2a = Std.isCPlusPlus2a();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
- Opts.GNUInline = Std.isC89();
+ Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus;
Opts.HexFloats = Std.hasHexFloats();
Opts.ImplicitInt = Std.hasImplicitInt();
// Set OpenCL Version.
- Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL;
- if (LangStd == LangStandard::lang_opencl)
+ Opts.OpenCL = Std.isOpenCL();
+ if (LangStd == LangStandard::lang_opencl10)
Opts.OpenCLVersion = 100;
else if (LangStd == LangStandard::lang_opencl11)
Opts.OpenCLVersion = 110;
@@ -1616,9 +1732,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
if (Opts.OpenCL) {
Opts.AltiVec = 0;
Opts.ZVector = 0;
- Opts.CXXOperatorNames = 1;
Opts.LaxVectorConversions = 0;
- Opts.DefaultFPContract = 1;
+ Opts.setDefaultFPContractMode(LangOptions::FPC_On);
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
// Include default header file for OpenCL.
@@ -1627,10 +1742,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
}
- Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
- LangStd == LangStandard::lang_cuda;
+ Opts.CUDA = IK.getLanguage() == InputKind::CUDA;
+ if (Opts.CUDA)
+ // Set default FP_CONTRACT to FAST.
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
- Opts.RenderScript = IK == IK_RenderScript;
+ Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript;
if (Opts.RenderScript) {
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
@@ -1671,6 +1788,70 @@ static Visibility parseVisibility(Arg *arg, ArgList &args,
return DefaultVisibility;
}
+/// Check if input file kind and language standard are compatible.
+static bool IsInputCompatibleWithStandard(InputKind IK,
+ const LangStandard &S) {
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
+ llvm_unreachable("should not parse language flags for this input");
+
+ case InputKind::C:
+ case InputKind::ObjC:
+ case InputKind::RenderScript:
+ return S.getLanguage() == InputKind::C;
+
+ case InputKind::OpenCL:
+ return S.getLanguage() == InputKind::OpenCL;
+
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
+ return S.getLanguage() == InputKind::CXX;
+
+ case InputKind::CUDA:
+ // FIXME: What -std= values should be permitted for CUDA compilations?
+ return S.getLanguage() == InputKind::CUDA ||
+ S.getLanguage() == InputKind::CXX;
+
+ case InputKind::Asm:
+ // Accept (and ignore) all -std= values.
+ // FIXME: The -std= value is not ignored; it affects the tokenization
+ // and preprocessing rules if we're preprocessing this asm input.
+ return true;
+ }
+
+ llvm_unreachable("unexpected input language");
+}
+
+/// Get language name for given input kind.
+static const StringRef GetInputKindName(InputKind IK) {
+ switch (IK.getLanguage()) {
+ case InputKind::C:
+ return "C";
+ case InputKind::ObjC:
+ return "Objective-C";
+ case InputKind::CXX:
+ return "C++";
+ case InputKind::ObjCXX:
+ return "Objective-C++";
+ case InputKind::OpenCL:
+ return "OpenCL";
+ case InputKind::CUDA:
+ return "CUDA";
+ case InputKind::RenderScript:
+ return "RenderScript";
+
+ case InputKind::Asm:
+ return "Asm";
+ case InputKind::LLVM_IR:
+ return "LLVM IR";
+
+ case InputKind::Unknown:
+ break;
+ }
+ llvm_unreachable("unknown input language");
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
const TargetOptions &TargetOpts,
PreprocessorOptions &PPOpts,
@@ -1679,49 +1860,45 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, LangStandard::lang_##id)
#define LANGSTANDARD_ALIAS(id, alias) \
.Case(alias, LangStandard::lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(LangStandard::lang_unspecified);
- if (LangStd == LangStandard::lang_unspecified)
+ if (LangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
- else {
+ // Report supported standards with short description.
+ for (unsigned KindValue = 0;
+ KindValue != LangStandard::lang_unspecified;
+ ++KindValue) {
+ const LangStandard &Std = LangStandard::getLangStandardForKind(
+ static_cast<LangStandard::Kind>(KindValue));
+ if (IsInputCompatibleWithStandard(IK, Std)) {
+ auto Diag = Diags.Report(diag::note_drv_use_standard);
+ Diag << Std.getName() << Std.getDescription();
+ unsigned NumAliases = 0;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) ++NumAliases;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
+ Diag << NumAliases;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) Diag << alias;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
+ }
+ }
+ } else {
// Valid standard, check to make sure language and standard are
// compatible.
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
- switch (IK) {
- case IK_C:
- case IK_ObjC:
- case IK_PreprocessedC:
- case IK_PreprocessedObjC:
- if (!(Std.isC89() || Std.isC99()))
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "C/ObjC";
- break;
- case IK_CXX:
- case IK_ObjCXX:
- case IK_PreprocessedCXX:
- case IK_PreprocessedObjCXX:
- if (!Std.isCPlusPlus())
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "C++/ObjC++";
- break;
- case IK_OpenCL:
- if (!isOpenCL(LangStd))
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "OpenCL";
- break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
- if (!Std.isCPlusPlus())
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "CUDA";
- break;
- default:
- break;
+ if (!IsInputCompatibleWithStandard(IK, Std)) {
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << GetInputKindName(IK);
}
}
}
@@ -1730,16 +1907,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// Override the -std option in this case.
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
LangStandard::Kind OpenCLLangStd
- = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
- .Cases("cl", "CL", LangStandard::lang_opencl)
- .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
- .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
- .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
- .Default(LangStandard::lang_unspecified);
+ = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
+ .Cases("cl", "CL", LangStandard::lang_opencl10)
+ .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
+ .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
+ .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
+ .Default(LangStandard::lang_unspecified);
if (OpenCLLangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue();
+ << A->getAsString(Args) << A->getValue();
}
else
LangStd = OpenCLLangStd;
@@ -1840,8 +2017,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fgnu89_inline)) {
if (Opts.CPlusPlus)
- Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fgnu89-inline"
- << "C++/ObjC++";
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << "-fgnu89-inline" << GetInputKindName(IK);
else
Opts.GNUInline = 1;
}
@@ -1858,9 +2035,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_constant_cfstrings))
Opts.NoConstantCFStrings = 1;
- if (Args.hasArg(OPT_faltivec))
- Opts.AltiVec = 1;
-
if (Args.hasArg(OPT_fzvector))
Opts.ZVector = 1;
@@ -1947,6 +2121,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
Opts.ModulesLocalVisibility =
Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS;
+ Opts.ModulesCodegen = Args.hasArg(OPT_fmodules_codegen);
+ Opts.ModulesDebugInfo = Args.hasArg(OPT_fmodules_debuginfo);
Opts.ModulesSearchAll = Opts.Modules &&
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
@@ -1967,6 +2143,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.AlignedAllocation =
Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation,
Opts.AlignedAllocation);
+ Opts.AlignedAllocationUnavailable =
+ Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable);
Opts.NewAlignOverride =
getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags);
if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) {
@@ -2045,12 +2223,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasFlag(OPT_fdeclspec, OPT_fno_declspec,
(Opts.MicrosoftExt || Opts.Borland || Opts.CUDA));
- // For now, we only support local submodule visibility in C++ (because we
- // heavily depend on the ODR for merging redefinitions).
- if (Opts.ModulesLocalVisibility && !Opts.CPlusPlus)
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << "-fmodules-local-submodule-visibility" << "C";
-
if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
switch (llvm::StringSwitch<unsigned>(A->getValue())
.Case("target", LangOptions::ASMM_Target)
@@ -2108,8 +2280,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
llvm::Triple T(TargetOpts.Triple);
llvm::Triple::ArchType Arch = T.getArch();
bool emitError = (DefaultCC == LangOptions::DCC_FastCall ||
- DefaultCC == LangOptions::DCC_StdCall) &&
- Arch != llvm::Triple::x86;
+ DefaultCC == LangOptions::DCC_StdCall) &&
+ Arch != llvm::Triple::x86;
emitError |= DefaultCC == LangOptions::DCC_VectorCall &&
!(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64);
if (emitError)
@@ -2214,6 +2386,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
+ if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+ StringRef Val = A->getValue();
+ if (Val == "fast")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
+ else if (Val == "on")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+ else if (Val == "off")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Off);
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ }
+
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -2236,11 +2420,66 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+
+ // -fxray-instrument
+ Opts.XRayInstrument =
+ Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false);
+
+ // -fxray-{always,never}-instrument= filenames.
+ Opts.XRayAlwaysInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_always_instrument);
+ Opts.XRayNeverInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_never_instrument);
+
+ // -fallow-editor-placeholders
+ Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
+}
+
+static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
+ switch (Action) {
+ case frontend::ASTDeclList:
+ case frontend::ASTDump:
+ case frontend::ASTPrint:
+ case frontend::ASTView:
+ case frontend::EmitAssembly:
+ case frontend::EmitBC:
+ case frontend::EmitHTML:
+ case frontend::EmitLLVM:
+ case frontend::EmitLLVMOnly:
+ case frontend::EmitCodeGenOnly:
+ case frontend::EmitObj:
+ case frontend::FixIt:
+ case frontend::GenerateModule:
+ case frontend::GenerateModuleInterface:
+ case frontend::GeneratePCH:
+ case frontend::GeneratePTH:
+ case frontend::ParseSyntaxOnly:
+ case frontend::ModuleFileInfo:
+ case frontend::VerifyPCH:
+ case frontend::PluginAction:
+ case frontend::PrintDeclContext:
+ case frontend::RewriteObjC:
+ case frontend::RewriteTest:
+ case frontend::RunAnalysis:
+ case frontend::MigrateSource:
+ return false;
+
+ case frontend::DumpRawTokens:
+ case frontend::DumpTokens:
+ case frontend::InitOnly:
+ case frontend::PrintPreamble:
+ case frontend::PrintPreprocessedInput:
+ case frontend::RewriteMacros:
+ case frontend::RunPreprocessorOnly:
+ return true;
+ }
+ llvm_unreachable("invalid frontend action");
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
FileManager &FileMgr,
- DiagnosticsEngine &Diags) {
+ DiagnosticsEngine &Diags,
+ frontend::ActionKind Action) {
using namespace options;
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
@@ -2251,6 +2490,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
+ Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors);
Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
for (const Arg *A : Args.filtered(OPT_error_on_deserialized_pch_decl))
@@ -2312,6 +2552,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
else
Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
}
+
+ // Always avoid lexing editor placeholders when we're just running the
+ // preprocessor as we never want to emit the
+ // "editor placeholder in source file" error in PP only mode.
+ if (isStrictlyPreprocessorAction(Action))
+ Opts.LexEditorPlaceholders = false;
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -2319,45 +2565,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
frontend::ActionKind Action) {
using namespace options;
- switch (Action) {
- case frontend::ASTDeclList:
- case frontend::ASTDump:
- case frontend::ASTPrint:
- case frontend::ASTView:
- case frontend::EmitAssembly:
- case frontend::EmitBC:
- case frontend::EmitHTML:
- case frontend::EmitLLVM:
- case frontend::EmitLLVMOnly:
- case frontend::EmitCodeGenOnly:
- case frontend::EmitObj:
- case frontend::FixIt:
- case frontend::GenerateModule:
- case frontend::GenerateModuleInterface:
- case frontend::GeneratePCH:
- case frontend::GeneratePTH:
- case frontend::ParseSyntaxOnly:
- case frontend::ModuleFileInfo:
- case frontend::VerifyPCH:
- case frontend::PluginAction:
- case frontend::PrintDeclContext:
- case frontend::RewriteObjC:
- case frontend::RewriteTest:
- case frontend::RunAnalysis:
- case frontend::MigrateSource:
- Opts.ShowCPP = 0;
- break;
-
- case frontend::DumpRawTokens:
- case frontend::DumpTokens:
- case frontend::InitOnly:
- case frontend::PrintPreamble:
- case frontend::PrintPreprocessedInput:
- case frontend::RewriteMacros:
- case frontend::RunPreprocessorOnly:
+ if (isStrictlyPreprocessorAction(Action))
Opts.ShowCPP = !Args.hasArg(OPT_dM);
- break;
- }
+ else
+ Opts.ShowCPP = 0;
Opts.ShowComments = Args.hasArg(OPT_C);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
@@ -2365,6 +2576,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
Opts.ShowIncludeDirectives = Args.hasArg(OPT_dI);
Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes);
+ Opts.RewriteImports = Args.hasArg(OPT_frewrite_imports);
Opts.UseLineDirectives = Args.hasArg(OPT_fuse_line_directives);
}
@@ -2384,7 +2596,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
<< Value;
else
- Opts.EABIVersion = Value;
+ Opts.EABIVersion = EABIVersion;
}
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
@@ -2405,7 +2617,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
bool Success = true;
// Parse the arguments.
- std::unique_ptr<OptTable> Opts(createDriverOptTable());
+ std::unique_ptr<OptTable> Opts = createDriverOptTable();
const unsigned IncludedFlagsBitmask = options::CC1Option;
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args =
@@ -2440,8 +2652,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags,
Res.getTargetOpts());
- ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args);
- if (DashX == IK_AST || DashX == IK_LLVM_IR) {
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args,
+ Res.getFileSystemOpts().WorkingDir);
+ if (DashX.getFormat() == InputKind::Precompiled ||
+ DashX.getLanguage() == InputKind::LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
// what the input type is.
@@ -2455,8 +2669,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Diags, LangOpts.Sanitize);
} else {
// Other LangOpts are only initialzed when the input is not AST or LLVM IR.
+ // FIXME: Should we really be calling this for an InputKind::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
- Res.getPreprocessorOpts(), Diags);
+ Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
}
@@ -2466,12 +2681,12 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// triple used for host compilation.
if (LangOpts.CUDAIsDevice)
Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
-
- // Set default FP_CONTRACT to FAST.
- if (!Args.hasArg(OPT_ffp_contract))
- Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast);
}
+ // Set the triple of the host for OpenMP device compile.
+ if (LangOpts.OpenMPIsDevice)
+ Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
+
// FIXME: Override value name discarding when asan or msan is used because the
// backend passes depend on the name of the alloca in order to print out
// names.
@@ -2484,7 +2699,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// ParsePreprocessorArgs and remove the FileManager
// parameters from the function and the "FileManager.h" #include.
FileManager FileMgr(Res.getFileSystemOpts());
- ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags,
+ Res.getFrontendOpts().ProgramAction);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
Res.getFrontendOpts().ProgramAction);
@@ -2569,28 +2785,12 @@ std::string CompilerInvocation::getModuleHash() const {
code = ext->hashExtension(code);
}
- // Darwin-specific hack: if we have a sysroot, use the contents and
- // modification time of
- // $sysroot/System/Library/CoreServices/SystemVersion.plist
- // as part of the module hash.
- if (!hsOpts.Sysroot.empty()) {
- SmallString<128> systemVersionFile;
- systemVersionFile += hsOpts.Sysroot;
- llvm::sys::path::append(systemVersionFile, "System");
- llvm::sys::path::append(systemVersionFile, "Library");
- llvm::sys::path::append(systemVersionFile, "CoreServices");
- llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
- llvm::MemoryBuffer::getFile(systemVersionFile);
- if (buffer) {
- code = hash_combine(code, buffer.get()->getBuffer());
-
- struct stat statBuf;
- if (stat(systemVersionFile.c_str(), &statBuf) == 0)
- code = hash_combine(code, statBuf.st_mtime);
- }
- }
+ // Extend the signature with the enabled sanitizers, if at least one is
+ // enabled. Sanitizers which cannot affect AST generation aren't hashed.
+ SanitizerSet SanHash = LangOpts->Sanitize;
+ SanHash.clear(getPPTransparentSanitizers());
+ if (!SanHash.empty())
+ code = hash_combine(code, SanHash.Mask);
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
@@ -2643,15 +2843,22 @@ void BuryPointer(const void *Ptr) {
IntrusiveRefCntPtr<vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags) {
+ return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem());
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
- return vfs::getRealFileSystem();
+ return BaseFS;
- IntrusiveRefCntPtr<vfs::OverlayFileSystem>
- Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay(
+ new vfs::OverlayFileSystem(BaseFS));
// earlier vfs files are on the bottom
for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
- llvm::MemoryBuffer::getFile(File);
+ BaseFS->getBufferForFile(File);
if (!Buffer) {
Diags.Report(diag::err_missing_vfs_overlay_file) << File;
return IntrusiveRefCntPtr<vfs::FileSystem>();
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 1626906..c3ce7ce 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,8 +31,8 @@ using namespace llvm::opt;
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
- ArrayRef<const char *> ArgList,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
+ ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -46,12 +46,14 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
- *Diags);
+ *Diags, VFS);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+ if (!C)
+ return nullptr;
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
index bd14c53..561eb9c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
@@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
llvm::sys::path::remove_leading_dotslash(FE->getName());
DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
- FileType != SrcMgr::C_User,
- /*IsModuleFile*/false, /*IsMissing*/false);
+ isSystem(FileType),
+ /*IsModuleFile*/false, /*IsMissing*/false);
}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
@@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
if (IncludeSystemHeaders)
return true;
- return FileType == SrcMgr::C_User;
+ return !isSystem(FileType);
}
void DFGImpl::FileChanged(SourceLocation Loc,
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
index 177feac..e326384 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -76,20 +76,19 @@ static void mergeFixits(ArrayRef<FixItHint> FixItHints,
}
}
-void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
+void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
- const SourceManager *SM,
DiagOrStoredDiag D) {
- assert(SM || Loc.isInvalid());
+ assert(Loc.hasManager() || Loc.isInvalid());
beginDiagnostic(D, Level);
if (!Loc.isValid())
// If we have no source location, just emit the diagnostic message.
- emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
+ emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D);
else {
// Get the ranges into a local array we can hack on.
SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
@@ -97,7 +96,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
SmallVector<FixItHint, 8> MergedFixits;
if (!FixItHints.empty()) {
- mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
+ mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
FixItHints = MergedFixits;
}
@@ -107,25 +106,25 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
if (I->RemoveRange.isValid())
MutableRanges.push_back(I->RemoveRange);
- SourceLocation UnexpandedLoc = Loc;
+ FullSourceLoc UnexpandedLoc = Loc;
// Find the ultimate expansion location for the diagnostic.
- Loc = SM->getFileLoc(Loc);
+ Loc = Loc.getFileLoc();
- PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// First, if this diagnostic is not in the main file, print out the
// "included from" lines.
- emitIncludeStack(Loc, PLoc, Level, *SM);
+ emitIncludeStack(Loc, PLoc, Level);
// Next, emit the actual diagnostic message and caret.
- emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
- emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
+ emitCaret(Loc, Level, MutableRanges, FixItHints);
// If this location is within a macro, walk from UnexpandedLoc up to Loc
// and produce a macro backtrace.
if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
- emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
}
}
@@ -139,15 +138,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
Diag.getRanges(), Diag.getFixIts(),
- Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
- : nullptr,
&Diag);
}
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
- emitDiagnosticMessage(
- SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
- None, nullptr, DiagOrStoredDiag());
+ emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note,
+ Message, None, DiagOrStoredDiag());
}
/// \brief Prints an include stack when appropriate for a particular
@@ -161,12 +157,11 @@ void DiagnosticRenderer::emitBasicNote(StringRef Message) {
/// \param Loc The diagnostic location.
/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
-void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- const SourceManager &SM) {
- SourceLocation IncludeLoc =
- PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc();
+void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level) {
+ FullSourceLoc IncludeLoc =
+ PLoc.isInvalid() ? FullSourceLoc()
+ : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
// Skip redundant include stacks altogether.
if (LastIncludeLoc == IncludeLoc)
@@ -178,74 +173,70 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
return;
if (IncludeLoc.isValid())
- emitIncludeStackRecursively(IncludeLoc, SM);
+ emitIncludeStackRecursively(IncludeLoc);
else {
- emitModuleBuildStack(SM);
- emitImportStack(Loc, SM);
+ emitModuleBuildStack(Loc.getManager());
+ emitImportStack(Loc);
}
}
/// \brief Helper to recursivly walk up the include stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
// If this source location was imported from a module, print the module
// import stack rather than the
// FIXME: We want submodule granularity here.
- std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
+ std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();
if (!Imported.second.empty()) {
// This location was imported by a module. Emit the module import stack.
- emitImportStackRecursively(Imported.first, Imported.second, SM);
+ emitImportStackRecursively(Imported.first, Imported.second);
return;
}
// Emit the other include frames first.
- emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
-
+ emitIncludeStackRecursively(
+ FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
+
// Emit the inclusion text/note.
- emitIncludeLocation(Loc, PLoc, SM);
+ emitIncludeLocation(Loc, PLoc);
}
/// \brief Emit the module import stack associated with the current location.
-void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
}
/// \brief Helper to recursivly walk up the import stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
+ StringRef ModuleName) {
if (ModuleName.empty()) {
return;
}
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// Emit the other import frames first.
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
// Emit the inclusion text/note.
- emitImportLocation(Loc, PLoc, ModuleName, SM);
+ emitImportLocation(Loc, PLoc, ModuleName);
}
/// \brief Emit the module build stack, for cases where a module is (re-)built
@@ -253,13 +244,9 @@ void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
ModuleBuildStack Stack = SM.getModuleBuildStack();
for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
- const SourceManager &CurSM = Stack[I].second.getManager();
- SourceLocation CurLoc = Stack[I].second;
- emitBuildingModuleLocation(CurLoc,
- CurSM.getPresumedLoc(CurLoc,
+ emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc(
DiagOpts->ShowPresumedLoc),
- Stack[I].first,
- CurSM);
+ Stack[I].first);
}
}
@@ -348,12 +335,12 @@ static void computeCommonMacroArgExpansionFileIDs(
// in the same expansion as the caret; otherwise, we crawl to the top of
// each chain. Two locations are part of the same macro expansion
// iff the FileID is the same.
-static void mapDiagnosticRanges(
- SourceLocation CaretLoc,
- ArrayRef<CharSourceRange> Ranges,
- SmallVectorImpl<CharSourceRange> &SpellingRanges,
- const SourceManager *SM) {
- FileID CaretLocFileID = SM->getFileID(CaretLoc);
+static void
+mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges,
+ SmallVectorImpl<CharSourceRange> &SpellingRanges) {
+ FileID CaretLocFileID = CaretLoc.getFileID();
+
+ const SourceManager *SM = &CaretLoc.getManager();
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
if (I->isInvalid()) continue;
@@ -404,42 +391,39 @@ static void mapDiagnosticRanges(
}
}
-void DiagnosticRenderer::emitCaret(SourceLocation Loc,
+void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
- emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints);
}
/// \brief A helper function for emitMacroExpansion to print the
/// macro expansion message
void DiagnosticRenderer::emitSingleMacroExpansion(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
// Find the spelling location for the macro definition. We must use the
// spelling location here to avoid emitting a macro backtrace for the note.
- SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
// Map the ranges into the FileID of the diagnostic location.
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- StringRef MacroName =
- Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts);
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Loc, Loc.getManager(), LangOpts);
if (MacroName.empty())
Message << "expanded from here";
else
Message << "expanded from macro '" << MacroName << "'";
emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
- SpellingRanges, None, &SM);
+ SpellingRanges, None);
}
/// Check that the macro argument location of Loc starts with ArgumentLoc.
@@ -473,13 +457,12 @@ static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
/// A helper function to check if the current ranges are all inside the same
/// macro argument expansion as Loc.
-static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc,
+ ArrayRef<CharSourceRange> Ranges) {
assert(Loc.isMacroID() && "Must be a macro expansion!");
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
/// Count all valid ranges.
unsigned ValidCount = 0;
@@ -490,15 +473,15 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
return false;
/// To store the source location of the argument location.
- SourceLocation ArgumentLoc;
+ FullSourceLoc ArgumentLoc;
/// Set the ArgumentLoc to the beginning location of the expansion of Loc
/// so to check if the ranges expands to the same beginning location.
- if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc))
+ if (!Loc.isMacroArgExpansion(&ArgumentLoc))
return false;
for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
- if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc))
+ if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc))
return false;
}
@@ -516,34 +499,33 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
+void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
// Produce a stack of macro backtraces.
- SmallVector<SourceLocation, 8> LocationStack;
+ SmallVector<FullSourceLoc, 8> LocationStack;
unsigned IgnoredEnd = 0;
while (Loc.isMacroID()) {
// If this is the expansion of a macro argument, point the caret at the
// use of the argument in the definition of the macro, not the expansion.
- if (SM.isMacroArgExpansion(Loc))
- LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first);
+ if (Loc.isMacroArgExpansion())
+ LocationStack.push_back(Loc.getImmediateExpansionRange().first);
else
LocationStack.push_back(Loc);
- if (checkRangesForMacroArgExpansion(Loc, Ranges, SM))
+ if (checkRangesForMacroArgExpansion(Loc, Ranges))
IgnoredEnd = LocationStack.size();
- Loc = SM.getImmediateMacroCallerLoc(Loc);
+ Loc = Loc.getImmediateMacroCallerLoc();
// Once the location no longer points into a macro, try stepping through
// the last found location. This sometimes produces additional useful
// backtraces.
if (Loc.isFileID())
- Loc = SM.getImmediateMacroCallerLoc(LocationStack.back());
+ Loc = LocationStack.back().getImmediateMacroCallerLoc();
assert(Loc.isValid() && "must have a valid source location here");
}
@@ -555,7 +537,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
if (MacroDepth <= MacroLimit || MacroLimit == 0) {
for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
return;
}
@@ -565,7 +547,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rbegin(),
E = LocationStack.rbegin() + MacroStartMessages;
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -577,26 +559,24 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rend() - MacroEndMessages,
E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
-void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "in file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
+void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -605,14 +585,12 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
Message << "' imported from " << PLoc.getFilename() << ':'
<< PLoc.getLine();
Message << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void
-DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -621,5 +599,5 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":";
else
Message << "while building module '" << ModuleName << "':";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
index 39fc137..704d5150 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
@@ -19,6 +19,7 @@
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/ParseAST.h"
@@ -135,6 +136,12 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
CurrentASTUnit = std::move(AST);
}
+Module *FrontendAction::getCurrentModule() const {
+ CompilerInstance &CI = getCompilerInstance();
+ return CI.getPreprocessor().getHeaderSearchInfo().lookupModule(
+ CI.getLangOpts().CurrentModule, /*AllowSearch*/false);
+}
+
std::unique_ptr<ASTConsumer>
FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
StringRef InFile) {
@@ -187,8 +194,324 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
+/// For preprocessed files, if the first line is the linemarker and specifies
+/// the original source file name, use that name as the input file name.
+/// Returns the location of the first token after the line marker directive.
+///
+/// \param CI The compiler instance.
+/// \param InputFile Populated with the filename from the line marker.
+/// \param IsModuleMap If \c true, add a line note corresponding to this line
+/// directive. (We need to do this because the directive will not be
+/// visited by the preprocessor.)
+static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
+ std::string &InputFile,
+ bool IsModuleMap = false) {
+ auto &SourceMgr = CI.getSourceManager();
+ auto MainFileID = SourceMgr.getMainFileID();
+
+ bool Invalid = false;
+ const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
+ std::unique_ptr<Lexer> RawLexer(
+ new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts()));
+
+ // If the first line has the syntax of
+ //
+ // # NUM "FILENAME"
+ //
+ // we use FILENAME as the input file name.
+ Token T;
+ if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash)
+ return SourceLocation();
+ if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() ||
+ T.getKind() != tok::numeric_constant)
+ return SourceLocation();
+
+ unsigned LineNo;
+ SourceLocation LineNoLoc = T.getLocation();
+ if (IsModuleMap) {
+ llvm::SmallString<16> Buffer;
+ if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts())
+ .getAsInteger(10, LineNo))
+ return SourceLocation();
+ }
+
+ RawLexer->LexFromRawLexer(T);
+ if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
+ return SourceLocation();
+
+ StringLiteralParser Literal(T, CI.getPreprocessor());
+ if (Literal.hadError)
+ return SourceLocation();
+ RawLexer->LexFromRawLexer(T);
+ if (T.isNot(tok::eof) && !T.isAtStartOfLine())
+ return SourceLocation();
+ InputFile = Literal.GetString().str();
+
+ if (IsModuleMap)
+ CI.getSourceManager().AddLineNote(
+ LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false,
+ false, SrcMgr::C_User_ModuleMap);
+
+ return T.getLocation();
+}
+
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+ Includes.append(RHS.begin(), RHS.end());
+ return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "extern \"C\" {\n";
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+
+ Includes += HeaderName;
+
+ Includes += "\"\n";
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "}\n";
+}
+
+/// \brief Collect the set of header includes needed to construct the given
+/// module and update the TopHeaders file set of the module.
+///
+/// \param Module The module we're collecting includes from.
+///
+/// \param Includes Will be augmented with the set of \#includes or \#imports
+/// needed to load all of the named headers.
+static std::error_code collectModuleHeaderIncludes(
+ const LangOptions &LangOpts, FileManager &FileMgr, DiagnosticsEngine &Diag,
+ ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) {
+ // Don't collect any headers for unavailable modules.
+ if (!Module->isAvailable())
+ return std::error_code();
+
+ // Resolve all lazy header directives to header files.
+ ModMap.resolveHeaderDirectives(Module);
+
+ // If any headers are missing, we can't build this module. In most cases,
+ // diagnostics for this should have already been produced; we only get here
+ // if explicit stat information was provided.
+ // FIXME: If the name resolves to a file with different stat information,
+ // produce a better diagnostic.
+ if (!Module->MissingHeaders.empty()) {
+ auto &MissingHeader = Module->MissingHeaders.front();
+ Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ return std::error_code();
+ }
+
+ // Add includes for each of these headers.
+ for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+ for (Module::Header &H : Module->Headers[HK]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
+ }
+ }
+ // Note that Module->PrivateHeaders will not be a TopHeader.
+
+ if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
+ Module->addTopHeader(UmbrellaHeader.Entry);
+ if (Module->Parent)
+ // Include the umbrella header for submodules.
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
+ Module->IsExternC);
+ } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
+ // Add all of the headers we find in this subdirectory.
+ std::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
+
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
+ Dir != End && !EC; Dir.increment(EC)) {
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ const FileEntry *Header = FileMgr.getFile(Dir->getName());
+ // FIXME: This shouldn't happen unless there is a file system race. Is
+ // that worth diagnosing?
+ if (!Header)
+ continue;
+
+ // If this header is marked 'unavailable' in this module, don't include
+ // it.
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
+ continue;
+
+ // Compute the relative path from the directory to this file.
+ SmallVector<StringRef, 16> Components;
+ auto PathIt = llvm::sys::path::rbegin(Dir->getName());
+ for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
+ Components.push_back(*PathIt);
+ SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
+ for (auto It = Components.rbegin(), End = Components.rend(); It != End;
+ ++It)
+ llvm::sys::path::append(RelativeHeader, *It);
+
+ // Include this header as part of the umbrella directory.
+ Module->addTopHeader(Header);
+ addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
+ }
+
+ if (EC)
+ return EC;
+ }
+
+ // Recurse into submodules.
+ for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+ SubEnd = Module->submodule_end();
+ Sub != SubEnd; ++Sub)
+ if (std::error_code Err = collectModuleHeaderIncludes(
+ LangOpts, FileMgr, Diag, ModMap, *Sub, Includes))
+ return Err;
+
+ return std::error_code();
+}
+
+static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem,
+ bool IsPreprocessed,
+ std::string &PresumedModuleMapFile,
+ unsigned &Offset) {
+ auto &SrcMgr = CI.getSourceManager();
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+
+ // Map the current input to a file.
+ FileID ModuleMapID = SrcMgr.getMainFileID();
+ const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID);
+
+ // If the module map is preprocessed, handle the initial line marker;
+ // line directives are not part of the module map syntax in general.
+ Offset = 0;
+ if (IsPreprocessed) {
+ SourceLocation EndOfLineMarker =
+ ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true);
+ if (EndOfLineMarker.isValid())
+ Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second;
+ }
+
+ // Load the module map file.
+ if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset,
+ PresumedModuleMapFile))
+ return true;
+
+ if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset)
+ Offset = 0;
+
+ return false;
+}
+
+static Module *prepareToBuildModule(CompilerInstance &CI,
+ StringRef ModuleMapFilename) {
+ if (CI.getLangOpts().CurrentModule.empty()) {
+ CI.getDiagnostics().Report(diag::err_missing_module_name);
+
+ // FIXME: Eventually, we could consider asking whether there was just
+ // a single module described in the module map, and use that as a
+ // default. Then it would be fairly trivial to just "compile" a module
+ // map with a single module (the common case).
+ return nullptr;
+ }
+
+ // Dig out the module definition.
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+ Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule,
+ /*AllowSearch=*/false);
+ if (!M) {
+ CI.getDiagnostics().Report(diag::err_missing_module)
+ << CI.getLangOpts().CurrentModule << ModuleMapFilename;
+
+ return nullptr;
+ }
+
+ // Check whether we can build this module at all.
+ if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(),
+ CI.getDiagnostics(), M))
+ return nullptr;
+
+ // Inform the preprocessor that includes from within the input buffer should
+ // be resolved relative to the build directory of the module map file.
+ CI.getPreprocessor().setMainFileDir(M->Directory);
+
+ // If the module was inferred from a different module map (via an expanded
+ // umbrella module definition), track that fact.
+ // FIXME: It would be preferable to fill this in as part of processing
+ // the module map, rather than adding it after the fact.
+ StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap;
+ if (!OriginalModuleMapName.empty()) {
+ auto *OriginalModuleMap =
+ CI.getFileManager().getFile(OriginalModuleMapName,
+ /*openFile*/ true);
+ if (!OriginalModuleMap) {
+ CI.getDiagnostics().Report(diag::err_module_map_not_found)
+ << OriginalModuleMapName;
+ return nullptr;
+ }
+ if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID(
+ CI.getSourceManager().getMainFileID())) {
+ M->IsInferred = true;
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()
+ .setInferredModuleAllowedBy(M, OriginalModuleMap);
+ }
+ }
+
+ // If we're being run from the command-line, the module build stack will not
+ // have been filled in yet, so complete it now in order to allow us to detect
+ // module cycles.
+ SourceManager &SourceMgr = CI.getSourceManager();
+ if (SourceMgr.getModuleBuildStack().empty())
+ SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
+ FullSourceLoc(SourceLocation(), SourceMgr));
+ return M;
+}
+
+/// Compute the input buffer that should be used to build the specified module.
+static std::unique_ptr<llvm::MemoryBuffer>
+getInputBufferForModule(CompilerInstance &CI, Module *M) {
+ FileManager &FileMgr = CI.getFileManager();
+
+ // Collect the set of #includes we need to build the module.
+ SmallString<256> HeaderContents;
+ std::error_code Err = std::error_code();
+ if (Module::Header UmbrellaHeader = M->getUmbrellaHeader())
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
+ CI.getLangOpts(), M->IsExternC);
+ Err = collectModuleHeaderIncludes(
+ CI.getLangOpts(), FileMgr, CI.getDiagnostics(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M,
+ HeaderContents);
+
+ if (Err) {
+ CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
+ << M->getFullModuleName() << Err.message();
+ return nullptr;
+ }
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ HeaderContents, Module::getModuleInputBufferName());
+}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
- const FrontendInputFile &Input) {
+ const FrontendInputFile &RealInput) {
+ FrontendInputFile Input(RealInput);
assert(!Instance && "Already processing a source file!");
assert(!Input.isEmpty() && "Unexpected empty filename!");
setCurrentInput(Input);
@@ -196,22 +519,88 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
StringRef InputFile = Input.getFile();
bool HasBegunSourceFile = false;
+ bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled &&
+ usesPreprocessorOnly();
if (!BeginInvocation(CI))
goto failure;
+ // If we're replaying the build of an AST file, import it and set up
+ // the initial state from its build.
+ if (ReplayASTFile) {
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+
+ // The AST unit populates its own diagnostics engine rather than ours.
+ IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
+ new DiagnosticsEngine(Diags->getDiagnosticIDs(),
+ &Diags->getDiagnosticOptions()));
+ ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
+
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
+ ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
+ if (!AST)
+ goto failure;
+
+ // Options relating to how we treat the input (but not what we do with it)
+ // are inherited from the AST unit.
+ CI.getHeaderSearchOpts() = AST->getHeaderSearchOpts();
+ CI.getPreprocessorOpts() = AST->getPreprocessorOpts();
+ CI.getLangOpts() = AST->getLangOpts();
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.createSourceManager(CI.getFileManager());
+ CI.getSourceManager().initializeForReplay(AST->getSourceManager());
+
+ // Preload all the module files loaded transitively by the AST unit. Also
+ // load all module map files that were parsed as part of building the AST
+ // unit.
+ if (auto ASTReader = AST->getASTReader()) {
+ auto &MM = ASTReader->getModuleManager();
+ auto &PrimaryModule = MM.getPrimaryModule();
+
+ for (ModuleFile &MF : MM)
+ if (&MF != &PrimaryModule)
+ CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName);
+
+ ASTReader->visitTopLevelModuleMaps(PrimaryModule,
+ [&](const FileEntry *FE) {
+ CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName());
+ });
+ }
+
+ // Set up the input file for replay purposes.
+ auto Kind = AST->getInputKind();
+ if (Kind.getFormat() == InputKind::ModuleMap) {
+ Module *ASTModule =
+ AST->getPreprocessor().getHeaderSearchInfo().lookupModule(
+ AST->getLangOpts().CurrentModule, /*AllowSearch*/ false);
+ assert(ASTModule && "module file does not define its own module");
+ Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind);
+ } else {
+ auto &SM = CI.getSourceManager();
+ FileID ID = SM.getMainFileID();
+ if (auto *File = SM.getFileEntryForID(ID))
+ Input = FrontendInputFile(File->getName(), Kind);
+ else
+ Input = FrontendInputFile(SM.getBuffer(ID), Kind);
+ }
+ setCurrentInput(Input, std::move(AST));
+ }
+
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (Input.getKind() == IK_AST) {
- assert(!usesPreprocessorOnly() &&
- "Attempt to pass AST file to preprocessor only action!");
+ if (Input.getKind().getFormat() == InputKind::Precompiled) {
+ assert(!usesPreprocessorOnly() && "this case was handled above");
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
- InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(),
- CI.getCodeGenOpts().DebugTypeExtRefs);
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
if (!AST)
goto failure;
@@ -225,12 +614,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setFileManager(&AST->getFileManager());
CI.setSourceManager(&AST->getSourceManager());
CI.setPreprocessor(AST->getPreprocessorPtr());
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOpts());
CI.setASTContext(&AST->getASTContext());
setCurrentInput(Input, std::move(AST));
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Create the AST consumer.
@@ -256,8 +648,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.hasSourceManager())
CI.createSourceManager(CI.getFileManager());
+ // Set up embedding for any specified files. Do this before we load any
+ // source files, including the primary module map for the compilation.
+ for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+ if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+ CI.getSourceManager().setFileIsTransient(FE);
+ else
+ CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+ }
+ if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+ CI.getSourceManager().setAllFilesAreTransient(true);
+
// IR files bypass the rest of initialization.
- if (Input.getKind() == IK_LLVM_IR) {
+ if (Input.getKind().getLanguage() == InputKind::LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -266,7 +669,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Initialize the main file entry.
@@ -319,13 +722,47 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
&CI.getPreprocessor());
HasBegunSourceFile = true;
- // Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ // Initialize the main file entry.
+ if (!CI.InitializeSourceManager(Input))
goto failure;
- // Initialize the main file entry. It is important that this occurs after
- // BeginSourceFileAction, which may change CurrentInput during module builds.
- if (!CI.InitializeSourceManager(CurrentInput))
+ // For module map files, we first parse the module map and synthesize a
+ // "<module-includes>" buffer before more conventional processing.
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
+
+ std::string PresumedModuleMapFile;
+ unsigned OffsetToContents;
+ if (loadModuleMapForModuleBuild(CI, Input.isSystem(),
+ Input.isPreprocessed(),
+ PresumedModuleMapFile, OffsetToContents))
+ goto failure;
+
+ auto *CurrentModule = prepareToBuildModule(CI, Input.getFile());
+ if (!CurrentModule)
+ goto failure;
+
+ CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile;
+
+ if (OffsetToContents)
+ // If the module contents are in the same file, skip to them.
+ CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true);
+ else {
+ // Otherwise, convert the module description to a suitable input buffer.
+ auto Buffer = getInputBufferForModule(CI, CurrentModule);
+ if (!Buffer)
+ goto failure;
+
+ // Reinitialize the main file entry to refer to the new input.
+ if (!CI.InitializeSourceManager(FrontendInputFile(
+ Buffer.release(), Input.getKind().withFormat(InputKind::Source),
+ CurrentModule->IsSystem)))
+ goto failure;
+ }
+ }
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI))
goto failure;
// Create the AST context and consumer unless this is a preprocessor only
@@ -335,8 +772,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!isModelParsingAction())
CI.createASTContext();
+ // For preprocessed files, check if the first line specifies the original
+ // source file name with a linemarker.
+ std::string PresumedInputFile = InputFile;
+ if (Input.isPreprocessed())
+ ReadOriginalFileName(CI, PresumedInputFile);
+
std::unique_ptr<ASTConsumer> Consumer =
- CreateWrappedASTConsumer(CI, InputFile);
+ CreateWrappedASTConsumer(CI, PresumedInputFile);
if (!Consumer)
goto failure;
@@ -352,8 +795,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get()));
CI.getASTContext().setExternalSource(source);
- } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
- // Use PCH.
+ } else if (CI.getLangOpts().Modules ||
+ !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ // Use PCM or PCH.
assert(hasPCHSupport() && "This action does not have PCH support!");
ASTDeserializationListener *DeserialListener =
Consumer->GetASTDeserializationListener();
@@ -370,13 +814,24 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
DeserialListener, DeleteDeserialListener);
DeleteDeserialListener = true;
}
- CI.createPCHExternalASTSource(
- CI.getPreprocessorOpts().ImplicitPCHInclude,
- CI.getPreprocessorOpts().DisablePCHValidation,
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ CI.createPCHExternalASTSource(
+ CI.getPreprocessorOpts().ImplicitPCHInclude,
+ CI.getPreprocessorOpts().DisablePCHValidation,
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
- DeleteDeserialListener);
- if (!CI.getASTContext().getExternalSource())
- goto failure;
+ DeleteDeserialListener);
+ if (!CI.getASTContext().getExternalSource())
+ goto failure;
+ }
+ // If modules are enabled, create the module manager before creating
+ // any builtins, so that all declarations know that they might be
+ // extended by an external source.
+ if (CI.getLangOpts().Modules || !CI.hasASTContext() ||
+ !CI.getASTContext().getExternalSource()) {
+ CI.createModuleManager();
+ CI.getModuleManager()->setDeserializationListener(DeserialListener,
+ DeleteDeserialListener);
+ }
}
CI.setASTConsumer(std::move(Consumer));
@@ -386,15 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Initialize built-in info as long as we aren't using an external AST
// source.
- if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+ if (CI.getLangOpts().Modules || !CI.hasASTContext() ||
+ !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
-
- // If modules are enabled, create the module manager before creating
- // any builtins, so that all declarations know that they might be
- // extended by an external source.
- if (CI.getLangOpts().Modules)
- CI.createModuleManager();
-
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
} else {
@@ -421,9 +870,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If there is a layout overrides file, attach an external AST source that
// provides the layouts from that file.
- if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
+ if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
- IntrusiveRefCntPtr<ExternalASTSource>
+ IntrusiveRefCntPtr<ExternalASTSource>
Override(new LayoutOverrideSource(
CI.getFrontendOpts().OverrideRecordLayoutsFile));
CI.getASTContext().setExternalSource(Override);
@@ -433,17 +882,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we failed, reset state since the client will not end up calling the
// matching EndSourceFile().
- failure:
- if (isCurrentFileAST()) {
- CI.setASTContext(nullptr);
- CI.setPreprocessor(nullptr);
- CI.setSourceManager(nullptr);
- CI.setFileManager(nullptr);
- }
-
+failure:
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
CI.clearOutputFiles(/*EraseFiles=*/true);
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
setCurrentInput(FrontendInputFile());
setCompilerInstance(nullptr);
return false;
@@ -517,6 +960,7 @@ void FrontendAction::EndSourceFile() {
CI.resetAndLeakPreprocessor();
CI.resetAndLeakSourceManager();
CI.resetAndLeakFileManager();
+ BuryPointer(CurrentASTUnit.release());
} else {
CI.setPreprocessor(nullptr);
CI.setSourceManager(nullptr);
@@ -526,6 +970,7 @@ void FrontendAction::EndSourceFile() {
setCompilerInstance(nullptr);
setCurrentInput(FrontendInputFile());
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
}
bool FrontendAction::shouldEraseOutputFiles() {
@@ -575,11 +1020,10 @@ WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
return WrappedAction->BeginInvocation(CI);
}
-bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) {
WrappedAction->setCurrentInput(getCurrentInput());
WrappedAction->setCompilerInstance(&CI);
- auto Ret = WrappedAction->BeginSourceFileAction(CI, Filename);
+ auto Ret = WrappedAction->BeginSourceFileAction(CI);
// BeginSourceFileAction may change CurrentInput, e.g. during module builds.
setCurrentInput(WrappedAction->getCurrentInput());
return Ret;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
index f795a1d..d424001 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
@@ -57,6 +57,7 @@ std::unique_ptr<ASTConsumer>
ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter,
CI.getFrontendOpts().ASTDumpDecls,
+ CI.getFrontendOpts().ASTDumpAll,
CI.getFrontendOpts().ASTDumpLookups);
}
@@ -93,7 +94,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Consumers.push_back(llvm::make_unique<PCHGenerator>(
CI.getPreprocessor(), OutputFile, Sysroot,
Buffer, CI.getFrontendOpts().ModuleFileExtensions,
- /*AllowASTWithErrors*/false,
+ /*AllowASTWithErrors*/CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
/*IncludeTimestamps*/
+CI.getFrontendOpts().IncludeTimestamps));
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
@@ -127,8 +128,13 @@ GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return OS;
}
-bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GeneratePCHAction::shouldEraseOutputFiles() {
+ if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
+ return false;
+ return ASTFrontendAction::shouldEraseOutputFiles();
+}
+
+bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
CI.getLangOpts().CompilingPCH = true;
return true;
}
@@ -157,242 +163,14 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
-bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
- // Set up embedding for any specified files. Do this before we load any
- // source files, including the primary module map for the compilation.
- for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
- CI.getSourceManager().setFileIsTransient(FE);
- else
- CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
- }
- if (CI.getFrontendOpts().ModulesEmbedAllFiles)
- CI.getSourceManager().setAllFilesAreTransient(true);
-
- return true;
-}
-
-
-static SmallVectorImpl<char> &
-operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
- Includes.append(RHS.begin(), RHS.end());
- return Includes;
-}
-
-static void addHeaderInclude(StringRef HeaderName,
- SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts,
- bool IsExternC) {
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "extern \"C\" {\n";
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
-
- Includes += HeaderName;
-
- Includes += "\"\n";
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "}\n";
-}
-
-/// \brief Collect the set of header includes needed to construct the given
-/// module and update the TopHeaders file set of the module.
-///
-/// \param Module The module we're collecting includes from.
-///
-/// \param Includes Will be augmented with the set of \#includes or \#imports
-/// needed to load all of the named headers.
-static std::error_code
-collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
- ModuleMap &ModMap, clang::Module *Module,
- SmallVectorImpl<char> &Includes) {
- // Don't collect any headers for unavailable modules.
- if (!Module->isAvailable())
- return std::error_code();
-
- // Add includes for each of these headers.
- for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
- for (Module::Header &H : Module->Headers[HK]) {
- Module->addTopHeader(H.Entry);
- // Use the path as specified in the module map file. We'll look for this
- // file relative to the module build directory (the directory containing
- // the module map file) so this will find the same file that we found
- // while parsing the module map.
- addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
- }
- }
- // Note that Module->PrivateHeaders will not be a TopHeader.
-
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
- Module->addTopHeader(UmbrellaHeader.Entry);
- if (Module->Parent)
- // Include the umbrella header for submodules.
- addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
- Module->IsExternC);
- } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
- // Add all of the headers we find in this subdirectory.
- std::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
-
- vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
- for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
- Dir != End && !EC; Dir.increment(EC)) {
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- const FileEntry *Header = FileMgr.getFile(Dir->getName());
- // FIXME: This shouldn't happen unless there is a file system race. Is
- // that worth diagnosing?
- if (!Header)
- continue;
-
- // If this header is marked 'unavailable' in this module, don't include
- // it.
- if (ModMap.isHeaderUnavailableInModule(Header, Module))
- continue;
-
- // Compute the relative path from the directory to this file.
- SmallVector<StringRef, 16> Components;
- auto PathIt = llvm::sys::path::rbegin(Dir->getName());
- for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
- Components.push_back(*PathIt);
- SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
- for (auto It = Components.rbegin(), End = Components.rend(); It != End;
- ++It)
- llvm::sys::path::append(RelativeHeader, *It);
-
- // Include this header as part of the umbrella directory.
- Module->addTopHeader(Header);
- addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
- }
-
- if (EC)
- return EC;
- }
-
- // Recurse into submodules.
- for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
- SubEnd = Module->submodule_end();
- Sub != SubEnd; ++Sub)
- if (std::error_code Err = collectModuleHeaderIncludes(
- LangOpts, FileMgr, ModMap, *Sub, Includes))
- return Err;
-
- return std::error_code();
-}
-
bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
- CompilerInstance &CI, StringRef Filename) {
- CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
-
- if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename))
- return false;
-
- // Find the module map file.
- const FileEntry *ModuleMap =
- CI.getFileManager().getFile(Filename, /*openFile*/true);
- if (!ModuleMap) {
- CI.getDiagnostics().Report(diag::err_module_map_not_found)
- << Filename;
+ CompilerInstance &CI) {
+ if (!CI.getLangOpts().Modules) {
+ CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules);
return false;
}
-
- // Parse the module map file.
- HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- if (HS.loadModuleMapFile(ModuleMap, IsSystem))
- return false;
-
- if (CI.getLangOpts().CurrentModule.empty()) {
- CI.getDiagnostics().Report(diag::err_missing_module_name);
-
- // FIXME: Eventually, we could consider asking whether there was just
- // a single module described in the module map, and use that as a
- // default. Then it would be fairly trivial to just "compile" a module
- // map with a single module (the common case).
- return false;
- }
-
- // If we're being run from the command-line, the module build stack will not
- // have been filled in yet, so complete it now in order to allow us to detect
- // module cycles.
- SourceManager &SourceMgr = CI.getSourceManager();
- if (SourceMgr.getModuleBuildStack().empty())
- SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
- FullSourceLoc(SourceLocation(), SourceMgr));
-
- // Dig out the module definition.
- Module = HS.lookupModule(CI.getLangOpts().CurrentModule,
- /*AllowSearch=*/false);
- if (!Module) {
- CI.getDiagnostics().Report(diag::err_missing_module)
- << CI.getLangOpts().CurrentModule << Filename;
-
- return false;
- }
-
- // Check whether we can build this module at all.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- CI.getDiagnostics().Report(diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first;
- }
-
- return false;
- }
-
- if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) {
- Module->IsInferred = true;
- HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing);
- } else {
- ModuleMapForUniquing = ModuleMap;
- }
- FileManager &FileMgr = CI.getFileManager();
-
- // Collect the set of #includes we need to build the module.
- SmallString<256> HeaderContents;
- std::error_code Err = std::error_code();
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader())
- addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
- CI.getLangOpts(), Module->IsExternC);
- Err = collectModuleHeaderIncludes(
- CI.getLangOpts(), FileMgr,
- CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module,
- HeaderContents);
-
- if (Err) {
- CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
- << Module->getFullModuleName() << Err.message();
- return false;
- }
-
- // Inform the preprocessor that includes from within the input buffer should
- // be resolved relative to the build directory of the module map file.
- CI.getPreprocessor().setMainFileDir(Module->Directory);
-
- std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
- llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
- Module::getModuleInputBufferName());
- // Ownership of InputBuffer will be transferred to the SourceManager.
- setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
- Module->IsSystem));
- return true;
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -401,10 +179,13 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
// If no output file was provided, figure out where this module would go
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
+ StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
+ if (ModuleMapFile.empty())
+ ModuleMapFile = InFile;
+
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
CI.getFrontendOpts().OutputFile =
- HS.getModuleFileName(CI.getLangOpts().CurrentModule,
- ModuleMapForUniquing->getName(),
+ HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile,
/*UsePrebuiltPath=*/false);
}
@@ -417,8 +198,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
/*CreateMissingDirectories=*/true);
}
-bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GenerateModuleInterfaceAction::BeginSourceFileAction(
+ CompilerInstance &CI) {
if (!CI.getLangOpts().ModulesTS) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts);
return false;
@@ -426,7 +207,7 @@ bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
- return GenerateModuleAction::BeginSourceFileAction(CI, Filename);
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -459,7 +240,7 @@ void VerifyPCHAction::ExecuteAction() {
bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
std::unique_ptr<ASTReader> Reader(new ASTReader(
- CI.getPreprocessor(), CI.getASTContext(), CI.getPCHContainerReader(),
+ CI.getPreprocessor(), &CI.getASTContext(), CI.getPCHContainerReader(),
CI.getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(),
/*DisableValidation*/ false,
@@ -567,6 +348,7 @@ namespace {
bool Complain) override {
Out.indent(2) << "Header search options:\n";
Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
+ Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n";
Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n";
DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
"Use builtin include directories [-nobuiltininc]");
@@ -745,7 +527,7 @@ void PrintPreprocessedAction::ExecuteAction() {
// file. This is mostly a sanity check in case the file has no
// newlines whatsoever.
if (end - cur > 256) end = cur + 256;
-
+
while (next < end) {
if (*cur == 0x0D) { // CR
if (*next == 0x0A) // CRLF
@@ -764,34 +546,47 @@ void PrintPreprocessedAction::ExecuteAction() {
CI.createDefaultOutputFile(BinaryMode, getCurrentFile());
if (!OS) return;
+ // If we're preprocessing a module map, start by dumping the contents of the
+ // module itself before switching to the input buffer.
+ auto &Input = getCurrentInput();
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ if (Input.isFile()) {
+ (*OS) << "# 1 \"";
+ OS->write_escaped(Input.getFile());
+ (*OS) << "\"\n";
+ }
+ // FIXME: Include additional information here so that we don't need the
+ // original source files to exist on disk.
+ getCurrentModule()->print(*OS);
+ (*OS) << "#pragma clang module contents\n";
+ }
+
DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(),
CI.getPreprocessorOutputOpts());
}
void PrintPreambleAction::ExecuteAction() {
- switch (getCurrentFileKind()) {
- case IK_C:
- case IK_CXX:
- case IK_ObjC:
- case IK_ObjCXX:
- case IK_OpenCL:
- case IK_CUDA:
+ switch (getCurrentFileKind().getLanguage()) {
+ case InputKind::C:
+ case InputKind::CXX:
+ case InputKind::ObjC:
+ case InputKind::ObjCXX:
+ case InputKind::OpenCL:
+ case InputKind::CUDA:
break;
- case IK_None:
- case IK_Asm:
- case IK_PreprocessedC:
- case IK_PreprocessedCuda:
- case IK_PreprocessedCXX:
- case IK_PreprocessedObjC:
- case IK_PreprocessedObjCXX:
- case IK_AST:
- case IK_LLVM_IR:
- case IK_RenderScript:
+ case InputKind::Unknown:
+ case InputKind::Asm:
+ case InputKind::LLVM_IR:
+ case InputKind::RenderScript:
// We can't do anything with these.
return;
}
+ // We don't expect to find any #include directives in a preprocessed input.
+ if (getCurrentFileKind().isPreprocessed())
+ return;
+
CompilerInstance &CI = getCompilerInstance();
auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
index 6a82084..dca4345 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
@@ -13,22 +13,22 @@ using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Cases("ast", "pcm", IK_AST)
- .Case("c", IK_C)
- .Cases("S", "s", IK_Asm)
- .Case("i", IK_PreprocessedC)
- .Case("ii", IK_PreprocessedCXX)
- .Case("cui", IK_PreprocessedCuda)
- .Case("m", IK_ObjC)
- .Case("mi", IK_PreprocessedObjC)
- .Cases("mm", "M", IK_ObjCXX)
- .Case("mii", IK_PreprocessedObjCXX)
- .Cases("C", "cc", "cp", IK_CXX)
- .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
- .Case("cppm", IK_CXX)
- .Case("iim", IK_PreprocessedCXX)
- .Case("cl", IK_OpenCL)
- .Case("cu", IK_CUDA)
- .Cases("ll", "bc", IK_LLVM_IR)
- .Default(IK_C);
+ .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("c", InputKind::C)
+ .Cases("S", "s", InputKind::Asm)
+ .Case("i", InputKind(InputKind::C).getPreprocessed())
+ .Case("ii", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cui", InputKind(InputKind::CUDA).getPreprocessed())
+ .Case("m", InputKind::ObjC)
+ .Case("mi", InputKind(InputKind::ObjC).getPreprocessed())
+ .Cases("mm", "M", InputKind::ObjCXX)
+ .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed())
+ .Cases("C", "cc", "cp", InputKind::CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX)
+ .Case("cppm", InputKind::CXX)
+ .Case("iim", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cl", InputKind::OpenCL)
+ .Case("cu", InputKind::CUDA)
+ .Cases("ll", "bc", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
index d50fb6d..1d7c8a0 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -221,6 +221,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
break;
+ LLVM_FALLTHROUGH;
default:
// FIXME: temporary hack: hard-coded paths.
AddPath("/usr/local/include", System, false);
@@ -343,6 +344,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath(BaseSDKPath + "/target/include", System, false);
if (triple.isPS4CPU())
AddPath(BaseSDKPath + "/target/include_common", System, false);
+ LLVM_FALLTHROUGH;
}
default:
AddPath("/usr/include", ExternCSystem, false);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
index 17603ad..92d6136 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
@@ -374,9 +374,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
- // FIXME: Use correct value for C++17.
- if (LangOpts.CPlusPlus1z)
- Builder.defineMacro("__cplusplus", "201406L");
+ // FIXME: Use correct value for C++20.
+ if (LangOpts.CPlusPlus2a)
+ Builder.defineMacro("__cplusplus", "201707L");
+ // C++17 [cpp.predefined]p1:
+ // The name __cplusplus is defined to the value 201703L when compiling a
+ // C++ translation unit.
+ else if (LangOpts.CPlusPlus1z)
+ Builder.defineMacro("__cplusplus", "201703L");
// C++1y [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201402L when compiling a
// C++ translation unit.
@@ -475,6 +480,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_user_defined_literals", "200809");
Builder.defineMacro("__cpp_lambdas", "200907");
Builder.defineMacro("__cpp_constexpr",
+ LangOpts.CPlusPlus1z ? "201603" :
LangOpts.CPlusPlus14 ? "201304" : "200704");
Builder.defineMacro("__cpp_range_based_for",
LangOpts.CPlusPlus1z ? "201603" : "200907");
@@ -491,6 +497,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_ref_qualifiers", "200710");
Builder.defineMacro("__cpp_alias_templates", "200704");
}
+ if (LangOpts.ThreadsafeStatics)
+ Builder.defineMacro("__cpp_threadsafe_static_init", "200806");
// C++14 features.
if (LangOpts.CPlusPlus14) {
@@ -513,6 +521,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_noexcept_function_type", "201510");
Builder.defineMacro("__cpp_capture_star_this", "201603");
Builder.defineMacro("__cpp_if_constexpr", "201606");
+ Builder.defineMacro("__cpp_deduction_guides", "201611");
Builder.defineMacro("__cpp_template_auto", "201606");
Builder.defineMacro("__cpp_namespace_attributes", "201411");
Builder.defineMacro("__cpp_enumerator_attributes", "201411");
@@ -530,7 +539,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
if (LangOpts.ConceptsTS)
Builder.defineMacro("__cpp_experimental_concepts", "1");
if (LangOpts.CoroutinesTS)
- Builder.defineMacro("__cpp_coroutines", "1");
+ Builder.defineMacro("__cpp_coroutines", "201703L");
}
static void InitializePredefinedMacros(const TargetInfo &TI,
@@ -593,9 +602,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
- Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
- Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
-
if (LangOpts.getGC() != LangOptions::NonGC)
Builder.defineMacro("__OBJC_GC__");
@@ -626,6 +632,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("IB_DESIGNABLE", "");
}
+ // Define a macro that describes the Objective-C boolean type even for C
+ // and C++ since BOOL can be used from non Objective-C code.
+ Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
+ Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
+
if (LangOpts.CPlusPlus)
InitializeCPlusPlusFeatureTestMacros(LangOpts, Builder);
@@ -875,14 +886,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// The value written by __atomic_test_and_set.
// FIXME: This is target-dependent.
Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
+ }
+ auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
-#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
- Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
- getLockFreeValue(TI.get##Type##Width(), \
- TI.get##Type##Align(), \
- InlineWidthBits));
+#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
+ Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \
+ getLockFreeValue(TI.get##Type##Width(), \
+ TI.get##Type##Align(), \
+ InlineWidthBits));
DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
DEFINE_LOCK_FREE_MACRO(CHAR, Char);
DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
@@ -892,12 +905,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DEFINE_LOCK_FREE_MACRO(INT, Int);
DEFINE_LOCK_FREE_MACRO(LONG, Long);
DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
- Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
+ Builder.defineMacro(Prefix + "POINTER_LOCK_FREE",
getLockFreeValue(TI.getPointerWidth(0),
TI.getPointerAlign(0),
InlineWidthBits));
#undef DEFINE_LOCK_FREE_MACRO
- }
+ };
+ addLockFreeMacros("__CLANG_ATOMIC_");
+ if (!LangOpts.MSVCCompat)
+ addLockFreeMacros("__GCC_ATOMIC_");
if (LangOpts.NoInlineDefine)
Builder.defineMacro("__NO_INLINE__");
@@ -1029,7 +1045,9 @@ void clang::InitializePreprocessor(
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines) {
- if (LangOpts.CUDA && PP.getAuxTargetInfo())
+ // FIXME: This will create multiple definitions for most of the predefined
+ // macros. This is not the right way to handle this.
+ if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
Builder);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
index f133327..47023e5 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
@@ -13,15 +13,15 @@
using namespace clang;
using namespace clang::frontend;
-#define LANGSTANDARD(id, name, desc, features) \
- static const LangStandard Lang_##id = { name, desc, features };
+#define LANGSTANDARD(id, name, lang, desc, features) \
+static const LangStandard Lang_##id = { name, desc, features, InputKind::lang };
#include "clang/Frontend/LangStandards.def"
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
case lang_unspecified:
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
}
@@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
Kind K = llvm::StringSwitch<Kind>(Name)
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(lang_unspecified);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
index 9b34d42..ede12aa 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
@@ -248,7 +248,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
// Always map a canonical src path to its real path into the YAML, by doing
// this we map different virtual src paths to the same entry in the VFS
// overlay, which is a way to emulate symlink inside the VFS; this is also
- // needed for correctness, not doing that can lead to module redifinition
+ // needed for correctness, not doing that can lead to module redefinition
// errors.
addFileMapping(VirtualPath, CacheDst);
return std::error_code();
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp
new file mode 100644
index 0000000..15b24cb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp
@@ -0,0 +1,563 @@
+//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper class to build precompiled preamble.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Serialization/ASTWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+
+using namespace clang;
+
+namespace {
+
+/// Keeps a track of files to be deleted in destructor.
+class TemporaryFiles {
+public:
+ // A static instance to be used by all clients.
+ static TemporaryFiles &getInstance();
+
+private:
+ // Disallow constructing the class directly.
+ TemporaryFiles() = default;
+ // Disallow copy.
+ TemporaryFiles(const TemporaryFiles &) = delete;
+
+public:
+ ~TemporaryFiles();
+
+ /// Adds \p File to a set of tracked files.
+ void addFile(StringRef File);
+
+ /// Remove \p File from disk and from the set of tracked files.
+ void removeFile(StringRef File);
+
+private:
+ llvm::sys::SmartMutex<false> Mutex;
+ llvm::StringSet<> Files;
+};
+
+TemporaryFiles &TemporaryFiles::getInstance() {
+ static TemporaryFiles Instance;
+ return Instance;
+}
+
+TemporaryFiles::~TemporaryFiles() {
+ llvm::MutexGuard Guard(Mutex);
+ for (const auto &File : Files)
+ llvm::sys::fs::remove(File.getKey());
+}
+
+void TemporaryFiles::addFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto IsInserted = Files.insert(File).second;
+ (void)IsInserted;
+ assert(IsInserted && "File has already been added");
+}
+
+void TemporaryFiles::removeFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto WasPresent = Files.erase(File);
+ (void)WasPresent;
+ assert(WasPresent && "File was not tracked");
+ llvm::sys::fs::remove(File);
+}
+
+class PreambleMacroCallbacks : public PPCallbacks {
+public:
+ PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {}
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ Callbacks.HandleMacroDefined(MacroNameTok, MD);
+ }
+
+private:
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleAction : public ASTFrontendAction {
+public:
+ PrecompilePreambleAction(PreambleCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+
+ bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
+
+ void setEmittedPreamblePCH(ASTWriter &Writer) {
+ this->HasEmittedPreamblePCH = true;
+ Callbacks.AfterPCHEmitted(Writer);
+ }
+
+ bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
+ bool hasCodeCompletionSupport() const override { return false; }
+ bool hasASTFileSupport() const override { return false; }
+ TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
+
+private:
+ friend class PrecompilePreambleConsumer;
+
+ bool HasEmittedPreamblePCH = false;
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleConsumer : public PCHGenerator {
+public:
+ PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
+ const Preprocessor &PP, StringRef isysroot,
+ std::unique_ptr<raw_ostream> Out)
+ : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
+ ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
+ /*AllowASTWithErrors=*/true),
+ Action(Action), Out(std::move(Out)) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ Action.Callbacks.HandleTopLevelDecl(DG);
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ PCHGenerator::HandleTranslationUnit(Ctx);
+ if (!hasEmittedPCH())
+ return;
+
+ // Write the generated bitstream to "Out".
+ *Out << getPCH();
+ // Make sure it hits disk now.
+ Out->flush();
+ // Free the buffer.
+ llvm::SmallVector<char, 0> Empty;
+ getPCH() = std::move(Empty);
+
+ Action.setEmittedPreamblePCH(getWriter());
+ }
+
+private:
+ PrecompilePreambleAction &Action;
+ std::unique_ptr<raw_ostream> Out;
+};
+
+std::unique_ptr<ASTConsumer>
+PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
+
+ StringRef InFile) {
+ std::string Sysroot;
+ std::string OutputFile;
+ std::unique_ptr<raw_ostream> OS =
+ GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile);
+ if (!OS)
+ return nullptr;
+
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+
+ CI.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<PreambleMacroCallbacks>(Callbacks));
+ return llvm::make_unique<PrecompilePreambleConsumer>(
+ *this, CI.getPreprocessor(), Sysroot, std::move(OS));
+}
+
+template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
+}
+
+} // namespace
+
+PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
+ llvm::MemoryBuffer *Buffer,
+ unsigned MaxLines) {
+ auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
+ return PreambleBounds(Pre.first, Pre.second);
+}
+
+llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
+ const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ PreambleCallbacks &Callbacks) {
+ assert(VFS && "VFS is null");
+
+ if (!Bounds.Size)
+ return BuildPreambleError::PreambleIsEmpty;
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ // Create a temporary file for the precompiled preamble. In rare
+ // circumstances, this can fail.
+ llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
+ PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
+ if (!PreamblePCHFile)
+ return BuildPreambleError::CouldntCreateTempFile;
+
+ // Save the preamble text for later; we'll need to compare against it for
+ // subsequent reparses.
+ std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
+ MainFileBuffer->getBufferStart() +
+ Bounds.Size);
+ bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
+
+ // Tell the compiler invocation to generate a temporary precompiled header.
+ FrontendOpts.ProgramAction = frontend::GeneratePCH;
+ // FIXME: Generate the precompiled header into memory?
+ FrontendOpts.OutputFile = PreamblePCHFile->getFilePath();
+ PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+ PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+
+ // Create the compiler instance to use for building the precompiled preamble.
+ std::unique_ptr<CompilerInstance> Clang(
+ new CompilerInstance(std::move(PCHContainerOps)));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
+ Clang.get());
+
+ Clang->setInvocation(std::move(PreambleInvocation));
+ Clang->setDiagnostics(&Diagnostics);
+
+ // Create the target instance.
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return BuildPreambleError::CouldntCreateTargetInfo;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang->getTarget().adjust(Clang->getLangOpts());
+
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
+
+ // Clear out old caches and data.
+ Diagnostics.Reset();
+ ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
+
+ VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
+ if (!VFS)
+ return BuildPreambleError::CouldntCreateVFSOverlay;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
+
+ // Create the source manager.
+ Clang->setSourceManager(
+ new SourceManager(Diagnostics, Clang->getFileManager()));
+
+ auto PreambleDepCollector = std::make_shared<DependencyCollector>();
+ Clang->addDependencyCollector(PreambleDepCollector);
+
+ // Remap the main source file to the preamble buffer.
+ StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
+ auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
+ MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
+ if (PreprocessorOpts.RetainRemappedFileBuffers) {
+ // MainFileBuffer will be deleted by unique_ptr after leaving the method.
+ PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
+ } else {
+ // In that case, remapped buffer will be deleted by CompilerInstance on
+ // BeginSourceFile, so we call release() to avoid double deletion.
+ PreprocessorOpts.addRemappedFile(MainFilePath,
+ PreambleInputBuffer.release());
+ }
+
+ std::unique_ptr<PrecompilePreambleAction> Act;
+ Act.reset(new PrecompilePreambleAction(Callbacks));
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
+ return BuildPreambleError::BeginSourceFileFailed;
+
+ Act->Execute();
+
+ // Run the callbacks.
+ Callbacks.AfterExecute(*Clang);
+
+ Act->EndSourceFile();
+
+ if (!Act->hasEmittedPreamblePCH())
+ return BuildPreambleError::CouldntEmitPCH;
+
+ // Keep track of all of the files that the source manager knows about,
+ // so we can verify whether they have changed or not.
+ llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
+
+ SourceManager &SourceMgr = Clang->getSourceManager();
+ for (auto &Filename : PreambleDepCollector->getDependencies()) {
+ const FileEntry *File = Clang->getFileManager().getFile(Filename);
+ if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
+ continue;
+ if (time_t ModTime = File->getModificationTime()) {
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
+ ModTime);
+ } else {
+ llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
+ }
+ }
+
+ return PrecompiledPreamble(
+ std::move(*PreamblePCHFile), std::move(PreambleBytes),
+ PreambleEndsAtStartOfLine, std::move(FilesInPreamble));
+}
+
+PreambleBounds PrecompiledPreamble::getBounds() const {
+ return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
+}
+
+bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer,
+ PreambleBounds Bounds,
+ vfs::FileSystem *VFS) const {
+
+ assert(
+ Bounds.Size <= MainFileBuffer->getBufferSize() &&
+ "Buffer is too large. Bounds were calculated from a different buffer?");
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ if (!Bounds.Size)
+ return false;
+
+ // We've previously computed a preamble. Check whether we have the same
+ // preamble now that we did before, and that there's enough space in
+ // the main-file buffer within the precompiled preamble to fit the
+ // new main file.
+ if (PreambleBytes.size() != Bounds.Size ||
+ PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
+ memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
+ Bounds.Size) != 0)
+ return false;
+ // The preamble has not changed. We may be able to re-use the precompiled
+ // preamble.
+
+ // Check that none of the files used by the preamble have changed.
+ // First, make a record of those files that have been overridden via
+ // remapping or unsaved_files.
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
+ for (const auto &R : PreprocessorOpts.RemappedFiles) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(R.second), Status)) {
+ // If we can't stat the file we're remapping to, assume that something
+ // horrible happened.
+ return false;
+ }
+
+ OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
+ Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
+ }
+
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(RB.first), Status))
+ return false;
+
+ OverriddenFiles[Status.getUniqueID()] =
+ PreambleFileHash::createForMemoryBuffer(RB.second);
+ }
+
+ // Check whether anything has changed.
+ for (const auto &F : FilesInPreamble) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(F.first()), Status)) {
+ // If we can't stat the file, assume that something horrible happened.
+ return false;
+ }
+
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
+ OverriddenFiles.find(Status.getUniqueID());
+ if (Overridden != OverriddenFiles.end()) {
+ // This file was remapped; check whether the newly-mapped file
+ // matches up with the previous mapping.
+ if (Overridden->second != F.second)
+ return false;
+ continue;
+ }
+
+ // The file was not remapped; check whether it has changed on disk.
+ if (Status.getSize() != uint64_t(F.second.Size) ||
+ llvm::sys::toTimeT(Status.getLastModificationTime()) !=
+ F.second.ModTime)
+ return false;
+ }
+ return true;
+}
+
+void PrecompiledPreamble::AddImplicitPreamble(
+ CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const {
+ auto &PreprocessorOpts = CI.getPreprocessorOpts();
+
+ // Configure ImpicitPCHInclude.
+ PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
+ PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
+ PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
+ PreprocessorOpts.DisablePCHValidation = true;
+
+ // Remap main file to point to MainFileBuffer.
+ auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
+ PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
+}
+
+PrecompiledPreamble::PrecompiledPreamble(
+ TempPCHFile PCHFile, std::vector<char> PreambleBytes,
+ bool PreambleEndsAtStartOfLine,
+ llvm::StringMap<PreambleFileHash> FilesInPreamble)
+ : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble),
+ PreambleBytes(std::move(PreambleBytes)),
+ PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
+ // FIXME: This is a hack so that we can override the preamble file during
+ // crash-recovery testing, which is the only case where the preamble files
+ // are not necessarily cleaned up.
+ const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
+ if (TmpFile)
+ return TempPCHFile::createFromCustomPath(TmpFile);
+ return TempPCHFile::createInSystemTempDir("preamble", "pch");
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
+ StringRef Suffix) {
+ llvm::SmallString<64> File;
+ auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File);
+ if (EC)
+ return EC;
+ return TempPCHFile(std::move(File).str());
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
+ return TempPCHFile(Path.str());
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
+ : FilePath(std::move(FilePath)) {
+ TemporaryFiles::getInstance().addFile(*this->FilePath);
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+}
+
+PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
+operator=(TempPCHFile &&Other) {
+ RemoveFileIfPresent();
+
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+ return *this;
+}
+
+PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
+
+void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
+ if (FilePath) {
+ TemporaryFiles::getInstance().removeFile(*FilePath);
+ FilePath = None;
+ }
+}
+
+llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
+ assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
+ return *FilePath;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
+ time_t ModTime) {
+ PreambleFileHash Result;
+ Result.Size = Size;
+ Result.ModTime = ModTime;
+ Result.MD5 = {};
+ return Result;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
+ const llvm::MemoryBuffer *Buffer) {
+ PreambleFileHash Result;
+ Result.Size = Buffer->getBufferSize();
+ Result.ModTime = 0;
+
+ llvm::MD5 MD5Ctx;
+ MD5Ctx.update(Buffer->getBuffer().data());
+ MD5Ctx.final(Result.MD5);
+
+ return Result;
+}
+
+void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
+void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
+void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
+void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {}
+
+std::error_code clang::make_error_code(BuildPreambleError Error) {
+ return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
+}
+
+const char *BuildPreambleErrorCategory::name() const noexcept {
+ return "build-preamble.error";
+}
+
+std::string BuildPreambleErrorCategory::message(int condition) const {
+ switch (static_cast<BuildPreambleError>(condition)) {
+ case BuildPreambleError::PreambleIsEmpty:
+ return "Preamble is empty";
+ case BuildPreambleError::CouldntCreateTempFile:
+ return "Could not create temporary file for PCH";
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ return "CreateTargetInfo() return null";
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ return "Could not create VFS Overlay";
+ case BuildPreambleError::BeginSourceFileFailed:
+ return "BeginSourceFile() return an error";
+ case BuildPreambleError::CouldntEmitPCH:
+ return "Could not emit PCH";
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index d48b952..914039a 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -38,8 +38,8 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.isFunctionLike()) {
OS << '(';
- if (!MI.arg_empty()) {
- MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ if (!MI.param_empty()) {
+ MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
for (; AI+1 != E; ++AI) {
OS << (*AI)->getName();
OS << ',';
@@ -172,7 +172,11 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override;
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
+
+ void BeginModule(const Module *M);
+ void EndModule(const Module *M);
};
} // end anonymous namespace
@@ -323,47 +327,68 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
StringRef SearchPath,
StringRef RelativePath,
const Module *Imported) {
- if (Imported) {
- // When preprocessing, turn implicit imports into @imports.
- // FIXME: This is a stop-gap until a more comprehensive "preprocessing with
- // modules" solution is introduced.
+ // In -dI mode, dump #include directives prior to dumping their content or
+ // interpretation.
+ if (DumpIncludeDirectives) {
startNewLineIfNeeded();
MoveToLine(HashLoc);
- if (PP.getLangOpts().ObjC2) {
- OS << "@import " << Imported->getFullModuleName() << ";"
- << " /* clang -E: implicit import for \"" << File->getName()
- << "\" */";
- } else {
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
- << (IsAngled ? '<' : '"')
- << FileName
- << (IsAngled ? '>' : '"')
- << " /* clang -E: implicit import for module "
- << Imported->getFullModuleName() << " */";
- }
- // Since we want a newline after the @import, but not a #<line>, start a new
- // line immediately.
- EmittedTokensOnThisLine = true;
+ const std::string TokenText = PP.getSpelling(IncludeTok);
+ assert(!TokenText.empty());
+ OS << "#" << TokenText << " "
+ << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
+ << " /* clang -E -dI */";
+ setEmittedDirectiveOnThisLine();
startNewLineIfNeeded();
- } else {
- // Not a module import; it's a more vanilla inclusion of some file using one
- // of: #include, #import, #include_next, #include_macros.
- if (DumpIncludeDirectives) {
+ }
+
+ // When preprocessing, turn implicit imports into module import pragmas.
+ if (Imported) {
+ switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next:
startNewLineIfNeeded();
MoveToLine(HashLoc);
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
+ OS << "#pragma clang module import " << Imported->getFullModuleName(true)
+ << " /* clang -E: implicit import for "
+ << "#" << PP.getSpelling(IncludeTok) << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
- << " /* clang -E -dI */";
- setEmittedDirectiveOnThisLine();
+ << " */";
+ // Since we want a newline after the pragma, but not a #<line>, start a
+ // new line immediately.
+ EmittedTokensOnThisLine = true;
startNewLineIfNeeded();
+ break;
+
+ case tok::pp___include_macros:
+ // #__include_macros has no effect on a user of a preprocessed source
+ // file; the only effect is on preprocessing.
+ //
+ // FIXME: That's not *quite* true: it causes the module in question to
+ // be loaded, which can affect downstream diagnostics.
+ break;
+
+ default:
+ llvm_unreachable("unknown include directive kind");
+ break;
}
}
}
+/// Handle entering the scope of a module during a module compilation.
+void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {
+ startNewLineIfNeeded();
+ OS << "#pragma clang module begin " << M->getFullModuleName(true);
+ setEmittedDirectiveOnThisLine();
+}
+
+/// Handle leaving the scope of a module during a module compilation.
+void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
+ startNewLineIfNeeded();
+ OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";
+ setEmittedDirectiveOnThisLine();
+}
+
/// Ident - Handle #ident directives when read by the preprocessor.
///
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
@@ -389,7 +414,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
@@ -676,13 +702,27 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
SourceLocation StartLoc = Tok.getLocation();
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
- } else if (Tok.is(tok::annot_module_include) ||
- Tok.is(tok::annot_module_begin) ||
- Tok.is(tok::annot_module_end)) {
+ } else if (Tok.is(tok::annot_module_include)) {
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
// appropriate output here. Ignore this token entirely.
PP.Lex(Tok);
continue;
+ } else if (Tok.is(tok::annot_module_begin)) {
+ // FIXME: We retrieve this token after the FileChanged callback, and
+ // retrieve the module_end token before the FileChanged callback, so
+ // we render this within the file and render the module end outside the
+ // file, but this is backwards from the token locations: the module_begin
+ // token is at the include location (outside the file) and the module_end
+ // token is at the EOF location (within the file).
+ Callbacks->BeginModule(
+ reinterpret_cast<Module *>(Tok.getAnnotationValue()));
+ PP.Lex(Tok);
+ continue;
+ } else if (Tok.is(tok::annot_module_end)) {
+ Callbacks->EndModule(
+ reinterpret_cast<Module *>(Tok.getAnnotationValue()));
+ PP.Lex(Tok);
+ continue;
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
@@ -773,26 +813,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Expand macros in pragmas with -fms-extensions. The assumption is that
// the majority of pragmas in such a file will be Microsoft pragmas.
- PP.AddPragmaHandler(new UnknownPragmaHandler(
- "#pragma", Callbacks,
+ // Remember the handlers we will add so that we can remove them later.
+ std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
+ new UnknownPragmaHandler(
+ "#pragma", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler(
+ "#pragma GCC", Callbacks,
/*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "GCC", new UnknownPragmaHandler(
- "#pragma GCC", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "clang", new UnknownPragmaHandler(
- "#pragma clang", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler(
+ "#pragma clang", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ PP.AddPragmaHandler(MicrosoftExtHandler.get());
+ PP.AddPragmaHandler("GCC", GCCHandler.get());
+ PP.AddPragmaHandler("clang", ClangHandler.get());
// The tokens after pragma omp need to be expanded.
//
// OpenMP [2.1, Directive format]
// Preprocessing tokens following the #pragma omp are subject to macro
// replacement.
- PP.AddPragmaHandler("omp",
- new UnknownPragmaHandler("#pragma omp", Callbacks,
- /*RequireTokenExpansion=*/true));
+ std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
+ new UnknownPragmaHandler("#pragma omp", Callbacks,
+ /*RequireTokenExpansion=*/true));
+ PP.AddPragmaHandler("omp", OpenMPHandler.get());
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
@@ -820,4 +867,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Read all the preprocessed tokens, printing them out to the stream.
PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
*OS << '\n';
+
+ // Remove the handlers we just added to leave the preprocessor in a sane state
+ // so that it can be reused (for example by a clang::Parser instance).
+ PP.RemovePragmaHandler(MicrosoftExtHandler.get());
+ PP.RemovePragmaHandler("GCC", GCCHandler.get());
+ PP.RemovePragmaHandler("clang", ClangHandler.get());
+ PP.RemovePragmaHandler("omp", OpenMPHandler.get());
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index 2e76e2e..5efa6ae 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -9,6 +9,8 @@
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -18,6 +20,11 @@
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -86,8 +93,7 @@ public:
};
} // end anonymous namespace
-bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
if (!FEOpts.FixItSuffix.empty()) {
FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
@@ -190,12 +196,123 @@ void RewriteTestAction::ExecuteAction() {
DoRewriteTest(CI.getPreprocessor(), OS.get());
}
+class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
+ CompilerInstance &CI;
+ std::weak_ptr<raw_ostream> Out;
+
+ llvm::DenseSet<const FileEntry*> Rewritten;
+
+public:
+ RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
+ : CI(CI), Out(Out) {}
+
+ void visitModuleFile(StringRef Filename,
+ serialization::ModuleKind Kind) override {
+ auto *File = CI.getFileManager().getFile(Filename);
+ assert(File && "missing file for loaded module?");
+
+ // Only rewrite each module file once.
+ if (!Rewritten.insert(File).second)
+ return;
+
+ serialization::ModuleFile *MF =
+ CI.getModuleManager()->getModuleManager().lookup(File);
+ assert(File && "missing module file for loaded module?");
+
+ // Not interested in PCH / preambles.
+ if (!MF->isModule())
+ return;
+
+ auto OS = Out.lock();
+ assert(OS && "loaded module file after finishing rewrite action?");
+
+ (*OS) << "#pragma clang module build ";
+ if (isValidIdentifier(MF->ModuleName))
+ (*OS) << MF->ModuleName;
+ else {
+ (*OS) << '"';
+ OS->write_escaped(MF->ModuleName);
+ (*OS) << '"';
+ }
+ (*OS) << '\n';
+
+ // Rewrite the contents of the module in a separate compiler instance.
+ CompilerInstance Instance(CI.getPCHContainerOperations(),
+ &CI.getPreprocessor().getPCMCache());
+ Instance.setInvocation(
+ std::make_shared<CompilerInvocation>(CI.getInvocation()));
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+ Instance.getFrontendOpts().DisableFree = false;
+ Instance.getFrontendOpts().Inputs.clear();
+ Instance.getFrontendOpts().Inputs.emplace_back(
+ Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
+ Instance.getFrontendOpts().ModuleFiles.clear();
+ Instance.getFrontendOpts().ModuleMapFiles.clear();
+ // Don't recursively rewrite imports. We handle them all at the top level.
+ Instance.getPreprocessorOutputOpts().RewriteImports = false;
+
+ llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
+ RewriteIncludesAction Action;
+ Action.OutputStream = OS;
+ Instance.ExecuteAction(Action);
+ });
+
+ (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
+ }
+};
+
+bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
+ if (!OutputStream) {
+ OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OutputStream)
+ return false;
+ }
+
+ auto &OS = *OutputStream;
+
+ // If we're preprocessing a module map, start by dumping the contents of the
+ // module itself before switching to the input buffer.
+ auto &Input = getCurrentInput();
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ if (Input.isFile()) {
+ OS << "# 1 \"";
+ OS.write_escaped(Input.getFile());
+ OS << "\"\n";
+ }
+ getCurrentModule()->print(OS);
+ OS << "#pragma clang module contents\n";
+ }
+
+ // If we're rewriting imports, set up a listener to track when we import
+ // module files.
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ CI.createModuleManager();
+ CI.getModuleManager()->addListener(
+ llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
+ }
+
+ return true;
+}
+
void RewriteIncludesAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- std::unique_ptr<raw_ostream> OS =
- CI.createDefaultOutputFile(true, getCurrentFile());
- if (!OS) return;
- RewriteIncludesInInput(CI.getPreprocessor(), OS.get(),
- CI.getPreprocessorOutputOpts());
+ // If we're rewriting imports, emit the module build output first rather
+ // than switching back and forth (potentially in the middle of a line).
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ RewriteIncludesInInput(CI.getPreprocessor(), &OS,
+ CI.getPreprocessorOutputOpts());
+
+ (*OutputStream) << OS.str();
+ } else {
+ RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
+ CI.getPreprocessorOutputOpts());
+ }
+
+ OutputStream.reset();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
index d953da2..e047706 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -46,17 +46,24 @@ class InclusionRewriter : public PPCallbacks {
std::map<unsigned, IncludedFile> FileIncludes;
/// Tracks where inclusions that import modules are found.
std::map<unsigned, const Module *> ModuleIncludes;
+ /// Tracks where inclusions that enter modules (in a module build) are found.
+ std::map<unsigned, const Module *> ModuleEntryIncludes;
/// Used transitively for building up the FileIncludes mapping over the
/// various \c PPCallbacks callbacks.
SourceLocation LastInclusionLocation;
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers,
bool UseLineDirectives);
- bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
+ void Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
PredefinesBuffer = Buf;
}
void detectMainFileEOL();
+ void handleModuleBegin(Token &Tok) {
+ assert(Tok.getKind() == tok::annot_module_begin);
+ ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(),
+ (Module *)Tok.getAnnotationValue()});
+ }
private:
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -84,6 +91,7 @@ private:
bool &FileExists);
const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const;
const Module *FindModuleAtLocation(SourceLocation Loc) const;
+ const Module *FindEnteredModule(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
};
@@ -132,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line,
}
void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
- OS << "@import " << Mod->getFullModuleName() << ";"
+ OS << "#pragma clang module import " << Mod->getFullModuleName(true)
<< " /* clang -frewrite-includes: implicit import */" << MainEOL;
}
@@ -169,7 +177,9 @@ void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/,
/// directives. It does not say whether the file has been included, but it
/// provides more information about the directive (hash location instead
/// of location inside the included file). It is assumed that the matching
-/// FileChanged() or FileSkipped() is called after this.
+/// FileChanged() or FileSkipped() is called after this (or neither is
+/// called if this #include results in an error or does not textually include
+/// anything).
void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
const Token &/*IncludeTok*/,
StringRef /*FileName*/,
@@ -179,9 +189,6 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
StringRef /*SearchPath*/,
StringRef /*RelativePath*/,
const Module *Imported) {
- assert(LastInclusionLocation.isInvalid() &&
- "Another inclusion directive was found before the previous one "
- "was processed");
if (Imported) {
auto P = ModuleIncludes.insert(
std::make_pair(HashLoc.getRawEncoding(), Imported));
@@ -211,6 +218,16 @@ InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const {
return nullptr;
}
+/// Simple lookup for a SourceLocation (specifically one denoting the hash in
+/// an inclusion directive) in the map of module entry information.
+const Module *
+InclusionRewriter::FindEnteredModule(SourceLocation Loc) const {
+ const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding());
+ if (I != ModuleEntryIncludes.end())
+ return I->second;
+ return nullptr;
+}
+
/// Detect the likely line ending style of \p FromFile by examining the first
/// newline found within it.
static StringRef DetectEOL(const MemoryBuffer &FromFile) {
@@ -392,7 +409,7 @@ bool InclusionRewriter::HandleHasInclude(
// FIXME: Why don't we call PP.LookupFile here?
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
- nullptr, nullptr, nullptr, false);
+ nullptr, nullptr, nullptr, nullptr);
FileExists = File != nullptr;
return true;
@@ -400,9 +417,8 @@ bool InclusionRewriter::HandleHasInclude(
/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
-bool InclusionRewriter::Process(FileID FileId,
- SrcMgr::CharacteristicKind FileType)
-{
+void InclusionRewriter::Process(FileID FileId,
+ SrcMgr::CharacteristicKind FileType) {
bool Invalid;
const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid);
assert(!Invalid && "Attempting to process invalid inclusion");
@@ -419,7 +435,7 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, 1, FileType, " 1");
if (SM.getFileIDSize(FileId) == 0)
- return false;
+ return;
// The next byte to be copied from the source file, which may be non-zero if
// the lexer handled a BOM.
@@ -450,19 +466,24 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, Line - 1, FileType, "");
StringRef LineInfoExtra;
SourceLocation Loc = HashToken.getLocation();
- if (const Module *Mod = PP.getLangOpts().ObjC2
- ? FindModuleAtLocation(Loc)
- : nullptr)
+ if (const Module *Mod = FindModuleAtLocation(Loc))
WriteImplicitModuleImport(Mod);
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
- // include and recursively process the file
- if (Process(Inc->Id, Inc->FileType)) {
- // and set lineinfo back to this file, if the nested one was
- // actually included
- // `2' indicates returning to a file (after having included
- // another file.
- LineInfoExtra = " 2";
- }
+ const Module *Mod = FindEnteredModule(Loc);
+ if (Mod)
+ OS << "#pragma clang module begin "
+ << Mod->getFullModuleName(true) << "\n";
+
+ // Include and recursively process the file.
+ Process(Inc->Id, Inc->FileType);
+
+ if (Mod)
+ OS << "#pragma clang module end /*"
+ << Mod->getFullModuleName(true) << "*/\n";
+
+ // Add line marker to indicate we're returning from an included
+ // file.
+ LineInfoExtra = " 2";
}
// fix up lineinfo (since commented out directive changed line
// numbers) for inclusions that were skipped due to header guards
@@ -571,7 +592,6 @@ bool InclusionRewriter::Process(FileID FileId,
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL,
Line, /*EnsureNewline=*/true);
- return true;
}
/// InclusionRewriterInInput - Implement -frewrite-includes mode.
@@ -597,6 +617,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
PP.SetMacroExpansionOnlyInDirectives();
do {
PP.Lex(Tok);
+ if (Tok.is(tok::annot_module_begin))
+ Rewrite->handleModuleBegin(Tok);
} while (Tok.isNot(tok::eof));
Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
index 0d0a991..ae6b51b 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
@@ -76,7 +76,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
RawLex.LexFromRawLexer(RawTok);
// If we have an identifier with no identifier info for our raw token, look
- // up the indentifier info. This is important for equality comparison of
+ // up the identifier info. This is important for equality comparison of
// identifier tokens.
if (RawTok.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawTok);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index e7bfced..21686b8 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -146,7 +147,7 @@ namespace {
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
llvm::DenseMap<ObjCInterfaceDecl *,
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars;
// ivar bitfield grouping containers
llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
@@ -1013,7 +1014,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Setr = "\nextern \"C\" __declspec(dllimport) "
"void objc_setProperty (id, SEL, long, id, bool, bool);\n";
}
-
+
RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getSetterMethodDecl(), Setr);
Setr += "{ ";
@@ -3965,10 +3966,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
std::string &Result) {
// write out ivar offset symbols which have been referenced in an ivar
// access expression.
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+
if (Ivars.empty())
return;
-
+
llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (ObjCIvarDecl *IvarDecl : Ivars) {
const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
@@ -4454,7 +4456,7 @@ static void BuildUniqueMethodName(std::string &Name,
Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = Name.find(":", loc)) != std::string::npos)
+ while ((loc = Name.find(':', loc)) != std::string::npos)
Name.replace(loc, 1, "_");
}
@@ -5141,7 +5143,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
if (!hasInit) {
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -6068,7 +6070,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
@@ -7500,7 +7502,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BinaryOperator *addExpr =
new (Context) BinaryOperator(castExpr, DRE, BO_Add,
Context->getPointerType(Context->CharTy),
- VK_RValue, OK_Ordinary, SourceLocation(), false);
+ VK_RValue, OK_Ordinary, SourceLocation(), FPOptions());
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
SourceLocation(),
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
index e842e59..e0d813d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -2992,7 +2993,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
VK_RValue, OK_Ordinary, SourceLocation(),
- false);
+ FPOptions());
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3629,7 +3630,7 @@ static void BuildUniqueMethodName(std::string &Name,
Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = Name.find(":", loc)) != std::string::npos)
+ while ((loc = Name.find(':', loc)) != std::string::npos)
Name.replace(loc, 1, "_");
}
@@ -4261,7 +4262,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
}
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -5052,7 +5053,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 7f88c91..7666fe1 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -63,27 +63,20 @@ public:
~SDiagsRenderer() override {}
protected:
- void emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override;
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override {}
+ ArrayRef<CharSourceRange> Ranges) override {}
- void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) override;
+ void emitNote(FullSourceLoc Loc, StringRef Message) override;
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override;
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override;
void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) override;
@@ -193,11 +186,8 @@ private:
void ExitDiagBlock();
/// \brief Emit a DIAG record.
- void EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- const SourceManager *SM,
+ void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
DiagOrStoredDiag D);
/// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
@@ -220,16 +210,14 @@ private:
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(const char *Filename);
- /// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
- PresumedLoc PLoc, RecordDataImpl &Record,
- unsigned TokSize = 0);
+ /// \brief Add SourceLocation information the specified record.
+ void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize = 0);
/// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
- const SourceManager *SM,
+ void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record,
unsigned TokSize = 0) {
- AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
+ AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(),
Record, TokSize);
}
@@ -350,11 +338,8 @@ static void EmitRecordID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
}
-void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
- const SourceManager *SM,
- PresumedLoc PLoc,
- RecordDataImpl &Record,
- unsigned TokSize) {
+void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize) {
if (PLoc.isInvalid()) {
// Emit a "sentinel" location.
Record.push_back((unsigned)0); // File.
@@ -367,19 +352,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Record.push_back(getEmitFile(PLoc.getFilename()));
Record.push_back(PLoc.getLine());
Record.push_back(PLoc.getColumn()+TokSize);
- Record.push_back(SM->getFileOffset(Loc));
+ Record.push_back(Loc.getFileOffset());
}
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
RecordDataImpl &Record,
const SourceManager &SM) {
- AddLocToRecord(Range.getBegin(), Record, &SM);
+ AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record);
unsigned TokSize = 0;
if (Range.isTokenRange())
TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
SM, *LangOpts);
-
- AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
+
+ AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize);
}
unsigned SDiagsWriter::getEmitFile(const char *FileName){
@@ -506,7 +491,7 @@ void SDiagsWriter::EmitBlockInfoBlock() {
Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
@@ -606,8 +591,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
if (DiagLevel == DiagnosticsEngine::Note)
EnterDiagBlock();
- EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- State->diagBuf, nullptr, &Info);
+ EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
+ State->diagBuf, &Info);
if (DiagLevel == DiagnosticsEngine::Note)
ExitDiagBlock();
@@ -618,12 +603,9 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
assert(Info.hasSourceManager() && LangOpts &&
"Unexpected diagnostic with valid location outside of a source file");
SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
- Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- State->diagBuf,
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager(),
- &Info);
+ Renderer.emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
+ State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
}
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
@@ -641,11 +623,9 @@ static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
llvm_unreachable("invalid diagnostic level");
}
-void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
+void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
- const SourceManager *SM,
DiagOrStoredDiag D) {
llvm::BitstreamWriter &Stream = State->Stream;
RecordData &Record = State->Record;
@@ -655,7 +635,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(getStableLevel(Level));
- AddLocToRecord(Loc, SM, PLoc, Record);
+ AddLocToRecord(Loc, PLoc, Record);
if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
// Emit the category string lazily and get the category ID.
@@ -672,15 +652,11 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
}
-void
-SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
- Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
+void SDiagsRenderer::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
}
void SDiagsWriter::EnterDiagBlock() {
@@ -733,20 +709,18 @@ void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
}
}
-void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange> &Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
- Writer.EmitCodeContext(Ranges, Hints, SM);
+ ArrayRef<FixItHint> Hints) {
+ Writer.EmitCodeContext(Ranges, Hints, Loc.getManager());
}
-void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) {
+void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
Writer.EnterDiagBlock();
- PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
- Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
- Message, SM, DiagOrStoredDiag());
+ PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc();
+ Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message,
+ DiagOrStoredDiag());
Writer.ExitDiagBlock();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
index c4461d4..08b7087 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
@@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
llvm::BitstreamCursor Stream(**Buffer);
Optional<llvm::BitstreamBlockInfo> BlockInfo;
+ if (Stream.AtEndOfStream())
+ return SDError::InvalidSignature;
+
// Sniff for the signature.
if (Stream.Read(8) != 'D' ||
Stream.Read(8) != 'I' ||
@@ -125,6 +128,7 @@ SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
case Cursor::BlockBegin:
if (Stream.SkipBlock())
return SDError::MalformedMetadataBlock;
+ LLVM_FALLTHROUGH;
case Cursor::BlockEnd:
if (!VersionChecked)
return SDError::MissingVersion;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
index a493738..6a72b00 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
@@ -672,20 +672,16 @@ TextDiagnostic::TextDiagnostic(raw_ostream &OS,
TextDiagnostic::~TextDiagnostic() {}
-void
-TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
+void TextDiagnostic::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
uint64_t StartOfLocationInfo = OS.tell();
// Emit the location of this particular diagnostic.
if (Loc.isValid())
- emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
-
+ emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
+
if (DiagOpts->ShowColors)
OS.resetColor();
@@ -787,17 +783,16 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
/// This includes extracting as much location information as is present for
/// the diagnostic and printing it, as well as any include stack or source
/// ranges necessary.
-void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ ArrayRef<CharSourceRange> Ranges) {
if (PLoc.isInvalid()) {
// At least print the file name if available:
- FileID FID = SM.getFileID(Loc);
+ FileID FID = Loc.getFileID();
if (FID.isValid()) {
- const FileEntry* FE = SM.getFileEntryForID(FID);
+ const FileEntry *FE = Loc.getFileEntry();
if (FE && FE->isValid()) {
- emitFilename(FE->getName(), SM);
+ emitFilename(FE->getName(), Loc.getManager());
if (FE->isInPCH())
OS << " (in PCH)";
OS << ": ";
@@ -813,7 +808,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- emitFilename(PLoc.getFilename(), SM);
+ emitFilename(PLoc.getFilename(), Loc.getManager());
switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
@@ -848,8 +843,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
}
if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
- FileID CaretFileID =
- SM.getFileID(SM.getExpansionLoc(Loc));
+ FileID CaretFileID = Loc.getExpansionLoc().getFileID();
bool PrintedRange = false;
for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
@@ -858,8 +852,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// Ignore invalid ranges.
if (!RI->isValid()) continue;
- SourceLocation B = SM.getExpansionLoc(RI->getBegin());
- SourceLocation E = SM.getExpansionLoc(RI->getEnd());
+ FullSourceLoc B =
+ FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc();
+ FullSourceLoc E =
+ FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc();
// If the End location and the start location are the same and are a
// macro location, then the range was something that came from a
@@ -867,10 +863,12 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// best we can do is to highlight the range. If this is a
// function-like macro, we'd also like to highlight the arguments.
if (B == E && RI->getEnd().isMacroID())
- E = SM.getExpansionRange(RI->getEnd()).second;
+ E = FullSourceLoc(RI->getEnd(), Loc.getManager())
+ .getExpansionRange()
+ .second;
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+ std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc();
+ std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc();
// If the start or end of the range is in another file, just discard
// it.
@@ -881,13 +879,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// tokens.
unsigned TokSize = 0;
if (RI->isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+ TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts);
- OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
- << '}';
+ OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-'
+ << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}';
PrintedRange = true;
}
@@ -897,9 +892,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
OS << ' ';
}
-void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":\n";
@@ -907,9 +900,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
-void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -917,10 +909,9 @@ void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
OS << "In module '" << ModuleName << "':\n";
}
-void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
+void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "While building module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -928,6 +919,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
OS << "While building module '" << ModuleName << "':\n";
}
+/// \brief Find the suitable set of lines to show to include a set of ranges.
+static llvm::Optional<std::pair<unsigned, unsigned>>
+findLinesForRange(const CharSourceRange &R, FileID FID,
+ const SourceManager &SM) {
+ if (!R.isValid()) return None;
+
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+ if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
+ return None;
+
+ return std::make_pair(SM.getExpansionLineNumber(Begin),
+ SM.getExpansionLineNumber(End));
+}
+
+/// Add as much of range B into range A as possible without exceeding a maximum
+/// size of MaxRange. Ranges are inclusive.
+static std::pair<unsigned, unsigned>
+maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
+ unsigned MaxRange) {
+ // If A is already the maximum size, we're done.
+ unsigned Slack = MaxRange - (A.second - A.first + 1);
+ if (Slack == 0)
+ return A;
+
+ // Easy case: merge succeeds within MaxRange.
+ unsigned Min = std::min(A.first, B.first);
+ unsigned Max = std::max(A.second, B.second);
+ if (Max - Min + 1 <= MaxRange)
+ return {Min, Max};
+
+ // If we can't reach B from A within MaxRange, there's nothing to do.
+ // Don't add lines to the range that contain nothing interesting.
+ if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
+ (B.second < A.second && A.second - B.second + 1 > MaxRange))
+ return A;
+
+ // Otherwise, expand A towards B to produce a range of size MaxRange. We
+ // attempt to expand by the same amount in both directions if B strictly
+ // contains A.
+
+ // Expand downwards by up to half the available amount, then upwards as
+ // much as possible, then downwards as much as possible.
+ A.second = std::min(A.second + (Slack + 1) / 2, Max);
+ Slack = MaxRange - (A.second - A.first + 1);
+ A.first = std::max(Min + Slack, A.first) - Slack;
+ A.second = std::min(A.first + MaxRange - 1, Max);
+ return A;
+}
+
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
static void highlightRange(const CharSourceRange &R,
unsigned LineNo, FileID FID,
@@ -990,9 +1031,12 @@ static void highlightRange(const CharSourceRange &R,
EndColNo = map.startOfPreviousColumn(EndColNo);
// If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ // range that just exists in whitespace. That most likely means we have
+ // a multi-line highlighting range that covers a blank line.
+ if (StartColNo > EndColNo) {
+ assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
+ StartColNo = EndColNo;
+ }
}
assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
@@ -1008,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R,
std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
}
-static std::string buildFixItInsertionLine(unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID,
+ unsigned LineNo,
const SourceColumnMap &map,
ArrayRef<FixItHint> Hints,
const SourceManager &SM,
@@ -1025,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
// code contains no newlines and is on the same line as the caret.
std::pair<FileID, unsigned> HintLocInfo
= SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
+ if (FID == HintLocInfo.first &&
+ LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
// Insert the new code into the line just below the code
// that the user wrote.
@@ -1061,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
PrevHintEndCol =
HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
- } else {
- FixItInsertionLine.clear();
- break;
}
}
}
@@ -1081,10 +1124,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
void TextDiagnostic::emitSnippetAndCaret(
- SourceLocation Loc, DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
assert(Loc.isFileID() && "must have a file location here");
@@ -1101,111 +1142,128 @@ void TextDiagnostic::emitSnippetAndCaret(
return;
// Decompose the location into a FID/Offset pair.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
+ const SourceManager &SM = Loc.getManager();
// Get information about the buffer it points into.
bool Invalid = false;
- StringRef BufData = SM.getBufferData(FID, &Invalid);
+ StringRef BufData = Loc.getBufferData(&Invalid);
if (Invalid)
return;
- const char *BufStart = BufData.data();
- const char *BufEnd = BufStart + BufData.size();
+ unsigned CaretLineNo = Loc.getLineNumber();
+ unsigned CaretColNo = Loc.getColumnNumber();
- unsigned LineNo = SM.getLineNumber(FID, FileOffset);
- unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
-
// Arbitrarily stop showing snippets when the line is too long.
static const size_t MaxLineLengthToPrint = 4096;
- if (ColNo > MaxLineLengthToPrint)
+ if (CaretColNo > MaxLineLengthToPrint)
return;
- // Rewind from the current position to the start of the line.
- const char *TokPtr = BufStart+FileOffset;
- const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
- // Compute the line end. Scan forward from the error position to the end of
- // the line.
- const char *LineEnd = TokPtr;
- while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
- ++LineEnd;
-
- // Arbitrarily stop showing snippets when the line is too long.
- if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
- return;
-
- // Trim trailing null-bytes.
- StringRef Line(LineStart, LineEnd - LineStart);
- while (Line.size() > ColNo && Line.back() == '\0')
- Line = Line.drop_back();
+ // Find the set of lines to include.
+ const unsigned MaxLines = DiagOpts->SnippetLineLimit;
+ std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ if (auto OptionalRange = findLinesForRange(*I, FID, SM))
+ Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
+
+ for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
+ const char *BufStart = BufData.data();
+ const char *BufEnd = BufStart + BufData.size();
+
+ // Rewind from the current position to the start of the line.
+ const char *LineStart =
+ BufStart +
+ SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
+ if (LineStart == BufEnd)
+ break;
- // Copy the line of code into an std::string for ease of manipulation.
- std::string SourceLine(Line.begin(), Line.end());
+ // Compute the line end.
+ const char *LineEnd = LineStart;
+ while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
+ ++LineEnd;
- // Build the byte to column map.
- const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+ // Arbitrarily stop showing snippets when the line is too long.
+ // FIXME: Don't print any lines in this case.
+ if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
+ return;
- // Create a line for the caret that is filled with spaces that is the same
- // number of columns as the line of source code.
- std::string CaretLine(sourceColMap.columns(), ' ');
+ // Trim trailing null-bytes.
+ StringRef Line(LineStart, LineEnd - LineStart);
+ while (!Line.empty() && Line.back() == '\0' &&
+ (LineNo != CaretLineNo || Line.size() > CaretColNo))
+ Line = Line.drop_back();
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(Line.begin(), Line.end());
+
+ // Build the byte to column map.
+ const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // number of columns as the line of source code.
+ std::string CaretLine(sourceColMap.columns(), ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
+
+ // Next, insert the caret itself.
+ if (CaretLineNo == LineNo) {
+ CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
+ if (CaretLine.size() < CaretColNo + 1)
+ CaretLine.resize(CaretColNo + 1, ' ');
+ CaretLine[CaretColNo] = '^';
+ }
- // Highlight all of the characters covered by Ranges with ~ characters.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
-
- // Next, insert the caret itself.
- ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
- if (CaretLine.size()<ColNo+1)
- CaretLine.resize(ColNo+1, ' ');
- CaretLine[ColNo] = '^';
-
- std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
- sourceColMap,
- Hints, SM,
- DiagOpts.get());
-
- // If the source line is too long for our terminal, select only the
- // "interesting" source region within that line.
- unsigned Columns = DiagOpts->MessageLength;
- if (Columns)
- selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
- Columns, sourceColMap);
-
- // If we are in -fdiagnostics-print-source-range-info mode, we are trying
- // to produce easily machine parsable output. Add a space before the
- // source line and the caret to make it trivial to tell the main diagnostic
- // line from what the user is intended to see.
- if (DiagOpts->ShowSourceRanges) {
- SourceLine = ' ' + SourceLine;
- CaretLine = ' ' + CaretLine;
- }
+ std::string FixItInsertionLine = buildFixItInsertionLine(
+ FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
+
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ unsigned Columns = DiagOpts->MessageLength;
+ if (Columns)
+ selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
+ Columns, sourceColMap);
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying
+ // to produce easily machine parsable output. Add a space before the
+ // source line and the caret to make it trivial to tell the main diagnostic
+ // line from what the user is intended to see.
+ if (DiagOpts->ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
- // Finally, remove any blank spaces from the end of CaretLine.
- while (CaretLine[CaretLine.size()-1] == ' ')
- CaretLine.erase(CaretLine.end()-1);
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
+ CaretLine.erase(CaretLine.end() - 1);
- // Emit what we have computed.
- emitSnippet(SourceLine);
+ // Emit what we have computed.
+ emitSnippet(SourceLine);
- if (DiagOpts->ShowColors)
- OS.changeColor(caretColor, true);
- OS << CaretLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!CaretLine.empty()) {
+ if (DiagOpts->ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
- if (!FixItInsertionLine.empty()) {
- if (DiagOpts->ShowColors)
- // Print fixit line in color
- OS.changeColor(fixitColor, false);
- if (DiagOpts->ShowSourceRanges)
- OS << ' ';
- OS << FixItInsertionLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts->ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts->ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
}
// Print out any parseable fixit information requested by the options.
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 17646b4..5dd3252 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -150,10 +150,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
"Unexpected diagnostic with no source manager");
assert(TextDiag && "Unexpected diagnostic outside source file processing");
- TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager());
+ TextDiag->emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
+ DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
OS.flush();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index ae16ea1..427d15e 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
const DirectoryLookup *CurDir;
const FileEntry *FE =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
OpenPOWER on IntegriCloud