diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Builtins.cpp | 24 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp | 914 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp | 586 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/FileManager.cpp | 464 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp | 120 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp | 31 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp | 10 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp | 350 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp | 52 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Targets.cpp | 409 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Version.cpp | 61 |
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(); } |