summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Basic
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic')
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Builtins.cpp24
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp914
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp586
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/FileManager.cpp464
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp120
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp350
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp52
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Targets.cpp409
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Version.cpp61
11 files changed, 1744 insertions, 1277 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp
index 040cdb5..845ae81 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp
@@ -14,12 +14,14 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/LangOptions.h"
using namespace clang;
static const Builtin::Info BuiltinInfo[] = {
- { "not a builtin function", 0, 0, 0, false },
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+ { "not a builtin function", 0, 0, 0, ALL_LANGUAGES, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\
+ BUILTIN_LANG, false },
#include "clang/Basic/Builtins.def"
};
@@ -41,17 +43,20 @@ Builtin::Context::Context(const TargetInfo &Target) {
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
/// such.
void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
- bool NoBuiltins) {
+ const LangOptions& LangOpts) {
// Step #1: mark all target-independent builtins with their ID's.
for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i)
if (!BuiltinInfo[i].Suppressed &&
- (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f')))
- Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
+ (!LangOpts.NoBuiltin || !strchr(BuiltinInfo[i].Attributes, 'f'))) {
+ if (LangOpts.ObjC1 ||
+ BuiltinInfo[i].builtin_lang != clang::OBJC_LANG)
+ Table.get(BuiltinInfo[i].Name).setBuiltinID(i);
+ }
// Step #2: Register target-specific builtins.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
if (!TSRecords[i].Suppressed &&
- (!NoBuiltins ||
+ (!LangOpts.NoBuiltin ||
(TSRecords[i].Attributes &&
!strchr(TSRecords[i].Attributes, 'f'))))
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
@@ -75,6 +80,10 @@ Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names,
Names.push_back(TSRecords[i].Name);
}
+void Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) {
+ Table.get(GetRecord(ID).Name).setBuiltinID(0);
+}
+
bool
Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
bool &HasVAListArg) {
@@ -112,4 +121,3 @@ Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
return true;
}
-
diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
index d8095f4..31e3331 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
@@ -11,227 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-
-#include <vector>
-#include <map>
-#include <cstring>
using namespace clang;
-//===----------------------------------------------------------------------===//
-// Builtin Diagnostic information
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-// Diagnostic classes.
-enum {
- CLASS_NOTE = 0x01,
- CLASS_WARNING = 0x02,
- CLASS_EXTENSION = 0x03,
- CLASS_ERROR = 0x04
-};
-
-struct StaticDiagInfoRec {
- unsigned short DiagID;
- unsigned Mapping : 3;
- unsigned Class : 3;
- bool SFINAE : 1;
- unsigned Category : 5;
-
- const char *Description;
- const char *OptionGroup;
-
- bool operator<(const StaticDiagInfoRec &RHS) const {
- return DiagID < RHS.DiagID;
- }
-};
-
-}
-
-static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE, CATEGORY) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, CATEGORY, DESC, GROUP },
-#include "clang/Basic/DiagnosticCommonKinds.inc"
-#include "clang/Basic/DiagnosticDriverKinds.inc"
-#include "clang/Basic/DiagnosticFrontendKinds.inc"
-#include "clang/Basic/DiagnosticLexKinds.inc"
-#include "clang/Basic/DiagnosticParseKinds.inc"
-#include "clang/Basic/DiagnosticASTKinds.inc"
-#include "clang/Basic/DiagnosticSemaKinds.inc"
-#include "clang/Basic/DiagnosticAnalysisKinds.inc"
- { 0, 0, 0, 0, 0, 0, 0}
-};
-#undef DIAG
-
-/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
-/// or null if the ID is invalid.
-static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
- unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
-
- // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
-#ifndef NDEBUG
- static bool IsFirst = true;
- if (IsFirst) {
- for (unsigned i = 1; i != NumDiagEntries; ++i) {
- assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
- "Diag ID conflict, the enums at the start of clang::diag (in "
- "Diagnostic.h) probably need to be increased");
-
- assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
- "Improperly sorted diag info");
- }
- IsFirst = false;
- }
-#endif
-
- // Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0 };
-
- const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
- if (Found == StaticDiagInfo + NumDiagEntries ||
- Found->DiagID != DiagID)
- return 0;
-
- return Found;
-}
-
-static unsigned GetDefaultDiagMapping(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Mapping;
- return diag::MAP_FATAL;
-}
-
-/// getWarningOptionForDiag - Return the lowest-level warning option that
-/// enables the specified diagnostic. If there is no -Wfoo flag that controls
-/// the diagnostic, this returns null.
-const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->OptionGroup;
- return 0;
-}
-
-/// getWarningOptionForDiag - Return the category number that a specified
-/// DiagID belongs to, or 0 if no category.
-unsigned Diagnostic::getCategoryNumberForDiag(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Category;
- return 0;
-}
-
-/// getCategoryNameFromID - Given a category ID, return the name of the
-/// category, an empty string if CategoryID is zero, or null if CategoryID is
-/// invalid.
-const char *Diagnostic::getCategoryNameFromID(unsigned CategoryID) {
- // Second the table of options, sorted by name for fast binary lookup.
- static const char *CategoryNameTable[] = {
-#define GET_CATEGORY_TABLE
-#define CATEGORY(X) X,
-#include "clang/Basic/DiagnosticGroups.inc"
-#undef GET_CATEGORY_TABLE
- "<<END>>"
- };
- static const size_t CategoryNameTableSize =
- sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
-
- if (CategoryID >= CategoryNameTableSize) return 0;
- return CategoryNameTable[CategoryID];
-}
-
-
-
-Diagnostic::SFINAEResponse
-Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
- if (!Info->SFINAE)
- return SFINAE_Report;
-
- if (Info->Class == CLASS_ERROR)
- return SFINAE_SubstitutionFailure;
-
- // Suppress notes, warnings, and extensions;
- return SFINAE_Suppress;
- }
-
- return SFINAE_Report;
-}
-
-/// getDiagClass - Return the class field of the diagnostic.
-///
-static unsigned getBuiltinDiagClass(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Class;
- return ~0U;
-}
-
-//===----------------------------------------------------------------------===//
-// Custom Diagnostic information
-//===----------------------------------------------------------------------===//
-
-namespace clang {
- namespace diag {
- class CustomDiagInfo {
- typedef std::pair<Diagnostic::Level, std::string> DiagDesc;
- std::vector<DiagDesc> DiagInfo;
- std::map<DiagDesc, unsigned> DiagIDs;
- public:
-
- /// getDescription - Return the description of the specified custom
- /// diagnostic.
- const char *getDescription(unsigned DiagID) const {
- assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
- }
-
- /// getLevel - Return the level of the specified custom diagnostic.
- Diagnostic::Level getLevel(unsigned DiagID) const {
- assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
- }
-
- unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message,
- Diagnostic &Diags) {
- DiagDesc D(L, Message);
- // Check to see if it already exists.
- std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
- if (I != DiagIDs.end() && I->first == D)
- return I->second;
-
- // If not, assign a new ID.
- unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
- DiagIDs.insert(std::make_pair(D, ID));
- DiagInfo.push_back(D);
- return ID;
- }
- };
-
- } // end diag namespace
-} // end clang namespace
-
-
-//===----------------------------------------------------------------------===//
-// Common Diagnostic implementation
-//===----------------------------------------------------------------------===//
-
static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
const char *Modifier, unsigned ML,
const char *Argument, unsigned ArgLen,
@@ -244,7 +30,10 @@ static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
}
-Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
+Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
+ DiagnosticClient *client, bool ShouldOwnClient)
+ : Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient),
+ SourceMgr(0) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
@@ -259,72 +48,41 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
- CustomDiagInfo = 0;
- // Set all mappings to 'unset'.
- DiagMappingsStack.clear();
- DiagMappingsStack.push_back(DiagMappings());
+ // Create a DiagState and DiagStatePoint representing diagnostic changes
+ // through command-line.
+ DiagStates.push_back(DiagState());
+ PushDiagStatePoint(&DiagStates.back(), SourceLocation());
Reset();
}
Diagnostic::~Diagnostic() {
- delete CustomDiagInfo;
-}
-
-
-void Diagnostic::pushMappings() {
- // Avoids undefined behavior when the stack has to resize.
- DiagMappingsStack.reserve(DiagMappingsStack.size() + 1);
- DiagMappingsStack.push_back(DiagMappingsStack.back());
-}
-
-bool Diagnostic::popMappings() {
- if (DiagMappingsStack.size() == 1)
- return false;
-
- DiagMappingsStack.pop_back();
- return true;
-}
-
-/// getCustomDiagID - Return an ID for a diagnostic with the specified message
-/// and level. If this is the first request for this diagnosic, it is
-/// registered and created, otherwise the existing ID is returned.
-unsigned Diagnostic::getCustomDiagID(Level L, llvm::StringRef Message) {
- if (CustomDiagInfo == 0)
- CustomDiagInfo = new diag::CustomDiagInfo();
- return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
+ if (OwnsDiagClient)
+ delete Client;
}
-
-/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
-/// level of the specified diagnostic ID is a Warning or Extension.
-/// This only works on builtin diagnostics, not custom ones, and is not legal to
-/// call on NOTEs.
-bool Diagnostic::isBuiltinWarningOrExtension(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) != CLASS_ERROR;
+void Diagnostic::setClient(DiagnosticClient *client, bool ShouldOwnClient) {
+ if (OwnsDiagClient && Client)
+ delete Client;
+
+ Client = client;
+ OwnsDiagClient = ShouldOwnClient;
}
-/// \brief Determine whether the given built-in diagnostic ID is a
-/// Note.
-bool Diagnostic::isBuiltinNote(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) == CLASS_NOTE;
+void Diagnostic::pushMappings(SourceLocation Loc) {
+ DiagStateOnPushStack.push_back(GetCurDiagState());
}
-/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
-/// ID is for an extension of some sort. This also returns EnabledByDefault,
-/// which is set to indicate whether the diagnostic is ignored by default (in
-/// which case -pedantic enables it) or treated as a warning/error by default.
-///
-bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID,
- bool &EnabledByDefault) {
- if (DiagID >= diag::DIAG_UPPER_LIMIT ||
- getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
+bool Diagnostic::popMappings(SourceLocation Loc) {
+ if (DiagStateOnPushStack.empty())
return false;
-
- EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
+
+ if (DiagStateOnPushStack.back() != GetCurDiagState()) {
+ // State changed at some point between push/pop.
+ PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
+ }
+ DiagStateOnPushStack.pop_back();
return true;
}
@@ -336,18 +94,14 @@ void Diagnostic::Reset() {
NumErrors = 0;
NumErrorsSuppressed = 0;
CurDiagID = ~0U;
- LastDiagLevel = Ignored;
+ // Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes
+ // using a Diagnostic associated to a translation unit that follow
+ // diagnostics from a Diagnostic associated to anoter t.u. will not be
+ // displayed.
+ LastDiagLevel = (DiagnosticIDs::Level)-1;
DelayedDiagID = 0;
}
-/// getDescription - Given a diagnostic ID, return a description of the
-/// issue.
-const char *Diagnostic::getDescription(unsigned DiagID) const {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Description;
- return CustomDiagInfo->getDescription(DiagID);
-}
-
void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
llvm::StringRef Arg2) {
if (DelayedDiagID)
@@ -365,264 +119,96 @@ void Diagnostic::ReportDelayed() {
DelayedDiagArg2.clear();
}
-/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
-/// object, classify the specified diagnostic ID into a Level, consumable by
-/// the DiagnosticClient.
-Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const {
- // Handle custom diagnostics, which cannot be mapped.
- if (DiagID >= diag::DIAG_UPPER_LIMIT)
- return CustomDiagInfo->getLevel(DiagID);
-
- unsigned DiagClass = getBuiltinDiagClass(DiagID);
- assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
- return getDiagnosticLevel(DiagID, DiagClass);
-}
-
-/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
-/// object, classify the specified diagnostic ID into a Level, consumable by
-/// the DiagnosticClient.
-Diagnostic::Level
-Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
- // Specific non-error diagnostics may be mapped to various levels from ignored
- // to error. Errors can only be mapped to fatal.
- Diagnostic::Level Result = Diagnostic::Fatal;
-
- // Get the mapping information, if unset, compute it lazily.
- unsigned MappingInfo = getDiagnosticMappingInfo((diag::kind)DiagID);
- if (MappingInfo == 0) {
- MappingInfo = GetDefaultDiagMapping(DiagID);
- setDiagnosticMappingInternal(DiagID, MappingInfo, false);
- }
-
- switch (MappingInfo & 7) {
- default: assert(0 && "Unknown mapping!");
- case diag::MAP_IGNORE:
- // Ignore this, unless this is an extension diagnostic and we're mapping
- // them onto warnings or errors.
- if (!isBuiltinExtensionDiag(DiagID) || // Not an extension
- ExtBehavior == Ext_Ignore || // Extensions ignored anyway
- (MappingInfo & 8) != 0) // User explicitly mapped it.
- return Diagnostic::Ignored;
- Result = Diagnostic::Warning;
- if (ExtBehavior == Ext_Error) Result = Diagnostic::Error;
- if (Result == Diagnostic::Error && ErrorsAsFatal)
- Result = Diagnostic::Fatal;
- break;
- case diag::MAP_ERROR:
- Result = Diagnostic::Error;
- if (ErrorsAsFatal)
- Result = Diagnostic::Fatal;
- break;
- case diag::MAP_FATAL:
- Result = Diagnostic::Fatal;
- break;
- case diag::MAP_WARNING:
- // If warnings are globally mapped to ignore or error, do it.
- if (IgnoreAllWarnings)
- return Diagnostic::Ignored;
-
- Result = Diagnostic::Warning;
-
- // If this is an extension diagnostic and we're in -pedantic-error mode, and
- // if the user didn't explicitly map it, upgrade to an error.
- if (ExtBehavior == Ext_Error &&
- (MappingInfo & 8) == 0 &&
- isBuiltinExtensionDiag(DiagID))
- Result = Diagnostic::Error;
-
- if (WarningsAsErrors)
- Result = Diagnostic::Error;
- if (Result == Diagnostic::Error && ErrorsAsFatal)
- Result = Diagnostic::Fatal;
- break;
-
- case diag::MAP_WARNING_NO_WERROR:
- // Diagnostics specified with -Wno-error=foo should be set to warnings, but
- // not be adjusted by -Werror or -pedantic-errors.
- Result = Diagnostic::Warning;
-
- // If warnings are globally mapped to ignore or error, do it.
- if (IgnoreAllWarnings)
- return Diagnostic::Ignored;
-
- break;
-
- case diag::MAP_ERROR_NO_WFATAL:
- // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
- // unaffected by -Wfatal-errors.
- Result = Diagnostic::Error;
- break;
- }
-
- // Okay, we're about to return this as a "diagnostic to emit" one last check:
- // if this is any sort of extension warning, and if we're in an __extension__
- // block, silence it.
- if (AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
- return Diagnostic::Ignored;
-
- return Result;
-}
-
-struct WarningOption {
- const char *Name;
- const short *Members;
- const short *SubGroups;
-};
-
-#define GET_DIAG_ARRAYS
-#include "clang/Basic/DiagnosticGroups.inc"
-#undef GET_DIAG_ARRAYS
-
-// Second the table of options, sorted by name for fast binary lookup.
-static const WarningOption OptionTable[] = {
-#define GET_DIAG_TABLE
-#include "clang/Basic/DiagnosticGroups.inc"
-#undef GET_DIAG_TABLE
-};
-static const size_t OptionTableSize =
-sizeof(OptionTable) / sizeof(OptionTable[0]);
-
-static bool WarningOptionCompare(const WarningOption &LHS,
- const WarningOption &RHS) {
- return strcmp(LHS.Name, RHS.Name) < 0;
-}
-
-static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
- Diagnostic &Diags) {
- // Option exists, poke all the members of its diagnostic set.
- if (const short *Member = Group->Members) {
- for (; *Member != -1; ++Member)
- Diags.setDiagnosticMapping(*Member, Mapping);
- }
+Diagnostic::DiagStatePointsTy::iterator
+Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const {
+ assert(!DiagStatePoints.empty());
+ assert(DiagStatePoints.front().Loc.isInvalid() &&
+ "Should have created a DiagStatePoint for command-line");
- // Enable/disable all subgroups along with this one.
- if (const short *SubGroups = Group->SubGroups) {
- for (; *SubGroups != (short)-1; ++SubGroups)
- MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Diags);
- }
-}
+ FullSourceLoc Loc(L, *SourceMgr);
+ if (Loc.isInvalid())
+ return DiagStatePoints.end() - 1;
-/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
-/// "unknown-pragmas" to have the specified mapping. This returns true and
-/// ignores the request if "Group" was unknown, false otherwise.
-bool Diagnostic::setDiagnosticGroupMapping(const char *Group,
- diag::Mapping Map) {
-
- WarningOption Key = { Group, 0, 0 };
- const WarningOption *Found =
- std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
- WarningOptionCompare);
- if (Found == OptionTable + OptionTableSize ||
- strcmp(Found->Name, Group) != 0)
- return true; // Option not found.
-
- MapGroupMembers(Found, Map, *this);
- return false;
+ DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
+ FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+ if (LastStateChangePos.isValid() &&
+ Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
+ Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
+ DiagStatePoint(0, Loc));
+ --Pos;
+ return Pos;
}
-
-/// ProcessDiag - This is the method used to report a diagnostic that is
-/// finally fully formed.
-bool Diagnostic::ProcessDiag() {
- DiagnosticInfo Info(this);
-
- if (SuppressAllDiagnostics)
- return false;
-
- // Figure out the diagnostic level of this message.
- Diagnostic::Level DiagLevel;
- unsigned DiagID = Info.getID();
-
- // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
- // in a system header.
- bool ShouldEmitInSystemHeader;
-
- if (DiagID >= diag::DIAG_UPPER_LIMIT) {
- // Handle custom diagnostics, which cannot be mapped.
- DiagLevel = CustomDiagInfo->getLevel(DiagID);
-
- // Custom diagnostics always are emitted in system headers.
- ShouldEmitInSystemHeader = true;
- } else {
- // Get the class of the diagnostic. If this is a NOTE, map it onto whatever
- // the diagnostic level was for the previous diagnostic so that it is
- // filtered the same as the previous diagnostic.
- unsigned DiagClass = getBuiltinDiagClass(DiagID);
- if (DiagClass == CLASS_NOTE) {
- DiagLevel = Diagnostic::Note;
- ShouldEmitInSystemHeader = false; // extra consideration is needed
- } else {
- // If this is not an error and we are in a system header, we ignore it.
- // Check the original Diag ID here, because we also want to ignore
- // extensions and warnings in -Werror and -pedantic-errors modes, which
- // *map* warnings/extensions to errors.
- ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
-
- DiagLevel = getDiagnosticLevel(DiagID, DiagClass);
- }
- }
-
- if (DiagLevel != Diagnostic::Note) {
- // Record that a fatal error occurred only when we see a second
- // non-note diagnostic. This allows notes to be attached to the
- // fatal error, but suppresses any diagnostics that follow those
- // notes.
- if (LastDiagLevel == Diagnostic::Fatal)
- FatalErrorOccurred = true;
-
- LastDiagLevel = DiagLevel;
+/// \brief This allows the client to specify that certain
+/// warnings are ignored. Notes can never be mapped, errors can only be
+/// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily.
+///
+/// \param The source location that this change of diagnostic state should
+/// take affect. It can be null if we are setting the latest state.
+void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
+ SourceLocation L) {
+ assert(Diag < diag::DIAG_UPPER_LIMIT &&
+ "Can only map builtin diagnostics");
+ assert((Diags->isBuiltinWarningOrExtension(Diag) ||
+ (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
+ "Cannot map errors into warnings!");
+ assert(!DiagStatePoints.empty());
+
+ bool isPragma = L.isValid();
+ FullSourceLoc Loc(L, *SourceMgr);
+ FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+
+ // Common case; setting all the diagnostics of a group in one place.
+ if (Loc.isInvalid() || Loc == LastStateChangePos) {
+ setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
+ return;
}
- // If a fatal error has already been emitted, silence all subsequent
- // diagnostics.
- if (FatalErrorOccurred) {
- if (DiagLevel >= Diagnostic::Error && Client->IncludeInDiagnosticCounts()) {
- ++NumErrors;
- ++NumErrorsSuppressed;
- }
-
- return false;
+ // Another common case; modifying diagnostic state in a source location
+ // after the previous one.
+ if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
+ LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
+ // A diagnostic pragma occured, create a new DiagState initialized with
+ // the current one and a new DiagStatePoint to record at which location
+ // the new state became active.
+ DiagStates.push_back(*GetCurDiagState());
+ PushDiagStatePoint(&DiagStates.back(), Loc);
+ setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
+ return;
}
- // If the client doesn't care about this message, don't issue it. If this is
- // a note and the last real diagnostic was ignored, ignore it too.
- if (DiagLevel == Diagnostic::Ignored ||
- (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored))
- return false;
-
- // If this diagnostic is in a system header and is not a clang error, suppress
- // it.
- if (SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
- Info.getLocation().isValid() &&
- Info.getLocation().getInstantiationLoc().isInSystemHeader() &&
- (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) {
- LastDiagLevel = Diagnostic::Ignored;
- return false;
- }
+ // We allow setting the diagnostic state in random source order for
+ // completeness but it should not be actually happening in normal practice.
- if (DiagLevel >= Diagnostic::Error) {
- if (Client->IncludeInDiagnosticCounts()) {
- ErrorOccurred = true;
- ++NumErrors;
- }
+ DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
+ assert(Pos != DiagStatePoints.end());
- // If we've emitted a lot of errors, emit a fatal error after it to stop a
- // flood of bogus errors.
- if (ErrorLimit && NumErrors >= ErrorLimit &&
- DiagLevel == Diagnostic::Error)
- SetDelayedDiagnostic(diag::fatal_too_many_errors);
+ // Update all diagnostic states that are active after the given location.
+ for (DiagStatePointsTy::iterator
+ I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
+ setDiagnosticMappingInternal(Diag, Map, I->State, true, isPragma);
}
- // Finally, report it.
- Client->HandleDiagnostic(DiagLevel, Info);
- if (Client->IncludeInDiagnosticCounts()) {
- if (DiagLevel == Diagnostic::Warning)
- ++NumWarnings;
+ // If the location corresponds to an existing point, just update its state.
+ if (Pos->Loc == Loc) {
+ setDiagnosticMappingInternal(Diag, Map, Pos->State, true, isPragma);
+ return;
}
- CurDiagID = ~0U;
+ // Create a new state/point and fit it into the vector of DiagStatePoints
+ // so that the vector is always ordered according to location.
+ Pos->Loc.isBeforeInTranslationUnitThan(Loc);
+ DiagStates.push_back(*Pos->State);
+ DiagState *NewState = &DiagStates.back();
+ setDiagnosticMappingInternal(Diag, Map, NewState, true, isPragma);
+ DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
+ FullSourceLoc(Loc, *SourceMgr)));
+}
- return true;
+void DiagnosticBuilder::FlushCounts() {
+ DiagObj->NumDiagArgs = NumArgs;
+ DiagObj->NumDiagRanges = NumRanges;
+ DiagObj->NumFixItHints = NumFixItHints;
}
bool DiagnosticBuilder::Emit() {
@@ -632,9 +218,7 @@ bool DiagnosticBuilder::Emit() {
// When emitting diagnostics, we set the final argument count into
// the Diagnostic object.
- DiagObj->NumDiagArgs = NumArgs;
- DiagObj->NumDiagRanges = NumRanges;
- DiagObj->NumFixItHints = NumFixItHints;
+ FlushCounts();
// Process the diagnostic, sending the accumulated information to the
// DiagnosticClient.
@@ -657,6 +241,16 @@ bool DiagnosticBuilder::Emit() {
DiagnosticClient::~DiagnosticClient() {}
+void DiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ if (!IncludeInDiagnosticCounts())
+ return;
+
+ if (DiagLevel == Diagnostic::Warning)
+ ++NumWarnings;
+ else if (DiagLevel >= Diagnostic::Error)
+ ++NumErrors;
+}
/// ModifierIs - Return true if the specified modifier matches specified string.
template <std::size_t StrLen>
@@ -855,7 +449,7 @@ static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
/// {1:form0|[2,4]:form1|:form2}
/// Polish (requires repeated form):
/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
-static void HandlePluralModifier(unsigned ValNo,
+static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
llvm::SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument + ArgumentLen;
@@ -869,7 +463,10 @@ static void HandlePluralModifier(unsigned ValNo,
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
Argument = ExprEnd + 1;
ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
- OutStr.append(Argument, ExprEnd);
+
+ // Recursively format the result of the plural clause into the
+ // output string.
+ DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
return;
}
Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
@@ -882,7 +479,7 @@ static void HandlePluralModifier(unsigned ValNo,
/// array.
void DiagnosticInfo::
FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
- const char *DiagStr = getDiags()->getDescription(getID());
+ const char *DiagStr = getDiags()->getDiagnosticIDs()->getDescription(getID());
const char *DiagEnd = DiagStr+strlen(DiagStr);
FormatDiagnostic(DiagStr, DiagEnd, OutStr);
@@ -971,11 +568,13 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
- HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr);
+ HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
+ OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
- HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
+ OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
HandleOrdinalModifier((unsigned)Val, OutStr);
} else {
@@ -992,7 +591,8 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
- HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
+ OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
HandleOrdinalModifier(Val, OutStr);
} else {
@@ -1043,13 +643,18 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
StoredDiagnostic::StoredDiagnostic() { }
-StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
+StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, unsigned ID,
llvm::StringRef Message)
- : Level(Level), Loc(), Message(Message) { }
+ : ID(ID), Level(Level), Loc(), Message(Message) { }
StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info)
- : Level(Level), Loc(Info.getLocation()) {
+ : ID(Info.getID()), Level(Level)
+{
+ assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
+ "Valid source location without setting a source manager for diagnostic");
+ if (Info.getLocation().isValid())
+ Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
llvm::SmallString<64> Message;
Info.FormatDiagnostic(Message);
this->Message.assign(Message.begin(), Message.end());
@@ -1065,251 +670,6 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
StoredDiagnostic::~StoredDiagnostic() { }
-static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
- OS.write((const char *)&Value, sizeof(unsigned));
-}
-
-static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) {
- WriteUnsigned(OS, String.size());
- OS.write(String.data(), String.size());
-}
-
-static void WriteSourceLocation(llvm::raw_ostream &OS,
- SourceManager *SM,
- SourceLocation Location) {
- if (!SM || Location.isInvalid()) {
- // If we don't have a source manager or this location is invalid,
- // just write an invalid location.
- WriteUnsigned(OS, 0);
- WriteUnsigned(OS, 0);
- WriteUnsigned(OS, 0);
- return;
- }
-
- Location = SM->getInstantiationLoc(Location);
- std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
-
- const FileEntry *FE = SM->getFileEntryForID(Decomposed.first);
- if (FE)
- WriteString(OS, FE->getName());
- else {
- // Fallback to using the buffer name when there is no entry.
- WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier());
- }
-
- WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
- WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
-}
-
-void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const {
- SourceManager *SM = 0;
- if (getLocation().isValid())
- SM = &const_cast<SourceManager &>(getLocation().getManager());
-
- // Write a short header to help identify diagnostics.
- OS << (char)0x06 << (char)0x07;
-
- // Write the diagnostic level and location.
- WriteUnsigned(OS, (unsigned)Level);
- WriteSourceLocation(OS, SM, getLocation());
-
- // Write the diagnostic message.
- llvm::SmallString<64> Message;
- WriteString(OS, getMessage());
-
- // Count the number of ranges that don't point into macros, since
- // only simple file ranges serialize well.
- unsigned NumNonMacroRanges = 0;
- for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) {
- if (R->getBegin().isMacroID() || R->getEnd().isMacroID())
- continue;
-
- ++NumNonMacroRanges;
- }
-
- // Write the ranges.
- WriteUnsigned(OS, NumNonMacroRanges);
- if (NumNonMacroRanges) {
- for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) {
- if (R->getBegin().isMacroID() || R->getEnd().isMacroID())
- continue;
-
- WriteSourceLocation(OS, SM, R->getBegin());
- WriteSourceLocation(OS, SM, R->getEnd());
- WriteUnsigned(OS, R->isTokenRange());
- }
- }
-
- // Determine if all of the fix-its involve rewrites with simple file
- // locations (not in macro instantiations). If so, we can write
- // fix-it information.
- unsigned NumFixIts = 0;
- for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) {
- if (F->RemoveRange.isValid() &&
- (F->RemoveRange.getBegin().isMacroID() ||
- F->RemoveRange.getEnd().isMacroID())) {
- NumFixIts = 0;
- break;
- }
-
- ++NumFixIts;
- }
-
- // Write the fix-its.
- WriteUnsigned(OS, NumFixIts);
- for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) {
- WriteSourceLocation(OS, SM, F->RemoveRange.getBegin());
- WriteSourceLocation(OS, SM, F->RemoveRange.getEnd());
- WriteUnsigned(OS, F->RemoveRange.isTokenRange());
- WriteString(OS, F->CodeToInsert);
- }
-}
-
-static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
- unsigned &Value) {
- if (Memory + sizeof(unsigned) > MemoryEnd)
- return true;
-
- memmove(&Value, Memory, sizeof(unsigned));
- Memory += sizeof(unsigned);
- return false;
-}
-
-static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
- const char *&Memory, const char *MemoryEnd,
- SourceLocation &Location) {
- // Read the filename.
- unsigned FileNameLen = 0;
- if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) ||
- Memory + FileNameLen > MemoryEnd)
- return true;
-
- llvm::StringRef FileName(Memory, FileNameLen);
- Memory += FileNameLen;
-
- // Read the line, column.
- unsigned Line = 0, Column = 0;
- if (ReadUnsigned(Memory, MemoryEnd, Line) ||
- ReadUnsigned(Memory, MemoryEnd, Column))
- return true;
-
- if (FileName.empty()) {
- Location = SourceLocation();
- return false;
- }
-
- const FileEntry *File = FM.getFile(FileName);
- if (!File)
- return true;
-
- // Make sure that this file has an entry in the source manager.
- if (!SM.hasFileInfo(File))
- SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
-
- Location = SM.getLocation(File, Line, Column);
- return false;
-}
-
-StoredDiagnostic
-StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
- const char *&Memory, const char *MemoryEnd) {
- while (true) {
- if (Memory == MemoryEnd)
- return StoredDiagnostic();
-
- if (*Memory != 0x06) {
- ++Memory;
- continue;
- }
-
- ++Memory;
- if (Memory == MemoryEnd)
- return StoredDiagnostic();
-
- if (*Memory != 0x07) {
- ++Memory;
- continue;
- }
-
- // We found the header. We're done.
- ++Memory;
- break;
- }
-
- // Read the severity level.
- unsigned Level = 0;
- if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Diagnostic::Fatal)
- return StoredDiagnostic();
-
- // Read the source location.
- SourceLocation Location;
- if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
- return StoredDiagnostic();
-
- // Read the diagnostic text.
- if (Memory == MemoryEnd)
- return StoredDiagnostic();
-
- unsigned MessageLen = 0;
- if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
- Memory + MessageLen > MemoryEnd)
- return StoredDiagnostic();
-
- llvm::StringRef Message(Memory, MessageLen);
- Memory += MessageLen;
-
-
- // At this point, we have enough information to form a diagnostic. Do so.
- StoredDiagnostic Diag;
- Diag.Level = (Diagnostic::Level)Level;
- Diag.Loc = FullSourceLoc(Location, SM);
- Diag.Message = Message;
- if (Memory == MemoryEnd)
- return Diag;
-
- // Read the source ranges.
- unsigned NumSourceRanges = 0;
- if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
- return Diag;
- for (unsigned I = 0; I != NumSourceRanges; ++I) {
- SourceLocation Begin, End;
- unsigned IsTokenRange;
- if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
- ReadSourceLocation(FM, SM, Memory, MemoryEnd, End) ||
- ReadUnsigned(Memory, MemoryEnd, IsTokenRange))
- return Diag;
-
- Diag.Ranges.push_back(CharSourceRange(SourceRange(Begin, End),
- IsTokenRange));
- }
-
- // Read the fix-it hints.
- unsigned NumFixIts = 0;
- if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
- return Diag;
- for (unsigned I = 0; I != NumFixIts; ++I) {
- SourceLocation RemoveBegin, RemoveEnd;
- unsigned InsertLen = 0, RemoveIsTokenRange;
- if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
- ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
- ReadUnsigned(Memory, MemoryEnd, RemoveIsTokenRange) ||
- ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
- Memory + InsertLen > MemoryEnd) {
- Diag.FixIts.clear();
- return Diag;
- }
-
- FixItHint Hint;
- Hint.RemoveRange = CharSourceRange(SourceRange(RemoveBegin, RemoveEnd),
- RemoveIsTokenRange);
- Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
- Memory += InsertLen;
- Diag.FixIts.push_back(Hint);
- }
-
- return Diag;
-}
-
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics
diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
new file mode 100644
index 0000000..8725e7f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
@@ -0,0 +1,586 @@
+//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Diagnostic IDs-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Analysis/AnalysisDiagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+#include <map>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Builtin Diagnostic information
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+// Diagnostic classes.
+enum {
+ CLASS_NOTE = 0x01,
+ CLASS_WARNING = 0x02,
+ CLASS_EXTENSION = 0x03,
+ CLASS_ERROR = 0x04
+};
+
+struct StaticDiagInfoRec {
+ unsigned short DiagID;
+ unsigned Mapping : 3;
+ unsigned Class : 3;
+ unsigned SFINAE : 1;
+ unsigned AccessControl : 1;
+ unsigned Category : 5;
+
+ const char *Description;
+ const char *OptionGroup;
+
+ bool operator<(const StaticDiagInfoRec &RHS) const {
+ return DiagID < RHS.DiagID;
+ }
+};
+
+}
+
+static const StaticDiagInfoRec StaticDiagInfo[] = {
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP },
+#include "clang/Basic/DiagnosticCommonKinds.inc"
+#include "clang/Basic/DiagnosticDriverKinds.inc"
+#include "clang/Basic/DiagnosticFrontendKinds.inc"
+#include "clang/Basic/DiagnosticLexKinds.inc"
+#include "clang/Basic/DiagnosticParseKinds.inc"
+#include "clang/Basic/DiagnosticASTKinds.inc"
+#include "clang/Basic/DiagnosticSemaKinds.inc"
+#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+ { 0, 0, 0, 0, 0, 0, 0, 0}
+};
+#undef DIAG
+
+/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
+/// or null if the ID is invalid.
+static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
+ unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
+
+ // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
+#ifndef NDEBUG
+ static bool IsFirst = true;
+ if (IsFirst) {
+ for (unsigned i = 1; i != NumDiagEntries; ++i) {
+ assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
+ "Diag ID conflict, the enums at the start of clang::diag (in "
+ "DiagnosticIDs.h) probably need to be increased");
+
+ assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] &&
+ "Improperly sorted diag info");
+ }
+ IsFirst = false;
+ }
+#endif
+
+ // Search the diagnostic table with a binary search.
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 };
+
+ const StaticDiagInfoRec *Found =
+ std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
+ if (Found == StaticDiagInfo + NumDiagEntries ||
+ Found->DiagID != DiagID)
+ return 0;
+
+ return Found;
+}
+
+static unsigned GetDefaultDiagMapping(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Mapping;
+ return diag::MAP_FATAL;
+}
+
+/// getWarningOptionForDiag - Return the lowest-level warning option that
+/// enables the specified diagnostic. If there is no -Wfoo flag that controls
+/// the diagnostic, this returns null.
+const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->OptionGroup;
+ return 0;
+}
+
+/// getWarningOptionForDiag - Return the category number that a specified
+/// DiagID belongs to, or 0 if no category.
+unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Category;
+ return 0;
+}
+
+/// getCategoryNameFromID - Given a category ID, return the name of the
+/// category, an empty string if CategoryID is zero, or null if CategoryID is
+/// invalid.
+const char *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
+ // Second the table of options, sorted by name for fast binary lookup.
+ static const char *CategoryNameTable[] = {
+#define GET_CATEGORY_TABLE
+#define CATEGORY(X) X,
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_CATEGORY_TABLE
+ "<<END>>"
+ };
+ static const size_t CategoryNameTableSize =
+ sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
+
+ if (CategoryID >= CategoryNameTableSize) return 0;
+ return CategoryNameTable[CategoryID];
+}
+
+
+
+DiagnosticIDs::SFINAEResponse
+DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
+ if (Info->AccessControl)
+ return SFINAE_AccessControl;
+
+ if (!Info->SFINAE)
+ return SFINAE_Report;
+
+ if (Info->Class == CLASS_ERROR)
+ return SFINAE_SubstitutionFailure;
+
+ // Suppress notes, warnings, and extensions;
+ return SFINAE_Suppress;
+ }
+
+ return SFINAE_Report;
+}
+
+/// getDiagClass - Return the class field of the diagnostic.
+///
+static unsigned getBuiltinDiagClass(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Class;
+ return ~0U;
+}
+
+//===----------------------------------------------------------------------===//
+// Custom Diagnostic information
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ namespace diag {
+ class CustomDiagInfo {
+ typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
+ std::vector<DiagDesc> DiagInfo;
+ std::map<DiagDesc, unsigned> DiagIDs;
+ public:
+
+ /// getDescription - Return the description of the specified custom
+ /// diagnostic.
+ const char *getDescription(unsigned DiagID) const {
+ assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ "Invalid diagnosic ID");
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
+ }
+
+ /// getLevel - Return the level of the specified custom diagnostic.
+ DiagnosticIDs::Level getLevel(unsigned DiagID) const {
+ assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ "Invalid diagnosic ID");
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
+ }
+
+ unsigned getOrCreateDiagID(DiagnosticIDs::Level L, llvm::StringRef Message,
+ DiagnosticIDs &Diags) {
+ DiagDesc D(L, Message);
+ // Check to see if it already exists.
+ std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
+ if (I != DiagIDs.end() && I->first == D)
+ return I->second;
+
+ // If not, assign a new ID.
+ unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
+ DiagIDs.insert(std::make_pair(D, ID));
+ DiagInfo.push_back(D);
+ return ID;
+ }
+ };
+
+ } // end diag namespace
+} // end clang namespace
+
+
+//===----------------------------------------------------------------------===//
+// Common Diagnostic implementation
+//===----------------------------------------------------------------------===//
+
+DiagnosticIDs::DiagnosticIDs() {
+ CustomDiagInfo = 0;
+}
+
+DiagnosticIDs::~DiagnosticIDs() {
+ delete CustomDiagInfo;
+}
+
+/// getCustomDiagID - Return an ID for a diagnostic with the specified message
+/// and level. If this is the first request for this diagnosic, it is
+/// registered and created, otherwise the existing ID is returned.
+unsigned DiagnosticIDs::getCustomDiagID(Level L, llvm::StringRef Message) {
+ if (CustomDiagInfo == 0)
+ CustomDiagInfo = new diag::CustomDiagInfo();
+ return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
+}
+
+
+/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
+/// level of the specified diagnostic ID is a Warning or Extension.
+/// This only works on builtin diagnostics, not custom ones, and is not legal to
+/// call on NOTEs.
+bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) != CLASS_ERROR;
+}
+
+/// \brief Determine whether the given built-in diagnostic ID is a
+/// Note.
+bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) == CLASS_NOTE;
+}
+
+/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
+/// ID is for an extension of some sort. This also returns EnabledByDefault,
+/// which is set to indicate whether the diagnostic is ignored by default (in
+/// which case -pedantic enables it) or treated as a warning/error by default.
+///
+bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
+ bool &EnabledByDefault) {
+ if (DiagID >= diag::DIAG_UPPER_LIMIT ||
+ getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
+ return false;
+
+ EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE;
+ return true;
+}
+
+/// getDescription - Given a diagnostic ID, return a description of the
+/// issue.
+const char *DiagnosticIDs::getDescription(unsigned DiagID) const {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Description;
+ return CustomDiagInfo->getDescription(DiagID);
+}
+
+/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+/// object, classify the specified diagnostic ID into a Level, consumable by
+/// the DiagnosticClient.
+DiagnosticIDs::Level
+DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
+ const Diagnostic &Diag) const {
+ // Handle custom diagnostics, which cannot be mapped.
+ if (DiagID >= diag::DIAG_UPPER_LIMIT)
+ return CustomDiagInfo->getLevel(DiagID);
+
+ unsigned DiagClass = getBuiltinDiagClass(DiagID);
+ assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
+ return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
+}
+
+/// \brief Based on the way the client configured the Diagnostic
+/// object, classify the specified diagnostic ID into a Level, consumable by
+/// the DiagnosticClient.
+///
+/// \param Loc The source location we are interested in finding out the
+/// diagnostic state. Can be null in order to query the latest state.
+DiagnosticIDs::Level
+DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
+ SourceLocation Loc,
+ const Diagnostic &Diag) const {
+ // Specific non-error diagnostics may be mapped to various levels from ignored
+ // to error. Errors can only be mapped to fatal.
+ DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
+
+ Diagnostic::DiagStatePointsTy::iterator
+ Pos = Diag.GetDiagStatePointForLoc(Loc);
+ Diagnostic::DiagState *State = Pos->State;
+
+ // Get the mapping information, if unset, compute it lazily.
+ unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
+ State);
+ if (MappingInfo == 0) {
+ MappingInfo = GetDefaultDiagMapping(DiagID);
+ Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
+ }
+
+ switch (MappingInfo & 7) {
+ default: assert(0 && "Unknown mapping!");
+ case diag::MAP_IGNORE:
+ // Ignore this, unless this is an extension diagnostic and we're mapping
+ // them onto warnings or errors.
+ if (!isBuiltinExtensionDiag(DiagID) || // Not an extension
+ Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored
+ (MappingInfo & 8) != 0) // User explicitly mapped it.
+ return DiagnosticIDs::Ignored;
+ Result = DiagnosticIDs::Warning;
+ if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error;
+ if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
+ Result = DiagnosticIDs::Fatal;
+ break;
+ case diag::MAP_ERROR:
+ Result = DiagnosticIDs::Error;
+ if (Diag.ErrorsAsFatal)
+ Result = DiagnosticIDs::Fatal;
+ break;
+ case diag::MAP_FATAL:
+ Result = DiagnosticIDs::Fatal;
+ break;
+ case diag::MAP_WARNING:
+ // If warnings are globally mapped to ignore or error, do it.
+ if (Diag.IgnoreAllWarnings)
+ return DiagnosticIDs::Ignored;
+
+ Result = DiagnosticIDs::Warning;
+
+ // If this is an extension diagnostic and we're in -pedantic-error mode, and
+ // if the user didn't explicitly map it, upgrade to an error.
+ if (Diag.ExtBehavior == Diagnostic::Ext_Error &&
+ (MappingInfo & 8) == 0 &&
+ isBuiltinExtensionDiag(DiagID))
+ Result = DiagnosticIDs::Error;
+
+ if (Diag.WarningsAsErrors)
+ Result = DiagnosticIDs::Error;
+ if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal)
+ Result = DiagnosticIDs::Fatal;
+ break;
+
+ case diag::MAP_WARNING_NO_WERROR:
+ // Diagnostics specified with -Wno-error=foo should be set to warnings, but
+ // not be adjusted by -Werror or -pedantic-errors.
+ Result = DiagnosticIDs::Warning;
+
+ // If warnings are globally mapped to ignore or error, do it.
+ if (Diag.IgnoreAllWarnings)
+ return DiagnosticIDs::Ignored;
+
+ break;
+
+ case diag::MAP_ERROR_NO_WFATAL:
+ // Diagnostics specified as -Wno-fatal-error=foo should be errors, but
+ // unaffected by -Wfatal-errors.
+ Result = DiagnosticIDs::Error;
+ break;
+ }
+
+ // Okay, we're about to return this as a "diagnostic to emit" one last check:
+ // if this is any sort of extension warning, and if we're in an __extension__
+ // block, silence it.
+ if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
+ return DiagnosticIDs::Ignored;
+
+ return Result;
+}
+
+struct WarningOption {
+ const char *Name;
+ const short *Members;
+ const short *SubGroups;
+};
+
+#define GET_DIAG_ARRAYS
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_ARRAYS
+
+// Second the table of options, sorted by name for fast binary lookup.
+static const WarningOption OptionTable[] = {
+#define GET_DIAG_TABLE
+#include "clang/Basic/DiagnosticGroups.inc"
+#undef GET_DIAG_TABLE
+};
+static const size_t OptionTableSize =
+sizeof(OptionTable) / sizeof(OptionTable[0]);
+
+static bool WarningOptionCompare(const WarningOption &LHS,
+ const WarningOption &RHS) {
+ return strcmp(LHS.Name, RHS.Name) < 0;
+}
+
+static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
+ SourceLocation Loc, Diagnostic &Diag) {
+ // Option exists, poke all the members of its diagnostic set.
+ if (const short *Member = Group->Members) {
+ for (; *Member != -1; ++Member)
+ Diag.setDiagnosticMapping(*Member, Mapping, Loc);
+ }
+
+ // Enable/disable all subgroups along with this one.
+ if (const short *SubGroups = Group->SubGroups) {
+ for (; *SubGroups != (short)-1; ++SubGroups)
+ MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
+ }
+}
+
+/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
+/// "unknown-pragmas" to have the specified mapping. This returns true and
+/// ignores the request if "Group" was unknown, false otherwise.
+bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
+ diag::Mapping Map,
+ SourceLocation Loc,
+ Diagnostic &Diag) const {
+ assert((Loc.isValid() ||
+ Diag.DiagStatePoints.empty() ||
+ Diag.DiagStatePoints.back().Loc.isInvalid()) &&
+ "Loc should be invalid only when the mapping comes from command-line");
+ assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
+ Diag.DiagStatePoints.back().Loc.isInvalid() ||
+ !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
+ Diag.DiagStatePoints.back().Loc)) &&
+ "Source location of new mapping is before the previous one!");
+
+ WarningOption Key = { Group, 0, 0 };
+ const WarningOption *Found =
+ std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
+ WarningOptionCompare);
+ if (Found == OptionTable + OptionTableSize ||
+ strcmp(Found->Name, Group) != 0)
+ return true; // Option not found.
+
+ MapGroupMembers(Found, Map, Loc, Diag);
+ return false;
+}
+
+/// ProcessDiag - This is the method used to report a diagnostic that is
+/// finally fully formed.
+bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
+ DiagnosticInfo Info(&Diag);
+
+ if (Diag.SuppressAllDiagnostics)
+ return false;
+
+ assert(Diag.getClient() && "DiagnosticClient not set!");
+
+ // Figure out the diagnostic level of this message.
+ DiagnosticIDs::Level DiagLevel;
+ unsigned DiagID = Info.getID();
+
+ // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
+ // in a system header.
+ bool ShouldEmitInSystemHeader;
+
+ if (DiagID >= diag::DIAG_UPPER_LIMIT) {
+ // Handle custom diagnostics, which cannot be mapped.
+ DiagLevel = CustomDiagInfo->getLevel(DiagID);
+
+ // Custom diagnostics always are emitted in system headers.
+ ShouldEmitInSystemHeader = true;
+ } else {
+ // Get the class of the diagnostic. If this is a NOTE, map it onto whatever
+ // the diagnostic level was for the previous diagnostic so that it is
+ // filtered the same as the previous diagnostic.
+ unsigned DiagClass = getBuiltinDiagClass(DiagID);
+ if (DiagClass == CLASS_NOTE) {
+ DiagLevel = DiagnosticIDs::Note;
+ ShouldEmitInSystemHeader = false; // extra consideration is needed
+ } else {
+ // If this is not an error and we are in a system header, we ignore it.
+ // Check the original Diag ID here, because we also want to ignore
+ // extensions and warnings in -Werror and -pedantic-errors modes, which
+ // *map* warnings/extensions to errors.
+ ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
+
+ DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
+ Diag);
+ }
+ }
+
+ if (DiagLevel != DiagnosticIDs::Note) {
+ // Record that a fatal error occurred only when we see a second
+ // non-note diagnostic. This allows notes to be attached to the
+ // fatal error, but suppresses any diagnostics that follow those
+ // notes.
+ if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
+ Diag.FatalErrorOccurred = true;
+
+ Diag.LastDiagLevel = DiagLevel;
+ }
+
+ // If a fatal error has already been emitted, silence all subsequent
+ // diagnostics.
+ if (Diag.FatalErrorOccurred) {
+ if (DiagLevel >= DiagnosticIDs::Error &&
+ Diag.Client->IncludeInDiagnosticCounts()) {
+ ++Diag.NumErrors;
+ ++Diag.NumErrorsSuppressed;
+ }
+
+ return false;
+ }
+
+ // If the client doesn't care about this message, don't issue it. If this is
+ // a note and the last real diagnostic was ignored, ignore it too.
+ if (DiagLevel == DiagnosticIDs::Ignored ||
+ (DiagLevel == DiagnosticIDs::Note &&
+ Diag.LastDiagLevel == DiagnosticIDs::Ignored))
+ return false;
+
+ // If this diagnostic is in a system header and is not a clang error, suppress
+ // it.
+ if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
+ Info.getLocation().isValid() &&
+ Diag.getSourceManager().isInSystemHeader(
+ Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) &&
+ (DiagLevel != DiagnosticIDs::Note ||
+ Diag.LastDiagLevel == DiagnosticIDs::Ignored)) {
+ Diag.LastDiagLevel = DiagnosticIDs::Ignored;
+ return false;
+ }
+
+ if (DiagLevel >= DiagnosticIDs::Error) {
+ if (Diag.Client->IncludeInDiagnosticCounts()) {
+ Diag.ErrorOccurred = true;
+ ++Diag.NumErrors;
+ }
+
+ // If we've emitted a lot of errors, emit a fatal error after it to stop a
+ // flood of bogus errors.
+ if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit &&
+ DiagLevel == DiagnosticIDs::Error)
+ Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
+ }
+
+ // If we have any Fix-Its, make sure that all of the Fix-Its point into
+ // source locations that aren't macro instantiations. If any point into
+ // macro instantiations, remove all of the Fix-Its.
+ for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
+ const FixItHint &FixIt = Diag.FixItHints[I];
+ if (FixIt.RemoveRange.isInvalid() ||
+ FixIt.RemoveRange.getBegin().isMacroID() ||
+ FixIt.RemoveRange.getEnd().isMacroID()) {
+ Diag.NumFixItHints = 0;
+ break;
+ }
+ }
+
+ // Finally, report it.
+ Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info);
+ if (Diag.Client->IncludeInDiagnosticCounts()) {
+ if (DiagLevel == DiagnosticIDs::Warning)
+ ++Diag.NumWarnings;
+ }
+
+ Diag.CurDiagID = ~0U;
+
+ return true;
+}
diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
index 565f8a6..342413d 100644
--- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
@@ -1,4 +1,4 @@
-///===--- FileManager.cpp - File System Probing and Caching ----------------===//
+//===--- FileManager.cpp - File System Probing and Caching ----------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,35 +18,52 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.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"
+#include "llvm/Support/system_error.h"
#include "llvm/Config/config.h"
#include <map>
#include <set>
#include <string>
+
+// FIXME: This is terrible, we need this for ::close.
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#include <sys/uio.h>
+#else
+#include <io.h>
+#endif
using namespace clang;
// FIXME: Enhance libsystem to support inode and other fields.
#include <sys/stat.h>
-#if defined(_MSC_VER)
-#define S_ISDIR(s) (_S_IFDIR & s)
-#endif
-
/// NON_EXISTENT_DIR - A special value distinct from null that is used to
/// represent a dir name that doesn't exist on the disk.
#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
+/// NON_EXISTENT_FILE - A special value distinct from null that is used to
+/// represent a filename that doesn't exist on the disk.
+#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
+
+
+FileEntry::~FileEntry() {
+ // If this FileEntry owns an open file descriptor that never got used, close
+ // it.
+ if (FD != -1) ::close(FD);
+}
+
//===----------------------------------------------------------------------===//
// Windows.
//===----------------------------------------------------------------------===//
#ifdef LLVM_ON_WIN32
-#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
-
namespace {
static std::string GetFullPath(const char *relPath) {
char *absPathStrPtr = _fullpath(NULL, relPath, 0);
@@ -65,15 +82,16 @@ class FileManager::UniqueDirContainer {
llvm::StringMap<DirectoryEntry> UniqueDirs;
public:
- DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+ /// getDirectory - Return an existing DirectoryEntry with the given
+ /// name if there is already one; otherwise create and return a
+ /// default-constructed DirectoryEntry.
+ DirectoryEntry &getDirectory(const char *Name,
+ const struct stat & /*StatBuf*/) {
std::string FullPath(GetFullPath(Name));
- return UniqueDirs.GetOrCreateValue(
- FullPath.c_str(),
- FullPath.c_str() + FullPath.size()
- ).getValue();
+ return UniqueDirs.GetOrCreateValue(FullPath).getValue();
}
- size_t size() { return UniqueDirs.size(); }
+ size_t size() const { return UniqueDirs.size(); }
};
class FileManager::UniqueFileContainer {
@@ -82,18 +100,18 @@ class FileManager::UniqueFileContainer {
llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
public:
- FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+ /// getFile - Return an existing FileEntry with the given name if
+ /// there is already one; otherwise create and return a
+ /// default-constructed FileEntry.
+ FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) {
std::string FullPath(GetFullPath(Name));
-
+
// LowercaseString because Windows filesystem is case insensitive.
FullPath = llvm::LowercaseString(FullPath);
- return UniqueFiles.GetOrCreateValue(
- FullPath.c_str(),
- FullPath.c_str() + FullPath.size()
- ).getValue();
+ return UniqueFiles.GetOrCreateValue(FullPath).getValue();
}
- size_t size() { return UniqueFiles.size(); }
+ size_t size() const { return UniqueFiles.size(); }
};
//===----------------------------------------------------------------------===//
@@ -102,28 +120,31 @@ public:
#else
-#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/')
-
class FileManager::UniqueDirContainer {
/// UniqueDirs - Cache from ID's to existing directories/files.
- ///
std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
public:
- DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
+ /// getDirectory - Return an existing DirectoryEntry with the given
+ /// ID's if there is already one; otherwise create and return a
+ /// default-constructed DirectoryEntry.
+ DirectoryEntry &getDirectory(const char * /*Name*/,
+ const struct stat &StatBuf) {
return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
}
- size_t size() { return UniqueDirs.size(); }
+ size_t size() const { return UniqueDirs.size(); }
};
class FileManager::UniqueFileContainer {
/// UniqueFiles - Cache from ID's to existing directories/files.
- ///
std::set<FileEntry> UniqueFiles;
public:
- FileEntry &getFile(const char *Name, struct stat &StatBuf) {
+ /// getFile - Return an existing FileEntry with the given ID's if
+ /// there is already one; otherwise create and return a
+ /// default-constructed FileEntry.
+ FileEntry &getFile(const char * /*Name*/, const struct stat &StatBuf) {
return
const_cast<FileEntry&>(
*UniqueFiles.insert(FileEntry(StatBuf.st_dev,
@@ -131,7 +152,7 @@ public:
StatBuf.st_mode)).first);
}
- size_t size() { return UniqueFiles.size(); }
+ size_t size() const { return UniqueFiles.size(); }
};
#endif
@@ -140,26 +161,26 @@ public:
// Common logic.
//===----------------------------------------------------------------------===//
-FileManager::FileManager()
- : UniqueDirs(*new UniqueDirContainer),
- UniqueFiles(*new UniqueFileContainer),
- DirEntries(64), FileEntries(64), NextFileUID(0) {
+FileManager::FileManager(const FileSystemOptions &FSO)
+ : FileSystemOpts(FSO),
+ UniqueRealDirs(*new UniqueDirContainer()),
+ UniqueRealFiles(*new UniqueFileContainer()),
+ SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
NumDirLookups = NumFileLookups = 0;
NumDirCacheMisses = NumFileCacheMisses = 0;
}
FileManager::~FileManager() {
- delete &UniqueDirs;
- delete &UniqueFiles;
- for (llvm::SmallVectorImpl<FileEntry *>::iterator
- V = VirtualFileEntries.begin(),
- VEnd = VirtualFileEntries.end();
- V != VEnd;
- ++V)
- delete *V;
+ delete &UniqueRealDirs;
+ delete &UniqueRealFiles;
+ for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
+ delete VirtualFileEntries[i];
+ for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
+ delete VirtualDirectoryEntries[i];
}
-void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
+void FileManager::addStatCache(FileSystemStatCache *statCache,
+ bool AtBeginning) {
assert(statCache && "No stat cache provided?");
if (AtBeginning || StatCache.get() == 0) {
statCache->setNextStatCache(StatCache.take());
@@ -167,14 +188,14 @@ void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
return;
}
- StatSysCallCache *LastCache = StatCache.get();
+ FileSystemStatCache *LastCache = StatCache.get();
while (LastCache->getNextStatCache())
LastCache = LastCache->getNextStatCache();
LastCache->setNextStatCache(statCache);
}
-void FileManager::removeStatCache(StatSysCallCache *statCache) {
+void FileManager::removeStatCache(FileSystemStatCache *statCache) {
if (!statCache)
return;
@@ -185,54 +206,74 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) {
}
// Find the stat cache in the list.
- StatSysCallCache *PrevCache = StatCache.get();
+ FileSystemStatCache *PrevCache = StatCache.get();
while (PrevCache && PrevCache->getNextStatCache() != statCache)
PrevCache = PrevCache->getNextStatCache();
- if (PrevCache)
- PrevCache->setNextStatCache(statCache->getNextStatCache());
- else
- assert(false && "Stat cache not found for removal");
+
+ assert(PrevCache && "Stat cache not found for removal");
+ PrevCache->setNextStatCache(statCache->getNextStatCache());
}
/// \brief Retrieve the directory that the given file name resides in.
+/// Filename can point to either a real file or a virtual file.
static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
- const char *NameStart,
- const char *NameEnd) {
- // Figure out what directory it is in. If the string contains a / in it,
- // strip off everything after it.
- // FIXME: this logic should be in sys::Path.
- const char *SlashPos = NameEnd-1;
- while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
- --SlashPos;
- // Ignore duplicate //'s.
- while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
- --SlashPos;
-
- if (SlashPos < NameStart) {
- // Use the current directory if file has no path component.
- const char *Name = ".";
- return FileMgr.getDirectory(Name, Name+1);
- } else if (SlashPos == NameEnd-1)
- return 0; // If filename ends with a /, it's a directory.
- else
- return FileMgr.getDirectory(NameStart, SlashPos);
+ llvm::StringRef Filename) {
+ if (Filename.empty())
+ return NULL;
+
+ if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
+ return NULL; // If Filename is a directory.
+
+ llvm::StringRef DirName = llvm::sys::path::parent_path(Filename);
+ // Use the current directory if file has no path component.
+ if (DirName.empty())
+ DirName = ".";
+
+ return FileMgr.getDirectory(DirName);
}
-/// getDirectory - Lookup, cache, and verify the specified directory. This
-/// returns null if the directory doesn't exist.
+/// Add all ancestors of the given path (pointing to either a file or
+/// a directory) as virtual directories.
+void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
+ llvm::StringRef DirName = llvm::sys::path::parent_path(Path);
+ if (DirName.empty())
+ return;
+
+ llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
+ SeenDirEntries.GetOrCreateValue(DirName);
+
+ // When caching a virtual directory, we always cache its ancestors
+ // at the same time. Therefore, if DirName is already in the cache,
+ // we don't need to recurse as its ancestors must also already be in
+ // the cache.
+ if (NamedDirEnt.getValue())
+ return;
+
+ // Add the virtual directory to the cache.
+ DirectoryEntry *UDE = new DirectoryEntry;
+ UDE->Name = NamedDirEnt.getKeyData();
+ NamedDirEnt.setValue(UDE);
+ VirtualDirectoryEntries.push_back(UDE);
+
+ // Recursively add the other ancestors.
+ addAncestorsAsVirtualDirs(DirName);
+}
+
+/// getDirectory - Lookup, cache, and verify the specified directory
+/// (real or virtual). This returns NULL if the directory doesn't
+/// exist.
///
-const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
- const char *NameEnd) {
+const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
// stat doesn't like trailing separators (at least on Windows).
- if (((NameEnd - NameStart) > 1) &&
- ((*(NameEnd - 1) == '/') || (*(NameEnd - 1) == '\\')))
- NameEnd--;
+ if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back()))
+ DirName = DirName.substr(0, DirName.size()-1);
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
- DirEntries.GetOrCreateValue(NameStart, NameEnd);
+ SeenDirEntries.GetOrCreateValue(DirName);
- // See if there is already an entry in the map.
+ // See if there was already an entry in the map. Note that the map
+ // contains both virtual and real directories.
if (NamedDirEnt.getValue())
return NamedDirEnt.getValue() == NON_EXISTENT_DIR
? 0 : NamedDirEnt.getValue();
@@ -243,43 +284,41 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
NamedDirEnt.setValue(NON_EXISTENT_DIR);
// Get the null-terminated directory name as stored as the key of the
- // DirEntries map.
+ // SeenDirEntries map.
const char *InterndDirName = NamedDirEnt.getKeyData();
// Check to see if the directory exists.
struct stat StatBuf;
- if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing.
- !S_ISDIR(StatBuf.st_mode)) // Not a directory?
+ if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
+ // There's no real directory at the given path.
return 0;
+ }
- // It exists. See if we have already opened a directory with the same inode.
- // This occurs when one dir is symlinked to another, for example.
- DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
+ // It exists. See if we have already opened a directory with the
+ // same inode (this occurs on Unix-like systems when one dir is
+ // symlinked to another, for example) or the same path (on
+ // Windows).
+ DirectoryEntry &UDE = UniqueRealDirs.getDirectory(InterndDirName, StatBuf);
NamedDirEnt.setValue(&UDE);
- if (UDE.getName()) // Already have an entry with this inode, return it.
- return &UDE;
+ if (!UDE.getName()) {
+ // We don't have this directory yet, add it. We use the string
+ // key from the SeenDirEntries map as the string.
+ UDE.Name = InterndDirName;
+ }
- // Otherwise, we don't have this directory yet, add it. We use the string
- // key from the DirEntries map as the string.
- UDE.Name = InterndDirName;
return &UDE;
}
-/// NON_EXISTENT_FILE - A special value distinct from null that is used to
-/// represent a filename that doesn't exist on the disk.
-#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
-
-/// getFile - Lookup, cache, and verify the specified file. This returns null
-/// if the file doesn't exist.
+/// getFile - Lookup, cache, and verify the specified file (real or
+/// virtual). This returns NULL if the file doesn't exist.
///
-const FileEntry *FileManager::getFile(const char *NameStart,
- const char *NameEnd) {
+const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
++NumFileLookups;
// See if there is already an entry in the map.
llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
- FileEntries.GetOrCreateValue(NameStart, NameEnd);
+ SeenFileEntries.GetOrCreateValue(Filename);
// See if there is already an entry in the map.
if (NamedFileEnt.getValue())
@@ -291,13 +330,16 @@ const FileEntry *FileManager::getFile(const char *NameStart,
// By default, initialize it to invalid.
NamedFileEnt.setValue(NON_EXISTENT_FILE);
-
// Get the null-terminated file name as stored as the key of the
- // FileEntries map.
+ // SeenFileEntries map.
const char *InterndFileName = NamedFileEnt.getKeyData();
- const DirectoryEntry *DirInfo
- = getDirectoryFromFile(*this, NameStart, NameEnd);
+ // Look up the directory for the file. When looking up something like
+ // sys/foo.h we'll discover all of the search directories that have a 'sys'
+ // subdirectory. This will let us avoid having to waste time on known-to-fail
+ // searches when we go to find sys/bar.h, because all the search directories
+ // without a 'sys' subdir will get a cached failure result.
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
return 0;
@@ -305,89 +347,218 @@ const FileEntry *FileManager::getFile(const char *NameStart,
// FIXME: This will reduce the # syscalls.
// Nope, there isn't. Check to see if the file exists.
+ int FileDescriptor = -1;
struct stat StatBuf;
- //llvm::errs() << "STATING: " << Filename;
- if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing.
- S_ISDIR(StatBuf.st_mode)) { // A directory?
- // If this file doesn't exist, we leave a null in FileEntries for this path.
- //llvm::errs() << ": Not existing\n";
+ if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
+ // There's no real file at the given path.
return 0;
}
- //llvm::errs() << ": exists\n";
// It exists. See if we have already opened a file with the same inode.
// This occurs when one dir is symlinked to another, for example.
- FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
+ FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
NamedFileEnt.setValue(&UFE);
- if (UFE.getName()) // Already have an entry with this inode, return it.
+ if (UFE.getName()) { // Already have an entry with this inode, return it.
+ // If the stat process opened the file, close it to avoid a FD leak.
+ if (FileDescriptor != -1)
+ close(FileDescriptor);
+
return &UFE;
+ }
// Otherwise, we don't have this directory yet, add it.
- // FIXME: Change the name to be a char* that points back to the 'FileEntries'
- // key.
+ // FIXME: Change the name to be a char* that points back to the
+ // 'SeenFileEntries' key.
UFE.Name = InterndFileName;
UFE.Size = StatBuf.st_size;
UFE.ModTime = StatBuf.st_mtime;
UFE.Dir = DirInfo;
UFE.UID = NextFileUID++;
+ UFE.FD = FileDescriptor;
return &UFE;
}
const FileEntry *
FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
time_t ModificationTime) {
- const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
-
++NumFileLookups;
// See if there is already an entry in the map.
llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
- FileEntries.GetOrCreateValue(NameStart, NameEnd);
+ SeenFileEntries.GetOrCreateValue(Filename);
// See if there is already an entry in the map.
- if (NamedFileEnt.getValue())
- return NamedFileEnt.getValue() == NON_EXISTENT_FILE
- ? 0 : NamedFileEnt.getValue();
+ if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
+ return NamedFileEnt.getValue();
++NumFileCacheMisses;
// By default, initialize it to invalid.
NamedFileEnt.setValue(NON_EXISTENT_FILE);
- const DirectoryEntry *DirInfo
- = getDirectoryFromFile(*this, NameStart, NameEnd);
- if (DirInfo == 0) // Directory doesn't exist, file can't exist.
- return 0;
+ addAncestorsAsVirtualDirs(Filename);
+ FileEntry *UFE = 0;
- FileEntry *UFE = new FileEntry();
- VirtualFileEntries.push_back(UFE);
- NamedFileEnt.setValue(UFE);
+ // Now that all ancestors of Filename are in the cache, the
+ // following call is guaranteed to find the DirectoryEntry from the
+ // cache.
+ const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
+ assert(DirInfo &&
+ "The directory of a virtual file should already be in the cache.");
- UFE->Name = NamedFileEnt.getKeyData();
+ // Check to see if the file exists. If so, drop the virtual file
+ int FileDescriptor = -1;
+ struct stat StatBuf;
+ const char *InterndFileName = NamedFileEnt.getKeyData();
+ if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
+ // If the stat process opened the file, close it to avoid a FD leak.
+ if (FileDescriptor != -1)
+ close(FileDescriptor);
+
+ StatBuf.st_size = Size;
+ StatBuf.st_mtime = ModificationTime;
+ UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
+
+ NamedFileEnt.setValue(UFE);
+
+ // If we had already opened this file, close it now so we don't
+ // leak the descriptor. We're not going to use the file
+ // descriptor anyway, since this is a virtual file.
+ if (UFE->FD != -1) {
+ close(UFE->FD);
+ UFE->FD = -1;
+ }
+
+ // If we already have an entry with this inode, return it.
+ if (UFE->getName())
+ return UFE;
+ }
+
+ if (!UFE) {
+ UFE = new FileEntry();
+ VirtualFileEntries.push_back(UFE);
+ NamedFileEnt.setValue(UFE);
+ }
+
+ UFE->Name = InterndFileName;
UFE->Size = Size;
UFE->ModTime = ModificationTime;
UFE->Dir = DirInfo;
UFE->UID = NextFileUID++;
+ UFE->FD = -1;
+ return UFE;
+}
+
+void FileManager::FixupRelativePath(llvm::sys::Path &path,
+ const FileSystemOptions &FSOpts) {
+ if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str()))
+ return;
+
+ llvm::SmallString<128> NewPath(FSOpts.WorkingDir);
+ llvm::sys::path::append(NewPath, path.str());
+ path = NewPath;
+}
+
+llvm::MemoryBuffer *FileManager::
+getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
+ llvm::OwningPtr<llvm::MemoryBuffer> Result;
+ llvm::error_code ec;
+ if (FileSystemOpts.WorkingDir.empty()) {
+ const char *Filename = Entry->getName();
+ // If the file is already open, use the open file descriptor.
+ if (Entry->FD != -1) {
+ ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
+ Entry->getSize());
+ if (ErrorStr)
+ *ErrorStr = ec.message();
+
+ close(Entry->FD);
+ Entry->FD = -1;
+ return Result.take();
+ }
+
+ // Otherwise, open the file.
+ ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize());
+ if (ec && ErrorStr)
+ *ErrorStr = ec.message();
+ return Result.take();
+ }
- // If this virtual file resolves to a file, also map that file to the
- // newly-created file entry.
- const char *InterndFileName = NamedFileEnt.getKeyData();
- struct stat StatBuf;
- if (!stat_cached(InterndFileName, &StatBuf) &&
- !S_ISDIR(StatBuf.st_mode)) {
- llvm::sys::Path FilePath(InterndFileName);
- FilePath.makeAbsolute();
- FileEntries[FilePath.str()] = UFE;
+ llvm::sys::Path FilePath(Entry->getName());
+ FixupRelativePath(FilePath, FileSystemOpts);
+ ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize());
+ if (ec && ErrorStr)
+ *ErrorStr = ec.message();
+ return Result.take();
+}
+
+llvm::MemoryBuffer *FileManager::
+getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
+ llvm::OwningPtr<llvm::MemoryBuffer> Result;
+ llvm::error_code ec;
+ if (FileSystemOpts.WorkingDir.empty()) {
+ ec = llvm::MemoryBuffer::getFile(Filename, Result);
+ if (ec && ErrorStr)
+ *ErrorStr = ec.message();
+ return Result.take();
}
+
+ llvm::sys::Path FilePath(Filename);
+ FixupRelativePath(FilePath, FileSystemOpts);
+ ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
+ if (ec && ErrorStr)
+ *ErrorStr = ec.message();
+ return Result.take();
+}
+
+/// getStatValue - Get the 'stat' information for the specified path,
+/// using the cache to accelerate it if possible. This returns true
+/// if the path points to a virtual file or does not exist, or returns
+/// false if it's an existent real file. If FileDescriptor is NULL,
+/// do directory look-up instead of file look-up.
+bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
+ int *FileDescriptor) {
+ // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
+ // absolute!
+ if (FileSystemOpts.WorkingDir.empty())
+ return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
+ StatCache.get());
+
+ llvm::sys::Path FilePath(Path);
+ FixupRelativePath(FilePath, FileSystemOpts);
+
+ return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
+ StatCache.get());
+}
+
+void FileManager::GetUniqueIDMapping(
+ llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
+ UIDToFiles.clear();
+ UIDToFiles.resize(NextFileUID);
- return UFE;
+ // Map file entries
+ for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
+ FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
+ FE != FEEnd; ++FE)
+ if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE)
+ UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
+
+ // Map virtual file entries
+ for (llvm::SmallVector<FileEntry*, 4>::const_iterator
+ VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
+ VFE != VFEEnd; ++VFE)
+ if (*VFE && *VFE != NON_EXISTENT_FILE)
+ UIDToFiles[(*VFE)->getUID()] = *VFE;
}
+
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
- llvm::errs() << UniqueFiles.size() << " files found, "
- << UniqueDirs.size() << " dirs found.\n";
+ llvm::errs() << UniqueRealFiles.size() << " real files found, "
+ << UniqueRealDirs.size() << " real dirs found.\n";
+ llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
+ << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
llvm::errs() << NumDirLookups << " dir lookups, "
<< NumDirCacheMisses << " dir cache misses.\n";
llvm::errs() << NumFileLookups << " file lookups, "
@@ -395,20 +566,3 @@ void FileManager::PrintStats() const {
//llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
}
-
-int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
- int result = StatSysCallCache::stat(path, buf);
-
- // Do not cache failed stats, it is easy to construct common inconsistent
- // situations if we do, and they are not important for PCH performance (which
- // currently only needs the stats to construct the initial FileManager
- // entries).
- if (result != 0)
- return result;
-
- // Cache file 'stat' results and directories with absolutely paths.
- if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute())
- StatCalls[path] = StatResult(result, *buf);
-
- return result;
-}
diff --git a/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp b/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp
new file mode 100644
index 0000000..c8b07af
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp
@@ -0,0 +1,120 @@
+//===--- FileSystemStatCache.cpp - Caching for 'stat' calls ---------------===//
+//
+// 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 FileSystemStatCache interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FileSystemStatCache.h"
+#include "llvm/Support/Path.h"
+#include <fcntl.h>
+
+// FIXME: This is terrible, we need this for ::close.
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#include <sys/uio.h>
+#else
+#include <io.h>
+#endif
+using namespace clang;
+
+#if defined(_MSC_VER)
+#define S_ISDIR(s) ((_S_IFDIR & s) !=0)
+#endif
+
+/// FileSystemStatCache::get - Get the 'stat' information for the specified
+/// path, using the cache to accelerate it if possible. This returns true if
+/// the path does not exist or false if it exists.
+///
+/// If FileDescriptor is non-null, then this lookup should only return success
+/// for files (not directories). If it is null this lookup should only return
+/// success for directories (not files). On a successful file lookup, the
+/// implementation can optionally fill in FileDescriptor with a valid
+/// descriptor and the client guarantees that it will close it.
+bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
+ int *FileDescriptor, FileSystemStatCache *Cache) {
+ LookupResult R;
+ bool isForDir = FileDescriptor == 0;
+
+ // If we have a cache, use it to resolve the stat query.
+ if (Cache)
+ R = Cache->getStat(Path, StatBuf, FileDescriptor);
+ else if (isForDir) {
+ // If this is a directory and we have no cache, just go to the file system.
+ R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
+ } else {
+ // Otherwise, we have to go to the filesystem. We can always just use
+ // 'stat' here, but (for files) the client is asking whether the file exists
+ // because it wants to turn around and *open* it. It is more efficient to
+ // do "open+fstat" on success than it is to do "stat+open".
+ //
+ // Because of this, check to see if the file exists with 'open'. If the
+ // open succeeds, use fstat to get the stat info.
+ int OpenFlags = O_RDONLY;
+#ifdef O_BINARY
+ OpenFlags |= O_BINARY; // Open input file in binary mode on win32.
+#endif
+ *FileDescriptor = ::open(Path, OpenFlags);
+
+ if (*FileDescriptor == -1) {
+ // If the open fails, our "stat" fails.
+ R = CacheMissing;
+ } else {
+ // Otherwise, the open succeeded. Do an fstat to get the information
+ // about the file. We'll end up returning the open file descriptor to the
+ // client to do what they please with it.
+ if (::fstat(*FileDescriptor, &StatBuf) == 0)
+ R = CacheExists;
+ else {
+ // fstat rarely fails. If it does, claim the initial open didn't
+ // succeed.
+ R = CacheMissing;
+ ::close(*FileDescriptor);
+ *FileDescriptor = -1;
+ }
+ }
+ }
+
+ // If the path doesn't exist, return failure.
+ if (R == CacheMissing) return true;
+
+ // If the path exists, make sure that its "directoryness" matches the clients
+ // demands.
+ if (S_ISDIR(StatBuf.st_mode) != isForDir) {
+ // If not, close the file if opened.
+ if (FileDescriptor && *FileDescriptor != -1) {
+ ::close(*FileDescriptor);
+ *FileDescriptor = -1;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+
+MemorizeStatCalls::LookupResult
+MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
+ int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
+
+ // Do not cache failed stats, it is easy to construct common inconsistent
+ // situations if we do, and they are not important for PCH performance (which
+ // currently only needs the stats to construct the initial FileManager
+ // entries).
+ if (Result == CacheMissing)
+ return Result;
+
+ // Cache file 'stat' results and directories with absolutely paths.
+ if (!S_ISDIR(StatBuf.st_mode) || llvm::sys::path::is_absolute(Path))
+ StatCalls[Path] = StatBuf;
+
+ return Result;
+}
diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
index 6b673e3..ef11d65 100644
--- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
@@ -44,8 +44,24 @@ IdentifierInfo::IdentifierInfo() {
// IdentifierTable Implementation
//===----------------------------------------------------------------------===//
+IdentifierIterator::~IdentifierIterator() { }
+
IdentifierInfoLookup::~IdentifierInfoLookup() {}
+namespace {
+ /// \brief A simple identifier lookup iterator that represents an
+ /// empty sequence of identifiers.
+ class EmptyLookupIterator : public IdentifierIterator
+ {
+ public:
+ virtual llvm::StringRef Next() { return llvm::StringRef(); }
+ };
+}
+
+IdentifierIterator *IdentifierInfoLookup::getIdentifiers() const {
+ return new EmptyLookupIterator();
+}
+
ExternalIdentifierLookup::~ExternalIdentifierLookup() {}
IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
@@ -73,8 +89,9 @@ namespace {
KEYMS = 32,
BOOLSUPPORT = 64,
KEYALTIVEC = 128,
- KEYNOMS = 256,
- KEYBORLAND = 512
+ KEYNOCXX = 256,
+ KEYBORLAND = 512,
+ KEYOPENCL = 1024
};
}
@@ -99,7 +116,8 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
- else if (!LangOpts.Microsoft && (Flags & KEYNOMS)) AddResult = 2;
+ else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
+ else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
@@ -308,6 +326,11 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
return SI->getIdentifierInfoForSlot(argIndex);
}
+llvm::StringRef Selector::getNameForSlot(unsigned int argIndex) const {
+ IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
+ return II? II->getName() : llvm::StringRef();
+}
+
std::string MultiKeywordSelector::getName() const {
llvm::SmallString<256> Str;
llvm::raw_svector_ostream OS(Str);
@@ -374,7 +397,7 @@ Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *);
MultiKeywordSelector *SI =
(MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size,
- llvm::alignof<MultiKeywordSelector>());
+ llvm::alignOf<MultiKeywordSelector>());
new (SI) MultiKeywordSelector(nKeys, IIV);
SelTabImpl.Table.InsertNode(SI, InsertPos);
return Selector(SI);
diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
index 7412b95..5062d43 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
@@ -43,6 +43,11 @@ void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{
if (isFileID()) {
PresumedLoc PLoc = SM.getPresumedLoc(*this);
+
+ if (PLoc.isInvalid()) {
+ OS << "<invalid>";
+ return;
+ }
// The instantiation and spelling pos is identical for file locs.
OS << PLoc.getFilename() << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
@@ -105,6 +110,11 @@ bool FullSourceLoc::isInSystemHeader() const {
return SrcMgr->isInSystemHeader(*this);
}
+bool FullSourceLoc::isBeforeInTranslationUnitThan(SourceLocation Loc) const {
+ assert(isValid());
+ return SrcMgr->isBeforeInTranslationUnit(*this, Loc);
+}
+
const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
assert(isValid());
return SrcMgr->getCharacterData(*this, Invalid);
diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
index 633d86c..044c88d 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
@@ -15,13 +15,16 @@
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
+#include "llvm/Support/Path.h"
#include <algorithm>
#include <string>
#include <cstring>
+#include <sys/stat.h>
using namespace clang;
using namespace SrcMgr;
@@ -66,100 +69,86 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
const SourceManager &SM,
SourceLocation Loc,
bool *Invalid) const {
- if (Invalid)
- *Invalid = false;
-
- // Lazily create the Buffer for ContentCaches that wrap files.
- if (!Buffer.getPointer() && Entry) {
- std::string ErrorStr;
- struct stat FileInfo;
- Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
- Entry->getSize(), &FileInfo));
+ // Lazily create the Buffer for ContentCaches that wrap files. If we already
+ // computed it, jsut return what we have.
+ if (Buffer.getPointer() || Entry == 0) {
+ if (Invalid)
+ *Invalid = isBufferInvalid();
- // If we were unable to open the file, then we are in an inconsistent
- // situation where the content cache referenced a file which no longer
- // exists. Most likely, we were using a stat cache with an invalid entry but
- // the file could also have been removed during processing. Since we can't
- // really deal with this situation, just create an empty buffer.
- //
- // FIXME: This is definitely not ideal, but our immediate clients can't
- // currently handle returning a null entry here. Ideally we should detect
- // that we are in an inconsistent situation and error out as quickly as
- // possible.
- if (!Buffer.getPointer()) {
- const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
- "<invalid>"));
- char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
- for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
- Ptr[i] = FillStr[i % FillStr.size()];
-
- if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
- Entry->getName(), ErrorStr);
- else
- Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file)
- << Entry->getName() << ErrorStr;
-
- Buffer.setInt(Buffer.getInt() | InvalidFlag);
-
- // FIXME: This conditionalization is horrible, but we see spurious failures
- // in the test suite due to this warning and no one has had time to hunt it
- // down. So for now, we just don't emit this diagnostic on Win32, and hope
- // nothing bad happens.
- //
- // PR6812.
-#if !defined(LLVM_ON_WIN32)
- } else if (FileInfo.st_size != Entry->getSize() ||
- FileInfo.st_mtime != Entry->getModificationTime()) {
- // Check that the file's size and modification time are the same
- // as in the file entry (which may have come from a stat cache).
- if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_file_modified,
- Entry->getName());
- else
- Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified)
- << Entry->getName();
-
- Buffer.setInt(Buffer.getInt() | InvalidFlag);
-#endif
- }
+ return Buffer.getPointer();
+ }
+
+ std::string ErrorStr;
+ Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr));
+
+ // If we were unable to open the file, then we are in an inconsistent
+ // situation where the content cache referenced a file which no longer
+ // exists. Most likely, we were using a stat cache with an invalid entry but
+ // the file could also have been removed during processing. Since we can't
+ // really deal with this situation, just create an empty buffer.
+ //
+ // FIXME: This is definitely not ideal, but our immediate clients can't
+ // currently handle returning a null entry here. Ideally we should detect
+ // that we are in an inconsistent situation and error out as quickly as
+ // possible.
+ if (!Buffer.getPointer()) {
+ const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
+ Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
+ "<invalid>"));
+ char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
+ for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
+ Ptr[i] = FillStr[i % FillStr.size()];
+
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
+ Entry->getName(), ErrorStr);
+ else
+ Diag.Report(Loc, diag::err_cannot_open_file)
+ << Entry->getName() << ErrorStr;
+
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
- // If the buffer is valid, check to see if it has a UTF Byte Order Mark
- // (BOM). We only support UTF-8 without a BOM right now. See
- // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
- if (!isBufferInvalid()) {
- llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
- const char *BOM = 0;
- if (BufStr.startswith("\xFE\xBB\xBF"))
- BOM = "UTF-8";
- else if (BufStr.startswith("\xFE\xFF"))
- BOM = "UTF-16 (BE)";
- else if (BufStr.startswith("\xFF\xFE"))
- BOM = "UTF-16 (LE)";
- else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4)))
- BOM = "UTF-32 (BE)";
- else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4)))
- BOM = "UTF-32 (LE)";
- else if (BufStr.startswith("\x2B\x2F\x76"))
- BOM = "UTF-7";
- else if (BufStr.startswith("\xF7\x64\x4C"))
- BOM = "UTF-1";
- else if (BufStr.startswith("\xDD\x73\x66\x73"))
- BOM = "UTF-EBCDIC";
- else if (BufStr.startswith("\x0E\xFE\xFF"))
- BOM = "SDSU";
- else if (BufStr.startswith("\xFB\xEE\x28"))
- BOM = "BOCU-1";
- else if (BufStr.startswith("\x84\x31\x95\x33"))
- BOM = "BOCU-1";
-
- if (BOM) {
- Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom)
- << BOM << Entry->getName();
- Buffer.setInt(1);
- }
- }
+ if (Invalid) *Invalid = true;
+ return Buffer.getPointer();
+ }
+
+ // Check that the file's size is the same as in the file entry (which may
+ // have come from a stat cache).
+ if (getRawBuffer()->getBufferSize() != (size_t)Entry->getSize()) {
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_file_modified,
+ Entry->getName());
+ else
+ Diag.Report(Loc, diag::err_file_modified)
+ << Entry->getName();
+
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
+ if (Invalid) *Invalid = true;
+ return Buffer.getPointer();
+ }
+
+ // If the buffer is valid, check to see if it has a UTF Byte Order Mark
+ // (BOM). We only support UTF-8 without a BOM right now. See
+ // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
+ llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
+ const char *BOM = llvm::StringSwitch<const char *>(BufStr)
+ .StartsWith("\xEF\xBB\xBF", "UTF-8")
+ .StartsWith("\xFE\xFF", "UTF-16 (BE)")
+ .StartsWith("\xFF\xFE", "UTF-16 (LE)")
+ .StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)")
+ .StartsWith("\xFF\xFE\x00\x00", "UTF-32 (LE)")
+ .StartsWith("\x2B\x2F\x76", "UTF-7")
+ .StartsWith("\xF7\x64\x4C", "UTF-1")
+ .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
+ .StartsWith("\x0E\xFE\xFF", "SDSU")
+ .StartsWith("\xFB\xEE\x28", "BOCU-1")
+ .StartsWith("\x84\x31\x95\x33", "GB-18030")
+ .Default(0);
+
+ if (BOM) {
+ Diag.Report(Loc, diag::err_unsupported_bom)
+ << BOM << Entry->getName();
+ Buffer.setInt(Buffer.getInt() | InvalidFlag);
}
if (Invalid)
@@ -350,6 +339,14 @@ LineTableInfo &SourceManager::getLineTable() {
// Private 'Create' methods.
//===----------------------------------------------------------------------===//
+SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
+ : Diag(Diag), FileMgr(FileMgr),
+ ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
+ NumBinaryProbes(0) {
+ clearIDTables();
+ Diag.setSourceManager(this);
+}
+
SourceManager::~SourceManager() {
delete LineTable;
@@ -525,25 +522,32 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File,
return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
}
-bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
+void SourceManager::overrideFileContents(const FileEntry *SourceFile,
const llvm::MemoryBuffer *Buffer,
bool DoNotFree) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
- if (IR == 0)
- return true;
+ assert(IR && "getOrCreateContentCache() cannot return NULL");
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
- return false;
}
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
- const llvm::MemoryBuffer *Buf = getBuffer(FID, &MyInvalid);
+ const SLocEntry &SLoc = getSLocEntry(FID.ID);
+ if (!SLoc.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+ return "<<<<<INVALID SOURCE LOCATION>>>>>";
+ }
+
+ const llvm::MemoryBuffer *Buf
+ = SLoc.getFile().getContentCache()->getBuffer(Diag, *this, SourceLocation(),
+ &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
- return "";
+ return "<<<<<INVALID SOURCE LOCATION>>>>>";
return Buf->getBuffer();
}
@@ -796,21 +800,30 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
return FilePos-LineStart+1;
}
+// isInvalid - Return the result of calling loc.isInvalid(), and
+// if Invalid is not null, set its value to same.
+static bool isInvalid(SourceLocation Loc, bool *Invalid) {
+ bool MyInvalid = Loc.isInvalid();
+ if (Invalid)
+ *Invalid = MyInvalid;
+ return MyInvalid;
+}
+
unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
bool *Invalid) const {
- if (Loc.isInvalid()) return 0;
+ if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
bool *Invalid) const {
- if (Loc.isInvalid()) return 0;
+ if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-static DISABLE_INLINE void
+static LLVM_ATTRIBUTE_NOINLINE void
ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid);
@@ -974,13 +987,13 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc,
bool *Invalid) const {
- if (Loc.isInvalid()) return 0;
+ if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
bool *Invalid) const {
- if (Loc.isInvalid()) return 0;
+ if (isInvalid(Loc, Invalid)) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
@@ -1021,7 +1034,7 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const {
/// for normal clients.
const char *SourceManager::getBufferName(SourceLocation Loc,
bool *Invalid) const {
- if (Loc.isInvalid()) return "<invalid loc>";
+ if (isInvalid(Loc, Invalid)) return "<invalid loc>";
return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier();
}
@@ -1051,8 +1064,14 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
Filename = C->Entry->getName();
else
Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
- unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second);
- unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second);
+ bool Invalid = false;
+ unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
+ if (Invalid)
+ return PresumedLoc();
+ unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid);
+ if (Invalid)
+ return PresumedLoc();
+
SourceLocation IncludeLoc = FI.getIncludeLoc();
// If we have #line directives in this file, update and overwrite the physical
@@ -1090,38 +1109,65 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
+/// \brief Retrieve the inode for the given file entry, if possible.
+///
+/// This routine involves a system call, and therefore should only be used
+/// in non-performance-critical code.
+static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) {
+ if (!File)
+ return llvm::Optional<ino_t>();
+
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf))
+ return llvm::Optional<ino_t>();
+
+ return StatBuf.st_ino;
+}
+
/// \brief Get the source location for the given file:line:col triplet.
///
/// If the source file is included multiple times, the source location will
/// be based upon the first inclusion.
SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
- unsigned Line, unsigned Col) const {
+ unsigned Line, unsigned Col) {
assert(SourceFile && "Null source file!");
assert(Line && Col && "Line and column should start from 1!");
- fileinfo_iterator FI = FileInfos.find(SourceFile);
- if (FI == FileInfos.end())
- return SourceLocation();
- ContentCache *Content = FI->second;
-
- // If this is the first use of line information for this buffer, compute the
- /// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0) {
- bool MyInvalid = false;
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
- if (MyInvalid)
- return SourceLocation();
- }
-
// Find the first file ID that corresponds to the given file.
FileID FirstFID;
// First, check the main file ID, since it is common to look for a
// location in the main file.
+ llvm::Optional<ino_t> SourceFileInode;
+ llvm::Optional<llvm::StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
- if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content)
- FirstFID = MainFileID;
+ if (MainSLoc.isFile()) {
+ const ContentCache *MainContentCache
+ = MainSLoc.getFile().getContentCache();
+ if (!MainContentCache) {
+ // Can't do anything
+ } else if (MainContentCache->Entry == SourceFile) {
+ FirstFID = MainFileID;
+ } else {
+ // Fall back: check whether we have the same base name and inode
+ // as the main file.
+ const FileEntry *MainFile = MainContentCache->Entry;
+ SourceFileName = llvm::sys::path::filename(SourceFile->getName());
+ if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
+ SourceFileInode = getActualFileInode(SourceFile);
+ if (SourceFileInode) {
+ if (llvm::Optional<ino_t> MainFileInode
+ = getActualFileInode(MainFile)) {
+ if (*SourceFileInode == *MainFileInode) {
+ FirstFID = MainFileID;
+ SourceFile = MainFile;
+ }
+ }
+ }
+ }
+ }
+ }
}
if (FirstFID.isInvalid()) {
@@ -1129,16 +1175,63 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
// through all of the source locations.
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
const SLocEntry &SLoc = getSLocEntry(I);
- if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) {
+ if (SLoc.isFile() &&
+ SLoc.getFile().getContentCache() &&
+ SLoc.getFile().getContentCache()->Entry == SourceFile) {
FirstFID = FileID::get(I);
break;
}
}
}
+
+ // If we haven't found what we want yet, try again, but this time stat()
+ // each of the files in case the files have changed since we originally
+ // parsed the file.
+ if (FirstFID.isInvalid() &&
+ (SourceFileName ||
+ (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
+ (SourceFileInode ||
+ (SourceFileInode = getActualFileInode(SourceFile)))) {
+ for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
+ const SLocEntry &SLoc = getSLocEntry(I);
+ if (SLoc.isFile()) {
+ const ContentCache *FileContentCache
+ = SLoc.getFile().getContentCache();
+ const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0;
+ if (Entry &&
+ *SourceFileName == llvm::sys::path::filename(Entry->getName())) {
+ if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
+ if (*SourceFileInode == *EntryInode) {
+ FirstFID = FileID::get(I);
+ SourceFile = Entry;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
if (FirstFID.isInvalid())
return SourceLocation();
+ if (Line == 1 && Col == 1)
+ return getLocForStartOfFile(FirstFID);
+
+ ContentCache *Content
+ = const_cast<ContentCache *>(getOrCreateContentCache(SourceFile));
+ if (!Content)
+ return SourceLocation();
+
+ // If this is the first use of line information for this buffer, compute the
+ /// SourceLineCache for it on demand.
+ if (Content->SourceLineCache == 0) {
+ bool MyInvalid = false;
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
+ if (MyInvalid)
+ return SourceLocation();
+ }
+
if (Line > Content->NumLines) {
unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
if (Size > 0)
@@ -1190,6 +1283,13 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
if (LHS == RHS)
return false;
+ // If both locations are macro instantiations, the order of their offsets
+ // reflect the order that the tokens, pointed to by these locations, were
+ // instantiated (during parsing each token that is instantiated by a macro,
+ // expands the SLocEntries).
+ if (LHS.isMacroID() && RHS.isMacroID())
+ return LHS.getOffset() < RHS.getOffset();
+
std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS);
std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS);
diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
index 6d42883..a9eeb8b 100644
--- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
+#include <cctype>
#include <cstdlib>
using namespace clang;
@@ -25,6 +26,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
TLSSupported = true;
NoAsmVariants = false;
PointerWidth = PointerAlign = 32;
+ BoolWidth = BoolAlign = 8;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
@@ -54,6 +56,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
+ MCountName = "mcount";
HasAlignMac68kSupport = false;
// Default to no types using fpret.
@@ -98,7 +101,7 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
}
}
-/// getTypeWidth - Return the width (in bits) of the specified integer type
+/// getTypeWidth - Return the width (in bits) of the specified integer type
/// enum. For example, SignedInt -> getIntWidth().
unsigned TargetInfo::getTypeWidth(IntType T) const {
switch (T) {
@@ -114,7 +117,7 @@ unsigned TargetInfo::getTypeWidth(IntType T) const {
};
}
-/// getTypeAlign - Return the alignment (in bits) of the specified integer type
+/// getTypeAlign - Return the alignment (in bits) of the specified integer type
/// enum. For example, SignedInt -> getIntAlign().
unsigned TargetInfo::getTypeAlign(IntType T) const {
switch (T) {
@@ -132,18 +135,18 @@ unsigned TargetInfo::getTypeAlign(IntType T) const {
/// isTypeSigned - Return whether an integer types is signed. Returns true if
/// the type is signed; false otherwise.
-bool TargetInfo::isTypeSigned(IntType T) const {
+bool TargetInfo::isTypeSigned(IntType T) {
switch (T) {
default: assert(0 && "not an integer!");
case SignedShort:
case SignedInt:
case SignedLong:
- case SignedLongLong:
+ case SignedLongLong:
return true;
case UnsignedShort:
case UnsignedInt:
case UnsignedLong:
- case UnsignedLongLong:
+ case UnsignedLongLong:
return false;
};
}
@@ -164,7 +167,7 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
if (Name[0] == '%' || Name[0] == '#')
Name = Name.substr(1);
-
+
return Name;
}
@@ -174,7 +177,7 @@ static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
if (Name.empty())
return false;
-
+
const char * const *Names;
unsigned NumNames;
@@ -216,7 +219,7 @@ bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
return false;
}
-llvm::StringRef
+llvm::StringRef
TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const {
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
@@ -283,6 +286,10 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
Info.setAllowsRegister();
break;
case 'm': // memory operand.
+ case 'o': // offsetable memory operand.
+ case 'V': // non-offsetable memory operand.
+ case '<': // autodecrement memory operand.
+ case '>': // autoincrement memory operand.
Info.setAllowsMemory();
break;
case 'g': // general register, memory operand or immediate integer.
@@ -291,13 +298,12 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
Info.setAllowsMemory();
break;
case ',': // multiple alternative constraint. Pass it.
- Name++;
// Handle additional optional '=' or '+' modifiers.
- if (*Name == '=' || *Name == '+')
+ if (Name[1] == '=' || Name[1] == '+')
Name++;
break;
case '?': // Disparage slightly code.
- case '!': // Disparage severly.
+ case '!': // Disparage severely.
break; // Pass them.
}
@@ -347,6 +353,15 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
if (i >= NumOutputs)
return false;
+ // A number must refer to an output only operand.
+ if (OutputConstraints[i].isReadWrite())
+ return false;
+
+ // If the constraint is already tied, it must be tied to the
+ // same operand referenced to by the number.
+ if (Info.hasTiedOperand() && Info.getTiedOperand() != i)
+ return false;
+
// The constraint should have the same info as the respective
// output constraint.
Info.setTiedOperand(i, OutputConstraints[i]);
@@ -362,6 +377,11 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index))
return false;
+ // If the constraint is already tied, it must be tied to the
+ // same operand referenced to by the number.
+ if (Info.hasTiedOperand() && Info.getTiedOperand() != Index)
+ return false;
+
Info.setTiedOperand(Index, OutputConstraints[Index]);
break;
}
@@ -384,8 +404,10 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
Info.setAllowsRegister();
break;
case 'm': // memory operand.
- case 'o': // offsettable memory operand
- case 'V': // non-offsettable memory operand
+ case 'o': // offsettable memory operand.
+ case 'V': // non-offsettable memory operand.
+ case '<': // autodecrement memory operand.
+ case '>': // autoincrement memory operand.
Info.setAllowsMemory();
break;
case 'g': // general register, memory operand or immediate integer.
@@ -393,6 +415,10 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
Info.setAllowsRegister();
Info.setAllowsMemory();
break;
+ case 'E': // immediate floating point.
+ case 'F': // immediate floating point.
+ case 'p': // address operand.
+ break;
case ',': // multiple alternative constraint. Ignore comma.
break;
case '?': // Disparage slightly code.
diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
index df20def..a8198e4 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/Type.h"
#include <algorithm>
using namespace clang;
@@ -160,12 +161,12 @@ public:
return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
TAA, StubSize);
}
-
+
virtual const char *getStaticInitSectionSpecifier() const {
// FIXME: We should return 0 when building kexts.
return "__TEXT,__StaticInit,regular,pure_instructions";
}
-
+
};
@@ -209,6 +210,25 @@ public:
FreeBSDTargetInfo(const std::string &triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
+
+ llvm::Triple Triple(triple);
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ this->MCountName = "_mcount";
+ break;
+ case llvm::Triple::arm:
+ this->MCountName = "__mcount";
+ break;
+ }
+
}
};
@@ -256,6 +276,7 @@ public:
LinuxTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
+ this->WIntType = TargetInfo::UnsignedInt;
}
};
@@ -405,6 +426,54 @@ public:
// FIXME: WIntType should be SignedLong
}
};
+
+// Windows target
+template<typename Target>
+class WindowsTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("_WIN32");
+ }
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (Opts.CPlusPlus) {
+ if (Opts.RTTI)
+ Builder.defineMacro("_CPPRTTI");
+
+ if (Opts.Exceptions)
+ Builder.defineMacro("_CPPUNWIND");
+ }
+
+ if (!Opts.CharIsSigned)
+ Builder.defineMacro("_CHAR_UNSIGNED");
+
+ // FIXME: POSIXThreads isn't exactly the option this should be defined for,
+ // but it works for now.
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_MT");
+
+ if (Opts.MSCVersion != 0)
+ Builder.defineMacro("_MSC_VER", llvm::Twine(Opts.MSCVersion));
+
+ if (Opts.Microsoft) {
+ Builder.defineMacro("_MSC_EXTENSIONS");
+
+ if (Opts.CPlusPlus0x) {
+ Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
+ Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
+ Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
+ }
+ }
+
+ Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
+ }
+
+public:
+ WindowsTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {}
+};
+
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -430,17 +499,6 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
- virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
- // This is the right definition for ABI/V4: System V.4/eabi.
- /*return "typedef struct __va_list_tag {"
- " unsigned char gpr;"
- " unsigned char fpr;"
- " unsigned short reserved;"
- " void* overflow_arg_area;"
- " void* reg_save_area;"
- "} __builtin_va_list[1];";*/
- }
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -458,16 +516,16 @@ public:
// FIXME: The following are added to allow parsing.
// I just took a guess at what the actions should be.
// Also, is more specific checking needed? I.e. specific registers?
- case 'd': // Floating point register (containing 64-bit value)
+ case 'd': // Floating point register (containing 64-bit value)
case 'v': // Altivec vector register
Info.setAllowsRegister();
break;
case 'w':
switch (Name[1]) {
- case 'd':// VSX vector register to hold vector double data
- case 'f':// VSX vector register to hold vector float data
- case 's':// VSX vector register to hold scalar float data
- case 'a':// Any VSX register
+ case 'd':// VSX vector register to hold vector double data
+ case 'f':// VSX vector register to hold vector float data
+ case 's':// VSX vector register to hold scalar float data
+ case 'a':// Any VSX register
break;
default:
return false;
@@ -475,27 +533,27 @@ public:
Info.setAllowsRegister();
Name++; // Skip over 'w'.
break;
- case 'h': // `MQ', `CTR', or `LINK' register
- case 'q': // `MQ' register
- case 'c': // `CTR' register
- case 'l': // `LINK' register
- case 'x': // `CR' register (condition register) number 0
- case 'y': // `CR' register (condition register)
- case 'z': // `XER[CA]' carry bit (part of the XER register)
+ case 'h': // `MQ', `CTR', or `LINK' register
+ case 'q': // `MQ' register
+ case 'c': // `CTR' register
+ case 'l': // `LINK' register
+ case 'x': // `CR' register (condition register) number 0
+ case 'y': // `CR' register (condition register)
+ case 'z': // `XER[CA]' carry bit (part of the XER register)
Info.setAllowsRegister();
break;
- case 'I': // Signed 16-bit constant
+ case 'I': // Signed 16-bit constant
case 'J': // Unsigned 16-bit constant shifted left 16 bits
- // (use `L' instead for SImode constants)
- case 'K': // Unsigned 16-bit constant
- case 'L': // Signed 16-bit constant shifted left 16 bits
- case 'M': // Constant larger than 31
- case 'N': // Exact power of 2
- case 'P': // Constant whose negation is a signed 16-bit constant
+ // (use `L' instead for SImode constants)
+ case 'K': // Unsigned 16-bit constant
+ case 'L': // Signed 16-bit constant shifted left 16 bits
+ case 'M': // Constant larger than 31
+ case 'N': // Exact power of 2
+ case 'P': // Constant whose negation is a signed 16-bit constant
case 'G': // Floating point constant that can be loaded into a
- // register with one instruction per word
+ // register with one instruction per word
case 'H': // Integer/Floating point constant that can be loaded
- // into a register using three instructions
+ // into a register using three instructions
break;
case 'm': // Memory operand. Note that on PowerPC targets, m can
// include addresses that update the base register. It
@@ -503,13 +561,13 @@ public:
// if that asm statement accesses the operand exactly once.
// The asm statement must also use `%U<opno>' as a
// placeholder for the "update" flag in the corresponding
- // load or store instruction. For example:
+ // load or store instruction. For example:
// asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val));
- // is correct but:
+ // is correct but:
// asm ("st %1,%0" : "=m" (mem) : "r" (val));
// is not. Use es rather than m if you don't want the base
- // register to be updated.
- case 'e':
+ // register to be updated.
+ case 'e':
if (Name[1] != 's')
return false;
// es: A "stable" memory operand; that is, one which does not
@@ -521,23 +579,23 @@ public:
Name++; // Skip over 'e'.
break;
case 'Q': // Memory operand that is an offset from a register (it is
- // usually better to use `m' or `es' in asm statements)
+ // usually better to use `m' or `es' in asm statements)
case 'Z': // Memory operand that is an indexed or indirect from a
// register (it is usually better to use `m' or `es' in
- // asm statements)
+ // asm statements)
Info.setAllowsMemory();
Info.setAllowsRegister();
break;
- case 'R': // AIX TOC entry
+ case 'R': // AIX TOC entry
case 'a': // Address operand that is an indexed or indirect from a
- // register (`p' is preferable for asm statements)
- case 'S': // Constant suitable as a 64-bit mask operand
- case 'T': // Constant suitable as a 32-bit mask operand
- case 'U': // System V Release 4 small data area reference
+ // register (`p' is preferable for asm statements)
+ case 'S': // Constant suitable as a 64-bit mask operand
+ case 'T': // Constant suitable as a 32-bit mask operand
+ case 'U': // System V Release 4 small data area reference
case 't': // AND masks that can be performed by two rldic{l, r}
- // instructions
- case 'W': // Vector constant that does not require memory
- case 'j': // Vector constant that is all zeros.
+ // instructions
+ case 'W': // Vector constant that does not require memory
+ case 'j': // Vector constant that is all zeros.
break;
// End FIXME.
}
@@ -549,8 +607,9 @@ public:
};
const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES, false },
#include "clang/Basic/BuiltinsPPC.def"
};
@@ -584,7 +643,7 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// FIXME: Should be controlled by command line option.
Builder.defineMacro("__LONG_DOUBLE_128__");
-
+
if (Opts.AltiVec) {
Builder.defineMacro("__VEC__", "10206");
Builder.defineMacro("__ALTIVEC__");
@@ -704,7 +763,18 @@ public:
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
if (getTriple().getOS() == llvm::Triple::FreeBSD)
- this->SizeType = TargetInfo::UnsignedInt;
+ SizeType = UnsignedInt;
+ }
+
+ virtual const char *getVAListDeclaration() const {
+ // This is the ELF definition, and is overridden by the Darwin sub-target
+ return "typedef struct __va_list_tag {"
+ " unsigned char gpr;"
+ " unsigned char fpr;"
+ " unsigned short reserved;"
+ " void* overflow_arg_area;"
+ " void* reg_save_area;"
+ "} __builtin_va_list[1];";
}
};
} // end anonymous namespace.
@@ -720,17 +790,24 @@ public:
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
}
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ }
};
} // end anonymous namespace.
namespace {
-class DarwinPPCTargetInfo :
- public DarwinTargetInfo<PPCTargetInfo> {
+class DarwinPPC32TargetInfo :
+ public DarwinTargetInfo<PPC32TargetInfo> {
public:
- DarwinPPCTargetInfo(const std::string& triple)
- : DarwinTargetInfo<PPCTargetInfo>(triple) {
+ DarwinPPC32TargetInfo(const std::string& triple)
+ : DarwinTargetInfo<PPC32TargetInfo>(triple) {
HasAlignMac68kSupport = true;
+ BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool?
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
}
};
@@ -752,8 +829,7 @@ class MBlazeTargetInfo : public TargetInfo {
public:
MBlazeTargetInfo(const std::string& triple) : TargetInfo(triple) {
- DescriptionString = "E-p:32:32-i8:8:8-i16:16:16-i64:32:32-f64:32:32-"
- "v64:32:32-v128:32:32-n32";
+ DescriptionString = "E-p:32:32:32-i8:8:8-i16:16:16";
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -875,8 +951,9 @@ void MBlazeTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
namespace {
// Namespace for x86 abstract base class
const Builtin::Info BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES, false },
#include "clang/Basic/BuiltinsX86.def"
};
@@ -1010,6 +1087,9 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
CPU == "athlon-fx") {
setFeatureEnabled(Features, "sse2", true);
setFeatureEnabled(Features, "3dnowa", true);
+ } else if (CPU == "k8-sse3") {
+ setFeatureEnabled(Features, "sse3", true);
+ setFeatureEnabled(Features, "3dnowa", true);
} else if (CPU == "c3-2")
setFeatureEnabled(Features, "sse", true);
}
@@ -1116,13 +1196,13 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.Case("mmx", MMX)
.Default(NoMMXSSE);
SSELevel = std::max(SSELevel, Level);
-
- AMD3DNowEnum ThreeDNowLevel =
+
+ AMD3DNowEnum ThreeDNowLevel =
llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1))
.Case("3dnowa", AMD3DNowAthlon)
.Case("3dnow", AMD3DNow)
.Default(NoAMD3DNow);
-
+
AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel);
}
}
@@ -1184,7 +1264,24 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case NoMMXSSE:
break;
}
-
+
+ if (Opts.Microsoft && PointerWidth == 32) {
+ switch (SSELevel) {
+ case SSE42:
+ case SSE41:
+ case SSSE3:
+ case SSE3:
+ case SSE2:
+ Builder.defineMacro("_M_IX86_FP", llvm::Twine(2));
+ break;
+ case SSE1:
+ Builder.defineMacro("_M_IX86_FP", llvm::Twine(1));
+ break;
+ default:
+ Builder.defineMacro("_M_IX86_FP", llvm::Twine(0));
+ }
+ }
+
// Each case falls through to the previous one here.
switch (AMD3DNowLevel) {
case AMD3DNowAthlon:
@@ -1241,6 +1338,7 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
return false;
}
+
std::string
X86TargetInfo::convertConstraint(const char Constraint) const {
switch (Constraint) {
@@ -1250,6 +1348,8 @@ X86TargetInfo::convertConstraint(const char Constraint) const {
case 'd': return std::string("{dx}");
case 'S': return std::string("{si}");
case 'D': return std::string("{di}");
+ case 'p': // address
+ return std::string("im");
case 't': // top of floating point stack.
return std::string("{st}");
case 'u': // second from top of floating point stack.
@@ -1284,7 +1384,7 @@ public:
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
}
-
+
int getEHDataRegisterNumber(unsigned RegNo) const {
if (RegNo == 0) return 0;
if (RegNo == 1) return 2;
@@ -1325,10 +1425,10 @@ public:
namespace {
// x86-32 Windows target
-class WindowsX86_32TargetInfo : public X86_32TargetInfo {
+class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
public:
WindowsX86_32TargetInfo(const std::string& triple)
- : X86_32TargetInfo(triple) {
+ : WindowsTargetInfo<X86_32TargetInfo>(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
@@ -1338,12 +1438,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- X86_32TargetInfo::getTargetDefines(Opts, Builder);
- // This list is based off of the the list of things MingW defines
- Builder.defineMacro("_WIN32");
- DefineStd(Builder, "WIN32", Opts);
- DefineStd(Builder, "WINNT", Opts);
- Builder.defineMacro("_X86_");
+ WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
}
};
} // end anonymous namespace
@@ -1355,16 +1450,17 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
: WindowsX86_32TargetInfo(triple) {
+ LongDoubleWidth = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder);
// The value of the following reflects processor type.
// 300=386, 400=486, 500=Pentium, 600=Blend (default)
// We lost the original triple, so we use the default.
Builder.defineMacro("_M_IX86", "600");
- Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
- Builder.defineMacro("_STDCALL_SUPPORTED");
}
};
} // end anonymous namespace
@@ -1379,6 +1475,9 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ DefineStd(Builder, "WIN32", Opts);
+ DefineStd(Builder, "WINNT", Opts);
+ Builder.defineMacro("_X86_");
Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW32__");
Builder.defineMacro("__declspec", "__declspec");
@@ -1420,6 +1519,7 @@ public:
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
+ this->UserLabelPrefix = "";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -1461,7 +1561,7 @@ public:
"} __va_list_tag;"
"typedef __va_list_tag __builtin_va_list[1];";
}
-
+
int getEHDataRegisterNumber(unsigned RegNo) const {
if (RegNo == 0) return 0;
if (RegNo == 1) return 1;
@@ -1472,23 +1572,29 @@ public:
namespace {
// x86-64 Windows target
-class WindowsX86_64TargetInfo : public X86_64TargetInfo {
+class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
public:
WindowsX86_64TargetInfo(const std::string& triple)
- : X86_64TargetInfo(triple) {
+ : WindowsTargetInfo<X86_64TargetInfo>(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
LongWidth = LongAlign = 32;
- DoubleAlign = LongLongAlign = 64;
+ DoubleAlign = LongLongAlign = 64;
IntMaxType = SignedLongLong;
UIntMaxType = UnsignedLongLong;
Int64Type = SignedLongLong;
+ SizeType = UnsignedLongLong;
+ PtrDiffType = SignedLongLong;
+ IntPtrType = SignedLongLong;
+ this->UserLabelPrefix = "";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- X86_64TargetInfo::getTargetDefines(Opts, Builder);
+ WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder);
Builder.defineMacro("_WIN64");
- DefineStd(Builder, "WIN64", Opts);
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
}
};
} // end anonymous namespace
@@ -1503,11 +1609,9 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder);
Builder.defineMacro("_M_X64");
- Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
- }
- virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
+ Builder.defineMacro("_M_AMD64");
}
};
} // end anonymous namespace
@@ -1522,9 +1626,10 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ DefineStd(Builder, "WIN64", Opts);
Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW64__");
- Builder.defineMacro("__declspec");
+ Builder.defineMacro("__declspec", "__declspec");
}
};
} // end anonymous namespace
@@ -1590,7 +1695,7 @@ public:
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
-
+
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
@@ -1655,7 +1760,7 @@ public:
else if (CPU == "cortex-a8" || CPU == "cortex-a9")
Features["neon"] = true;
}
-
+
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const {
@@ -1715,6 +1820,7 @@ public:
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a8", "cortex-a9", "7A")
+ .Case("cortex-m3", "7M")
.Default(0);
}
virtual bool setCPU(const std::string &Name) {
@@ -1816,10 +1922,17 @@ const char * const ARMTargetInfo::GCCRegNames[] = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
- "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
- // FIXME: Need double and NEON registers, but we need support for aliasing
- // multiple registers for that.
+ // Double registers
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+ "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+
+ // Quad registers
+ "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
+ "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
};
void ARMTargetInfo::getGCCRegNames(const char * const *&Names,
@@ -1845,6 +1958,8 @@ const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
{ { "r13" }, "sp" },
{ { "r14" }, "lr" },
{ { "r15" }, "pc" },
+ // The S, D and Q registers overlap, but aren't really aliases; we
+ // don't want to substitute one of these for a different-sized one.
};
void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -1854,8 +1969,9 @@ void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
}
const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false },
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES, false },
#include "clang/Basic/BuiltinsARM.def"
};
} // end anonymous namespace.
@@ -1882,17 +1998,37 @@ namespace {
class SparcV8TargetInfo : public TargetInfo {
static const TargetInfo::GCCRegAlias GCCRegAliases[];
static const char * const GCCRegNames[];
+ bool SoftFloat;
public:
SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) {
// FIXME: Support Sparc quad-precision long double?
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ const std::string &Name,
+ bool Enabled) const {
+ if (Name == "soft-float")
+ Features[Name] = Enabled;
+ else
+ return false;
+
+ return true;
+ }
+ virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ SoftFloat = false;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i)
+ if (Features[i] == "+soft-float")
+ SoftFloat = true;
+ }
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
DefineStd(Builder, "sparc", Opts);
Builder.defineMacro("__sparcv8");
Builder.defineMacro("__REGISTER_PREFIX__", "");
+
+ if (SoftFloat)
+ Builder.defineMacro("SOFT_FLOAT", "1");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1991,75 +2127,6 @@ public:
} // end anonymous namespace.
namespace {
- class PIC16TargetInfo : public TargetInfo{
- public:
- PIC16TargetInfo(const std::string& triple) : TargetInfo(triple) {
- TLSSupported = false;
- IntWidth = 16;
- LongWidth = LongLongWidth = 32;
- PointerWidth = 16;
- IntAlign = 8;
- LongAlign = LongLongAlign = 8;
- PointerAlign = 8;
- SizeType = UnsignedInt;
- IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
- IntPtrType = SignedShort;
- PtrDiffType = SignedInt;
- SigAtomicType = SignedLong;
- FloatWidth = 32;
- FloatAlign = 32;
- DoubleWidth = 32;
- DoubleAlign = 32;
- LongDoubleWidth = 32;
- LongDoubleAlign = 32;
- FloatFormat = &llvm::APFloat::IEEEsingle;
- DoubleFormat = &llvm::APFloat::IEEEsingle;
- LongDoubleFormat = &llvm::APFloat::IEEEsingle;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32-n8";
-
- }
- virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
- virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__pic16");
- Builder.defineMacro("__PIC16");
- Builder.defineMacro("rom", "__attribute__((address_space(1)))");
- Builder.defineMacro("ram", "__attribute__((address_space(0)))");
- Builder.defineMacro("__section(SectName)",
- "__attribute__((section(SectName)))");
- Builder.defineMacro("near",
- "__attribute__((section(\"Address=NEAR\")))");
- Builder.defineMacro("__address(Addr)",
- "__attribute__((section(\"Address=\"#Addr)))");
- Builder.defineMacro("__config(conf)", "asm(\"CONFIG \"#conf)");
- Builder.defineMacro("__idlocs(value)", "asm(\"__IDLOCS \"#value)");
- Builder.defineMacro("interrupt",
- "__attribute__((section(\"interrupt=0x4\"))) \
- __attribute__((used))");
- }
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {}
- virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
- }
- virtual const char *getClobbers() const {
- return "";
- }
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
- return true;
- }
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {}
- virtual bool useGlobalsForAutomaticVariables() const {return true;}
- };
-}
-
-namespace {
class MSP430TargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
public:
@@ -2294,8 +2361,8 @@ namespace {
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-"
"i16:16:32-i32:32:32-i64:32:32-"
- "f32:32:32-f64:64:64-v64:64:64-"
- "v128:128:128-a0:0:64-n32";
+ "f32:32:32-f64:32:32-v64:32:32-"
+ "v128:32:32-a0:0:32-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -2399,7 +2466,7 @@ public:
};
const char * const MipsTargetInfo::GCCRegNames[] = {
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
"$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
@@ -2526,12 +2593,9 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new LinuxTargetInfo<MipselTargetInfo>(T);
return new MipselTargetInfo(T);
- case llvm::Triple::pic16:
- return new PIC16TargetInfo(T);
-
case llvm::Triple::ppc:
if (os == llvm::Triple::Darwin)
- return new DarwinPPCTargetInfo(T);
+ return new DarwinPPC32TargetInfo(T);
else if (os == llvm::Triple::FreeBSD)
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
return new PPC32TargetInfo(T);
@@ -2615,10 +2679,13 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new FreeBSDTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::Solaris:
return new SolarisTargetInfo<X86_64TargetInfo>(T);
- case llvm::Triple::MinGW64:
+ case llvm::Triple::MinGW32:
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
- return new VisualStudioWindowsX86_64TargetInfo(T);
+ if (Triple.getEnvironment() == llvm::Triple::MachO)
+ return new DarwinX86_64TargetInfo(T);
+ else
+ return new VisualStudioWindowsX86_64TargetInfo(T);
default:
return new X86_64TargetInfo(T);
}
diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp
index 986f4d5..3a82e5d 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp
@@ -13,6 +13,7 @@
#include "clang/Basic/Version.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Config/config.h"
#include <cstring>
#include <cstdlib>
@@ -20,45 +21,52 @@ using namespace std;
namespace clang {
-llvm::StringRef getClangRepositoryPath() {
- static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_28/lib/Basic/Version.cpp $";
- const char *URLEnd = URL + strlen(URL);
+std::string getClangRepositoryPath() {
+#ifdef SVN_REPOSITORY
+ llvm::StringRef URL(SVN_REPOSITORY);
+#else
+ llvm::StringRef URL("");
+#endif
- const char *End = strstr(URL, "/lib/Basic");
- if (End)
- URLEnd = End;
+ // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
+ // pick up a tag in an SVN export, for example.
+ static llvm::StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
+ if (URL.empty()) {
+ URL = SVNRepository.slice(SVNRepository.find(':'),
+ SVNRepository.find("/lib/Basic"));
+ }
// Strip off version from a build from an integration branch.
- End = strstr(URL, "/src/tools/clang");
- if (End)
- URLEnd = End;
+ URL = URL.slice(0, URL.find("/src/tools/clang"));
- const char *Begin = strstr(URL, "cfe/");
- if (Begin)
- return llvm::StringRef(Begin + 4, URLEnd - Begin - 4);
+ // Trim path prefix off, assuming path came from standard cfe path.
+ size_t Start = URL.find("cfe/");
+ if (Start != llvm::StringRef::npos)
+ URL = URL.substr(Start + 4);
- return llvm::StringRef(URL, URLEnd - URL);
+ return URL;
}
std::string getClangRevision() {
#ifdef SVN_REVISION
- if (SVN_REVISION[0] != '\0') {
- std::string revision;
- llvm::raw_string_ostream OS(revision);
- OS << strtol(SVN_REVISION, 0, 10);
- return OS.str();
- }
-#endif
+ return SVN_REVISION;
+#else
return "";
+#endif
}
std::string getClangFullRepositoryVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);
- OS << getClangRepositoryPath();
- const std::string &Revision = getClangRevision();
- if (!Revision.empty())
- OS << ' ' << Revision;
+ std::string Path = getClangRepositoryPath();
+ std::string Revision = getClangRevision();
+ if (!Path.empty())
+ OS << Path;
+ if (!Revision.empty()) {
+ if (!Path.empty())
+ OS << ' ';
+ OS << Revision;
+ }
return OS.str();
}
@@ -70,9 +78,14 @@ std::string getClangFullVersion() {
#endif
OS << "clang version " CLANG_VERSION_STRING " ("
<< getClangFullRepositoryVersion() << ')';
+
#ifdef CLANG_VENDOR_SUFFIX
OS << CLANG_VENDOR_SUFFIX;
+#elif defined(CLANG_VENDOR)
+ // If vendor supplied, include the base LLVM version as well.
+ OS << " (based on LLVM " << PACKAGE_VERSION << ")";
#endif
+
return OS.str();
}
OpenPOWER on IntegriCloud