diff options
Diffstat (limited to 'lib/Basic')
-rw-r--r-- | lib/Basic/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 23 | ||||
-rw-r--r-- | lib/Basic/DiagnosticIDs.cpp | 144 | ||||
-rw-r--r-- | lib/Basic/FileManager.cpp | 73 | ||||
-rw-r--r-- | lib/Basic/IdentifierTable.cpp | 85 | ||||
-rw-r--r-- | lib/Basic/SourceManager.cpp | 220 | ||||
-rw-r--r-- | lib/Basic/TargetInfo.cpp | 12 | ||||
-rw-r--r-- | lib/Basic/Targets.cpp | 227 | ||||
-rw-r--r-- | lib/Basic/Version.cpp | 19 | ||||
-rw-r--r-- | lib/Basic/VersionTuple.cpp | 36 |
10 files changed, 661 insertions, 182 deletions
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 91e7deb..c1e7cf6 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangBasic Targets.cpp TokenKinds.cpp Version.cpp + VersionTuple.cpp ) # Determine Subversion revision. @@ -39,5 +40,6 @@ add_dependencies(clangBasic ClangDiagnosticGroups ClangDiagnosticLex ClangDiagnosticParse - ClangDiagnosticSema) + ClangDiagnosticSema + ClangDiagnosticIndexName) diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 31e3331..e8cd218 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -16,6 +16,8 @@ #include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CrashRecoveryContext.h" + using namespace clang; static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, @@ -49,11 +51,6 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, ErrorLimit = 0; TemplateBacktraceLimit = 0; - // Create a DiagState and DiagStatePoint representing diagnostic changes - // through command-line. - DiagStates.push_back(DiagState()); - PushDiagStatePoint(&DiagStates.back(), SourceLocation()); - Reset(); } @@ -100,6 +97,16 @@ void Diagnostic::Reset() { // displayed. LastDiagLevel = (DiagnosticIDs::Level)-1; DelayedDiagID = 0; + + // Clear state related to #pragma diagnostic. + DiagStates.clear(); + DiagStatePoints.clear(); + DiagStateOnPushStack.clear(); + + // Create a DiagState and DiagStatePoint representing diagnostic changes + // through command-line. + DiagStates.push_back(DiagState()); + PushDiagStatePoint(&DiagStates.back(), SourceLocation()); } void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, @@ -168,7 +175,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, // after the previous one. if ((Loc.isValid() && LastStateChangePos.isInvalid()) || LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) { - // A diagnostic pragma occured, create a new DiagState initialized with + // A diagnostic pragma occurred, 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()); @@ -683,5 +690,7 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() { } PartialDiagnostic::StorageAllocator::~StorageAllocator() { - assert(NumFreeListEntries == NumCached && "A partial is on the lamb"); + // Don't assert if we are in a CrashRecovery context, as this + // invariant may be invalidated during a crash. + assert((NumFreeListEntries == NumCached || llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lamb"); } diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 553e4c9..b4dd575 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -46,19 +46,41 @@ struct StaticDiagInfoRec { unsigned AccessControl : 1; unsigned Category : 5; + const char *Name; + const char *Description; const char *OptionGroup; + const char *BriefExplanation; + const char *FullExplanation; + bool operator<(const StaticDiagInfoRec &RHS) const { return DiagID < RHS.DiagID; } }; +struct StaticDiagNameIndexRec { + const char *Name; + unsigned short DiagID; + + bool operator<(const StaticDiagNameIndexRec &RHS) const { + assert(Name && RHS.Name && "Null Diagnostic Name"); + return strcmp(Name, RHS.Name) == -1; + } + + bool operator==(const StaticDiagNameIndexRec &RHS) const { + assert(Name && RHS.Name && "Null Diagnostic Name"); + return strcmp(Name, RHS.Name) == 0; + } +}; + } 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 }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ + SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \ + ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -67,20 +89,32 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #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 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +static const unsigned StaticDiagInfoSize = + sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1; + +/// To be sorted before first use (since it's splitted among multiple files) +static StaticDiagNameIndexRec StaticDiagNameIndex[] = { +#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM }, +#include "clang/Basic/DiagnosticIndexName.inc" +#undef DIAG_NAME_INDEX + { 0, 0 } +}; + +static const unsigned StaticDiagNameIndexSize = + sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1; /// 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) { + for (unsigned i = 1; i != StaticDiagInfoSize; ++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"); @@ -93,11 +127,11 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const StaticDiagInfoRec *Found = - std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); - if (Found == StaticDiagInfo + NumDiagEntries || + std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find); + if (Found == StaticDiagInfo + StaticDiagInfoSize || Found->DiagID != DiagID) return 0; @@ -119,7 +153,7 @@ const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { return 0; } -/// getWarningOptionForDiag - Return the category number that a specified +/// getCategoryNumberForDiag - 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)) @@ -167,7 +201,48 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { return SFINAE_Report; } -/// getDiagClass - Return the class field of the diagnostic. +/// getName - Given a diagnostic ID, return its name +const char *DiagnosticIDs::getName(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Name; + return 0; +} + +/// getIdFromName - Given a diagnostic name, return its ID, or 0 +unsigned DiagnosticIDs::getIdFromName(char const *Name) { + StaticDiagNameIndexRec *StaticDiagNameIndexEnd = + StaticDiagNameIndex + StaticDiagNameIndexSize; + + if (Name == 0) { return diag::DIAG_UPPER_LIMIT; } + + StaticDiagNameIndexRec Find = { Name, 0 }; + + const StaticDiagNameIndexRec *Found = + std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find); + if (Found == StaticDiagNameIndexEnd || + strcmp(Found->Name, Name) != 0) + return diag::DIAG_UPPER_LIMIT; + + return Found->DiagID; +} + +/// getBriefExplanation - Given a diagnostic ID, return a brief explanation +/// of the issue +const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->BriefExplanation; + return 0; +} + +/// getFullExplanation - Given a diagnostic ID, return a full explanation +/// of the issue +const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->FullExplanation; + return 0; +} + +/// getBuiltinDiagClass - Return the class field of the diagnostic. /// static unsigned getBuiltinDiagClass(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) @@ -329,6 +404,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, if (mapping) *mapping = (diag::Mapping) (MappingInfo & 7); + bool ShouldEmitInSystemHeader = false; + switch (MappingInfo & 7) { default: assert(0 && "Unknown mapping!"); case diag::MAP_IGNORE: @@ -351,6 +428,9 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, case diag::MAP_FATAL: Result = DiagnosticIDs::Fatal; break; + case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER: + ShouldEmitInSystemHeader = true; + // continue as MAP_WARNING. case diag::MAP_WARNING: // If warnings are globally mapped to ignore or error, do it. if (Diag.IgnoreAllWarnings) @@ -395,6 +475,20 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) return DiagnosticIDs::Ignored; + // If we are in a system header, we ignore it. + // We also want to ignore extensions and warnings in -Werror and + // -pedantic-errors modes, which *map* warnings/extensions to errors. + if (Result >= DiagnosticIDs::Warning && + DiagClass != CLASS_ERROR && + // Custom diagnostics always are emitted in system headers. + DiagID < diag::DIAG_UPPER_LIMIT && + !ShouldEmitInSystemHeader && + Diag.SuppressSystemWarnings && + Loc.isValid() && + Diag.getSourceManager().isInSystemHeader( + Diag.getSourceManager().getInstantiationLoc(Loc))) + return DiagnosticIDs::Ignored; + return Result; } @@ -480,16 +574,9 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { 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 @@ -497,14 +584,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { 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); } @@ -540,18 +620,6 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { 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; diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 342413d..4e5a129 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -313,7 +313,7 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { /// getFile - Lookup, cache, and verify the specified file (real or /// virtual). This returns NULL if the file doesn't exist. /// -const FileEntry *FileManager::getFile(llvm::StringRef Filename) { +const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { ++NumFileLookups; // See if there is already an entry in the map. @@ -354,6 +354,11 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) { return 0; } + if (FileDescriptor != -1 && !openFile) { + close(FileDescriptor); + FileDescriptor = -1; + } + // 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 = UniqueRealFiles.getFile(InterndFileName, StatBuf); @@ -450,13 +455,15 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, return UFE; } -void FileManager::FixupRelativePath(llvm::sys::Path &path, - const FileSystemOptions &FSOpts) { - if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str())) +void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const { + llvm::StringRef pathRef(path.data(), path.size()); + + if (FileSystemOpts.WorkingDir.empty() + || llvm::sys::path::is_absolute(pathRef)) return; - llvm::SmallString<128> NewPath(FSOpts.WorkingDir); - llvm::sys::path::append(NewPath, path.str()); + llvm::SmallString<128> NewPath(FileSystemOpts.WorkingDir); + llvm::sys::path::append(NewPath, pathRef); path = NewPath; } @@ -464,30 +471,32 @@ 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. + 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. + + if (FileSystemOpts.WorkingDir.empty()) { ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize()); if (ec && ErrorStr) *ErrorStr = ec.message(); return Result.take(); } - - llvm::sys::Path FilePath(Entry->getName()); - FixupRelativePath(FilePath, FileSystemOpts); - ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize()); + + llvm::SmallString<128> FilePath(Entry->getName()); + FixupRelativePath(FilePath); + ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize()); if (ec && ErrorStr) *ErrorStr = ec.message(); return Result.take(); @@ -504,8 +513,8 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) { return Result.take(); } - llvm::sys::Path FilePath(Filename); - FixupRelativePath(FilePath, FileSystemOpts); + llvm::SmallString<128> FilePath(Filename); + FixupRelativePath(FilePath); ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result); if (ec && ErrorStr) *ErrorStr = ec.message(); @@ -525,13 +534,21 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf, return FileSystemStatCache::get(Path, StatBuf, FileDescriptor, StatCache.get()); - llvm::sys::Path FilePath(Path); - FixupRelativePath(FilePath, FileSystemOpts); + llvm::SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor, StatCache.get()); } +bool FileManager::getNoncachedStatValue(llvm::StringRef Path, + struct stat &StatBuf) { + llvm::SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + return ::stat(FilePath.c_str(), &StatBuf) != 0; +} + void FileManager::GetUniqueIDMapping( llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const { UIDToFiles.clear(); diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index ef11d65..cb1f55b 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -81,17 +81,18 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { enum { - KEYALL = 1, - KEYC99 = 2, - KEYCXX = 4, - KEYCXX0X = 8, - KEYGNU = 16, - KEYMS = 32, - BOOLSUPPORT = 64, - KEYALTIVEC = 128, - KEYNOCXX = 256, - KEYBORLAND = 512, - KEYOPENCL = 1024 + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX0X = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCL = 0x200, + KEYC1X = 0x400, + KEYALL = 0x7ff }; } @@ -107,7 +108,7 @@ static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, const LangOptions &LangOpts, IdentifierTable &Table) { unsigned AddResult = 0; - if (Flags & KEYALL) AddResult = 2; + if (Flags == KEYALL) AddResult = 2; else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; @@ -118,6 +119,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2; else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2; + else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2; // Don't add this keyword if disabled in this language. if (AddResult == 0) return; @@ -162,7 +164,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { #define OBJC2_AT_KEYWORD(NAME) \ if (LangOpts.ObjC2) \ AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); +#define TESTING_KEYWORD(NAME, FLAGS) #include "clang/Basic/TokenKinds.def" + + if (LangOpts.ParseUnknownAnytype) + AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL, + LangOpts, *this); } tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { @@ -364,6 +371,56 @@ std::string Selector::getAsString() const { return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName(); } +/// Interpreting the given string using the normal CamelCase +/// conventions, determine whether the given string starts with the +/// given "word", which is assumed to end in a lowercase letter. +static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) { + if (name.size() < word.size()) return false; + return ((name.size() == word.size() || + !islower(name[word.size()])) + && name.startswith(word)); +} + +ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { + IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + if (!first) return OMF_None; + + llvm::StringRef name = first->getName(); + if (sel.isUnarySelector()) { + if (name == "autorelease") return OMF_autorelease; + if (name == "dealloc") return OMF_dealloc; + if (name == "release") return OMF_release; + if (name == "retain") return OMF_retain; + if (name == "retainCount") return OMF_retainCount; + } + + // The other method families may begin with a prefix of underscores. + while (!name.empty() && name.front() == '_') + name = name.substr(1); + + if (name.empty()) return OMF_None; + switch (name.front()) { + case 'a': + if (startsWithWord(name, "alloc")) return OMF_alloc; + break; + case 'c': + if (startsWithWord(name, "copy")) return OMF_copy; + break; + case 'i': + if (startsWithWord(name, "init")) return OMF_init; + break; + case 'm': + if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy; + break; + case 'n': + if (startsWithWord(name, "new")) return OMF_new; + break; + default: + break; + } + + return OMF_None; +} namespace { struct SelectorTableImpl { @@ -376,6 +433,10 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) { return *static_cast<SelectorTableImpl*>(P); } +size_t SelectorTable::getTotalMemory() const { + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); + return SelTabImpl.Allocator.getTotalMemory(); +} Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { if (nKeys < 2) diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index e2783ba..c3e0393 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -46,13 +46,26 @@ unsigned ContentCache::getSizeBytesMapped() const { return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0; } +/// Returns the kind of memory used to back the memory buffer for +/// this content cache. This is used for performance analysis. +llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const { + assert(Buffer.getPointer()); + + // Should be unreachable, but keep for sanity. + if (!Buffer.getPointer()) + return llvm::MemoryBuffer::MemoryBuffer_Malloc; + + const llvm::MemoryBuffer *buf = Buffer.getPointer(); + return buf->getBufferKind(); +} + /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that /// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() - : (unsigned) Entry->getSize(); + : (unsigned) ContentsEntry->getSize(); } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, @@ -70,8 +83,8 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, SourceLocation Loc, bool *Invalid) const { // Lazily create the Buffer for ContentCaches that wrap files. If we already - // computed it, jsut return what we have. - if (Buffer.getPointer() || Entry == 0) { + // computed it, just return what we have. + if (Buffer.getPointer() || ContentsEntry == 0) { if (Invalid) *Invalid = isBufferInvalid(); @@ -79,7 +92,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, } std::string ErrorStr; - Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr)); + Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &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 @@ -93,18 +106,18 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // possible. if (!Buffer.getPointer()) { const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); - Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(), + Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(), "<invalid>")); char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); - for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, - Entry->getName(), ErrorStr); + ContentsEntry->getName(), ErrorStr); else Diag.Report(Loc, diag::err_cannot_open_file) - << Entry->getName() << ErrorStr; + << ContentsEntry->getName() << ErrorStr; Buffer.setInt(Buffer.getInt() | InvalidFlag); @@ -114,25 +127,24 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // 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 (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) { if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_file_modified, - Entry->getName()); + ContentsEntry->getName()); else Diag.Report(Loc, diag::err_file_modified) - << Entry->getName(); + << ContentsEntry->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 + // (BOM). We only support UTF-8 with and 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") + const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr) .StartsWith("\xFE\xFF", "UTF-16 (BE)") .StartsWith("\xFF\xFE", "UTF-16 (LE)") .StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)") @@ -145,9 +157,9 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, .StartsWith("\x84\x31\x95\x33", "GB-18030") .Default(0); - if (BOM) { + if (InvalidBOM) { Diag.Report(Loc, diag::err_unsupported_bom) - << BOM << Entry->getName(); + << InvalidBOM << ContentsEntry->getName(); Buffer.setInt(Buffer.getInt() | InvalidFlag); } @@ -279,7 +291,12 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID) { std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (!Entry.isFile() || Invalid) + return; + + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); // Remember that this file has #line directives now if it doesn't already. const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); @@ -303,7 +320,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, } std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (!Entry.isFile() || Invalid) + return; + + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); // Remember that this file has #line directives now if it doesn't already. const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); @@ -340,9 +363,9 @@ LineTableInfo &SourceManager::getLineTable() { //===----------------------------------------------------------------------===// SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr) - : Diag(Diag), FileMgr(FileMgr), + : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0) { + NumBinaryProbes(0), FakeBufferForRecovery(0) { clearIDTables(); Diag.setSourceManager(this); } @@ -362,6 +385,8 @@ SourceManager::~SourceManager() { I->second->~ContentCache(); ContentCacheAlloc.Deallocate(I->second); } + + delete FakeBufferForRecovery; } void SourceManager::clearIDTables() { @@ -395,7 +420,18 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment; EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); - new (Entry) ContentCache(FileEnt); + + // If the file contents are overridden with contents from another file, + // pass that file to ContentCache. + llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator + overI = OverriddenFiles.find(FileEnt); + if (overI == OverriddenFiles.end()) + new (Entry) ContentCache(FileEnt); + else + new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt + : overI->second, + overI->second); + return Entry; } @@ -445,6 +481,15 @@ void SourceManager::ClearPreallocatedSLocEntries() { ExternalSLocEntries = 0; } +/// \brief As part of recovering from missing or changed content, produce a +/// fake, non-empty buffer. +const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { + if (!FakeBufferForRecovery) + FakeBufferForRecovery + = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>"); + + return FakeBufferForRecovery; +} //===----------------------------------------------------------------------===// // Methods to create new FileID's and instantiations. @@ -531,10 +576,21 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile, const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree); } +void SourceManager::overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile) { + assert(SourceFile->getSize() == NewFile->getSize() && + "Different sizes, use the FileManager to create a virtual file with " + "the correct size"); + assert(FileInfos.count(SourceFile) == 0 && + "This function should be called at the initialization stage, before " + "any parsing occurs."); + OverriddenFiles[SourceFile] = NewFile; +} + llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { bool MyInvalid = false; - const SLocEntry &SLoc = getSLocEntry(FID.ID); - if (!SLoc.isFile()) { + const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid); + if (!SLoc.isFile() || MyInvalid) { if (Invalid) *Invalid = true; return "<<<<<INVALID SOURCE LOCATION>>>>>"; @@ -562,7 +618,8 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { /// SLocEntryTable which contains the specified location. /// FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { - assert(SLocOffset && "Invalid FileID"); + if (!SLocOffset) + return FileID::get(0); // After the first and second level caches, I see two common sorts of // behavior: 1) a lot of searched FileID's are "near" the cached file location @@ -590,8 +647,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { unsigned NumProbes = 0; while (1) { --I; - if (ExternalSLocEntries) - getSLocEntry(FileID::get(I - SLocEntryTable.begin())); + if (ExternalSLocEntries) { + bool Invalid = false; + getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid); + if (Invalid) + return FileID::get(0); + } + if (I->getOffset() <= SLocOffset) { #if 0 printf("lin %d -> %d [%s] %d %d\n", SLocOffset, @@ -621,9 +683,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { unsigned LessIndex = 0; NumProbes = 0; while (1) { + bool Invalid = false; unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; - unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset(); - + unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid) + .getOffset(); + if (Invalid) + return FileID::get(0); + ++NumProbes; // If the offset of the midpoint is too large, chop the high side of the @@ -773,9 +839,16 @@ const char *SourceManager::getCharacterData(SourceLocation SL, // Note that calling 'getBuffer()' may lazily page in a source file. bool CharDataInvalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid); + if (CharDataInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return "<<<<INVALID BUFFER>>>>"; + } const llvm::MemoryBuffer *Buffer - = getSLocEntry(LocInfo.first).getFile().getContentCache() - ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); + = Entry.getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); @@ -891,10 +964,18 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, ContentCache *Content; if (LastLineNoFileIDQuery == FID) Content = LastLineNoContentCache; - else - Content = const_cast<ContentCache*>(getSLocEntry(FID) - .getFile().getContentCache()); - + else { + bool MyInvalid = false; + const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + return 1; + } + + Content = const_cast<ContentCache*>(Entry.getFile().getContentCache()); + } + // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { @@ -1021,7 +1102,12 @@ SrcMgr::CharacteristicKind SourceManager::getFileCharacteristic(SourceLocation Loc) const { assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!"); std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !SEntry.isFile()) + return C_User; + + const SrcMgr::FileInfo &FI = SEntry.getFile(); // If there are no #line directives in this file, just return the whole-file // state. @@ -1064,18 +1150,23 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // Presumed locations are always for instantiation points. std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !Entry.isFile()) + return PresumedLoc(); + + const SrcMgr::FileInfo &FI = Entry.getFile(); const SrcMgr::ContentCache *C = FI.getContentCache(); // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. const char *Filename; - if (C->Entry) - Filename = C->Entry->getName(); + if (C->OrigEntry) + Filename = C->OrigEntry->getName(); else Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); - bool Invalid = false; + unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid); if (Invalid) return PresumedLoc(); @@ -1152,18 +1243,22 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, llvm::Optional<ino_t> SourceFileInode; llvm::Optional<llvm::StringRef> SourceFileName; if (!MainFileID.isInvalid()) { - const SLocEntry &MainSLoc = getSLocEntry(MainFileID); + bool Invalid = false; + const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); + if (Invalid) + return SourceLocation(); + if (MainSLoc.isFile()) { const ContentCache *MainContentCache = MainSLoc.getFile().getContentCache(); if (!MainContentCache) { // Can't do anything - } else if (MainContentCache->Entry == SourceFile) { + } else if (MainContentCache->OrigEntry == 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; + const FileEntry *MainFile = MainContentCache->OrigEntry; SourceFileName = llvm::sys::path::filename(SourceFile->getName()); if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) { SourceFileInode = getActualFileInode(SourceFile); @@ -1185,10 +1280,14 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, // The location we're looking for isn't in the main file; look // through all of the source locations. for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getSLocEntry(I); + bool Invalid = false; + const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + if (Invalid) + return SourceLocation(); + if (SLoc.isFile() && SLoc.getFile().getContentCache() && - SLoc.getFile().getContentCache()->Entry == SourceFile) { + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { FirstFID = FileID::get(I); break; } @@ -1203,12 +1302,16 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) && (SourceFileInode || (SourceFileInode = getActualFileInode(SourceFile)))) { + bool Invalid = false; for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getSLocEntry(I); + const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + if (Invalid) + return SourceLocation(); + if (SLoc.isFile()) { const ContentCache *FileContentCache = SLoc.getFile().getContentCache(); - const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0; + const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0; if (Entry && *SourceFileName == llvm::sys::path::filename(Entry->getName())) { if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) { @@ -1367,7 +1470,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/; while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/; - // If exactly one location is a memory buffer, assume it preceeds the other. + // If exactly one location is a memory buffer, assume it precedes the other. // Strip off macro instantation locations, going up to the top-level File // SLocEntry. @@ -1403,3 +1506,24 @@ void SourceManager::PrintStats() const { } ExternalSLocEntrySource::~ExternalSLocEntrySource() { } + +/// Return the amount of memory used by memory buffers, breaking down +/// by heap-backed versus mmap'ed memory. +SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const { + size_t malloc_bytes = 0; + size_t mmap_bytes = 0; + + for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) + if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped()) + switch (MemBufferInfos[i]->getMemoryBufferKind()) { + case llvm::MemoryBuffer::MemoryBuffer_MMap: + mmap_bytes += sized_mapped; + break; + case llvm::MemoryBuffer::MemoryBuffer_Malloc: + malloc_bytes += sized_mapped; + break; + } + + return MemoryBufferSizes(malloc_bytes, mmap_bytes); +} + diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index a9eeb8b..dcf0cb4 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/APFloat.h" @@ -19,6 +20,8 @@ #include <cstdlib> using namespace clang; +static const LangAS::Map DefaultAddrSpaceMap = { 0 }; + // TargetInfo Constructor. TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or @@ -64,6 +67,13 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Default to using the Itanium ABI. CXXABI = CXXABI_Itanium; + + // Default to an empty address space map. + AddrSpaceMap = &DefaultAddrSpaceMap; + + // Default to an unknown platform name. + PlatformName = "unknown"; + PlatformMinVersion = VersionTuple(); } // Out of line virtual dtor for TargetInfo. @@ -422,7 +432,7 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, case ',': // multiple alternative constraint. Ignore comma. break; case '?': // Disparage slightly code. - case '!': // Disparage severly. + case '!': // Disparage severely. break; // Pass them. } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 55321f24..97109ca 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -76,7 +76,9 @@ public: static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, - const llvm::Triple &Triple) { + const llvm::Triple &Triple, + llvm::StringRef &PlatformName, + VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "5621"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("__MACH__"); @@ -99,19 +101,40 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); - // Get the OS version number from the triple. + // Get the platform type and version number from the triple. unsigned Maj, Min, Rev; // If no version was given, default to to 10.4.0, for simplifying tests. - if (Triple.getOSName() == "darwin") { + if (Triple.getOSName() == "darwin" || Triple.getOSName() == "osx") { + PlatformName = "macosx"; Min = Rev = 0; Maj = 8; - } else - Triple.getDarwinNumber(Maj, Min, Rev); + } else { + // Otherwise, honor all three triple forms ("-darwinNNN[-iphoneos]", + // "-osxNNN", and "-iosNNN"). + + if (Triple.getOS() == llvm::Triple::Darwin) { + // For historical reasons that make little sense, the version passed here + // is the "darwin" version, which drops the 10 and offsets by 4. + Triple.getOSVersion(Maj, Min, Rev); + + if (Triple.getEnvironmentName() == "iphoneos") { + PlatformName = "ios"; + } else { + PlatformName = "macosx"; + Rev = Min; + Min = Maj - 4; + Maj = 10; + } + } else { + Triple.getOSVersion(Maj, Min, Rev); + PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + } + } // Set the appropriate OS version define. - if (Triple.getEnvironmentName() == "iphoneos") { - assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!"); + if (PlatformName == "ios") { + assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[6]; Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); @@ -121,22 +144,22 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Str[5] = '\0'; Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); } else { - // For historical reasons that make little sense, the version passed here is - // the "darwin" version, which drops the 10 and offsets by 4. - Rev = Min; - Min = Maj - 4; - Maj = 10; - + // Note that the Driver allows versions which aren't representable in the + // define (because we only get a single digit for the minor and micro + // revision numbers). So, we limit them to the maximum representable + // version. assert(Triple.getEnvironmentName().empty() && "Invalid environment!"); - assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!"); + assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[5]; Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); - Str[2] = '0' + Min; - Str[3] = '0' + Rev; + Str[2] = '0' + std::min(Min, 9U); + Str[3] = '0' + std::min(Rev, 9U); Str[4] = '\0'; Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); } + + PlatformMinVersion = VersionTuple(Maj, Min, Rev); } namespace { @@ -145,7 +168,8 @@ class DarwinTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, this->PlatformName, + this->PlatformMinVersion); } public: @@ -159,8 +183,9 @@ public: // Let MCSectionMachO validate this. llvm::StringRef Segment, Section; unsigned TAA, StubSize; + bool HasTAA; return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, - TAA, StubSize); + TAA, HasTAA, StubSize); } virtual const char *getStaticInitSectionSpecifier() const { @@ -823,6 +848,87 @@ public: } // end anonymous namespace. namespace { + class PTXTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; + public: + PTXTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + LongWidth = LongAlign = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__PTX__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::PTX::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // FIXME: implement + return true; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual const char *getVAListDeclaration() const { + // FIXME: implement + return "typedef char* __builtin_va_list;"; + } + }; + + const Builtin::Info PTXTargetInfo::BuiltinInfo[] = { +#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/BuiltinsPTX.def" + }; + + const char * const PTXTargetInfo::GCCRegNames[] = { + "r0" + }; + + void PTXTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + + class PTX32TargetInfo : public PTXTargetInfo { + public: + PTX32TargetInfo(const std::string& triple) : PTXTargetInfo(triple) { + PointerWidth = PointerAlign = 32; + SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt; + DescriptionString + = "e-p:32:32-i64:64:64-f64:64:64-n1:8:16:32:64"; + } + }; + + class PTX64TargetInfo : public PTXTargetInfo { + public: + PTX64TargetInfo(const std::string& triple) : PTXTargetInfo(triple) { + PointerWidth = PointerAlign = 64; + SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong; + DescriptionString + = "e-p:64:64-i64:64:64-f64:64:64-n1:8:16:32:64"; + } + }; +} + +namespace { // MBlaze abstract base class class MBlazeTargetInfo : public TargetInfo { static const char * const GCCRegNames[]; @@ -1074,8 +1180,11 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, else if (CPU == "corei7") { setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); - } - else if (CPU == "k6" || CPU == "winchip-c6") + } else if (CPU == "sandybridge") { + setFeatureEnabled(Features, "sse4", true); + setFeatureEnabled(Features, "aes", true); +// setFeatureEnabled(Features, "avx", true); + } else if (CPU == "k6" || CPU == "winchip-c6") setFeatureEnabled(Features, "mmx", true); else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") { @@ -1133,7 +1242,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["avx"] = true; } else { if (Name == "mmx") - Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = + Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "sse") Features["sse"] = Features["sse2"] = Features["sse3"] = @@ -1146,12 +1256,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["sse42"] = false; else if (Name == "ssse3") Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; - else if (Name == "sse4") + else if (Name == "sse4" || Name == "sse4.1") Features["sse41"] = Features["sse42"] = false; else if (Name == "sse4.2") Features["sse42"] = false; - else if (Name == "sse4.1") - Features["sse41"] = Features["sse42"] = false; else if (Name == "3dnow") Features["3dnow"] = Features["3dnowa"] = false; else if (Name == "3dnowa") @@ -1451,7 +1559,7 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo { public: VisualStudioWindowsX86_32TargetInfo(const std::string& triple) : WindowsX86_32TargetInfo(triple) { - LongDoubleWidth = 64; + LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } virtual void getTargetDefines(const LangOptions &Opts, @@ -1481,7 +1589,15 @@ public: Builder.defineMacro("_X86_"); Builder.defineMacro("__MSVCRT__"); Builder.defineMacro("__MINGW32__"); - Builder.defineMacro("__declspec", "__declspec"); + + // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). + // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. + if (Opts.Microsoft) + // Provide "as-is" __declspec. + Builder.defineMacro("__declspec", "__declspec"); + else + // Provide alias of __attribute__ like mingw32-gcc. + Builder.defineMacro("__declspec(a)", "__attribute__((a))"); } }; } // end anonymous namespace @@ -1606,6 +1722,8 @@ class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo { public: VisualStudioWindowsX86_64TargetInfo(const std::string& triple) : WindowsX86_64TargetInfo(triple) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -1629,8 +1747,17 @@ public: WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN64", Opts); Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); Builder.defineMacro("__MINGW64__"); - Builder.defineMacro("__declspec", "__declspec"); + + // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). + // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. + if (Opts.Microsoft) + // Provide "as-is" __declspec. + Builder.defineMacro("__declspec", "__declspec"); + else + // Provide alias of __attribute__ like mingw32-gcc. + Builder.defineMacro("__declspec(a)", "__attribute__((a))"); } }; } // end anonymous namespace @@ -1700,13 +1827,15 @@ public: // FIXME: Should we just treat this as a feature? IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:128:128-a0:0:32-n32"); + "v64:64:64-v128:64:128-a0:0:32-n32"); } else { 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-v128:128:128-a0:0:64-n32"); + "v64:64:64-v128:64:128-a0:0:64-n32"); } // ARM targets default to using the ARM C++ ABI. @@ -1729,13 +1858,15 @@ public: UseBitFieldTypeAlignment = false; if (IsThumb) { + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:32-n32"); + "v64:32:64-v128:32:128-a0:0:32-n32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:64-n32"); + "i64:32:64-f32:32:32-f64:32:64-" + "v64:32:64-v128:32:128-a0:0:32-n32"); } // FIXME: Override "preferred align" for double and long long. @@ -1822,6 +1953,7 @@ public: .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") .Cases("cortex-a8", "cortex-a9", "7A") .Case("cortex-m3", "7M") + .Case("cortex-m0", "6M") .Default(0); } virtual bool setCPU(const std::string &Name) { @@ -1984,7 +2116,7 @@ class DarwinARMTargetInfo : protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: @@ -2563,11 +2695,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::arm: case llvm::Triple::thumb: + if (Triple.isOSDarwin()) + return new DarwinARMTargetInfo(T); + switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo<ARMTargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinARMTargetInfo(T); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<ARMTargetInfo>(T); default: @@ -2595,14 +2728,14 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MipselTargetInfo(T); case llvm::Triple::ppc: - if (os == llvm::Triple::Darwin) + if (Triple.isOSDarwin()) return new DarwinPPC32TargetInfo(T); else if (os == llvm::Triple::FreeBSD) return new FreeBSDTargetInfo<PPC32TargetInfo>(T); return new PPC32TargetInfo(T); case llvm::Triple::ppc64: - if (os == llvm::Triple::Darwin) + if (Triple.isOSDarwin()) return new DarwinPPC64TargetInfo(T); else if (os == llvm::Triple::Lv2) return new PS3PPUTargetInfo<PPC64TargetInfo>(T); @@ -2610,6 +2743,11 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new FreeBSDTargetInfo<PPC64TargetInfo>(T); return new PPC64TargetInfo(T); + case llvm::Triple::ptx32: + return new PTX32TargetInfo(T); + case llvm::Triple::ptx64: + return new PTX64TargetInfo(T); + case llvm::Triple::mblaze: return new MBlazeTargetInfo(T); @@ -2631,11 +2769,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new TCETargetInfo(T); case llvm::Triple::x86: + if (Triple.isOSDarwin()) + return new DarwinI386TargetInfo(T); + switch (os) { case llvm::Triple::AuroraUX: return new AuroraUXTargetInfo<X86_32TargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinI386TargetInfo(T); case llvm::Triple::Linux: return new LinuxTargetInfo<X86_32TargetInfo>(T); case llvm::Triple::DragonFly: @@ -2663,11 +2802,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { } case llvm::Triple::x86_64: + if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO) + return new DarwinX86_64TargetInfo(T); + switch (os) { case llvm::Triple::AuroraUX: return new AuroraUXTargetInfo<X86_64TargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinX86_64TargetInfo(T); case llvm::Triple::Linux: return new LinuxTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::DragonFly: @@ -2683,10 +2823,7 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::MinGW32: return new MinGWX86_64TargetInfo(T); case llvm::Triple::Win32: // This is what Triple.h supports now. - if (Triple.getEnvironment() == llvm::Triple::MachO) - return new DarwinX86_64TargetInfo(T); - else - return new VisualStudioWindowsX86_64TargetInfo(T); + return new VisualStudioWindowsX86_64TargetInfo(T); default: return new X86_64TargetInfo(T); } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 6573eb9..8f71352 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -17,11 +17,12 @@ #include <cstring> #include <cstdlib> -using namespace std; - namespace clang { std::string getClangRepositoryPath() { +#if defined(CLANG_REPOSITORY_STRING) + return CLANG_REPOSITORY_STRING; +#else #ifdef SVN_REPOSITORY llvm::StringRef URL(SVN_REPOSITORY); #else @@ -45,6 +46,7 @@ std::string getClangRepositoryPath() { URL = URL.substr(Start + 4); return URL; +#endif } std::string getClangRevision() { @@ -87,4 +89,17 @@ std::string getClangFullVersion() { return OS.str(); } +std::string getClangFullCPPVersion() { + // The version string we report in __VERSION__ is just a compacted version of + // the one we report on the command line. + std::string buf; + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "Clang " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + return OS.str(); +} + } // end namespace clang diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp new file mode 100644 index 0000000..d5cf126 --- /dev/null +++ b/lib/Basic/VersionTuple.cpp @@ -0,0 +1,36 @@ +//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// +// +// 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 VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +std::string VersionTuple::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out, + const VersionTuple &V) { + Out << V.getMajor(); + if (llvm::Optional<unsigned> Minor = V.getMinor()) + Out << '.' << *Minor; + if (llvm::Optional<unsigned> Subminor = V.getSubminor()) + Out << '.' << *Subminor; + return Out; +} |