summaryrefslogtreecommitdiffstats
path: root/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend')
-rw-r--r--lib/Frontend/ASTConsumers.cpp40
-rw-r--r--lib/Frontend/ASTMerge.cpp21
-rw-r--r--lib/Frontend/ASTUnit.cpp770
-rw-r--r--lib/Frontend/CMakeLists.txt13
-rw-r--r--lib/Frontend/CacheTokens.cpp46
-rw-r--r--lib/Frontend/CompilerInstance.cpp221
-rw-r--r--lib/Frontend/CompilerInvocation.cpp334
-rw-r--r--lib/Frontend/DeclXML.cpp20
-rw-r--r--lib/Frontend/DependencyFile.cpp25
-rw-r--r--lib/Frontend/DocumentXML.cpp19
-rw-r--r--lib/Frontend/FrontendAction.cpp125
-rw-r--r--lib/Frontend/FrontendActions.cpp33
-rw-r--r--lib/Frontend/FrontendOptions.cpp1
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp113
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp230
-rw-r--r--lib/Frontend/InitPreprocessor.cpp22
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp221
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp114
-rw-r--r--lib/Frontend/StmtXML.cpp16
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp3
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp186
-rw-r--r--lib/Frontend/TypeXML.cpp6
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp10
23 files changed, 1766 insertions, 823 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index eb7f270..92fb1e8 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -24,7 +24,7 @@
#include "llvm/Module.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Path.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -354,8 +354,18 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
PrintDeclContext(DC, Indentation+2);
break;
}
+ case Decl::IndirectField: {
+ IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I);
+ Out << "<IndirectField> " << IFD << '\n';
+ break;
+ }
+ case Decl::Label: {
+ LabelDecl *LD = cast<LabelDecl>(*I);
+ Out << "<Label> " << LD << '\n';
+ break;
+ }
case Decl::Field: {
- FieldDecl* FD = cast<FieldDecl>(*I);
+ FieldDecl *FD = cast<FieldDecl>(*I);
Out << "<field> " << FD << '\n';
break;
}
@@ -423,29 +433,21 @@ ASTConsumer *clang::CreateDeclContextPrinter() {
}
//===----------------------------------------------------------------------===//
-/// InheritanceViewer - C++ Inheritance Visualization
+/// ASTDumperXML - In-depth XML dumping.
namespace {
-class InheritanceViewer : public ASTConsumer {
- const std::string clsname;
+class ASTDumpXML : public ASTConsumer {
+ llvm::raw_ostream &OS;
+
public:
- InheritanceViewer(const std::string& cname) : clsname(cname) {}
+ ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {}
void HandleTranslationUnit(ASTContext &C) {
- for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I)
- if (RecordType *T = dyn_cast<RecordType>(*I)) {
- if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) {
- // FIXME: This lookup needs to be generalized to handle namespaces and
- // (when we support them) templates.
- if (D->getNameAsString() == clsname) {
- D->viewInheritance(C);
- }
- }
- }
- }
+ C.getTranslationUnitDecl()->dumpXML(OS);
+ }
};
}
-ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
- return new InheritanceViewer(clsname);
+ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) {
+ return new ASTDumpXML(OS);
}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index b46212f..3905b99 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -38,23 +38,22 @@ void ASTMergeAction::ExecuteAction() {
CI.getASTContext().getLangOptions());
CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
&CI.getASTContext());
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs>
+ DiagIDs(CI.getDiagnostics().getDiagnosticIDs());
for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
- ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, false);
+ llvm::IntrusiveRefCntPtr<Diagnostic>
+ Diags(new Diagnostic(DiagIDs, CI.getDiagnostics().getClient(),
+ /*ShouldOwnClient=*/false));
+ ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
+ CI.getFileSystemOpts(), false);
if (!Unit)
continue;
- // Reset the argument -> string function so that it has the AST
- // context we want, since the Sema object created by
- // LoadFromASTFile will override it.
- CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
- &CI.getASTContext());
-
- ASTImporter Importer(CI.getDiagnostics(),
- CI.getASTContext(),
+ ASTImporter Importer(CI.getASTContext(),
CI.getFileManager(),
Unit->getASTContext(),
- Unit->getFileManager());
+ Unit->getFileManager(),
+ /*MinimalImport=*/false);
TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
for (DeclContext::decl_iterator D = TU->decls_begin(),
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index c76488b..4a5a51d 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -25,17 +25,21 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTSerializationListener.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Atomic.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/System/Host.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
#include <cstdlib>
@@ -43,20 +47,63 @@
#include <sys/stat.h>
using namespace clang;
+using llvm::TimeRecord;
+
+namespace {
+ class SimpleTimer {
+ bool WantTiming;
+ TimeRecord Start;
+ std::string Output;
+
+ public:
+ explicit SimpleTimer(bool WantTiming) : WantTiming(WantTiming) {
+ if (WantTiming)
+ Start = TimeRecord::getCurrentTime();
+ }
+
+ void setOutput(const llvm::Twine &Output) {
+ if (WantTiming)
+ this->Output = Output.str();
+ }
+
+ ~SimpleTimer() {
+ if (WantTiming) {
+ TimeRecord Elapsed = TimeRecord::getCurrentTime();
+ Elapsed -= Start;
+ llvm::errs() << Output << ':';
+ Elapsed.print(Elapsed, llvm::errs());
+ llvm::errs() << '\n';
+ }
+ }
+ };
+}
+
/// \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
/// preamble.
const unsigned DefaultPreambleRebuildInterval = 5;
+/// \brief Tracks the number of ASTUnit objects that are currently active.
+///
+/// Used for debugging purposes only.
+static llvm::sys::cas_flag ActiveASTUnitObjects;
+
ASTUnit::ASTUnit(bool _MainFileIsAST)
: CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
- CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked),
+ CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")),
+ NumStoredDiagnosticsFromDriver(0),
+ ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
- NumTopLevelDeclsAtLastCompletionCache(0),
- CacheCodeCompletionCoolDown(0),
+ CompletionCacheTopLevelHashValue(0),
+ PreambleTopLevelHashValue(0),
+ CurrentTopLevelHashValue(0),
UnsafeToFree(false) {
+ if (getenv("LIBCLANG_OBJTRACKING")) {
+ llvm::sys::AtomicIncrement(&ActiveASTUnitObjects);
+ fprintf(stderr, "+++ %d translation units\n", ActiveASTUnitObjects);
+ }
}
ASTUnit::~ASTUnit() {
@@ -82,10 +129,12 @@ ASTUnit::~ASTUnit() {
delete SavedMainFileBuffer;
delete PreambleBuffer;
- ClearCachedCompletionResults();
+ ClearCachedCompletionResults();
- for (unsigned I = 0, N = Timers.size(); I != N; ++I)
- delete Timers[I];
+ if (getenv("LIBCLANG_OBJTRACKING")) {
+ llvm::sys::AtomicDecrement(&ActiveASTUnitObjects);
+ fprintf(stderr, "--- %d translation units\n", ActiveASTUnitObjects);
+ }
}
void ASTUnit::CleanTemporaryFiles() {
@@ -115,7 +164,8 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
| (1 << (CodeCompletionContext::CCC_Statement - 1))
- | (1 << (CodeCompletionContext::CCC_Type - 1));
+ | (1 << (CodeCompletionContext::CCC_Type - 1))
+ | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1));
// In C++, types can appear in expressions contexts (for functional casts).
if (LangOpts.CPlusPlus)
@@ -141,12 +191,13 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
if (LangOpts.CPlusPlus)
IsNestedNameSpecifier = true;
- } else if (isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND))
+ } else if (isa<ClassTemplateDecl>(ND))
IsNestedNameSpecifier = true;
} else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
// Values can appear in these contexts.
Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1))
| (1 << (CodeCompletionContext::CCC_Expression - 1))
+ | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
} else if (isa<ObjCProtocolDecl>(ND)) {
Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
@@ -164,13 +215,8 @@ void ASTUnit::CacheCodeCompletionResults() {
if (!TheSema)
return;
- llvm::Timer *CachingTimer = 0;
- if (TimerGroup.get()) {
- CachingTimer = new llvm::Timer("Cache global code completions",
- *TimerGroup);
- CachingTimer->startTimer();
- Timers.push_back(CachingTimer);
- }
+ SimpleTimer Timer(WantTiming);
+ Timer.setOutput("Cache global code completions for " + getMainFileName());
// Clear out the previous results.
ClearCachedCompletionResults();
@@ -178,7 +224,8 @@ void ASTUnit::CacheCodeCompletionResults() {
// Gather the set of global code completions.
typedef CodeCompletionResult Result;
llvm::SmallVector<Result, 8> Results;
- TheSema->GatherGlobalCodeCompletions(Results);
+ CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
+ TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results);
// Translate global code completions into cached completions.
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
@@ -188,7 +235,8 @@ void ASTUnit::CacheCodeCompletionResults() {
case Result::RK_Declaration: {
bool IsNestedNameSpecifier = false;
CachedCodeCompletionResult CachedResult;
- CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+ CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema,
+ *CachedCompletionAllocator);
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
Ctx->getLangOptions(),
IsNestedNameSpecifier);
@@ -237,7 +285,8 @@ void ASTUnit::CacheCodeCompletionResults() {
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
| (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1))
| (1 << (CodeCompletionContext::CCC_Type - 1))
- | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1));
+ | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1))
+ | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1));
if (isa<NamespaceDecl>(Results[I].Declaration) ||
isa<NamespaceAliasDecl>(Results[I].Declaration))
@@ -249,7 +298,9 @@ void ASTUnit::CacheCodeCompletionResults() {
// nested-name-specifier but isn't already an option, create a
// nested-name-specifier completion.
Results[I].StartsNestedNameSpecifier = true;
- CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+ CachedResult.Completion
+ = Results[I].CreateCodeCompletionString(*TheSema,
+ *CachedCompletionAllocator);
CachedResult.ShowInContexts = RemainingContexts;
CachedResult.Priority = CCP_NestedNameSpecifier;
CachedResult.TypeClass = STC_Void;
@@ -268,7 +319,9 @@ void ASTUnit::CacheCodeCompletionResults() {
case Result::RK_Macro: {
CachedCodeCompletionResult CachedResult;
- CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
+ CachedResult.Completion
+ = Results[I].CreateCodeCompletionString(*TheSema,
+ *CachedCompletionAllocator);
CachedResult.ShowInContexts
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
| (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
@@ -279,7 +332,9 @@ void ASTUnit::CacheCodeCompletionResults() {
| (1 << (CodeCompletionContext::CCC_Expression - 1))
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
| (1 << (CodeCompletionContext::CCC_MacroNameUse - 1))
- | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1));
+ | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1))
+ | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
+ | (1 << (CodeCompletionContext::CCC_OtherWithMacros - 1));
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
@@ -290,22 +345,16 @@ void ASTUnit::CacheCodeCompletionResults() {
break;
}
}
- Results[I].Destroy();
}
-
- if (CachingTimer)
- CachingTimer->stopTimer();
- // Make a note of the state when we performed this caching.
- NumTopLevelDeclsAtLastCompletionCache = top_level_size();
- CacheCodeCompletionCoolDown = 15;
+ // Save the current top-level hash value.
+ CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue;
}
void ASTUnit::ClearCachedCompletionResults() {
- for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I)
- delete CachedCompletionResults[I].Completion;
CachedCompletionResults.clear();
CachedCompletionTypes.clear();
+ CachedCompletionAllocator = 0;
}
namespace {
@@ -378,7 +427,7 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
- llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
+ llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
: Diags(Diags), Client(StoredDiags), PreviousClient(0)
{
if (RequestCapture || Diags.getClient() == 0) {
@@ -399,6 +448,9 @@ public:
void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info) {
+ // Default implementation (Warnings/errors count).
+ DiagnosticClient::HandleDiagnostic(Level, Info);
+
StoredDiags.push_back(StoredDiagnostic(Level, Info));
}
@@ -411,32 +463,48 @@ const std::string &ASTUnit::getASTFileName() {
return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName();
}
+llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename,
+ std::string *ErrorStr) {
+ assert(FileMgr);
+ return FileMgr->getBufferForFile(Filename, ErrorStr);
+}
+
+/// \brief Configure the diagnostics object for use with ASTUnit.
+void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
+ const char **ArgBegin, const char **ArgEnd,
+ ASTUnit &AST, bool CaptureDiagnostics) {
+ if (!Diags.getPtr()) {
+ // No diagnostics engine was provided, so create our own diagnostics object
+ // with the default options.
+ DiagnosticOptions DiagOpts;
+ DiagnosticClient *Client = 0;
+ if (CaptureDiagnostics)
+ Client = new StoredDiagnosticClient(AST.StoredDiagnostics);
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin,
+ ArgBegin, Client);
+ } else if (CaptureDiagnostics) {
+ Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics));
+ }
+}
+
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
bool CaptureDiagnostics) {
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
-
- if (!Diags.getPtr()) {
- // No diagnostics engine was provided, so create our own diagnostics object
- // with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
- }
+ ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
- AST->CaptureDiagnostics = CaptureDiagnostics;
AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
- AST->FileMgr.reset(new FileManager);
- AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
+ AST->FileMgr.reset(new FileManager(FileSystemOpts));
+ AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(),
+ AST->getFileManager()));
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
- // If requested, capture diagnostics in the ASTUnit.
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
- AST->StoredDiagnostics);
-
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
// Create the file entry for the file that we're mapping from.
const FileEntry *FromFile
@@ -471,7 +539,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
- switch (Reader->ReadAST(Filename)) {
+ switch (Reader->ReadAST(Filename, ASTReader::MainFile)) {
case ASTReader::Success:
break;
@@ -538,12 +606,69 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
namespace {
+/// \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 {
+ unsigned &Hash;
+
+public:
+ explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
+
+ virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ }
+};
+
+/// \brief Add the given declaration to the hash of all top-level entities.
+void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
+ if (!D)
+ return;
+
+ DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return;
+
+ if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit()))
+ return;
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (ND->getIdentifier())
+ Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash);
+ else if (DeclarationName Name = ND->getDeclName()) {
+ std::string NameStr = Name.getAsString();
+ Hash = llvm::HashString(NameStr, Hash);
+ }
+ return;
+ }
+
+ if (ObjCForwardProtocolDecl *Forward
+ = dyn_cast<ObjCForwardProtocolDecl>(D)) {
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ P = Forward->protocol_begin(),
+ PEnd = Forward->protocol_end();
+ P != PEnd; ++P)
+ AddTopLevelDeclarationToHash(*P, Hash);
+ return;
+ }
+
+ if (ObjCClassDecl *Class = llvm::dyn_cast<ObjCClassDecl>(D)) {
+ for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
+ I != IEnd; ++I)
+ AddTopLevelDeclarationToHash(I->getInterface(), Hash);
+ return;
+ }
+}
+
class TopLevelDeclTrackerConsumer : public ASTConsumer {
ASTUnit &Unit;
-
+ unsigned &Hash;
+
public:
- TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
-
+ TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash)
+ : Unit(_Unit), Hash(Hash) {
+ Hash = 0;
+ }
+
void HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
Decl *D = *it;
@@ -553,6 +678,8 @@ public:
// fundamental problem in the parser right now.
if (isa<ObjCMethodDecl>(D))
continue;
+
+ AddTopLevelDeclarationToHash(D, Hash);
Unit.addTopLevelDecl(D);
}
}
@@ -567,7 +694,10 @@ public:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return new TopLevelDeclTrackerConsumer(Unit);
+ CI.getPreprocessor().addPPCallbacks(
+ new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
+ return new TopLevelDeclTrackerConsumer(Unit,
+ Unit.getCurrentTopLevelHashValue());
}
public:
@@ -579,15 +709,20 @@ public:
}
};
-class PrecompilePreambleConsumer : public PCHGenerator {
+class PrecompilePreambleConsumer : public PCHGenerator,
+ public ASTSerializationListener {
ASTUnit &Unit;
+ unsigned &Hash;
std::vector<Decl *> TopLevelDecls;
-
+
public:
PrecompilePreambleConsumer(ASTUnit &Unit,
const Preprocessor &PP, bool Chaining,
const char *isysroot, llvm::raw_ostream *Out)
- : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
+ : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit),
+ Hash(Unit.getCurrentTopLevelHashValue()) {
+ Hash = 0;
+ }
virtual void HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
@@ -598,6 +733,7 @@ public:
// fundamental problem in the parser right now.
if (isa<ObjCMethodDecl>(D))
continue;
+ AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
}
@@ -614,6 +750,15 @@ public:
getWriter().getDeclID(TopLevelDecls[I]));
}
}
+
+ virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity,
+ uint64_t Offset) {
+ Unit.addPreprocessedEntityFromPreamble(Offset);
+ }
+
+ virtual ASTSerializationListener *GetASTSerializationListener() {
+ return this;
+ }
};
class PrecompilePreambleAction : public ASTFrontendAction {
@@ -625,14 +770,18 @@ public:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
std::string Sysroot;
+ std::string OutputFile;
llvm::raw_ostream *OS = 0;
bool Chaining;
- if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile,
OS, Chaining))
return 0;
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
Sysroot.c_str() : 0;
+ CI.getPreprocessor().addPPCallbacks(
+ new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining,
isysroot, OS);
}
@@ -666,11 +815,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
Clang.setDiagnostics(&getDiagnostics());
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
- getDiagnostics(),
- StoredDiagnostics);
// Create the target instance.
+ Clang.getTargetOpts().Features = TargetFeatures;
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget()) {
@@ -693,20 +840,25 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Configure the various subsystems.
// FIXME: Should we retain the previous file manager?
- FileMgr.reset(new FileManager);
- SourceMgr.reset(new SourceManager(getDiagnostics()));
+ FileSystemOpts = Clang.getFileSystemOpts();
+ FileMgr.reset(new FileManager(Clang.getFileSystemOpts()));
+ SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr));
TheSema.reset();
Ctx.reset();
PP.reset();
// Clear out old caches and data.
TopLevelDecls.clear();
+ PreprocessedEntities.clear();
CleanTemporaryFiles();
PreprocessedEntitiesByFile.clear();
if (!OverrideMainBuffer) {
- StoredDiagnostics.clear();
+ StoredDiagnostics.erase(
+ StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+ StoredDiagnostics.end());
TopLevelDeclsInPreamble.clear();
+ PreprocessedEntitiesInPreamble.clear();
}
// Create a file manager object to provide access to and cache the filesystem.
@@ -728,19 +880,21 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
PreprocessorOpts.DisablePCHValidation = true;
- // Keep track of the override buffer;
- SavedMainFileBuffer = OverrideMainBuffer;
-
// The stored diagnostic has the old source manager in it; update
// the locations to refer into the new source manager. Since we've
// been careful to make sure that the source manager's state
// before and after are identical, so that we can reuse the source
// location itself.
- for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) {
+ for (unsigned I = NumStoredDiagnosticsFromDriver,
+ N = StoredDiagnostics.size();
+ I < N; ++I) {
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
getSourceManager());
StoredDiagnostics[I].setLocation(Loc);
}
+
+ // Keep track of the override buffer;
+ SavedMainFileBuffer = OverrideMainBuffer;
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
@@ -774,12 +928,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
}
Invocation.reset(Clang.takeInvocation());
-
- // If we were asked to cache code-completion results and don't have any
- // results yet, do so now.
- if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty())
- CacheCodeCompletionResults();
-
return false;
error:
@@ -787,11 +935,12 @@ error:
if (OverrideMainBuffer) {
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
- PreprocessorOpts.DisablePCHValidation = true;
PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
delete OverrideMainBuffer;
+ SavedMainFileBuffer = 0;
}
+ StoredDiagnostics.clear();
Clang.takeSourceManager();
Clang.takeFileManager();
Invocation.reset(Clang.takeInvocation());
@@ -803,15 +952,27 @@ static std::string GetPreamblePCHPath() {
// FIXME: This is lame; sys::Path should provide this function (in particular,
// it should know how to find the temporary files dir).
// FIXME: This is really lame. I copied this code from the Driver!
+ // 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;
+
std::string Error;
const char *TmpDir = ::getenv("TMPDIR");
if (!TmpDir)
TmpDir = ::getenv("TEMP");
if (!TmpDir)
TmpDir = ::getenv("TMP");
+#ifdef LLVM_ON_WIN32
+ if (!TmpDir)
+ TmpDir = ::getenv("USERPROFILE");
+#endif
if (!TmpDir)
TmpDir = "/tmp";
llvm::sys::Path P(TmpDir);
+ P.createDirectoryOnDisk(true);
P.appendComponent("preamble");
P.appendSuffix("pch");
if (P.createTemporaryFileOnDisk())
@@ -827,8 +988,7 @@ std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
unsigned MaxLines, bool &CreatedBuffer) {
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts
- = Invocation.getPreprocessorOpts();
+ PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
CreatedBuffer = false;
// Try to determine if the main file has been remapped, either from the
@@ -852,17 +1012,11 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
CreatedBuffer = false;
}
- Buffer = llvm::MemoryBuffer::getFile(M->second);
+ Buffer = getBufferForFile(M->second);
if (!Buffer)
return std::make_pair((llvm::MemoryBuffer*)0,
std::make_pair(0, true));
CreatedBuffer = true;
-
- // Remove this remapping. We've captured the buffer already.
- M = PreprocessorOpts.eraseRemappedFile(M);
- E = PreprocessorOpts.remapped_file_end();
- if (M == E)
- break;
}
}
}
@@ -884,12 +1038,6 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
}
Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
-
- // Remove this remapping. We've captured the buffer already.
- M = PreprocessorOpts.eraseRemappedFile(M);
- E = PreprocessorOpts.remapped_file_buffer_end();
- if (M == E)
- break;
}
}
}
@@ -897,7 +1045,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// If the main source file was not remapped, load it now.
if (!Buffer) {
- Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
+ Buffer = getBufferForFile(FrontendOpts.Inputs[0].second);
if (!Buffer)
return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
@@ -908,7 +1056,6 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
}
static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
- bool DeleteOld,
unsigned NewSize,
llvm::StringRef NewName) {
llvm::MemoryBuffer *Result
@@ -919,9 +1066,6 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
' ', NewSize - Old->getBufferSize() - 1);
const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
- if (DeleteOld)
- delete Old;
-
return Result;
}
@@ -957,6 +1101,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
= ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer);
+ // If ComputePreamble() Take ownership of the
+ llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
+ if (CreatedPreambleBuffer)
+ OwnedPreambleBuffer.reset(NewPreamble.first);
+
if (!NewPreamble.second.first) {
// 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.
@@ -965,8 +1114,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
llvm::sys::Path(PreambleFile).eraseFromDisk();
PreambleFile.clear();
}
- if (CreatedPreambleBuffer)
- delete NewPreamble.first;
// The next time we actually see a preamble, precompile it.
PreambleRebuildCounter = 1;
@@ -1049,7 +1196,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Set the state of the diagnostic object to mimic its state
// after parsing the preamble.
+ // FIXME: This won't catch any #pragma push warning changes that
+ // have occurred in the preamble.
getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocation.getDiagnosticOpts());
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble)
StoredDiagnostics.erase(
@@ -1059,7 +1210,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Create a version of the main file buffer that is padded to
// buffer size we reserved when creating the preamble.
return CreatePaddedMainFileBuffer(NewPreamble.first,
- CreatedPreambleBuffer,
PreambleReservedSize,
FrontendOpts.Inputs[0].second);
}
@@ -1069,7 +1219,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// return now.
if (!AllowRebuild)
return 0;
-
+
// We can't reuse the previously-computed preamble. Build a new one.
Preamble.clear();
llvm::sys::Path(PreambleFile).eraseFromDisk();
@@ -1088,14 +1238,19 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
return 0;
}
- // We did not previously compute a preamble, or it can't be reused anyway.
- llvm::Timer *PreambleTimer = 0;
- if (TimerGroup.get()) {
- PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup);
- PreambleTimer->startTimer();
- Timers.push_back(PreambleTimer);
+ // 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 0;
}
+ // We did not previously compute a preamble, or it can't be reused anyway.
+ SimpleTimer PreambleTimer(WantTiming);
+ PreambleTimer.setOutput("Precompiling preamble");
+
// Create a new buffer that stores the preamble. The buffer also contains
// extra space for the original contents of the file (which will be present
// when we actually parse the file) along with more room in case the file
@@ -1129,11 +1284,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Tell the compiler invocation to generate a temporary precompiled header.
FrontendOpts.ProgramAction = frontend::GeneratePCH;
- // FIXME: Set ChainedPCH unconditionally, once it is ready.
- if (::getenv("LIBCLANG_CHAINING"))
- FrontendOpts.ChainedPCH = true;
+ FrontendOpts.ChainedPCH = true;
// FIXME: Generate the precompiled header into memory?
- FrontendOpts.OutputFile = GetPreamblePCHPath();
+ FrontendOpts.OutputFile = PreamblePCHPath;
+ PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+ PreprocessorOpts.PrecompiledPreambleBytes.second = false;
// Create the compiler instance to use for building the precompiled preamble.
CompilerInstance Clang;
@@ -1142,20 +1297,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Set up diagnostics, capturing all of the diagnostics produced.
Clang.setDiagnostics(&getDiagnostics());
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
- getDiagnostics(),
- StoredDiagnostics);
// Create the target instance.
+ Clang.getTargetOpts().Features = TargetFeatures;
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
- if (CreatedPreambleBuffer)
- delete NewPreamble.first;
- if (PreambleTimer)
- PreambleTimer->stopTimer();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
@@ -1176,15 +1325,22 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
"IR inputs not support here!");
// Clear out old caches and data.
- StoredDiagnostics.clear();
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts());
+ StoredDiagnostics.erase(
+ StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+ StoredDiagnostics.end());
TopLevelDecls.clear();
TopLevelDeclsInPreamble.clear();
+ PreprocessedEntities.clear();
+ PreprocessedEntitiesInPreamble.clear();
// Create a file manager object to provide access to and cache the filesystem.
- Clang.setFileManager(new FileManager);
+ Clang.setFileManager(new FileManager(Clang.getFileSystemOpts()));
// Create the source manager.
- Clang.setSourceManager(new SourceManager(getDiagnostics()));
+ Clang.setSourceManager(new SourceManager(getDiagnostics(),
+ Clang.getFileManager()));
llvm::OwningPtr<PrecompilePreambleAction> Act;
Act.reset(new PrecompilePreambleAction(*this));
@@ -1193,10 +1349,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Clang.takeInvocation();
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
- if (CreatedPreambleBuffer)
- delete NewPreamble.first;
- if (PreambleTimer)
- PreambleTimer->stopTimer();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
@@ -1213,11 +1365,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// FIXME: Should we leave a note for ourselves to try again?
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
- if (CreatedPreambleBuffer)
- delete NewPreamble.first;
- if (PreambleTimer)
- PreambleTimer->stopTimer();
TopLevelDeclsInPreamble.clear();
+ PreprocessedEntities.clear();
+ PreprocessedEntitiesInPreamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
@@ -1247,14 +1397,19 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
= std::make_pair(F->second->getSize(), File->getModificationTime());
}
- if (PreambleTimer)
- PreambleTimer->stopTimer();
-
PreambleRebuildCounter = 1;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
+
+ // 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
+ // cache.
+ if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) {
+ CompletionCacheTopLevelHashValue = 0;
+ PreambleTopLevelHashValue = CurrentTopLevelHashValue;
+ }
+
return CreatePaddedMainFileBuffer(NewPreamble.first,
- CreatedPreambleBuffer,
PreambleReservedSize,
FrontendOpts.Inputs[0].second);
}
@@ -1274,14 +1429,90 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
}
+void ASTUnit::RealizePreprocessedEntitiesFromPreamble() {
+ if (!PP)
+ return;
+
+ PreprocessingRecord *PPRec = PP->getPreprocessingRecord();
+ if (!PPRec)
+ return;
+
+ ExternalPreprocessingRecordSource *External = PPRec->getExternalSource();
+ if (!External)
+ return;
+
+ for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) {
+ if (PreprocessedEntity *PE
+ = External->ReadPreprocessedEntityAtOffset(
+ PreprocessedEntitiesInPreamble[I]))
+ PreprocessedEntities.push_back(PE);
+ }
+
+ if (PreprocessedEntities.empty())
+ return;
+
+ PreprocessedEntities.insert(PreprocessedEntities.end(),
+ PPRec->begin(true), PPRec->end(true));
+}
+
+ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() {
+ if (!PreprocessedEntitiesInPreamble.empty() &&
+ PreprocessedEntities.empty())
+ RealizePreprocessedEntitiesFromPreamble();
+
+ if (PreprocessedEntities.empty())
+ if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
+ return PPRec->begin(true);
+
+ return PreprocessedEntities.begin();
+}
+
+ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() {
+ if (!PreprocessedEntitiesInPreamble.empty() &&
+ PreprocessedEntities.empty())
+ RealizePreprocessedEntitiesFromPreamble();
+
+ if (PreprocessedEntities.empty())
+ if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
+ return PPRec->end(true);
+
+ return PreprocessedEntities.end();
+}
+
unsigned ASTUnit::getMaxPCHLevel() const {
if (!getOnlyLocalDecls())
return Decl::MaxPCHLevel;
- unsigned Result = 0;
- if (isMainFileAST() || SavedMainFileBuffer)
- ++Result;
- return Result;
+ return 0;
+}
+
+llvm::StringRef ASTUnit::getMainFileName() const {
+ return Invocation->getFrontendOpts().Inputs[0].second;
+}
+
+bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
+ if (!Invocation)
+ return true;
+
+ // We'll manage file buffers ourselves.
+ Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
+ Invocation->getFrontendOpts().DisableFree = false;
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
+
+ // Save the target features.
+ TargetFeatures = Invocation->getTargetOpts().Features;
+
+ llvm::MemoryBuffer *OverrideMainBuffer = 0;
+ if (PrecompilePreamble) {
+ PreambleRebuildCounter = 2;
+ OverrideMainBuffer
+ = getMainBufferWithPrecompiledPreamble(*Invocation);
+ }
+
+ SimpleTimer ParsingTimer(WantTiming);
+ ParsingTimer.setOutput("Parsing " + getMainFileName());
+
+ return Parse(OverrideMainBuffer);
}
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
@@ -1290,50 +1521,19 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
bool CaptureDiagnostics,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
- bool CacheCodeCompletionResults) {
- if (!Diags.getPtr()) {
- // No diagnostics engine was provided, so create our own diagnostics object
- // with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
- }
-
+ bool CacheCodeCompletionResults) {
// Create the AST unit.
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
+ ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
- AST->CaptureDiagnostics = CaptureDiagnostics;
AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->CaptureDiagnostics = CaptureDiagnostics;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation.reset(CI);
- CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
-
- if (getenv("LIBCLANG_TIMING"))
- AST->TimerGroup.reset(
- new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second));
-
- llvm::MemoryBuffer *OverrideMainBuffer = 0;
- // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
- if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) {
- AST->PreambleRebuildCounter = 1;
- OverrideMainBuffer
- = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation);
- }
-
- llvm::Timer *ParsingTimer = 0;
- if (AST->TimerGroup.get()) {
- ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup);
- ParsingTimer->startTimer();
- AST->Timers.push_back(ParsingTimer);
- }
-
- bool Failed = AST->Parse(OverrideMainBuffer);
- if (ParsingTimer)
- ParsingTimer->stopTimer();
-
- return Failed? 0 : AST.take();
+ return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
}
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
@@ -1341,20 +1541,20 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls,
+ bool CaptureDiagnostics,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
- bool CaptureDiagnostics,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
- bool CacheCodeCompletionResults) {
- bool CreatedDiagnosticsObject = false;
-
+ bool CacheCodeCompletionResults,
+ bool CXXPrecompilePreamble,
+ bool CXXChainedPCH) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
- CreatedDiagnosticsObject = true;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin,
+ ArgBegin);
}
llvm::SmallVector<const char *, 16> Args;
@@ -1365,40 +1565,49 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// also want to force it to use clang.
Args.push_back("-fsyntax-only");
- // FIXME: We shouldn't have to pass in the path info.
- driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
- "a.out", false, false, *Diags);
-
- // Don't check that inputs exist, they have been remapped.
- TheDriver.setCheckInputsExist(false);
-
- llvm::OwningPtr<driver::Compilation> C(
- TheDriver.BuildCompilation(Args.size(), Args.data()));
+ llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+
+ llvm::OwningPtr<CompilerInvocation> CI;
- // We expect to get back exactly one command job, if we didn't something
- // failed.
- const driver::JobList &Jobs = C->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
- llvm::SmallString<256> Msg;
- llvm::raw_svector_ostream OS(Msg);
- C->PrintJob(OS, C->getJobs(), "; ", true);
- Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
- return 0;
- }
+ {
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+ StoredDiagnostics);
+
+ // FIXME: We shouldn't have to pass in the path info.
+ driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
+ "a.out", false, false, *Diags);
+
+ // Don't check that inputs exist, they have been remapped.
+ TheDriver.setCheckInputsExist(false);
+
+ llvm::OwningPtr<driver::Compilation> C(
+ TheDriver.BuildCompilation(Args.size(), Args.data()));
+
+ // We expect to get back exactly one command job, if we didn't something
+ // failed.
+ const driver::JobList &Jobs = C->getJobs();
+ if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ llvm::SmallString<256> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ C->PrintJob(OS, C->getJobs(), "; ", true);
+ Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
+ return 0;
+ }
- const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diags->Report(diag::err_fe_expected_clang_command);
- return 0;
- }
+ const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diags->Report(diag::err_fe_expected_clang_command);
+ return 0;
+ }
- const driver::ArgStringList &CCArgs = Cmd->getArguments();
- llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*CI,
+ const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ CI.reset(new CompilerInvocation);
+ CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
const_cast<const char **>(CCArgs.data()) +
- CCArgs.size(),
- *Diags);
+ CCArgs.size(),
+ *Diags);
+ }
// Override any files that need remapping
for (unsigned I = 0; I != NumRemappedFiles; ++I)
@@ -1408,26 +1617,44 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
- CI->getFrontendOpts().DisableFree = false;
- return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
- CaptureDiagnostics, PrecompilePreamble,
- CompleteTranslationUnit,
- CacheCodeCompletionResults);
+ // Check whether we should precompile the preamble and/or use chained PCH.
+ // FIXME: This is a temporary hack while we debug C++ chained PCH.
+ if (CI->getLangOpts().CPlusPlus) {
+ PrecompilePreamble = PrecompilePreamble && CXXPrecompilePreamble;
+
+ if (PrecompilePreamble && !CXXChainedPCH &&
+ !CI->getPreprocessorOpts().ImplicitPCHInclude.empty())
+ PrecompilePreamble = false;
+ }
+
+ // Create the AST unit.
+ llvm::OwningPtr<ASTUnit> AST;
+ AST.reset(new ASTUnit(false));
+ ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
+ AST->Diagnostics = Diags;
+
+ AST->FileMgr.reset(new FileManager(FileSystemOptions()));
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->CaptureDiagnostics = CaptureDiagnostics;
+ AST->CompleteTranslationUnit = CompleteTranslationUnit;
+ AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
+ AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
+ AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
+ AST->StoredDiagnostics.swap(StoredDiagnostics);
+ AST->Invocation.reset(CI.take());
+ return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take();
}
bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
if (!Invocation.get())
return true;
- llvm::Timer *ReparsingTimer = 0;
- if (TimerGroup.get()) {
- ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup);
- ReparsingTimer->startTimer();
- Timers.push_back(ReparsingTimer);
- }
-
+ SimpleTimer ParsingTimer(WantTiming);
+ ParsingTimer.setOutput("Reparsing " + getMainFileName());
+
// Remap files.
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+ PPOpts.DisableStatCache = true;
for (PreprocessorOptions::remapped_file_buffer_iterator
R = PPOpts.remapped_file_buffer_begin(),
REnd = PPOpts.remapped_file_buffer_end();
@@ -1447,21 +1674,20 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
// Clear out the diagnostics state.
- if (!OverrideMainBuffer)
+ if (!OverrideMainBuffer) {
getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
+ }
// Parse the sources
- bool Result = Parse(OverrideMainBuffer);
- if (ReparsingTimer)
- ReparsingTimer->stopTimer();
-
- if (ShouldCacheCodeCompletionResults) {
- if (CacheCodeCompletionCoolDown > 0)
- --CacheCodeCompletionCoolDown;
- else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache)
- CacheCodeCompletionResults();
- }
+ bool Result = Parse(OverrideMainBuffer);
+ // If we're caching global code-completion results, and the top-level
+ // declarations have changed, clear out the code-completion cache.
+ if (!Result && ShouldCacheCodeCompletionResults &&
+ CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue)
+ CacheCodeCompletionResults();
+
return Result;
}
@@ -1496,8 +1722,10 @@ namespace {
| (1 << (CodeCompletionContext::CCC_Expression - 1))
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
| (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
- | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
-
+ | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
+ | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
+ | (1 << (CodeCompletionContext::CCC_Recovery - 1));
+
if (AST.getASTContext().getLangOptions().CPlusPlus)
NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1))
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
@@ -1514,19 +1742,23 @@ namespace {
unsigned NumCandidates) {
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates);
}
+
+ virtual CodeCompletionAllocator &getAllocator() {
+ return Next.getAllocator();
+ }
};
}
/// \brief Helper function that computes which global names are hidden by the
/// local code-completion results.
-void CalculateHiddenNames(const CodeCompletionContext &Context,
- CodeCompletionResult *Results,
- unsigned NumResults,
- ASTContext &Ctx,
- llvm::StringSet<> &HiddenNames) {
+static void CalculateHiddenNames(const CodeCompletionContext &Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults,
+ ASTContext &Ctx,
+ llvm::StringSet<llvm::BumpPtrAllocator> &HiddenNames){
bool OnlyTagNames = false;
switch (Context.getKind()) {
- case CodeCompletionContext::CCC_Other:
+ case CodeCompletionContext::CCC_Recovery:
case CodeCompletionContext::CCC_TopLevel:
case CodeCompletionContext::CCC_ObjCInterface:
case CodeCompletionContext::CCC_ObjCImplementation:
@@ -1540,6 +1772,7 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_Type:
case CodeCompletionContext::CCC_Name:
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
+ case CodeCompletionContext::CCC_ParenthesizedExpression:
break;
case CodeCompletionContext::CCC_EnumTag:
@@ -1556,6 +1789,8 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
case CodeCompletionContext::CCC_NaturalLanguage:
case CodeCompletionContext::CCC_SelectorName:
case CodeCompletionContext::CCC_TypeQualifiers:
+ case CodeCompletionContext::CCC_Other:
+ case CodeCompletionContext::CCC_OtherWithMacros:
// We're looking for nothing, or we're looking for names that cannot
// be hidden.
return;
@@ -1600,12 +1835,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
// Merge the results we were given with the results we cached.
bool AddedResult = false;
unsigned InContexts
- = (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts
+ = (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts
: (1 << (Context.getKind() - 1)));
// Contains the set of names that are hidden by "local" completion results.
- llvm::StringSet<> HiddenNames;
- llvm::SmallVector<CodeCompletionString *, 4> StringsToDestroy;
+ llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames;
typedef CodeCompletionResult Result;
llvm::SmallVector<Result, 8> AllResults;
for (ASTUnit::cached_completion_iterator
@@ -1638,6 +1872,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
if (!Context.getPreferredType().isNull()) {
if (C->Kind == CXCursor_MacroDefinition) {
Priority = getMacroUsagePriority(C->Completion->getTypedText(),
+ S.getLangOptions(),
Context.getPreferredType()->isAnyPointerType());
} else if (C->Type) {
CanQualType Expected
@@ -1663,11 +1898,12 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) {
// Create a new code-completion string that just contains the
// macro name, without its arguments.
- Completion = new CodeCompletionString;
- Completion->AddTypedTextChunk(C->Completion->getTypedText());
- StringsToDestroy.push_back(Completion);
+ CodeCompletionBuilder Builder(getAllocator(), CCP_CodePattern,
+ C->Availability);
+ Builder.AddTypedTextChunk(C->Completion->getTypedText());
CursorKind = CXCursor_NotImplemented;
Priority = CCP_CodePattern;
+ Completion = Builder.TakeString();
}
AllResults.push_back(Result(Completion, Priority, CursorKind,
@@ -1683,9 +1919,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
Next.ProcessCodeCompleteResults(S, Context, AllResults.data(),
AllResults.size());
-
- for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I)
- delete StringsToDestroy[I];
}
@@ -1703,16 +1936,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
if (!Invocation.get())
return;
- llvm::Timer *CompletionTimer = 0;
- if (TimerGroup.get()) {
- llvm::SmallString<128> TimerName;
- llvm::raw_svector_ostream TimerNameOut(TimerName);
- TimerNameOut << "Code completion @ " << File << ":" << Line << ":"
- << Column;
- CompletionTimer = new llvm::Timer(TimerNameOut.str(), *TimerGroup);
- CompletionTimer->startTimer();
- Timers.push_back(CompletionTimer);
- }
+ SimpleTimer CompletionTimer(WantTiming);
+ CompletionTimer.setOutput("Code completion @ " + File + ":" +
+ llvm::Twine(Line) + ":" + llvm::Twine(Column));
CompilerInvocation CCInvocation(*Invocation);
FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts();
@@ -1727,11 +1953,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
FrontendOpts.CodeCompletionAt.Line = Line;
FrontendOpts.CodeCompletionAt.Column = Column;
- // Turn on spell-checking when performing code completion. It leads
- // to better results.
- unsigned SpellChecking = CCInvocation.getLangOpts().SpellChecking;
- CCInvocation.getLangOpts().SpellChecking = 1;
-
// Set the language options appropriately.
LangOpts = CCInvocation.getLangOpts();
@@ -1741,16 +1962,17 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
// Set up diagnostics, capturing any diagnostics produced.
Clang.setDiagnostics(&Diag);
+ ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts());
CaptureDroppedDiagnostics Capture(true,
- Clang.getDiagnostics(),
+ Clang.getDiagnostics(),
StoredDiagnostics);
// Create the target instance.
+ Clang.getTargetOpts().Features = TargetFeatures;
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
Clang.getTargetOpts()));
if (!Clang.hasTarget()) {
Clang.takeInvocation();
- CCInvocation.getLangOpts().SpellChecking = SpellChecking;
return;
}
@@ -1783,11 +2005,12 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
// Use the code completion consumer we were given, but adding any cached
// code-completion results.
- AugmentedCodeCompleteConsumer
- AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion,
- FrontendOpts.ShowCodePatternsInCodeCompletion,
- FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
- Clang.setCodeCompletionConsumer(&AugmentedConsumer);
+ AugmentedCodeCompleteConsumer *AugmentedConsumer
+ = new AugmentedCodeCompleteConsumer(*this, Consumer,
+ FrontendOpts.ShowMacrosInCodeCompletion,
+ FrontendOpts.ShowCodePatternsInCodeCompletion,
+ FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
+ Clang.setCodeCompletionConsumer(AugmentedConsumer);
// If we have a precompiled preamble, try to use it. We only allow
// the use of the precompiled preamble if we're if the completion
@@ -1808,6 +2031,10 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
+ PreprocessorOpts.DisableStatCache = true;
+ StoredDiagnostics.insert(StoredDiagnostics.end(),
+ this->StoredDiagnostics.begin(),
+ this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver);
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
@@ -1819,12 +2046,14 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
// The stored diagnostics have the old source manager. Copy them
// to our output set of stored diagnostics, updating the source
// manager to the one we were given.
- for (unsigned I = 0, N = this->StoredDiagnostics.size(); I != N; ++I) {
+ for (unsigned I = NumStoredDiagnosticsFromDriver,
+ N = this->StoredDiagnostics.size();
+ I < N; ++I) {
StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
StoredDiagnostics[I].setLocation(Loc);
}
-
+
OwnedBuffers.push_back(OverrideMainBuffer);
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -1839,15 +2068,10 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
Act->EndSourceFile();
}
- if (CompletionTimer)
- CompletionTimer->stopTimer();
-
// Steal back our resources.
Clang.takeFileManager();
Clang.takeSourceManager();
Clang.takeInvocation();
- Clang.takeCodeCompletionConsumer();
- CCInvocation.getLangOpts().SpellChecking = SpellChecking;
}
bool ASTUnit::Save(llvm::StringRef File) {
@@ -1865,7 +2089,7 @@ bool ASTUnit::Save(llvm::StringRef File) {
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
- Writer.WriteAST(getSema(), 0, 0);
+ Writer.WriteAST(getSema(), 0, std::string(), 0);
// Write the generated bitstream to "Out".
if (!Buffer.empty())
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 5a31495..9f197b4 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -1,4 +1,12 @@
-set(LLVM_NO_RTTI 1)
+set( LLVM_USED_LIBS
+ clangAST
+ clangBasic
+ clangDriver
+ clangLex
+ clangParse
+ clangSema
+ clangSerialization
+ )
add_clang_library(clangFrontend
ASTConsumers.cpp
@@ -15,9 +23,11 @@ add_clang_library(clangFrontend
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
+ HeaderIncludeGen.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
LangStandards.cpp
+ MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
StmtXML.cpp
TextDiagnosticBuffer.cpp
@@ -38,6 +48,7 @@ ENDIF(MSVC)
add_dependencies(clangFrontend
ClangAttrClasses
ClangAttrList
+ ClangCC1Options
ClangDiagnosticFrontend
ClangDiagnosticLex
ClangDiagnosticSema
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 53f7362..ee3fdd8 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -13,18 +13,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Path.h"
// FIXME: put this somewhere else?
#ifndef S_ISDIR
@@ -189,8 +191,6 @@ class PTHWriter {
void Emit16(uint32_t V) { ::Emit16(Out, V); }
- void Emit24(uint32_t V) { ::Emit24(Out, V); }
-
void Emit32(uint32_t V) { ::Emit32(Out, V); }
void EmitBuf(const char *Ptr, unsigned NumBytes) {
@@ -300,7 +300,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
ParsingPreprocessorDirective = false;
}
- if (Tok.is(tok::identifier)) {
+ if (Tok.is(tok::raw_identifier)) {
PP.LookUpIdentifierInfo(Tok);
EmitToken(Tok);
continue;
@@ -320,13 +320,13 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
// this case, discard both tokens.
if (NextTok.isAtStartOfLine())
goto NextToken;
-
+
// The token is the start of a directive. Emit it.
EmitToken(Tok);
Tok = NextTok;
// Did we see 'include'/'import'/'include_next'?
- if (Tok.isNot(tok::identifier)) {
+ if (Tok.isNot(tok::raw_identifier)) {
EmitToken(Tok);
continue;
}
@@ -353,7 +353,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
L.LexIncludeFilename(Tok);
L.setParsingPreprocessorDirective(false);
assert(!Tok.isAtStartOfLine());
- if (Tok.is(tok::identifier))
+ if (Tok.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(Tok);
break;
@@ -476,8 +476,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
const FileEntry *FE = C.Entry;
// FIXME: Handle files with non-absolute paths.
- llvm::sys::Path P(FE->getName());
- if (!P.isAbsolute())
+ if (llvm::sys::path::is_relative(FE->getName()))
continue;
const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM);
@@ -512,26 +511,27 @@ namespace {
/// as input to PTH generation. StatListener populates the PTHWriter's
/// file map with stat information for directories as well as negative stats.
/// Stat information for files are populated elsewhere.
-class StatListener : public StatSysCallCache {
+class StatListener : public FileSystemStatCache {
PTHMap &PM;
public:
StatListener(PTHMap &pm) : PM(pm) {}
~StatListener() {}
- int stat(const char *path, struct stat *buf) {
- int result = StatSysCallCache::stat(path, buf);
+ LookupResult getStat(const char *Path, struct stat &StatBuf,
+ int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
- if (result != 0) // Failed 'stat'.
- PM.insert(PTHEntryKeyVariant(path), PTHEntry());
- else if (S_ISDIR(buf->st_mode)) {
+ if (Result == CacheMissing) // Failed 'stat'.
+ PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
+ else if (S_ISDIR(StatBuf.st_mode)) {
// Only cache directories with absolute paths.
- if (!llvm::sys::Path(path).isAbsolute())
- return result;
+ if (llvm::sys::path::is_relative(Path))
+ return Result;
- PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry());
+ PM.insert(PTHEntryKeyVariant(&StatBuf, Path), PTHEntry());
}
- return result;
+ return Result;
}
};
} // end anonymous namespace
@@ -541,9 +541,9 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Get the name of the main file.
const SourceManager &SrcMgr = PP.getSourceManager();
const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
- llvm::sys::Path MainFilePath(MainFile->getName());
+ llvm::SmallString<128> MainFilePath(MainFile->getName());
- MainFilePath.makeAbsolute();
+ llvm::sys::fs::make_absolute(MainFilePath);
// Create the PTHWriter.
PTHWriter PW(*OS, PP);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ce0b072..fd593de 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -27,14 +27,16 @@
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/LLVMContext.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Timer.h"
-#include "llvm/System/Host.h"
-#include "llvm/System/Path.h"
-#include "llvm/System/Program.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/system_error.h"
using namespace clang;
CompilerInstance::CompilerInstance()
@@ -44,10 +46,6 @@ CompilerInstance::CompilerInstance()
CompilerInstance::~CompilerInstance() {
}
-void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) {
- LLVMContext.reset(Value);
-}
-
void CompilerInstance::setInvocation(CompilerInvocation *Value) {
Invocation.reset(Value);
}
@@ -89,26 +87,8 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
-namespace {
- class BinaryDiagnosticSerializer : public DiagnosticClient {
- llvm::raw_ostream &OS;
- SourceManager *SourceMgr;
- public:
- explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
- : OS(OS), SourceMgr(0) { }
-
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
- };
-}
-
-void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info) {
- StoredDiagnostic(DiagLevel, Info).Serialize(OS);
-}
-
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
- unsigned argc, char **argv,
+ unsigned argc, const char* const *argv,
Diagnostic &Diags) {
std::string ErrorInfo;
llvm::OwningPtr<llvm::raw_ostream> OS(
@@ -130,33 +110,24 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
}
-void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
- Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv);
+void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
+ DiagnosticClient *Client) {
+ Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client);
}
llvm::IntrusiveRefCntPtr<Diagnostic>
CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
- int Argc, char **Argv) {
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic());
+ int Argc, const char* const *Argv,
+ DiagnosticClient *Client) {
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID));
// Create the diagnostic client for reporting errors or for
// implementing -verify.
- llvm::OwningPtr<DiagnosticClient> DiagClient;
- if (Opts.BinaryOutput) {
- if (llvm::sys::Program::ChangeStderrToBinary()) {
- // We weren't able to set standard error to binary, which is a
- // bit of a problem. So, just create a text diagnostic printer
- // to complain about this problem, and pretend that the user
- // didn't try to use binary output.
- Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
- Diags->Report(diag::err_fe_stderr_binary);
- return Diags;
- } else {
- Diags->setClient(new BinaryDiagnosticSerializer(llvm::errs()));
- }
- } else {
+ if (Client)
+ Diags->setClient(Client);
+ else
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
- }
// Chain in -verify checker, if requested.
if (Opts.VerifyDiagnostics)
@@ -174,13 +145,13 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
// File Manager
void CompilerInstance::createFileManager() {
- FileMgr.reset(new FileManager());
+ FileMgr.reset(new FileManager(getFileSystemOpts()));
}
// Source Manager
-void CompilerInstance::createSourceManager() {
- SourceMgr.reset(new SourceManager(getDiagnostics()));
+void CompilerInstance::createSourceManager(FileManager &FileMgr) {
+ SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr));
}
// Preprocessor
@@ -231,6 +202,16 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
if (!DepOpts.OutputFile.empty())
AttachDependencyFileGen(*PP, DepOpts);
+ // Handle generating header include information, if requested.
+ if (DepOpts.ShowHeaderIncludes)
+ AttachHeaderIncludeGen(*PP);
+ if (!DepOpts.HeaderIncludeOutputFile.empty()) {
+ llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
+ if (OutputPath == "-")
+ OutputPath = "";
+ AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath);
+ }
+
return PP;
}
@@ -248,12 +229,16 @@ void CompilerInstance::createASTContext() {
void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
bool DisablePCHValidation,
+ bool DisableStatCache,
void *DeserializationListener){
llvm::OwningPtr<ExternalASTSource> Source;
+ bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
- DisablePCHValidation,
+ DisablePCHValidation,
+ DisableStatCache,
getPreprocessor(), getASTContext(),
- DeserializationListener));
+ DeserializationListener,
+ Preamble));
getASTContext().setExternalSource(Source);
}
@@ -261,17 +246,20 @@ ExternalASTSource *
CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
const std::string &Sysroot,
bool DisablePCHValidation,
+ bool DisableStatCache,
Preprocessor &PP,
ASTContext &Context,
- void *DeserializationListener) {
+ void *DeserializationListener,
+ bool Preamble) {
llvm::OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, &Context,
Sysroot.empty() ? 0 : Sysroot.c_str(),
- DisablePCHValidation));
+ DisablePCHValidation, DisableStatCache));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
- switch (Reader->ReadAST(Path)) {
+ switch (Reader->ReadAST(Path,
+ Preamble ? ASTReader::Preamble : ASTReader::PCH)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
@@ -316,7 +304,6 @@ void CompilerInstance::createCodeCompletionConsumer() {
CompletionConsumer.reset(
createCodeCompletionConsumer(getPreprocessor(),
Loc.FileName, Loc.Line, Loc.Column,
- getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
getFrontendOpts().ShowCodePatternsInCodeCompletion,
getFrontendOpts().ShowGlobalSymbolsInCodeCompletion,
@@ -345,7 +332,6 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
const std::string &Filename,
unsigned Line,
unsigned Column,
- bool UseDebugPrinter,
bool ShowMacros,
bool ShowCodePatterns,
bool ShowGlobals,
@@ -354,11 +340,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
return 0;
// Set up the creation routine for code-completion.
- if (UseDebugPrinter)
- return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
- ShowGlobals, OS);
- else
- return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
+ return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
ShowGlobals, OS);
}
@@ -370,18 +352,34 @@ void CompilerInstance::createSema(bool CompleteTranslationUnit,
// Output Files
-void CompilerInstance::addOutputFile(llvm::StringRef Path,
- llvm::raw_ostream *OS) {
- assert(OS && "Attempt to add empty stream to output list!");
- OutputFiles.push_back(std::make_pair(Path, OS));
+void CompilerInstance::addOutputFile(const OutputFile &OutFile) {
+ assert(OutFile.OS && "Attempt to add empty stream to output list!");
+ OutputFiles.push_back(OutFile);
}
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
- for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
+ for (std::list<OutputFile>::iterator
it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
- delete it->second;
- if (EraseFiles && !it->first.empty())
- llvm::sys::Path(it->first).eraseFromDisk();
+ delete it->OS;
+ if (!it->TempFilename.empty()) {
+ llvm::sys::Path TempPath(it->TempFilename);
+ if (EraseFiles)
+ TempPath.eraseFromDisk();
+ else {
+ std::string Error;
+ llvm::sys::Path NewOutFile(it->Filename);
+ // If '-working-directory' was passed, the output filename should be
+ // relative to that.
+ FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts());
+ if (TempPath.renamePathOnDisk(NewOutFile, &Error)) {
+ getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
+ << it->TempFilename << it->Filename << Error;
+ TempPath.eraseFromDisk();
+ }
+ }
+ } else if (!it->Filename.empty() && EraseFiles)
+ llvm::sys::Path(it->Filename).eraseFromDisk();
+
}
OutputFiles.clear();
}
@@ -391,18 +389,20 @@ CompilerInstance::createDefaultOutputFile(bool Binary,
llvm::StringRef InFile,
llvm::StringRef Extension) {
return createOutputFile(getFrontendOpts().OutputFile, Binary,
- InFile, Extension);
+ /*RemoveFileOnSignal=*/true, InFile, Extension);
}
llvm::raw_fd_ostream *
CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
- bool Binary,
+ bool Binary, bool RemoveFileOnSignal,
llvm::StringRef InFile,
llvm::StringRef Extension) {
- std::string Error, OutputPathName;
+ std::string Error, OutputPathName, TempPathName;
llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
+ RemoveFileOnSignal,
InFile, Extension,
- &OutputPathName);
+ &OutputPathName,
+ &TempPathName);
if (!OS) {
getDiagnostics().Report(diag::err_fe_unable_to_open_output)
<< OutputPath << Error;
@@ -411,7 +411,8 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
// Add the output file -- but don't try to remove "-", since this means we are
// using stdin.
- addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
+ addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
+ TempPathName, OS));
return OS;
}
@@ -420,10 +421,12 @@ llvm::raw_fd_ostream *
CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
std::string &Error,
bool Binary,
+ bool RemoveFileOnSignal,
llvm::StringRef InFile,
llvm::StringRef Extension,
- std::string *ResultPathName) {
- std::string OutFile;
+ std::string *ResultPathName,
+ std::string *TempPathName) {
+ std::string OutFile, TempFile;
if (!OutputPath.empty()) {
OutFile = OutputPath;
} else if (InFile == "-") {
@@ -436,15 +439,39 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
} else {
OutFile = "-";
}
+
+ if (OutFile != "-") {
+ llvm::sys::Path OutPath(OutFile);
+ // Only create the temporary if we can actually write to OutPath, otherwise
+ // we want to fail early.
+ bool Exists;
+ if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) ||
+ (OutPath.isRegularFile() && OutPath.canWrite())) {
+ // Create a temporary file.
+ llvm::sys::Path TempPath(OutFile);
+ if (!TempPath.createTemporaryFileOnDisk())
+ TempFile = TempPath.str();
+ }
+ }
+
+ std::string OSFile = OutFile;
+ if (!TempFile.empty())
+ OSFile = TempFile;
llvm::OwningPtr<llvm::raw_fd_ostream> OS(
- new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ new llvm::raw_fd_ostream(OSFile.c_str(), Error,
(Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
if (!Error.empty())
return 0;
+ // Make sure the out stream file gets removed if we crash.
+ if (RemoveFileOnSignal)
+ llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile));
+
if (ResultPathName)
*ResultPathName = OutFile;
+ if (TempPathName)
+ *TempPathName = TempFile;
return OS.take();
}
@@ -461,23 +488,32 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
FileManager &FileMgr,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
- // Figure out where to get and map in the main file.
- if (InputFile != "-") {
+ // Figure out where to get and map in the main file, unless it's already
+ // been created (e.g., by a precompiled preamble).
+ if (!SourceMgr.getMainFileID().isInvalid()) {
+ // Do nothing: the main file has already been set.
+ } else if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
- if (File) SourceMgr.createMainFileID(File);
- if (SourceMgr.getMainFileID().isInvalid()) {
+ if (!File) {
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}
+ SourceMgr.createMainFileID(File);
} else {
- llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
- if (SB) SourceMgr.createMainFileIDForMemBuffer(SB);
- if (SourceMgr.getMainFileID().isInvalid()) {
+ llvm::OwningPtr<llvm::MemoryBuffer> SB;
+ if (llvm::MemoryBuffer::getSTDIN(SB)) {
+ // FIXME: Give ec.message() in this diag.
Diags.Report(diag::err_fe_error_reading_stdin);
return false;
}
+ const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
+ SB->getBufferSize(), 0);
+ SourceMgr.createMainFileID(File);
+ SourceMgr.overrideFileContents(File, SB.take());
}
+ assert(!SourceMgr.getMainFileID().isInvalid() &&
+ "Couldn't establish MainFileID!");
return true;
}
@@ -529,9 +565,10 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
if (getDiagnosticOpts().ShowCarets) {
- unsigned NumWarnings = getDiagnostics().getNumWarnings();
- unsigned NumErrors = getDiagnostics().getNumErrors() -
- getDiagnostics().getNumErrorsSuppressed();
+ // We can have multiple diagnostics sharing one diagnostic client.
+ // Get the total number of warnings/errors from the client.
+ unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
+ unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();
if (NumWarnings)
OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
@@ -548,15 +585,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
OS << "\n";
}
- // Return the appropriate status when verifying diagnostics.
- //
- // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
- // this.
- if (getDiagnosticOpts().VerifyDiagnostics)
- return !static_cast<VerifyDiagnosticsClient&>(
- getDiagnosticClient()).HadErrors();
-
- return !getDiagnostics().getNumErrors();
+ return !getDiagnostics().getClient()->getNumErrors();
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 8c64483..103d251 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -10,6 +10,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/CC1Options.h"
@@ -25,8 +26,8 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/System/Host.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
using namespace clang;
static const char *getAnalysisName(Analyses Kind) {
@@ -99,6 +100,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-display-progress");
if (Opts.AnalyzeNestedBlocks)
Res.push_back("-analyzer-opt-analyze-nested-blocks");
+ if (Opts.AnalyzerStats)
+ Res.push_back("-analyzer-stats");
if (Opts.EagerlyAssume)
Res.push_back("-analyzer-eagerly-assume");
if (!Opts.PurgeDead)
@@ -113,8 +116,17 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-experimental-checks");
if (Opts.EnableExperimentalInternalChecks)
Res.push_back("-analyzer-experimental-internal-checks");
- if (Opts.IdempotentOps)
- Res.push_back("-analyzer-check-idempotent-operations");
+ if (Opts.BufferOverflows)
+ Res.push_back("-analyzer-check-buffer-overflows");
+
+ for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) {
+ const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i];
+ if (opt.second)
+ Res.push_back("-analyzer-disable-checker");
+ else
+ Res.push_back("-analyzer-checker");
+ Res.push_back(opt.first);
+ }
}
static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
@@ -150,7 +162,7 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
// TimePasses is only derived.
// UnitAtATime is unused.
// Inlining is only derived.
-
+
// UnrollLoops is derived, but also accepts an option, no
// harm in pushing it back here.
if (Opts.UnrollLoops)
@@ -195,6 +207,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fobjc-dispatch-method=non-legacy");
break;
}
+ if (Opts.NumRegisterParameters) {
+ Res.push_back("-mregparm");
+ Res.push_back(llvm::utostr(Opts.NumRegisterParameters));
+ }
if (Opts.RelaxAll)
Res.push_back("-mrelax-all");
if (Opts.SoftFloat)
@@ -213,6 +229,12 @@ static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
std::vector<std::string> &Res) {
if (Opts.IncludeSystemHeaders)
Res.push_back("-sys-header-deps");
+ if (Opts.ShowHeaderIncludes)
+ Res.push_back("-H");
+ if (!Opts.HeaderIncludeOutputFile.empty()) {
+ Res.push_back("-header-include-file");
+ Res.push_back(Opts.HeaderIncludeOutputFile);
+ }
if (Opts.UsePhonyTargets)
Res.push_back("-MP");
if (!Opts.OutputFile.empty()) {
@@ -251,8 +273,6 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
- if (Opts.BinaryOutput)
- Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.ShowCategories == 1)
@@ -301,6 +321,7 @@ static const char *getInputKindName(InputKind Kind) {
case IK_ObjC: return "objective-c";
case IK_ObjCXX: return "objective-c++";
case IK_OpenCL: return "cl";
+ case IK_CUDA: return "cuda";
case IK_PreprocessedC: return "cpp-output";
case IK_PreprocessedCXX: return "c++-cpp-output";
case IK_PreprocessedObjC: return "objective-c-cpp-output";
@@ -314,10 +335,10 @@ static const char *getInputKindName(InputKind Kind) {
static const char *getActionName(frontend::ActionKind Kind) {
switch (Kind) {
case frontend::PluginAction:
- case frontend::InheritanceView:
llvm_unreachable("Invalid kind!");
case frontend::ASTDump: return "-ast-dump";
+ case frontend::ASTDumpXML: return "-ast-dump-xml";
case frontend::ASTPrint: return "-ast-print";
case frontend::ASTPrintXML: return "-ast-print-xml";
case frontend::ASTView: return "-ast-view";
@@ -351,10 +372,16 @@ static const char *getActionName(frontend::ActionKind Kind) {
return 0;
}
+static void FileSystemOptsToArgs(const FileSystemOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.WorkingDir.empty()) {
+ Res.push_back("-working-directory");
+ Res.push_back(Opts.WorkingDir);
+ }
+}
+
static void FrontendOptsToArgs(const FrontendOptions &Opts,
std::vector<std::string> &Res) {
- if (!Opts.DebugCodeCompletionPrinter)
- Res.push_back("-no-code-completion-debug-printer");
if (Opts.DisableFree)
Res.push_back("-disable-free");
if (Opts.RelocatablePCH)
@@ -397,18 +424,13 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-o");
Res.push_back(Opts.OutputFile);
}
- if (!Opts.ViewClassInheritance.empty()) {
- Res.push_back("-cxx-inheritance-view");
- Res.push_back(Opts.ViewClassInheritance);
- }
if (!Opts.CodeCompletionAt.FileName.empty()) {
Res.push_back("-code-completion-at");
Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
llvm::utostr(Opts.CodeCompletionAt.Column));
}
- if (Opts.ProgramAction != frontend::InheritanceView &&
- Opts.ProgramAction != frontend::PluginAction)
+ if (Opts.ProgramAction != frontend::PluginAction)
Res.push_back(getActionName(Opts.ProgramAction));
if (!Opts.ActionName.empty()) {
Res.push_back("-plugin");
@@ -422,6 +444,14 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-load");
Res.push_back(Opts.Plugins[i]);
}
+ for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
+ Res.push_back("-add-plugin");
+ Res.push_back(Opts.AddPluginActions[i]);
+ for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) {
+ Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i]);
+ Res.push_back(Opts.AddPluginArgs[i][ai]);
+ }
+ }
for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
Res.push_back("-ast-merge");
Res.push_back(Opts.ASTMergeFiles[i]);
@@ -443,6 +473,11 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back(Opts.Sysroot);
}
+ for (unsigned i = 0, e = Opts.CXXSystemIncludes.size(); i != e; ++i) {
+ Res.push_back("-cxx-system-include");
+ Res.push_back(Opts.CXXSystemIncludes[i]);
+ }
+
/// User specified include entries.
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
@@ -526,12 +561,16 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fgnu-keywords");
if (Opts.Microsoft)
Res.push_back("-fms-extensions");
+ if (Opts.MSCVersion != 0)
+ Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
if (Opts.Borland)
Res.push_back("-fborland-extensions");
if (Opts.ObjCNonFragileABI)
Res.push_back("-fobjc-nonfragile-abi");
if (Opts.ObjCNonFragileABI2)
- Res.push_back("-fobjc-nonfragile-abi2");
+ Res.push_back("-fobjc-nonfragile-abi");
+ if (Opts.ObjCDefaultSynthProperties)
+ Res.push_back("-fobjc-default-synthesize-properties");
// NoInline is implicit.
if (!Opts.CXXOperatorNames)
Res.push_back("-fno-operator-names");
@@ -551,8 +590,12 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fexceptions");
if (Opts.SjLjExceptions)
Res.push_back("-fsjlj-exceptions");
+ if (!Opts.ObjCExceptions)
+ Res.push_back("-fno-objc-exceptions");
if (!Opts.RTTI)
Res.push_back("-fno-rtti");
+ if (Opts.MSBitfields)
+ Res.push_back("-mms-bitfields");
if (!Opts.NeXTRuntime)
Res.push_back("-fgnu-runtime");
if (Opts.Freestanding)
@@ -574,7 +617,12 @@ static void LangOptsToArgs(const LangOptions &Opts,
switch (Opts.getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined: break;
case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break;
- case LangOptions::SOB_Trapping: Res.push_back("-ftrapv"); break;
+ case LangOptions::SOB_Trapping:
+ Res.push_back("-ftrapv"); break;
+ if (!Opts.OverflowHandler.empty()) {
+ Res.push_back("-ftrapv-handler");
+ Res.push_back(Opts.OverflowHandler);
+ }
}
if (Opts.HeinousExtensions)
Res.push_back("-fheinous-gnu-extensions");
@@ -588,8 +636,6 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fdump-vtable-layouts");
if (Opts.NoBitFieldTypeAlign)
Res.push_back("-fno-bitfield-type-alignment");
- if (Opts.SjLjExceptions)
- Res.push_back("-fsjlj-exceptions");
if (Opts.PICLevel) {
Res.push_back("-pic-level");
Res.push_back(llvm::utostr(Opts.PICLevel));
@@ -614,19 +660,22 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fobjc-gc-only");
}
}
- if (Opts.getVisibilityMode() != LangOptions::Default) {
+ if (Opts.AppleKext)
+ Res.push_back("-fapple-kext");
+
+ if (Opts.getVisibilityMode() != DefaultVisibility) {
Res.push_back("-fvisibility");
- if (Opts.getVisibilityMode() == LangOptions::Hidden) {
+ if (Opts.getVisibilityMode() == HiddenVisibility) {
Res.push_back("hidden");
} else {
- assert(Opts.getVisibilityMode() == LangOptions::Protected &&
+ assert(Opts.getVisibilityMode() == ProtectedVisibility &&
"Invalid visibility!");
Res.push_back("protected");
}
}
if (Opts.InlineVisibilityHidden)
Res.push_back("-fvisibility-inlines-hidden");
-
+
if (Opts.getStackProtectorMode() != 0) {
Res.push_back("-stack-protector");
Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
@@ -692,8 +741,6 @@ static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
else if (!Opts.ShowCPP && Opts.ShowMacros)
Res.push_back("-dM");
- if (Opts.ShowHeaderIncludes)
- Res.push_back("-H");
if (!Opts.ShowLineMarkers)
Res.push_back("-P");
if (Opts.ShowComments)
@@ -733,6 +780,7 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
CodeGenOptsToArgs(getCodeGenOpts(), Res);
DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
+ FileSystemOptsToArgs(getFileSystemOpts(), Res);
FrontendOptsToArgs(getFrontendOpts(), Res);
HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
LangOptsToArgs(getLangOpts(), Res);
@@ -750,6 +798,16 @@ using namespace clang::driver::cc1options;
//
+static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
+ Diagnostic &Diags) {
+ unsigned DefaultOpt = 0;
+ if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
+ DefaultOpt = 2;
+ // -Os implies -O2
+ return Args.hasArg(OPT_Os) ? 2 :
+ Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags);
+}
+
static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Diagnostic &Diags) {
using namespace cc1options;
@@ -810,33 +868,44 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
+ Opts.AnalyzerStats = Args.hasArg(OPT_analysis_AnalyzerStats);
Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
+ Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors);
+ Opts.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers);
Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
Opts.EnableExperimentalInternalChecks =
Args.hasArg(OPT_analyzer_experimental_internal_checks);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
- Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags);
+ Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
+ Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
- Opts.IdempotentOps = Args.hasArg(OPT_analysis_WarnIdempotentOps);
+ Opts.BufferOverflows = Args.hasArg(OPT_analysis_WarnBufferOverflows);
+
+ Opts.CheckersControlList.clear();
+ for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
+ OPT_analyzer_disable_checker),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ A->claim();
+ bool enable = (A->getOption().getID() == OPT_analyzer_checker);
+ Opts.CheckersControlList.push_back(std::make_pair(A->getValue(Args),
+ enable));
+ }
}
-static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
+static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diagnostic &Diags) {
using namespace cc1options;
- // -Os implies -O2
- if (Args.hasArg(OPT_Os))
- Opts.OptimizationLevel = 2;
- else {
- Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags);
- if (Opts.OptimizationLevel > 3) {
- Diags.Report(diag::err_drv_invalid_value)
- << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
- Opts.OptimizationLevel = 3;
- }
+
+ Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
+ if (Opts.OptimizationLevel > 3) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
+ Opts.OptimizationLevel = 3;
}
// We must always run at least the always inlining pass.
@@ -844,8 +913,10 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
: CodeGenOptions::OnlyAlwaysInlining;
Opts.DebugInfo = Args.hasArg(OPT_g);
+ Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
+ Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
@@ -853,7 +924,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.OptimizeSize = Args.hasArg(OPT_Os);
Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
Args.hasArg(OPT_ffreestanding));
- Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) ||
+ Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) ||
(Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
@@ -864,11 +935,17 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables);
+ Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
+ Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)||
+ Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
+ Opts.UnsafeFPMath = 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");
@@ -879,6 +956,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+ Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
llvm::StringRef Name = A->getValue(Args);
@@ -901,6 +979,8 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.Targets = Args.getAllArgValues(OPT_MT);
Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps);
Opts.UsePhonyTargets = Args.hasArg(OPT_MP);
+ Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
+ Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file);
}
static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
@@ -940,18 +1020,17 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
-
+
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
- Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
Opts.MacroBacktraceLimit
- = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
+ = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
DiagnosticOptions::DefaultMacroBacktraceLimit, Diags);
Opts.TemplateBacktraceLimit
- = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
- DiagnosticOptions::DefaultTemplateBacktraceLimit,
+ = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
+ DiagnosticOptions::DefaultTemplateBacktraceLimit,
Diags);
Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
@@ -965,6 +1044,10 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.Warnings = Args.getAllArgValues(OPT_W);
}
+static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
+ Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory);
+}
+
static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Diagnostic &Diags) {
using namespace cc1options;
@@ -975,6 +1058,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
assert(0 && "Invalid option in group!");
case OPT_ast_dump:
Opts.ProgramAction = frontend::ASTDump; break;
+ case OPT_ast_dump_xml:
+ Opts.ProgramAction = frontend::ASTDumpXML; break;
case OPT_ast_print:
Opts.ProgramAction = frontend::ASTPrint; break;
case OPT_ast_print_xml:
@@ -1047,6 +1132,16 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
}
}
+ Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin);
+ Opts.AddPluginArgs.resize(Opts.AddPluginActions.size());
+ for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
+ for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
+ end = Args.filtered_end(); it != end; ++it) {
+ if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i])
+ Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1));
+ }
+ }
+
if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
Opts.CodeCompletionAt =
ParsedSourceLocation::FromString(A->getValue(Args));
@@ -1054,8 +1149,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue(Args);
}
- Opts.DebugCodeCompletionPrinter =
- !Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.OutputFile = Args.getLastArgValue(OPT_o);
@@ -1071,7 +1164,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ShowStats = Args.hasArg(OPT_print_stats);
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.ShowVersion = Args.hasArg(OPT_version);
- Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view);
Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
@@ -1084,6 +1176,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("cl", IK_OpenCL)
.Case("c", IK_C)
.Case("cl", IK_OpenCL)
+ .Case("cuda", IK_CUDA)
.Case("c++", IK_CXX)
.Case("objective-c", IK_ObjC)
.Case("objective-c++", IK_ObjCXX)
@@ -1143,6 +1236,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
using namespace cc1options;
+ Opts.CXXSystemIncludes = Args.getAllArgValues(OPT_cxx_system_include);
Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
@@ -1186,10 +1280,8 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
// FIXME: Need options for the various environment variables!
}
-static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
- Diagnostic &Diags) {
- // FIXME: Cleanup per-file based stuff.
-
+void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
+ LangStandard::Kind LangStd) {
// Set some properties which depend soley 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.
@@ -1202,18 +1294,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ObjC1 = Opts.ObjC2 = 1;
}
- LangStandard::Kind LangStd = LangStandard::lang_unspecified;
- if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
- LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
-#define LANGSTANDARD(id, name, desc, features) \
- .Case(name, LangStandard::lang_##id)
-#include "clang/Frontend/LangStandards.def"
- .Default(LangStandard::lang_unspecified);
- if (LangStd == LangStandard::lang_unspecified)
- Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
- }
-
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
switch (IK) {
@@ -1224,6 +1304,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
case IK_OpenCL:
LangStd = LangStandard::lang_opencl;
break;
+ case IK_CUDA:
+ LangStd = LangStandard::lang_cuda;
+ break;
case IK_Asm:
case IK_C:
case IK_PreprocessedC:
@@ -1257,26 +1340,71 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.AltiVec = 1;
Opts.CXXOperatorNames = 1;
Opts.LaxVectorConversions = 1;
+ Opts.DefaultFPContract = 1;
}
+ if (LangStd == LangStandard::lang_cuda)
+ Opts.CUDA = 1;
+
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ Opts.GNUKeywords = Opts.GNUMode;
+ Opts.CXXOperatorNames = Opts.CPlusPlus;
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ Opts.Trigraphs = !Opts.GNUMode;
+
+ Opts.DollarIdents = !Opts.AsmPreprocessor;
+}
+
+static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
+ Diagnostic &Diags) {
+ // FIXME: Cleanup per-file based stuff.
+ LangStandard::Kind LangStd = LangStandard::lang_unspecified;
+ if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
+ LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+#define LANGSTANDARD(id, name, desc, features) \
+ .Case(name, LangStandard::lang_##id)
+#include "clang/Frontend/LangStandards.def"
+ .Default(LangStandard::lang_unspecified);
+ if (LangStd == LangStandard::lang_unspecified)
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+
+ if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
+ if (strcmp(A->getValue(Args), "CL1.1") != 0) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue(Args);
+ }
+ }
+
+ CompilerInvocation::setLangDefaults(Opts, IK, LangStd);
+
// We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension
// keywords. This behavior is provided by GCC's poorly named '-fasm' flag,
// while a subset (the non-C++ GNU keywords) is provided by GCC's
// '-fgnu-keywords'. Clang conflates the two for simplicity under the single
// name, as it doesn't seem a useful distinction.
Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
- Opts.GNUMode);
+ Opts.GNUKeywords);
- if (Opts.CPlusPlus)
- Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
+ if (Args.hasArg(OPT_fno_operator_names))
+ Opts.CXXOperatorNames = 0;
if (Args.hasArg(OPT_fobjc_gc_only))
Opts.setGCMode(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
Opts.setGCMode(LangOptions::HybridGC);
+
+ if (Args.hasArg(OPT_fapple_kext)) {
+ if (!Opts.CPlusPlus)
+ Diags.Report(diag::warn_c_kext);
+ else
+ Opts.AppleKext = 1;
+ }
if (Args.hasArg(OPT_print_ivar_layout))
Opts.ObjCGCBitmapPrint = 1;
@@ -1291,34 +1419,36 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
if (Vis == "default")
- Opts.setVisibilityMode(LangOptions::Default);
+ Opts.setVisibilityMode(DefaultVisibility);
else if (Vis == "hidden")
- Opts.setVisibilityMode(LangOptions::Hidden);
+ Opts.setVisibilityMode(HiddenVisibility);
else if (Vis == "protected")
- Opts.setVisibilityMode(LangOptions::Protected);
+ Opts.setVisibilityMode(ProtectedVisibility);
else
Diags.Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
if (Args.hasArg(OPT_fvisibility_inlines_hidden))
Opts.InlineVisibilityHidden = 1;
-
- if (Args.hasArg(OPT_ftrapv))
- Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping);
+
+ if (Args.hasArg(OPT_ftrapv)) {
+ Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping);
+ // Set the handler, if one is specified.
+ Opts.OverflowHandler =
+ Args.getLastArgValue(OPT_ftrapv_handler);
+ }
else if (Args.hasArg(OPT_fwrapv))
- Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
+ Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
- // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
- // is specified, or -std is set to a conforming mode.
- Opts.Trigraphs = !Opts.GNUMode;
if (Args.hasArg(OPT_trigraphs))
Opts.Trigraphs = 1;
Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
OPT_fno_dollars_in_identifiers,
- !Opts.AsmPreprocessor);
+ Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+ Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
@@ -1327,10 +1457,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_threadsafe_statics))
Opts.ThreadsafeStatics = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
+ Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions);
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
+ Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
@@ -1340,27 +1472,33 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
Diags);
+ Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy,
+ 0, Diags);
+ Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
Opts.ObjCConstantStringClass =
Args.getLastArgValue(OPT_fconstant_string_class);
Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
- Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2);
- if (Opts.ObjCNonFragileABI2)
- Opts.ObjCNonFragileABI = true;
+ if (Opts.ObjCNonFragileABI)
+ Opts.ObjCNonFragileABI2 = true;
+ Opts.ObjCDefaultSynthProperties =
+ Args.hasArg(OPT_fobjc_default_synthesize_properties);
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
+ Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking);
Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
+ Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant);
+ Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.OptimizeSize = 0;
// FIXME: Eliminate this dependency.
- unsigned Opt =
- Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags);
+ unsigned Opt = getOptimizationLevel(Args, IK, Diags);
Opts.Optimize = Opt != 0;
// This is the __NO_INLINE__ define, which just depends on things like the
@@ -1383,6 +1521,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
+ FileManager &FileMgr,
Diagnostic &Diags) {
using namespace cc1options;
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
@@ -1395,12 +1534,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
+ Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
+ for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args));
+ }
+
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
llvm::StringRef Value(A->getValue(Args));
size_t Comma = Value.find(',');
unsigned Bytes = 0;
unsigned EndOfLine = 0;
-
+
if (Comma == llvm::StringRef::npos ||
Value.substr(0, Comma).getAsInteger(10, Bytes) ||
Value.substr(Comma + 1).getAsInteger(10, EndOfLine))
@@ -1410,7 +1556,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0);
}
}
-
+
// Add macros from the command line.
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
@@ -1430,7 +1576,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
// PCH is handled specially, we need to extra the original include path.
if (A->getOption().matches(OPT_include_pch)) {
std::string OriginalFile =
- ASTReader::getOriginalSourceFile(A->getValue(Args), Diags);
+ ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags);
if (OriginalFile.empty())
continue;
@@ -1463,7 +1609,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
using namespace cc1options;
Opts.ShowCPP = !Args.hasArg(OPT_dM);
Opts.ShowComments = Args.hasArg(OPT_C);
- Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
Opts.ShowMacroComments = Args.hasArg(OPT_CC);
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
@@ -1486,8 +1631,8 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
//
void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
- const char **ArgBegin,
- const char **ArgEnd,
+ const char *const *ArgBegin,
+ const char *const *ArgEnd,
Diagnostic &Diags) {
// Parse the arguments.
llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
@@ -1506,14 +1651,21 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args);
ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags);
- ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags);
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+ ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
+ // FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
+ ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags);
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != IK_AST && DashX != IK_LLVM_IR)
ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
- ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags);
+ // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of
+ // PCH file and find the original header name. Remove the need to do that in
+ // ParsePreprocessorArgs and remove the FileManager
+ // parameters from the function and the "FileManager.h" #include.
+ FileManager FileMgr(Res.getFileSystemOpts());
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
}
diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp
index 97a7f55..8d3d225 100644
--- a/lib/Frontend/DeclXML.cpp
+++ b/lib/Frontend/DeclXML.cpp
@@ -38,10 +38,12 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
}
void addSubNodes(RecordDecl* RD) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- Visit(*i);
- Doc.toParent();
+ for (RecordDecl::decl_iterator i = RD->decls_begin(),
+ e = RD->decls_end(); i != e; ++i) {
+ if (!(*i)->isImplicit()) {
+ Visit(*i);
+ Doc.toParent();
+ }
}
}
@@ -71,15 +73,7 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
Doc.addAttribute("is_virtual", base->isVirtual());
Doc.toParent();
}
-
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- Visit(*i);
- Doc.toParent();
- }
-
}
-
}
void addSubNodes(EnumDecl* ED) {
@@ -110,7 +104,7 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
Doc.PrintStmt(argDecl->getDefaultArg());
}
- void addSubNodes(NamespaceDecl* ns) {
+ void addSubNodes(DeclContext* ns) {
for (DeclContext::decl_iterator
d = ns->decls_begin(),
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index cdff807..bc5a55d 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -13,7 +13,6 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -22,7 +21,6 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/raw_ostream.h"
-#include <string>
using namespace clang;
@@ -117,6 +115,16 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
Files.push_back(Filename);
}
+/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other
+/// scary characters.
+static void PrintFilename(llvm::raw_ostream &OS, llvm::StringRef Filename) {
+ for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
+ if (Filename[i] == ' ')
+ OS << '\\';
+ OS << Filename[i];
+ }
+}
+
void DependencyFileCallback::OutputDependencyFile() {
// Write out the dependency targets, trying to avoid overly long
// lines when possible. We try our best to emit exactly the same
@@ -130,14 +138,15 @@ void DependencyFileCallback::OutputDependencyFile() {
unsigned N = I->length();
if (Columns == 0) {
Columns += N;
- *OS << *I;
} else if (Columns + N + 2 > MaxColumns) {
Columns = N + 2;
- *OS << " \\\n " << *I;
+ *OS << " \\\n ";
} else {
Columns += N + 1;
- *OS << ' ' << *I;
+ *OS << ' ';
}
+ // Targets already quoted as needed.
+ *OS << *I;
}
*OS << ':';
@@ -155,7 +164,8 @@ void DependencyFileCallback::OutputDependencyFile() {
*OS << " \\\n ";
Columns = 2;
}
- *OS << ' ' << *I;
+ *OS << ' ';
+ PrintFilename(*OS, *I);
Columns += N + 1;
}
*OS << '\n';
@@ -166,7 +176,8 @@ void DependencyFileCallback::OutputDependencyFile() {
for (std::vector<std::string>::iterator I = Files.begin() + 1,
E = Files.end(); I != E; ++I) {
*OS << '\n';
- *OS << *I << ":\n";
+ PrintFilename(*OS, *I);
+ *OS << ":\n";
}
}
}
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index 894f230..b24ece5 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -17,6 +17,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include <cstdio>
namespace clang {
@@ -104,7 +106,11 @@ std::string DocumentXML::escapeString(const char* pStr,
if (isprint(C))
value += C;
else {
+#ifdef LLVM_ON_WIN32
sprintf(buffer, "\\%03o", C);
+#else
+ snprintf(buffer, sizeof(buffer), "\\%03o", C);
+#endif
value += buffer;
}
break;
@@ -321,9 +327,11 @@ PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
if (!SpellingLoc.isInvalid())
{
PLoc = SM.getPresumedLoc(SpellingLoc);
- addSourceFileAttribute(PLoc.getFilename());
- addAttribute("line", PLoc.getLine());
- addAttribute("col", PLoc.getColumn());
+ if (PLoc.isValid()) {
+ addSourceFileAttribute(PLoc.getFilename());
+ addAttribute("line", PLoc.getLine());
+ addAttribute("col", PLoc.getColumn());
+ }
}
// else there is no error in some cases (eg. CXXThisExpr)
return PLoc;
@@ -340,8 +348,9 @@ void DocumentXML::addLocationRange(const SourceRange& R)
if (!SpellingLoc.isInvalid())
{
PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
- if (PStartLoc.isInvalid() ||
- strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
+ if (PLoc.isInvalid()) {
+ } else if (PStartLoc.isInvalid() ||
+ strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
addAttribute("endfile", PLoc.getFilename());
addAttribute("endline", PLoc.getLine());
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index b244c5c..e3d8b85 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -10,18 +10,73 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclGroup.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Parse/ParseAST.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+namespace {
+
+/// \brief Dumps deserialized declarations.
+class DeserializedDeclsDumper : public ASTDeserializationListener {
+ ASTDeserializationListener *Previous;
+
+public:
+ DeserializedDeclsDumper(ASTDeserializationListener *Previous)
+ : Previous(Previous) { }
+
+ virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ llvm::outs() << "PCH DECL: " << D->getDeclKindName();
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ llvm::outs() << " - " << ND->getNameAsString();
+ llvm::outs() << "\n";
+
+ if (Previous)
+ Previous->DeclRead(ID, D);
+ }
+};
+
+ /// \brief Checks deserialized declarations and emits error if a name
+ /// matches one given in command-line using -error-on-deserialized-decl.
+ class DeserializedDeclsChecker : public ASTDeserializationListener {
+ ASTContext &Ctx;
+ std::set<std::string> NamesToCheck;
+ ASTDeserializationListener *Previous;
+
+ public:
+ DeserializedDeclsChecker(ASTContext &Ctx,
+ const std::set<std::string> &NamesToCheck,
+ ASTDeserializationListener *Previous)
+ : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
+
+ virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
+ unsigned DiagID
+ = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error,
+ "%0 was deserialized");
+ Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
+ << ND->getNameAsString();
+ }
+
+ if (Previous)
+ Previous->DeclRead(ID, D);
+ }
+};
+
+} // end anonymous namespace
+
FrontendAction::FrontendAction() : Instance(0) {}
FrontendAction::~FrontendAction() {}
@@ -33,6 +88,39 @@ void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
CurrentASTUnit.reset(AST);
}
+ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ ASTConsumer* Consumer = CreateASTConsumer(CI, InFile);
+ if (!Consumer)
+ return 0;
+
+ if (CI.getFrontendOpts().AddPluginActions.size() == 0)
+ return Consumer;
+
+ // Make sure the non-plugin consumer is first, so that plugins can't
+ // modifiy the AST.
+ std::vector<ASTConsumer*> Consumers(1, Consumer);
+
+ for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size();
+ i != e; ++i) {
+ // This is O(|plugins| * |add_plugins|), but since both numbers are
+ // way below 50 in practice, that's ok.
+ for (FrontendPluginRegistry::iterator
+ it = FrontendPluginRegistry::begin(),
+ ie = FrontendPluginRegistry::end();
+ it != ie; ++it) {
+ if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) {
+ llvm::OwningPtr<PluginASTAction> P(it->instantiate());
+ FrontendAction* c = P.get();
+ if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
+ Consumers.push_back(c->CreateASTConsumer(CI, InFile));
+ }
+ }
+ }
+
+ return new MultiplexConsumer(Consumers);
+}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
llvm::StringRef Filename,
InputKind InputKind) {
@@ -51,7 +139,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
std::string Error;
- ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
+ ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
+ CI.getFileSystemOpts());
if (!AST)
goto failure;
@@ -69,7 +158,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
/// Create the AST consumer.
- CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ CI.setASTConsumer(CreateWrappedASTConsumer(CI, Filename));
if (!CI.hasASTConsumer())
goto failure;
@@ -80,7 +169,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.hasFileManager())
CI.createFileManager();
if (!CI.hasSourceManager())
- CI.createSourceManager();
+ CI.createSourceManager(CI.getFileManager());
// IR files bypass the rest of initialization.
if (InputKind == IK_LLVM_IR) {
@@ -113,16 +202,30 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!usesPreprocessorOnly()) {
CI.createASTContext();
- llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
+ llvm::OwningPtr<ASTConsumer> Consumer(
+ CreateWrappedASTConsumer(CI, Filename));
+ if (!Consumer)
+ goto failure;
+
+ CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
/// Use PCH?
if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
assert(hasPCHSupport() && "This action does not have PCH support!");
+ ASTDeserializationListener *DeserialListener
+ = CI.getInvocation().getFrontendOpts().ChainedPCH ?
+ Consumer->GetASTDeserializationListener() : 0;
+ if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
+ DeserialListener = new DeserializedDeclsDumper(DeserialListener);
+ if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
+ DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
+ CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
+ DeserialListener);
CI.createPCHExternalASTSource(
CI.getPreprocessorOpts().ImplicitPCHInclude,
CI.getPreprocessorOpts().DisablePCHValidation,
- CI.getInvocation().getFrontendOpts().ChainedPCH?
- Consumer->GetASTDeserializationListener() : 0);
+ CI.getPreprocessorOpts().DisableStatCache,
+ DeserialListener);
if (!CI.getASTContext().getExternalSource())
goto failure;
}
@@ -137,7 +240,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
- PP.getLangOptions().NoBuiltin);
+ PP.getLangOptions());
}
return true;
@@ -187,6 +290,9 @@ void FrontendAction::Execute() {
void FrontendAction::EndSourceFile() {
CompilerInstance &CI = getCompilerInstance();
+ // Inform the diagnostic client we are done with this source file.
+ CI.getDiagnosticClient().EndSourceFile();
+
// Finalize the action.
EndSourceFileAction();
@@ -223,10 +329,7 @@ void FrontendAction::EndSourceFile() {
// Cleanup the output streams, and erase the output files if we encountered
// an error.
- CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
-
- // Inform the diagnostic client we are done with this source file.
- CI.getDiagnosticClient().EndSourceFile();
+ CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred());
if (isCurrentFileAST()) {
CI.takeSema();
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 5bc6506..d8e7d29 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -59,6 +59,17 @@ ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
return CreateASTDumper();
}
+ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ llvm::raw_ostream *OS;
+ if (CI.getFrontendOpts().OutputFile.empty())
+ OS = &llvm::outs();
+ else
+ OS = CI.createDefaultOutputFile(false, InFile);
+ if (!OS) return 0;
+ return CreateASTDumperXML(*OS);
+}
+
ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
return CreateASTViewer();
@@ -72,19 +83,21 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
std::string Sysroot;
+ std::string OutputFile;
llvm::raw_ostream *OS = 0;
bool Chaining;
- if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining))
+ if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining))
return 0;
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
Sysroot.c_str() : 0;
- return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS);
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
llvm::StringRef InFile,
std::string &Sysroot,
+ std::string &OutputFile,
llvm::raw_ostream *&OS,
bool &Chaining) {
Sysroot = CI.getHeaderSearchOpts().Sysroot;
@@ -93,20 +106,19 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return true;
}
- OS = CI.createDefaultOutputFile(true, InFile);
+ // We use createOutputFile here because this is exposed via libclang, and we
+ // must disable the RemoveFileOnSignal behavior.
+ OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+ /*RemoveFileOnSignal=*/false, InFile);
if (!OS)
return true;
+ OutputFile = CI.getFrontendOpts().OutputFile;
Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH &&
!CI.getPreprocessorOpts().ImplicitPCHInclude.empty();
return false;
}
-ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
-}
-
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
return new ASTConsumer();
@@ -193,6 +205,7 @@ void PrintPreambleAction::ExecuteAction() {
case IK_ObjC:
case IK_ObjCXX:
case IK_OpenCL:
+ case IK_CUDA:
break;
case IK_None:
@@ -207,7 +220,9 @@ void PrintPreambleAction::ExecuteAction() {
return;
}
- llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile());
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::MemoryBuffer *Buffer
+ = CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
unsigned Preamble = Lexer::ComputePreamble(Buffer).first;
llvm::outs().write(Buffer->getBufferStart(), Preamble);
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index 9dfee24..0a20051 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -26,6 +26,7 @@ InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) {
.Cases("C", "cc", "cp", IK_CXX)
.Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
.Case("cl", IK_OpenCL)
+ .Case("cu", IK_CUDA)
.Cases("ll", "bc", IK_LLVM_IR)
.Default(IK_C);
}
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
new file mode 100644
index 0000000..45ff1d2
--- /dev/null
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -0,0 +1,113 @@
+//===--- HeaderIncludes.cpp - Generate Header Includes --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+class HeaderIncludesCallback : public PPCallbacks {
+ SourceManager &SM;
+ llvm::raw_ostream *OutputFile;
+ unsigned CurrentIncludeDepth;
+ bool HasProcessedPredefines;
+ bool OwnsOutputFile;
+ bool ShowAllHeaders;
+
+public:
+ HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
+ llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_)
+ : SM(PP->getSourceManager()), OutputFile(OutputFile_),
+ CurrentIncludeDepth(0), HasProcessedPredefines(false),
+ OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_) {}
+
+ ~HeaderIncludesCallback() {
+ if (OwnsOutputFile)
+ delete OutputFile;
+ }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+};
+}
+
+void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
+ llvm::StringRef OutputPath) {
+ llvm::raw_ostream *OutputFile = &llvm::errs();
+ bool OwnsOutputFile = false;
+
+ // Open the output file, if used.
+ if (!OutputPath.empty()) {
+ std::string Error;
+ llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
+ OutputPath.str().c_str(), Error, llvm::raw_fd_ostream::F_Append);
+ if (!Error.empty()) {
+ PP.getDiagnostics().Report(
+ clang::diag::warn_fe_cc_print_header_failure) << Error;
+ delete OS;
+ } else {
+ OS->SetUnbuffered();
+ OS->SetUseAtomicWrites(true);
+ OutputFile = OS;
+ OwnsOutputFile = true;
+ }
+ }
+
+ PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
+ OutputFile, OwnsOutputFile));
+}
+
+void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind NewFileType) {
+ // Unless we are exiting a #include, make sure to skip ahead to the line the
+ // #include directive was at.
+ PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
+ if (UserLoc.isInvalid())
+ return;
+
+ // Adjust the current include depth.
+ if (Reason == PPCallbacks::EnterFile) {
+ ++CurrentIncludeDepth;
+ } else {
+ if (CurrentIncludeDepth)
+ --CurrentIncludeDepth;
+
+ // We track when we are done with the predefines by watching for the first
+ // place where we drop back to a nesting depth of 0.
+ if (CurrentIncludeDepth == 0 && !HasProcessedPredefines)
+ HasProcessedPredefines = true;
+ }
+
+ // Show the header if we are (a) past the predefines, or (b) showing all
+ // headers and in the predefines at a depth past the initial file and command
+ // line buffers.
+ bool ShowHeader = (HasProcessedPredefines ||
+ (ShowAllHeaders && CurrentIncludeDepth > 2));
+
+ // Dump the header include information we are past the predefines buffer or
+ // are showing all headers.
+ if (ShowHeader && Reason == PPCallbacks::EnterFile) {
+ // Write to a temporary string to avoid unnecessary flushing on errs().
+ llvm::SmallString<512> Filename(UserLoc.getFilename());
+ Lexer::Stringify(Filename);
+
+ llvm::SmallString<256> Msg;
+ for (unsigned i = 0; i != CurrentIncludeDepth; ++i)
+ Msg += '.';
+ Msg += ' ';
+ Msg += Filename;
+ Msg += '\n';
+
+ OutputFile->write(Msg.data(), Msg.size());
+ }
+}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index df91713..4855b62 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -11,6 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#ifdef HAVE_CLANG_CONFIG_H
+# include "clang/Config/config.h"
+#endif
+
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
@@ -23,7 +27,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Path.h"
#include "llvm/Config/config.h"
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN 1
@@ -41,13 +45,15 @@ class InitHeaderSearch {
std::vector<DirectoryLookup> IncludeGroup[4];
HeaderSearch& Headers;
bool Verbose;
- std::string isysroot;
+ std::string IncludeSysroot;
+ bool IsNotEmptyOrRoot;
public:
- InitHeaderSearch(HeaderSearch &HS,
- bool verbose = false, const std::string &iSysroot = "")
- : Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
+ InitHeaderSearch(HeaderSearch &HS, bool verbose, llvm::StringRef sysroot)
+ : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot),
+ IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) {
+ }
/// AddPath - Add the specified path to the specified group list.
void AddPath(const llvm::Twine &Path, IncludeDirGroup Group,
@@ -62,7 +68,7 @@ public:
llvm::StringRef Dir64,
const llvm::Triple &triple);
- /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW
+ /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW
/// libstdc++.
void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef Arch,
@@ -101,19 +107,18 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
FileManager &FM = Headers.getFileMgr();
// Compute the actual path, taking into consideration -isysroot.
- llvm::SmallString<256> MappedPathStr;
- llvm::raw_svector_ostream MappedPath(MappedPathStr);
+ llvm::SmallString<256> MappedPathStorage;
+ llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
// Handle isysroot.
- if (Group == System && !IgnoreSysRoot) {
- // FIXME: Portability. This should be a sys::Path interface, this doesn't
- // handle things like C:\ right, nor win32 \\network\device\blah.
- if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
- MappedPath << isysroot;
+ if (Group == System && !IgnoreSysRoot &&
+ llvm::sys::path::is_absolute(MappedPathStr) &&
+ IsNotEmptyOrRoot) {
+ MappedPathStorage.clear();
+ MappedPathStr =
+ (IncludeSysroot + Path).toStringRef(MappedPathStorage);
}
- Path.print(MappedPath);
-
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
if (Group == Quoted || Group == Angled)
@@ -125,7 +130,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
// If the directory exists, add it.
- if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) {
+ if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) {
IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
isFramework));
return;
@@ -134,7 +139,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
// Check to see if this is an apple-style headermap (which are not allowed to
// be frameworks).
if (!isFramework) {
- if (const FileEntry *FE = FM.getFile(MappedPath.str())) {
+ if (const FileEntry *FE = FM.getFile(MappedPathStr)) {
if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
// It is a headermap, add it to the search path.
IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
@@ -145,7 +150,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
if (Verbose)
llvm::errs() << "ignoring nonexistent directory \""
- << MappedPath.str() << "\"\n";
+ << MappedPathStr << "\"\n";
}
@@ -191,8 +196,6 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef Arch,
llvm::StringRef Version) {
- AddPath(Base + "/" + Arch + "/" + Version + "/include",
- System, true, false, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
System, true, false, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
@@ -344,7 +347,7 @@ static bool getVisualStudioDir(std::string &path) {
bool hasVCExpressDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
"InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
+ // If we have both vc80 and vc90, pick version we were compiled with.
if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
if (p)
@@ -366,7 +369,7 @@ static bool getVisualStudioDir(std::string &path) {
const char* vs80comntools = getenv("VS80COMNTOOLS");
const char* vscomntools = NULL;
- // Try to find the version that we were compiled with
+ // Try to find the version that we were compiled with
if(false) {}
#if (_MSC_VER >= 1600) // VC100
else if(vs100comntools) {
@@ -409,7 +412,7 @@ static bool getWindowsSDKDir(std::string &path) {
bool hasSDKDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
+ // If we have both vc80 and vc90, pick version we were compiled with.
if (hasSDKDir && windowsSDKInstallDir[0]) {
path = windowsSDKInstallDir;
return(true);
@@ -419,8 +422,16 @@ static bool getWindowsSDKDir(std::string &path) {
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- // FIXME: temporary hack: hard-coded paths.
- AddPath("/usr/local/include", System, true, false, false);
+ llvm::Triple::OSType os = triple.getOS();
+
+ switch (os) {
+ case llvm::Triple::NetBSD:
+ break;
+ default:
+ // FIXME: temporary hack: hard-coded paths.
+ AddPath("/usr/local/include", System, true, false, false);
+ break;
+ }
// Builtin includes use #include_next directives and should be positioned
// just prior C include dirs.
@@ -439,47 +450,39 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
CIncludeDirs.split(dirs, ":");
for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin();
i != dirs.end();
- ++i)
+ ++i)
AddPath(*i, System, false, false, false);
return;
}
- llvm::Triple::OSType os = triple.getOS();
+
switch (os) {
- case llvm::Triple::Win32:
- {
- std::string VSDir;
- std::string WindowsSDKDir;
- if (getVisualStudioDir(VSDir)) {
- AddPath(VSDir + "\\VC\\include", System, false, false, false);
- if (getWindowsSDKDir(WindowsSDKDir))
- AddPath(WindowsSDKDir + "\\include", System, false, false, false);
- else
- AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
- System, false, false, false);
- }
- else {
- // Default install paths.
- AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
- System, false, false, false);
- AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- System, false, false, false);
- AddPath(
+ case llvm::Triple::Win32: {
+ std::string VSDir;
+ std::string WindowsSDKDir;
+ if (getVisualStudioDir(VSDir)) {
+ AddPath(VSDir + "\\VC\\include", System, false, false, false);
+ if (getWindowsSDKDir(WindowsSDKDir))
+ AddPath(WindowsSDKDir + "\\include", System, false, false, false);
+ else
+ AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
+ System, false, false, false);
+ } else {
+ // Default install paths.
+ AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ System, false, false, false);
+ AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ System, false, false, false);
+ AddPath(
"C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- System, false, false, false);
- AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include",
- System, false, false, false);
- AddPath(
+ System, false, false, false);
+ AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ System, false, false, false);
+ AddPath(
"C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include",
- System, false, false, false);
- // For some clang developers.
- AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- System, false, false, false);
- AddPath(
- "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- System, false, false, false);
- }
+ System, false, false, false);
}
break;
+ }
case llvm::Triple::Haiku:
AddPath("/boot/common/include", System, true, false, false);
AddPath("/boot/develop/headers/os", System, true, false, false);
@@ -487,7 +490,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/boot/develop/headers/os/arch", System, true, false, false);
AddPath("/boot/develop/headers/os/device", System, true, false, false);
AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
- AddPath("/boot/develop/headers/os/game", System, true, false, false);
+ AddPath("/boot/develop/headers/os/game", System, true, false, false);
AddPath("/boot/develop/headers/os/interface", System, true, false, false);
AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
AddPath("/boot/develop/headers/os/locale", System, true, false, false);
@@ -500,13 +503,13 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/boot/develop/headers/os/support", System, true, false, false);
AddPath("/boot/develop/headers/os/translation",
System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/graphics",
+ AddPath("/boot/develop/headers/os/add-ons/graphics",
System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/input_server",
+ AddPath("/boot/develop/headers/os/add-ons/input_server",
System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/screen_saver",
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver",
System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/tracker",
+ AddPath("/boot/develop/headers/os/add-ons/tracker",
System, true, false, false);
AddPath("/boot/develop/headers/os/be_apps/Deskbar",
System, true, false, false);
@@ -515,7 +518,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/boot/develop/headers/os/be_apps/Tracker",
System, true, false, false);
AddPath("/boot/develop/headers/cpp", System, true, false, false);
- AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
System, true, false, false);
AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
AddPath("/boot/develop/headers/bsd", System, true, false, false);
@@ -523,7 +526,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/boot/develop/headers/posix", System, true, false, false);
AddPath("/boot/develop/headers", System, true, false, false);
break;
- case llvm::Triple::MinGW64:
+ case llvm::Triple::Cygwin:
+ AddPath("/usr/include/w32api", System, true, false, false);
+ break;
case llvm::Triple::MinGW32:
AddPath("c:/mingw/include", System, true, false, false);
break;
@@ -553,24 +558,24 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
// FIXME: temporary hack: hard-coded paths.
switch (os) {
case llvm::Triple::Cygwin:
- AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include",
- System, true, false, false);
- AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++",
- System, true, false, false);
- AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/i686-pc-cygwin",
- System, true, false, false);
+ // Cygwin-1.7
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
+ // g++-4 / Cygwin-1.5
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
+ // FIXME: Do we support g++-3.4.4?
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4");
break;
- case llvm::Triple::MinGW64:
- // Try gcc 4.5.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.5.0");
- // Try gcc 4.4.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0");
- // Try gcc 4.3.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0");
- // Fall through.
case llvm::Triple::MinGW32:
- // Try gcc 4.5.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
+ // mingw-w64-20110207
+ AddPath("c:/MinGW/include/c++/4.5.3", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.3/backward", System, true, false, false);
+ // mingw-w64-20101129
+ AddPath("c:/MinGW/include/c++/4.5.2", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", System, true, false, false);
+ AddPath("c:/MinGW/include/c++/4.5.2/backward", System, true, false, false);
+ // Try gcc 4.5.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
// Try gcc 4.4.0
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
// Try gcc 4.3.0
@@ -580,13 +585,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
switch (triple.getArch()) {
default: break;
- case llvm::Triple::ppc:
+ case llvm::Triple::ppc:
case llvm::Triple::ppc64:
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
- "powerpc-apple-darwin10", "", "ppc64",
+ "powerpc-apple-darwin10", "", "ppc64",
triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
- "powerpc-apple-darwin10", "", "ppc64",
+ "powerpc-apple-darwin10", "", "ppc64",
triple);
break;
@@ -615,6 +620,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
// Debian based distros.
// Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y
//===------------------------------------------------------------------===//
+ // Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "i686-linux-gnu", "", "64", triple);
+ // The rest of 10.10 is the same as previous versions.
+
// Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3
// Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1
// Debian 6.0 "squeeze" -- gcc-4.4.2
@@ -622,6 +632,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"x86_64-linux-gnu", "32", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
"i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
+ "arm-linux-gnueabi", "", "", triple);
// Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3
// Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2
// Debian 5.0 "lenny" -- gcc-4.3.2
@@ -646,6 +658,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
//===------------------------------------------------------------------===//
// Redhat based distros.
//===------------------------------------------------------------------===//
+ // Fedora 14
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1",
+ "i686-redhat-linux", "", "", triple);
// Fedora 13
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4",
"x86_64-redhat-linux", "32", "", triple);
@@ -701,11 +718,22 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"i586-suse-linux", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
"x86_64-suse-linux", "", "", triple);
+
+ // openSUSE 11.4
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "i586-suse-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "x86_64-suse-linux", "", "", triple);
+
// Arch Linux 2008-06-24
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
"i686-pc-linux-gnu", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
"x86_64-unknown-linux-gnu", "", "", triple);
+ // Gentoo x86 2010.0 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
// Gentoo x86 2009.1 stable
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4",
@@ -718,26 +746,33 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
"i686-pc-linux-gnu", "", "", triple);
- // Gentoo amd64 stable
+
+ // Gentoo amd64 gcc 4.4.5
AddGnuCPlusPlusIncludePaths(
- "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
- "i686-pc-linux-gnu", "", "", triple);
-
- // Gentoo amd64 gcc 4.3.2
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4",
+ "x86_64-pc-linux-gnu", "32", "", triple);
+ // Gentoo amd64 gcc 4.4.4
AddGnuCPlusPlusIncludePaths(
- "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4",
- "x86_64-pc-linux-gnu", "", "", triple);
-
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4",
+ "x86_64-pc-linux-gnu", "32", "", triple);
// Gentoo amd64 gcc 4.4.3
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4",
"x86_64-pc-linux-gnu", "32", "", triple);
+ // Gentoo amd64 gcc 4.3.2
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4",
+ "x86_64-pc-linux-gnu", "", "", triple);
+ // Gentoo amd64 stable
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
// Gentoo amd64 llvm-gcc trunk
AddGnuCPlusPlusIncludePaths(
"/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1",
"x86_64-pc-linux-gnu", "", "", triple);
-
+
break;
case llvm::Triple::FreeBSD:
// FreeBSD 8.0
@@ -774,8 +809,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes)
- AddDefaultCPlusPlusIncludePaths(triple);
+ if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) {
+ if (!HSOpts.CXXSystemIncludes.empty()) {
+ for (unsigned i = 0, e = HSOpts.CXXSystemIncludes.size(); i != e; ++i)
+ AddPath(HSOpts.CXXSystemIncludes[i], System, true, false, false);
+ } else
+ AddDefaultCPlusPlusIncludePaths(triple);
+ }
AddDefaultCIncludePaths(triple, HSOpts);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 0d07192..d0111a5 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -22,8 +22,9 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Path.h"
using namespace clang;
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
@@ -55,9 +56,10 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
// it has not file entry. For now, workaround this by using an
// absolute path if we find the file here, and otherwise letting
// header search handle it.
- llvm::sys::Path Path(File);
- Path.makeAbsolute();
- if (!Path.exists())
+ llvm::SmallString<128> Path(File);
+ llvm::sys::fs::make_absolute(Path);
+ bool exists;
+ if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
Path = File;
return Lexer::Stringify(Path.str());
@@ -342,6 +344,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
Builder.append("class type_info;");
}
+
+ if (LangOpts.CPlusPlus0x) {
+ Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1");
+ }
}
if (LangOpts.Optimize)
@@ -465,6 +471,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (FEOpts.ProgramAction == frontend::RunAnalysis)
Builder.defineMacro("__clang_analyzer__");
+ if (LangOpts.FastRelaxedMath)
+ Builder.defineMacro("__FAST_RELAXED_MATH__");
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
@@ -515,8 +524,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
// Create the file entry for the file that we're mapping from.
const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
- ToFile->getSize(),
- 0);
+ ToFile->getSize(), 0);
if (!FromFile) {
Diags.Report(diag::err_fe_remap_missing_from_file)
<< Remap->first;
@@ -526,7 +534,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
// Load the contents of the file we're mapping to.
std::string ErrorStr;
const llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
+ = FileMgr.getBufferForFile(ToFile->getName(), &ErrorStr);
if (!Buffer) {
Diags.Report(diag::err_fe_error_opening)
<< Remap->second << ErrorStr;
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
new file mode 100644
index 0000000..3649c3c
--- /dev/null
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -0,0 +1,221 @@
+//===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MultiplexConsumer class. It also declares and defines
+// MultiplexASTDeserializationListener and MultiplexASTMutationListener, which
+// are implementation details of MultiplexConsumer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/MultiplexConsumer.h"
+
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+
+using namespace clang;
+
+namespace clang {
+
+// This ASTDeserializationListener forwards its notifications to a set of
+// child listeners.
+class MultiplexASTDeserializationListener
+ : public ASTDeserializationListener {
+public:
+ // Does NOT take ownership of the elements in L.
+ MultiplexASTDeserializationListener(
+ const std::vector<ASTDeserializationListener*>& L);
+ virtual void ReaderInitialized(ASTReader *Reader);
+ virtual void IdentifierRead(serialization::IdentID ID,
+ IdentifierInfo *II);
+ virtual void TypeRead(serialization::TypeIdx Idx, QualType T);
+ virtual void DeclRead(serialization::DeclID ID, const Decl *D);
+ virtual void SelectorRead(serialization::SelectorID iD, Selector Sel);
+ virtual void MacroDefinitionRead(serialization::MacroID,
+ MacroDefinition *MD);
+private:
+ std::vector<ASTDeserializationListener*> Listeners;
+};
+
+MultiplexASTDeserializationListener::MultiplexASTDeserializationListener(
+ const std::vector<ASTDeserializationListener*>& L)
+ : Listeners(L) {
+}
+
+void MultiplexASTDeserializationListener::ReaderInitialized(
+ ASTReader *Reader) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->ReaderInitialized(Reader);
+}
+
+void MultiplexASTDeserializationListener::IdentifierRead(
+ serialization::IdentID ID, IdentifierInfo *II) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->IdentifierRead(ID, II);
+}
+
+void MultiplexASTDeserializationListener::TypeRead(
+ serialization::TypeIdx Idx, QualType T) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->TypeRead(Idx, T);
+}
+
+void MultiplexASTDeserializationListener::DeclRead(
+ serialization::DeclID ID, const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DeclRead(ID, D);
+}
+
+void MultiplexASTDeserializationListener::SelectorRead(
+ serialization::SelectorID ID, Selector Sel) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->SelectorRead(ID, Sel);
+}
+
+void MultiplexASTDeserializationListener::MacroDefinitionRead(
+ serialization::MacroID ID, MacroDefinition *MD) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->MacroDefinitionRead(ID, MD);
+}
+
+// This ASTMutationListener forwards its notifications to a set of
+// child listeners.
+class MultiplexASTMutationListener : public ASTMutationListener {
+public:
+ // Does NOT take ownership of the elements in L.
+ MultiplexASTMutationListener(const std::vector<ASTMutationListener*>& L);
+ virtual void CompletedTagDefinition(const TagDecl *D);
+ virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
+ virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
+ virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
+ const ClassTemplateSpecializationDecl *D);
+private:
+ std::vector<ASTMutationListener*> Listeners;
+};
+
+MultiplexASTMutationListener::MultiplexASTMutationListener(
+ const std::vector<ASTMutationListener*>& L)
+ : Listeners(L) {
+}
+
+void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->CompletedTagDefinition(D);
+}
+
+void MultiplexASTMutationListener::AddedVisibleDecl(
+ const DeclContext *DC, const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedVisibleDecl(DC, D);
+}
+
+void MultiplexASTMutationListener::AddedCXXImplicitMember(
+ const CXXRecordDecl *RD, const Decl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedCXXImplicitMember(RD, D);
+}
+void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
+ const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
+}
+
+} // end namespace clang
+
+
+MultiplexConsumer::MultiplexConsumer(const std::vector<ASTConsumer*>& C)
+ : Consumers(C), MutationListener(0), DeserializationListener(0) {
+ // Collect the mutation listeners and deserialization listeners of all
+ // children, and create a multiplex listener each if so.
+ std::vector<ASTMutationListener*> mutationListeners;
+ std::vector<ASTDeserializationListener*> serializationListeners;
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i) {
+ ASTMutationListener* mutationListener =
+ Consumers[i]->GetASTMutationListener();
+ if (mutationListener)
+ mutationListeners.push_back(mutationListener);
+ ASTDeserializationListener* serializationListener =
+ Consumers[i]->GetASTDeserializationListener();
+ if (serializationListener)
+ serializationListeners.push_back(serializationListener);
+ }
+ if (mutationListeners.size()) {
+ MutationListener.reset(new MultiplexASTMutationListener(mutationListeners));
+ }
+ if (serializationListeners.size()) {
+ DeserializationListener.reset(
+ new MultiplexASTDeserializationListener(serializationListeners));
+ }
+}
+
+MultiplexConsumer::~MultiplexConsumer() {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ delete Consumers[i];
+}
+
+void MultiplexConsumer::Initialize(ASTContext &Context) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->Initialize(Context);
+}
+
+void MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleTopLevelDecl(D);
+}
+
+void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleInterestingDecl(D);
+}
+
+void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleTranslationUnit(Ctx);
+}
+
+void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleTagDeclDefinition(D);
+}
+
+void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->CompleteTentativeDefinition(D);
+}
+
+void MultiplexConsumer::HandleVTable(
+ CXXRecordDecl *RD, bool DefinitionRequired) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleVTable(RD, DefinitionRequired);
+}
+
+ASTMutationListener *MultiplexConsumer::GetASTMutationListener() {
+ return MutationListener.get();
+}
+
+ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() {
+ return DeserializationListener.get();
+}
+
+void MultiplexConsumer::PrintStats() {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->PrintStats();
+}
+
+void MultiplexConsumer::InitializeSema(Sema &S) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
+ SC->InitializeSema(S);
+}
+
+void MultiplexConsumer::ForgetSema() {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i]))
+ SC->ForgetSema();
+}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index cfaf8a2..922d743 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -86,9 +86,6 @@ public:
private:
unsigned CurLine;
- /// The current include nesting level, used by header include dumping (-H).
- unsigned CurrentIncludeDepth;
-
bool EmittedTokensOnThisLine;
bool EmittedMacroOnThisLine;
SrcMgr::CharacteristicKind FileType;
@@ -96,22 +93,19 @@ private:
bool Initialized;
bool DisableLineMarkers;
bool DumpDefines;
- bool DumpHeaderIncludes;
bool UseLineDirective;
- bool HasProcessedPredefines;
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
- bool lineMarkers, bool defines, bool headers)
+ bool lineMarkers, bool defines)
: PP(pp), SM(PP.getSourceManager()),
ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
- DumpDefines(defines), DumpHeaderIncludes(headers) {
- CurLine = CurrentIncludeDepth = 0;
+ DumpDefines(defines) {
+ CurLine = 0;
CurFilename += "<uninit>";
EmittedTokensOnThisLine = false;
EmittedMacroOnThisLine = false;
FileType = SrcMgr::C_User;
Initialized = false;
- HasProcessedPredefines = false;
// If we're in microsoft mode, use normal #line instead of line markers.
UseLineDirective = PP.getLangOptions().Microsoft;
@@ -120,6 +114,8 @@ public:
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
+ bool StartNewLineIfNeeded();
+
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType);
virtual void Ident(SourceLocation Loc, const std::string &str);
@@ -129,7 +125,10 @@ public:
bool HandleFirstTokOnLine(Token &Tok);
bool MoveToLine(SourceLocation Loc) {
- return MoveToLine(SM.getPresumedLoc(Loc).getLine());
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ if (PLoc.isInvalid())
+ return false;
+ return MoveToLine(PLoc.getLine());
}
bool MoveToLine(unsigned LineNo);
@@ -138,15 +137,14 @@ public:
return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
}
void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
-
+ bool LineMarkersAreDisabled() const { return DisableLineMarkers; }
void HandleNewlinesInToken(const char *TokStr, unsigned Len);
/// MacroDefined - This hook is called whenever a macro definition is seen.
- void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+ void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI);
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
- void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II,
- const MacroInfo *MI);
+ void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI);
};
} // end anonymous namespace
@@ -162,11 +160,11 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
// Emit #line directives or GNU line markers depending on what mode we're in.
if (UseLineDirective) {
OS << "#line" << ' ' << LineNo << ' ' << '"';
- OS.write(&CurFilename[0], CurFilename.size());
+ OS.write(CurFilename.data(), CurFilename.size());
OS << '"';
} else {
OS << '#' << ' ' << LineNo << ' ' << '"';
- OS.write(&CurFilename[0], CurFilename.size());
+ OS.write(CurFilename.data(), CurFilename.size());
OS << '"';
if (ExtraLen)
@@ -213,6 +211,17 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
return true;
}
+bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() {
+ if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ ++CurLine;
+ return true;
+ }
+
+ return false;
+}
/// FileChanged - Whenever the preprocessor enters or exits a #include file
/// it invokes this handler. Update our conception of the current source
@@ -225,10 +234,13 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
SourceManager &SourceMgr = SM;
PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc);
+ if (UserLoc.isInvalid())
+ return;
+
unsigned NewLine = UserLoc.getLine();
if (Reason == PPCallbacks::EnterFile) {
- SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
+ SourceLocation IncludeLoc = UserLoc.getIncludeLoc();
if (IncludeLoc.isValid())
MoveToLine(IncludeLoc);
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
@@ -238,19 +250,6 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
// directive and emits a bunch of spaces that aren't needed. Emulate this
// strange behavior.
}
-
- // Adjust the current include depth.
- if (Reason == PPCallbacks::EnterFile) {
- ++CurrentIncludeDepth;
- } else {
- if (CurrentIncludeDepth)
- --CurrentIncludeDepth;
-
- // We track when we are done with the predefines by watching for the first
- // place where we drop back to a nesting depth of 0.
- if (CurrentIncludeDepth == 0 && !HasProcessedPredefines)
- HasProcessedPredefines = true;
- }
CurLine = NewLine;
@@ -259,18 +258,6 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
Lexer::Stringify(CurFilename);
FileType = NewFileType;
- // Dump the header include information, if enabled and we are past the
- // predefines buffer.
- if (DumpHeaderIncludes && HasProcessedPredefines &&
- Reason == PPCallbacks::EnterFile) {
- llvm::SmallString<256> Msg;
- llvm::raw_svector_ostream OS(Msg);
- for (unsigned i = 0; i != CurrentIncludeDepth; ++i)
- OS << '.';
- OS << ' ' << CurFilename << '\n';
- llvm::errs() << OS.str();
- }
-
if (DisableLineMarkers) return;
if (!Initialized) {
@@ -303,7 +290,7 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
-void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
+void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
const MacroInfo *MI) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines ||
@@ -311,18 +298,17 @@ void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II,
MI->isBuiltinMacro()) return;
MoveToLine(MI->getDefinitionLoc());
- PrintMacroDefinition(*II, *MI, PP, OS);
+ PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS);
EmittedMacroOnThisLine = true;
}
-void PrintPPOutputPPCallbacks::MacroUndefined(SourceLocation Loc,
- const IdentifierInfo *II,
+void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
const MacroInfo *MI) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
- MoveToLine(Loc);
- OS << "#undef " << II->getName();
+ MoveToLine(MacroNameTok.getLocation());
+ OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName();
EmittedMacroOnThisLine = true;
}
@@ -437,12 +423,14 @@ struct UnknownPragmaHandler : public PragmaHandler {
UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
: Prefix(prefix), Callbacks(callbacks) {}
- virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &PragmaTok) {
// Figure out what line we went to and insert the appropriate number of
// newline characters.
+ Callbacks->StartNewLineIfNeeded();
Callbacks->MoveToLine(PragmaTok.getLocation());
Callbacks->OS.write(Prefix, strlen(Prefix));
-
+ Callbacks->SetEmittedTokensOnThisLine();
// Read and print all of the pragma tokens.
while (PragmaTok.isNot(tok::eom)) {
if (PragmaTok.hasLeadingSpace())
@@ -451,7 +439,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
Callbacks->OS.write(&TokSpell[0], TokSpell.size());
PP.LexUnexpandedToken(PragmaTok);
}
- Callbacks->OS << '\n';
+ Callbacks->StartNewLineIfNeeded();
}
};
} // end anonymous namespace
@@ -561,10 +549,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
- Opts.ShowMacros, Opts.ShowHeaderIncludes);
+ Opts.ShowMacros);
PP.AddPragmaHandler(new UnknownPragmaHandler("#pragma", Callbacks));
- PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
- Callbacks));
+ PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
+ PP.AddPragmaHandler("clang",
+ new UnknownPragmaHandler("#pragma clang", Callbacks));
PP.addPPCallbacks(Callbacks);
@@ -576,13 +565,20 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
// start.
const SourceManager &SourceMgr = PP.getSourceManager();
Token Tok;
- do PP.Lex(Tok);
- while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
- !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
- "<built-in>"));
+ do {
+ PP.Lex(Tok);
+ if (Tok.is(tok::eof) || !Tok.getLocation().isFileID())
+ break;
+
+ PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+ if (PLoc.isInvalid())
+ break;
+
+ if (strcmp(PLoc.getFilename(), "<built-in>"))
+ break;
+ } while (true);
// Read all the preprocessed tokens, printing them out to the stream.
PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
*OS << '\n';
}
-
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index b660734..c113cc1 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -61,8 +61,7 @@ namespace {
Doc.PrintDecl(*DI);
}
} else {
- for (Stmt::child_iterator i = S->child_begin(), e = S->child_end();
- i != e; ++i)
+ for (Stmt::child_range i = S->children(); i; ++i)
DumpSubTree(*i);
}
Doc.toParent();
@@ -133,7 +132,6 @@ namespace {
void VisitBinaryOperator(BinaryOperator *Node);
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
- void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -150,7 +148,6 @@ namespace {
void VisitObjCImplicitSetterGetterRefExpr(
ObjCImplicitSetterGetterRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
- void VisitObjCSuperExpr(ObjCSuperExpr *Node);
#endif
};
}
@@ -357,12 +354,6 @@ void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) {
Doc.addAttribute("name", Node->getLabel()->getName());
}
-void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
- DumpExpr(Node);
- DumpTypeExpr(Node->getArgType1());
- DumpTypeExpr(Node->getArgType2());
-}
-
//===----------------------------------------------------------------------===//
// C++ Expressions
//===----------------------------------------------------------------------===//
@@ -428,11 +419,6 @@ void StmtXML::VisitObjCImplicitSetterGetterRefExpr(
Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
}
-void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("super", "1");
-}
-
void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
Doc.addAttribute("kind", Node->getDecl()->getDeclKindName());
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index fdf2ec8..069c86d 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -20,6 +20,9 @@ using namespace clang;
///
void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info) {
+ // Default implementation (Warnings/errors count).
+ DiagnosticClient::HandleDiagnostic(Level, Info);
+
llvm::SmallString<100> Buf;
Info.FormatDiagnostic(Buf);
switch (Level) {
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 1e453a0..04c6a68 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
@@ -57,7 +58,9 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
if (Loc.isInvalid()) return;
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-
+ if (PLoc.isInvalid())
+ return;
+
// Print out the other include frames first.
PrintIncludeStack(PLoc.getIncludeLoc(), SM);
@@ -137,8 +140,9 @@ void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
--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.
+ // 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??");
}
@@ -328,7 +332,9 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
if (!Suppressed) {
// Get the pretty name, according to #line directives etc.
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-
+ if (PLoc.isInvalid())
+ return;
+
// If this diagnostic is not in the main file, print out the
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
@@ -567,6 +573,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
// We specifically do not do word-wrapping or tab-expansion here,
// because this is supposed to be easy to parse.
+ PresumedLoc PLoc = SM.getPresumedLoc(B);
+ if (PLoc.isInvalid())
+ break;
+
OS << "fix-it:\"";
OS.write_escaped(SM.getPresumedLoc(B).getFilename());
OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
@@ -756,6 +766,9 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS,
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info) {
+ // Default implementation (Warnings/errors count).
+ DiagnosticClient::HandleDiagnostic(Level, Info);
+
// Keeps track of the the starting position of the location
// information (e.g., "foo.c:10:4:") that precedes the error
// message. We use this information to determine how long the
@@ -768,77 +781,96 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// If the location is specified, print out a file/line/col and include trace
// if enabled.
if (Info.getLocation().isValid()) {
- const SourceManager &SM = Info.getLocation().getManager();
+ const SourceManager &SM = Info.getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
- unsigned LineNo = PLoc.getLine();
-
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- if (LastWarningLoc != PLoc.getIncludeLoc()) {
- LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(LastWarningLoc, SM);
- StartOfLocationInfo = OS.tell();
- }
+ if (PLoc.isInvalid()) {
+ // At least print the file name if available:
+ FileID FID = SM.getFileID(Info.getLocation());
+ if (!FID.isInvalid()) {
+ const FileEntry* FE = SM.getFileEntryForID(FID);
+ if (FE && FE->getName()) {
+ OS << FE->getName();
+ if (FE->getDevice() == 0 && FE->getInode() == 0
+ && FE->getFileMode() == 0) {
+ // in PCH is a guess, but a good one:
+ OS << " (in PCH)";
+ }
+ OS << ": ";
+ }
+ }
+ } else {
+ unsigned LineNo = PLoc.getLine();
- // Compute the column number.
- if (DiagOpts->ShowLocation) {
- if (DiagOpts->ShowColors)
- OS.changeColor(savedColor, true);
-
- // Emit a Visual Studio compatible line number syntax.
- if (LangOpts && LangOpts->Microsoft) {
- OS << PLoc.getFilename() << '(' << LineNo << ')';
- OS << " : ";
- } else {
- OS << PLoc.getFilename() << ':' << LineNo << ':';
- if (DiagOpts->ShowColumn)
- if (unsigned ColNo = PLoc.getColumn())
- OS << ColNo << ':';
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ if (LastWarningLoc != PLoc.getIncludeLoc()) {
+ LastWarningLoc = PLoc.getIncludeLoc();
+ PrintIncludeStack(LastWarningLoc, SM);
+ StartOfLocationInfo = OS.tell();
}
- if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
- FileID CaretFileID =
- SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
- bool PrintedRange = false;
-
- for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
- // Ignore invalid ranges.
- if (!Info.getRange(i).isValid()) continue;
-
- SourceLocation B = Info.getRange(i).getBegin();
- SourceLocation E = Info.getRange(i).getEnd();
- B = SM.getInstantiationLoc(B);
- E = SM.getInstantiationLoc(E);
-
- // 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 macro
- // expansion or _Pragma. If this is an object-like macro, the 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 && Info.getRange(i).getEnd().isMacroID())
- E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
-
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
-
- // If the start or end of the range is in another file, just discard
- // it.
- if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
- continue;
-
- // Add in the length of the token, so that we cover multi-char tokens.
- unsigned TokSize = 0;
- if (Info.getRange(i).isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, *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) << '}';
- PrintedRange = true;
- }
- if (PrintedRange)
- OS << ':';
+ // Compute the column number.
+ if (DiagOpts->ShowLocation && PLoc.isValid()) {
+ if (DiagOpts->ShowColors)
+ OS.changeColor(savedColor, true);
+
+ // Emit a Visual Studio compatible line number syntax.
+ if (LangOpts && LangOpts->Microsoft) {
+ OS << PLoc.getFilename() << '(' << LineNo << ')';
+ OS << " : ";
+ } else {
+ OS << PLoc.getFilename() << ':' << LineNo << ':';
+ if (DiagOpts->ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn())
+ OS << ColNo << ':';
+ }
+ if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
+ FileID CaretFileID =
+ SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
+ bool PrintedRange = false;
+
+ for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
+ // Ignore invalid ranges.
+ if (!Info.getRange(i).isValid()) continue;
+
+ SourceLocation B = Info.getRange(i).getBegin();
+ SourceLocation E = Info.getRange(i).getEnd();
+ B = SM.getInstantiationLoc(B);
+ E = SM.getInstantiationLoc(E);
+
+ // 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
+ // macro expansion or _Pragma. If this is an object-like macro, the
+ // 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 && Info.getRange(i).getEnd().isMacroID())
+ E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second;
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char
+ // tokens.
+ unsigned TokSize = 0;
+ if (Info.getRange(i).isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(E, SM, *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)
+ << '}';
+ PrintedRange = true;
+ }
+
+ if (PrintedRange)
+ OS << ':';
+ }
}
OS << ' ';
if (DiagOpts->ShowColors)
@@ -873,7 +905,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
std::string OptionName;
if (DiagOpts->ShowOptionNames) {
- if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
+ if (const char *
+ Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) {
OptionName = "-W";
OptionName += Opt;
} else if (Info.getID() == diag::fatal_too_many_errors) {
@@ -882,7 +915,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// If the diagnostic is an extension diagnostic and not enabled by default
// then it must have been turned on with -pedantic.
bool EnabledByDefault;
- if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
+ if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(),
+ EnabledByDefault) &&
!EnabledByDefault)
OptionName = "-pedantic";
}
@@ -891,7 +925,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// If the user wants to see category information, include it too.
unsigned DiagCategory = 0;
if (DiagOpts->ShowCategories)
- DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID());
+ DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
// If there is any categorization information, include it.
if (!OptionName.empty() || DiagCategory != 0) {
@@ -909,7 +943,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OutStr += llvm::utostr(DiagCategory);
else {
assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value");
- OutStr += Diagnostic::getCategoryNameFromID(DiagCategory);
+ OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory);
}
}
@@ -951,7 +985,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
(LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
Info.getNumFixItHints())) {
// Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
- LastLoc = Info.getLocation();
+ LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
// Get the ranges into a local array we can hack on.
diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp
index be9db42..a8c8f75 100644
--- a/lib/Frontend/TypeXML.cpp
+++ b/lib/Frontend/TypeXML.cpp
@@ -29,7 +29,7 @@ public:
TypeWriter(DocumentXML& doc) : Doc(doc) {}
#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(CLASS* T) { \
+ void Visit##CLASS(const CLASS* T) { \
Doc.addSubNode(NAME);
#define ID_ATTRIBUTE_XML // done by the Document class itself
@@ -82,7 +82,7 @@ public:
TypeAdder(DocumentXML& doc) : Doc(doc) {}
#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(CLASS* T) \
+ void Visit##CLASS(const CLASS* T) \
{
#define ID_ATTRIBUTE_XML
@@ -101,7 +101,7 @@ public:
//---------------------------------------------------------
void DocumentXML::addParentTypes(const Type* pType) {
- TypeAdder(*this).Visit(const_cast<Type*>(pType));
+ TypeAdder(*this).Visit(pType);
}
//---------------------------------------------------------
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
index 31eb28f..51b351f 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -23,7 +23,7 @@ using namespace clang;
VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
DiagnosticClient *_Primary)
: Diags(_Diags), PrimaryClient(_Primary),
- Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) {
+ Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) {
}
VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
@@ -57,14 +57,6 @@ void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
Buffer->HandleDiagnostic(DiagLevel, Info);
}
-// FIXME: It would be nice to just get this from the primary diagnostic client
-// or something.
-bool VerifyDiagnosticsClient::HadErrors() {
- CheckDiagnostics();
-
- return NumErrors != 0;
-}
-
//===----------------------------------------------------------------------===//
// Checking diagnostics implementation.
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud