diff options
author | dim <dim@FreeBSD.org> | 2017-09-26 19:56:36 +0000 |
---|---|---|
committer | Luiz Souza <luiz@netgate.com> | 2018-02-21 15:12:19 -0300 |
commit | 1dcd2e8d24b295bc73e513acec2ed1514bb66be4 (patch) | |
tree | 4bd13a34c251e980e1a6b13584ca1f63b0dfe670 /contrib/llvm/tools/clang/lib/Frontend | |
parent | f45541ca2a56a1ba1202f94c080b04e96c1fa239 (diff) | |
download | FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.zip FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.tar.gz |
Merge clang, llvm, lld, lldb, compiler-rt and libc++ 5.0.0 release.
MFC r309126 (by emaste):
Correct lld llvm-tblgen dependency file name
MFC r309169:
Get rid of separate Subversion mergeinfo properties for llvm-dwarfdump
and llvm-lto. The mergeinfo confuses Subversion enormously, and these
directories will just use the mergeinfo for llvm itself.
MFC r312765:
Pull in r276136 from upstream llvm trunk (by Wei Mi):
Use ValueOffsetPair to enhance value reuse during SCEV expansion.
In D12090, the ExprValueMap was added to reuse existing value during
SCEV expansion. However, const folding and sext/zext distribution can
make the reuse still difficult.
A simplified case is: suppose we know S1 expands to V1 in
ExprValueMap, and
S1 = S2 + C_a
S3 = S2 + C_b
where C_a and C_b are different SCEVConstants. Then we'd like to
expand S3 as V1 - C_a + C_b instead of expanding S2 literally. It is
helpful when S2 is a complex SCEV expr and S2 has no entry in
ExprValueMap, which is usually caused by the fact that S3 is
generated from S1 after const folding.
In order to do that, we represent ExprValueMap as a mapping from SCEV
to ValueOffsetPair. We will save both S1->{V1, 0} and S2->{V1, C_a}
into the ExprValueMap when we create SCEV for V1. When S3 is
expanded, it will first expand S2 to V1 - C_a because of S2->{V1,
C_a} in the map, then expand S3 to V1 - C_a + C_b.
Differential Revision: https://reviews.llvm.org/D21313
This should fix assertion failures when building OpenCV >= 3.1.
PR: 215649
MFC r312831:
Revert r312765 for now, since it causes assertions when building
lang/spidermonkey24.
Reported by: antoine
PR: 215649
MFC r316511 (by jhb):
Add an implementation of __ffssi2() derived from __ffsdi2().
Newer versions of GCC include an __ffssi2() symbol in libgcc and the
compiler can emit calls to it in generated code. This is true for at
least GCC 6.2 when compiling world for mips and mips64.
Reviewed by: jmallett, dim
Sponsored by: DARPA / AFRL
Differential Revision: https://reviews.freebsd.org/D10086
MFC r318601 (by adrian):
[libcompiler-rt] add bswapdi2/bswapsi2
This is required for mips gcc 6.3 userland to build/run.
Reviewed by: emaste, dim
Approved by: emaste
Differential Revision: https://reviews.freebsd.org/D10838
MFC r318884 (by emaste):
lldb: map TRAP_CAP to a trace trap
In the absense of a more specific handler for TRAP_CAP (generated by
ENOTCAPABLE or ECAPMODE while in capability mode) treat it as a trace
trap.
Example usage (testing the bug in PR219173):
% proccontrol -m trapcap lldb usr.bin/hexdump/obj/hexdump -- -Cv -s 1 /bin/ls
...
(lldb) run
Process 12980 launching
Process 12980 launched: '.../usr.bin/hexdump/obj/hexdump' (x86_64)
Process 12980 stopped
* thread #1, stop reason = trace
frame #0: 0x0000004b80c65f1a libc.so.7`__sys_lseek + 10
...
In the future we should have LLDB control the trapcap procctl itself
(as it does with ASLR), as well as report a specific stop reason.
This change eliminates an assertion failure from LLDB for now.
MFC r319796:
Remove a few unneeded files from libllvm, libclang and liblldb.
MFC r319885 (by emaste):
lld: ELF: Fix ICF crash on absolute symbol relocations.
If two sections contained relocations to absolute symbols with the same
value we would crash when trying to access their sections. Add a check that
both symbols point to sections before accessing their sections, and treat
absolute symbols as equal if their values are equal.
Obtained from: LLD commit r292578
MFC r319918:
Revert r319796 for now, it can cause undefined references when linking
in some circumstances.
Reported by: Shawn Webb <shawn.webb@hardenedbsd.org>
MFC r319957 (by emaste):
lld: Add armelf emulation mode
Obtained from: LLD r305375
MFC r321369:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 (trunk r308421). Upstream has branched for the 5.0.0 release,
which should be in about a month. Please report bugs and regressions,
so we can get them into the release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
MFC r321420:
Add a few more object files to liblldb, which should solve errors when
linking the lldb executable in some cases. In particular, when the
-ffunction-sections -fdata-sections options are turned off, or
ineffective.
Reported by: Shawn Webb, Mark Millard
MFC r321433:
Cleanup stale Options.inc files from the previous libllvm build for
clang 4.0.0. Otherwise, these can get included before the two newly
generated ones (which are different) for clang 5.0.0.
Reported by: Mark Millard
MFC r321439 (by bdrewery):
Move llvm Options.inc hack from r321433 for NO_CLEAN to lib/clang/libllvm.
The files are only ever generated to .OBJDIR, not to WORLDTMP (as a
sysroot) and are only ever included from a compilation. So using
a beforebuild target here removes the file before the compilation
tries to include it.
MFC r321664:
Pull in r308891 from upstream llvm trunk (by Benjamin Kramer):
[CodeGenPrepare] Cut off FindAllMemoryUses if there are too many uses.
This avoids excessive compile time. The case I'm looking at is
Function.cpp from an old version of LLVM that still had the giant
memcmp string matcher in it. Before r308322 this compiled in about 2
minutes, after it, clang takes infinite* time to compile it. With
this patch we're at 5 min, which is still bad but this is a
pathological case.
The cut off at 20 uses was chosen by looking at other cut-offs in LLVM
for user scanning. It's probably too high, but does the job and is
very unlikely to regress anything.
Fixes PR33900.
* I'm impatient and aborted after 15 minutes, on the bug report it was
killed after 2h.
Pull in r308986 from upstream llvm trunk (by Simon Pilgrim):
[X86][CGP] Reduce memcmp() expansion to 2 load pairs (PR33914)
D35067/rL308322 attempted to support up to 4 load pairs for memcmp
inlining which resulted in regressions for some optimized libc memcmp
implementations (PR33914).
Until we can match these more optimal cases, this patch reduces the
memcmp expansion to a maximum of 2 load pairs (which matches what we
do for -Os).
This patch should be considered for the 5.0.0 release branch as well
Differential Revision: https://reviews.llvm.org/D35830
These fix a hang (or extremely long compile time) when building older
LLVM ports.
Reported by: antoine
PR: 219139
MFC r321719:
Pull in r309503 from upstream clang trunk (by Richard Smith):
PR33902: Invalidate line number cache when adding more text to
existing buffer.
This led to crashes as the line number cache would report a bogus
line number for a line of code, and we'd try to find a nonexistent
column within the line when printing diagnostics.
This fixes an assertion when building the graphics/champlain port.
Reported by: antoine, kwm
PR: 219139
MFC r321723:
Upgrade our copies of clang, llvm, lld and lldb to r309439 from the
upstream release_50 branch. This is just after upstream's 5.0.0-rc1.
MFC r322320:
Upgrade our copies of clang, llvm and libc++ to r310316 from the
upstream release_50 branch.
MFC r322326 (by emaste):
lldb: Make i386-*-freebsd expression work on JIT path
* Enable i386 ABI creation for freebsd
* Added an extra argument in ABISysV_i386::PrepareTrivialCall for mmap
syscall
* Unlike linux, the last argument of mmap is actually 64-bit(off_t).
This requires us to push an additional word for the higher order bits.
* Prior to this change, ktrace dump will show mmap failures due to
invalid argument coming from the 6th mmap argument.
Submitted by: Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D34776
MFC r322360 (by emaste):
lldb: Report inferior signals as signals, not exceptions, on FreeBSD
This is the FreeBSD equivalent of LLVM r238549.
This serves 2 purposes:
* LLDB should handle inferior process signals SIGSEGV/SIGILL/SIGBUS/
SIGFPE the way it is suppose to be handled. Prior to this fix these
signals will neither create a coredump, nor exit from the debugger
or work for signal handling scenario.
* eInvalidCrashReason need not report "unknown crash reason" if we have
a valid si_signo
llvm.org/pr23699
Patch by Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D35223
Submitted by: Karnajit Wangkhem
Obtained from: LLVM r310591
MFC r322474 (by emaste):
lld: Add `-z muldefs` option.
Obtained from: LLVM r310757
MFC r322740:
Upgrade our copies of clang, llvm, lld and libc++ to r311219 from the
upstream release_50 branch.
MFC r322855:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r311606 from
the upstream release_50 branch.
As of this version, lib/msun's trig test should also work correctly
again (see bug 220989 for more information).
PR: 220989
MFC r323112:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r312293 from
the upstream release_50 branch. This corresponds to 5.0.0 rc4.
As of this version, the cad/stepcode port should now compile in a more
reasonable time on i386 (see bug 221836 for more information).
PR: 221836
MFC r323245:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 release (upstream r312559).
Release notes for llvm, clang and lld will be available here soon:
<http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
(cherry picked from commit 12cd91cf4c6b96a24427c0de5374916f2808d263)
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
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; |