diff --git a/src/main/native/cpp/llvm/Path.cpp b/src/main/native/cpp/llvm/Path.cpp index 758886119b..b29f6d13f2 100644 --- a/src/main/native/cpp/llvm/Path.cpp +++ b/src/main/native/cpp/llvm/Path.cpp @@ -657,6 +657,143 @@ bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot) { } } // end namespace path + +namespace fs { + +std::error_code getUniqueID(const Twine Path, UniqueID &Result) { + file_status Status; + std::error_code EC = status(Path, Status); + if (EC) + return EC; + Result = Status.getUniqueID(); + return std::error_code(); +} + +static std::error_code make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path, + bool use_current_directory) { + StringRef p(path.data(), path.size()); + + bool rootDirectory = path::has_root_directory(p), +#ifdef _WIN32 + rootName = path::has_root_name(p); +#else + rootName = true; +#endif + + // Already absolute. + if (rootName && rootDirectory) + return std::error_code(); + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + if (use_current_directory) + current_directory.toVector(current_dir); + else if (std::error_code ec = current_path(current_dir)) + return ec; + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + path::append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return std::error_code(); + } + + if (!rootName && rootDirectory) { + StringRef cdrn = path::root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + path::append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return std::error_code(); + } + + if (rootName && !rootDirectory) { + StringRef pRootName = path::root_name(p); + StringRef bRootDirectory = path::root_directory(current_dir); + StringRef bRelativePath = path::relative_path(current_dir); + StringRef pRelativePath = path::relative_path(p); + + SmallString<128> res; + path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return std::error_code(); + } + + assert(false && "All rootName and rootDirectory combinations should have " + "occurred above!"); + return std::error_code(); +} + +std::error_code make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path) { + return make_absolute(current_directory, path, true); +} + +std::error_code make_absolute(SmallVectorImpl &path) { + return make_absolute(Twine(), path, false); +} + +bool exists(file_status status) { + return status_known(status) && status.type() != file_type::file_not_found; +} + +bool status_known(file_status s) { + return s.type() != file_type::status_error; +} + +bool is_directory(file_status status) { + return status.type() == file_type::directory_file; +} + +std::error_code is_directory(const Twine &path, bool &result) { + file_status st; + if (std::error_code ec = status(path, st)) + return ec; + result = is_directory(st); + return std::error_code(); +} + +bool is_regular_file(file_status status) { + return status.type() == file_type::regular_file; +} + +std::error_code is_regular_file(const Twine &path, bool &result) { + file_status st; + if (std::error_code ec = status(path, st)) + return ec; + result = is_regular_file(st); + return std::error_code(); +} + +bool is_other(file_status status) { + return exists(status) && + !is_regular_file(status) && + !is_directory(status); +} + +std::error_code is_other(const Twine &Path, bool &Result) { + file_status FileStatus; + if (std::error_code EC = status(Path, FileStatus)) + return EC; + Result = is_other(FileStatus); + return std::error_code(); +} + +void directory_entry::replace_filename(const Twine &filename, file_status st) { + SmallString<128> path = path::parent_path(Path); + path::append(path, filename); + Path = path.str(); + Status = st; +} + +std::error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result); +} + +} // end namespace fs } // end namespace sys } // end namespace llvm diff --git a/src/main/native/cpp/llvm/Unix/Path.inc b/src/main/native/cpp/llvm/Unix/Path.inc index 94d09e3488..c62fc72bec 100644 --- a/src/main/native/cpp/llvm/Unix/Path.inc +++ b/src/main/native/cpp/llvm/Unix/Path.inc @@ -20,6 +20,10 @@ #include #include #include +#include +#include +#include +#define NAMLEN(dirent) strlen((dirent)->d_name) #include #include #include @@ -27,6 +31,180 @@ namespace llvm { namespace sys { namespace fs { +UniqueID file_status::getUniqueID() const { + return UniqueID(fs_st_dev, fs_st_ino); +} + +std::error_code current_path(SmallVectorImpl &result) { + result.clear(); + + const char *pwd = ::getenv("PWD"); + llvm::sys::fs::file_status PWDStatus, DotStatus; + if (pwd && llvm::sys::path::is_absolute(pwd) && + !llvm::sys::fs::status(pwd, PWDStatus) && + !llvm::sys::fs::status(".", DotStatus) && + PWDStatus.getUniqueID() == DotStatus.getUniqueID()) { + result.append(pwd, pwd + strlen(pwd)); + return std::error_code(); + } + +#ifdef MAXPATHLEN + result.reserve(MAXPATHLEN); +#else + result.reserve(1024); +#endif + + while (true) { + if (::getcwd(result.data(), result.capacity()) == nullptr) { + // See if there was a real error. + if (errno != ENOMEM) + return std::error_code(errno, std::generic_category()); + // Otherwise there just wasn't enough space. + result.reserve(result.capacity() * 2); + } else + break; + } + + result.set_size(strlen(result.data())); + return std::error_code(); +} + +static int convertAccessMode(AccessMode Mode) { + switch (Mode) { + case AccessMode::Exist: + return F_OK; + case AccessMode::Write: + return W_OK; + case AccessMode::Execute: + return R_OK | X_OK; // scripts also need R_OK. + default: + return F_OK; + } +} + +std::error_code access(const Twine &Path, AccessMode Mode) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + if (::access(P.begin(), convertAccessMode(Mode)) == -1) + return std::error_code(errno, std::generic_category()); + + if (Mode == AccessMode::Execute) { + // Don't say that directories are executable. + struct stat buf; + if (0 != stat(P.begin(), &buf)) + return std::make_error_code(std::errc::permission_denied); + if (!S_ISREG(buf.st_mode)) + return std::make_error_code(std::errc::permission_denied); + } + + return std::error_code(); +} + +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.fs_st_dev == B.fs_st_dev && + A.fs_st_ino == B.fs_st_ino; +} + +std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (std::error_code ec = status(A, fsA)) + return ec; + if (std::error_code ec = status(B, fsB)) + return ec; + result = equivalent(fsA, fsB); + return std::error_code(); +} + +static std::error_code fillStatus(int StatRet, const struct stat &Status, + file_status &Result) { + if (StatRet != 0) { + std::error_code ec(errno, std::generic_category()); + if (ec == std::errc::no_such_file_or_directory) + Result = file_status(file_type::file_not_found); + else + Result = file_status(file_type::status_error); + return ec; + } + + file_type Type = file_type::type_unknown; + + if (S_ISDIR(Status.st_mode)) + Type = file_type::directory_file; + else if (S_ISREG(Status.st_mode)) + Type = file_type::regular_file; + else if (S_ISBLK(Status.st_mode)) + Type = file_type::block_file; + else if (S_ISCHR(Status.st_mode)) + Type = file_type::character_file; + else if (S_ISFIFO(Status.st_mode)) + Type = file_type::fifo_file; + else if (S_ISSOCK(Status.st_mode)) + Type = file_type::socket_file; + + perms Perms = static_cast(Status.st_mode); + Result = + file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime, + Status.st_mtime, Status.st_uid, Status.st_gid, + Status.st_size); + + return std::error_code(); +} + +std::error_code status(const Twine &Path, file_status &Result) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + struct stat Status; + int StatRet = ::stat(P.begin(), &Status); + return fillStatus(StatRet, Status, Result); +} + +std::error_code status(int FD, file_status &Result) { + struct stat Status; + int StatRet = ::fstat(FD, &Status); + return fillStatus(StatRet, Status, Result); +} + +std::error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallString<128> path_null(path); + DIR *directory = ::opendir(path_null.c_str()); + if (!directory) + return std::error_code(errno, std::generic_category()); + + it.IterationHandle = reinterpret_cast(directory); + // Add something for replace_filename to replace. + path::append(path_null, "."); + it.CurrentEntry = directory_entry(path_null.str()); + return directory_iterator_increment(it); +} + +std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { + if (it.IterationHandle) + ::closedir(reinterpret_cast(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return std::error_code(); +} + +std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { + errno = 0; + dirent *cur_dir = ::readdir(reinterpret_cast(it.IterationHandle)); + if (cur_dir == nullptr && errno != 0) { + return std::error_code(errno, std::generic_category()); + } else if (cur_dir != nullptr) { + StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + if ((name.size() == 1 && name[0] == '.') || + (name.size() == 2 && name[0] == '.' && name[1] == '.')) + return directory_iterator_increment(it); + it.CurrentEntry.replace_filename(name); + } else + return directory_iterator_destruct(it); + + return std::error_code(); +} #if !defined(F_GETPATH) static bool hasProcSelfFD() { @@ -103,11 +281,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, } } // end namespace fs -} // end namespace sys -} // end namespace llvm -namespace llvm { -namespace sys { namespace path { bool home_directory(SmallVectorImpl &result) { diff --git a/src/main/native/cpp/llvm/Windows/Path.inc b/src/main/native/cpp/llvm/Windows/Path.inc index 52bab57a4f..0c4a6fce13 100644 --- a/src/main/native/cpp/llvm/Windows/Path.inc +++ b/src/main/native/cpp/llvm/Windows/Path.inc @@ -17,22 +17,565 @@ //===----------------------------------------------------------------------===// #include "llvm/STLExtras.h" +#include "llvm/WindowsError.h" #include #include #include #include -#include + +// These two headers must be included last, and make sure shlobj is required +// after Windows.h to make sure it picks up our definition of _WIN32_WINNT +#include "WindowsSupport.h" #include -#include "llvm/WindowsError.h" +#undef max #ifdef _MSC_VER # pragma comment(lib, "shell32.lib") # pragma comment(lib, "ole32.lib") #endif +using namespace llvm; + +using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::UTF16ToUTF8; +using llvm::sys::path::widenPath; + +static bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; + } +} + namespace llvm { namespace sys { +namespace path { + +// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the +// path is longer than CreateDirectory can tolerate, make it absolute and +// prefixed by '\\?\'. +std::error_code widenPath(const Twine &Path8, + SmallVectorImpl &Path16) { + const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. + + // Several operations would convert Path8 to SmallString; more efficient to + // do it once up front. + SmallString<128> Path8Str; + Path8.toVector(Path8Str); + + // If we made this path absolute, how much longer would it get? + size_t CurPathLen; + if (llvm::sys::path::is_absolute(Twine(Path8Str))) + CurPathLen = 0; // No contribution from current_path needed. + else { + CurPathLen = ::GetCurrentDirectoryW(0, NULL); + if (CurPathLen == 0) + return mapWindowsError(::GetLastError()); + } + + // Would the absolute path be longer than our limit? + if ((Path8Str.size() + CurPathLen) >= MaxDirLen && + !Path8Str.startswith("\\\\?\\")) { + SmallString<2*MAX_PATH> FullPath("\\\\?\\"); + if (CurPathLen) { + SmallString<80> CurPath; + if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) + return EC; + FullPath.append(CurPath); + } + // Traverse the requested path, canonicalizing . and .. as we go (because + // the \\?\ prefix is documented to treat them as real components). + // The iterators don't report separators and append() always attaches + // preferred_separator so we don't need to call native() on the result. + for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), + E = llvm::sys::path::end(Path8Str); + I != E; ++I) { + if (I->size() == 1 && *I == ".") + continue; + if (I->size() == 2 && *I == "..") + llvm::sys::path::remove_filename(FullPath); + else + llvm::sys::path::append(FullPath, *I); + } + return UTF8ToUTF16(FullPath, Path16); + } + + // Just use the caller's original path. + return UTF8ToUTF16(Path8Str, Path16); +} +} // end namespace path + +namespace fs { + +UniqueID file_status::getUniqueID() const { + // The file is uniquely identified by the volume serial number along + // with the 64-bit file identifier. + uint64_t FileID = (static_cast(FileIndexHigh) << 32ULL) | + static_cast(FileIndexLow); + + return UniqueID(VolumeSerialNumber, FileID); +} + +std::error_code current_path(SmallVectorImpl &result) { + SmallVector cur_path; + DWORD len = MAX_PATH; + + do { + cur_path.reserve(len); + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return mapWindowsError(::GetLastError()); + + // If there's insufficient space, the len returned is larger than the len + // given. + } while (len > cur_path.capacity()); + + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. + cur_path.set_size(len); + return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); +} + + +std::error_code access(const Twine &Path, AccessMode Mode) { + SmallVector PathUtf16; + + if (std::error_code EC = widenPath(Path, PathUtf16)) + return EC; + + DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); + + if (Attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && + LastError != ERROR_PATH_NOT_FOUND) + return mapWindowsError(LastError); + return std::make_error_code(std::errc::no_such_file_or_directory); + } + + if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) + return std::make_error_code(std::errc::permission_denied); + + return std::error_code(); +} + +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.FileIndexHigh == B.FileIndexHigh && + A.FileIndexLow == B.FileIndexLow && + A.FileSizeHigh == B.FileSizeHigh && + A.FileSizeLow == B.FileSizeLow && + A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && + A.LastAccessedTimeLow == B.LastAccessedTimeLow && + A.LastWriteTimeHigh == B.LastWriteTimeHigh && + A.LastWriteTimeLow == B.LastWriteTimeLow && + A.VolumeSerialNumber == B.VolumeSerialNumber; +} + +std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (std::error_code ec = status(A, fsA)) + return ec; + if (std::error_code ec = status(B, fsB)) + return ec; + result = equivalent(fsA, fsB); + return std::error_code(); +} + +static bool isReservedName(StringRef path) { + // This list of reserved names comes from MSDN, at: + // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", + "com1", "com2", "com3", "com4", + "com5", "com6", "com7", "com8", + "com9", "lpt1", "lpt2", "lpt3", + "lpt4", "lpt5", "lpt6", "lpt7", + "lpt8", "lpt9" }; + + // First, check to see if this is a device namespace, which always + // starts with \\.\, since device namespaces are not legal file paths. + if (path.startswith("\\\\.\\")) + return true; + + // Then compare against the list of ancient reserved names. + for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { + if (path.equals_lower(sReservedNames[i])) + return true; + } + + // The path isn't what we consider reserved. + return false; +} + +static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { + if (FileHandle == INVALID_HANDLE_VALUE) + goto handle_status_error; + + switch (::GetFileType(FileHandle)) { + default: + Result = file_status(file_type::type_unknown); + return std::error_code(); + case FILE_TYPE_UNKNOWN: { + DWORD Err = ::GetLastError(); + if (Err != NO_ERROR) + return mapWindowsError(Err); + Result = file_status(file_type::type_unknown); + return std::error_code(); + } + case FILE_TYPE_DISK: + break; + case FILE_TYPE_CHAR: + Result = file_status(file_type::character_file); + return std::error_code(); + case FILE_TYPE_PIPE: + Result = file_status(file_type::fifo_file); + return std::error_code(); + } + + BY_HANDLE_FILE_INFORMATION Info; + if (!::GetFileInformationByHandle(FileHandle, &Info)) + goto handle_status_error; + + { + file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? file_type::directory_file + : file_type::regular_file; + Result = + file_status(Type, Info.ftLastAccessTime.dwHighDateTime, + Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, + Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, + Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); + return std::error_code(); + } + +handle_status_error: + DWORD LastError = ::GetLastError(); + if (LastError == ERROR_FILE_NOT_FOUND || + LastError == ERROR_PATH_NOT_FOUND) + Result = file_status(file_type::file_not_found); + else if (LastError == ERROR_SHARING_VIOLATION) + Result = file_status(file_type::type_unknown); + else + Result = file_status(file_type::status_error); + return mapWindowsError(LastError); +} + +std::error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + SmallVector path_utf16; + + StringRef path8 = path.toStringRef(path_storage); + if (isReservedName(path8)) { + result = file_status(file_type::character_file); + return std::error_code(); + } + + if (std::error_code ec = widenPath(path8, path_utf16)) + return ec; + + DWORD attr = ::GetFileAttributesW(path_utf16.begin()); + if (attr == INVALID_FILE_ATTRIBUTES) + return getStatus(INVALID_HANDLE_VALUE, result); + + // Handle reparse points. + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), + 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); + } + + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); + + return getStatus(h, result); +} + +std::error_code status(int FD, file_status &Result) { + HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); + return getStatus(FileHandle, Result); +} + +std::error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallVector path_utf16; + + if (std::error_code ec = widenPath(path, path_utf16)) + return ec; + + // Convert path to the format that Windows is happy with. + if (path_utf16.size() > 0 && + !is_separator(path_utf16[path.size() - 1]) && + path_utf16[path.size() - 1] != L':') { + path_utf16.push_back(L'\\'); + path_utf16.push_back(L'*'); + } else { + path_utf16.push_back(L'*'); + } + + // Get the first directory entry. + WIN32_FIND_DATAW FirstFind; + ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); + if (!FindHandle) + return mapWindowsError(::GetLastError()); + + size_t FilenameLen = ::wcslen(FirstFind.cFileName); + while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || + (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && + FirstFind.cFileName[1] == L'.')) + if (!::FindNextFileW(FindHandle, &FirstFind)) { + DWORD LastError = ::GetLastError(); + // Check for end. + if (LastError == ERROR_NO_MORE_FILES) + return detail::directory_iterator_destruct(it); + return mapWindowsError(LastError); + } else + FilenameLen = ::wcslen(FirstFind.cFileName); + + // Construct the current directory entry. + SmallString<128> directory_entry_name_utf8; + if (std::error_code ec = + UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), + directory_entry_name_utf8)) + return ec; + + it.IterationHandle = intptr_t(FindHandle.take()); + SmallString<128> directory_entry_path(path); + path::append(directory_entry_path, directory_entry_name_utf8); + it.CurrentEntry = directory_entry(directory_entry_path); + + return std::error_code(); +} + +std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { + if (it.IterationHandle != 0) + // Closes the handle if it's valid. + ScopedFindHandle close(HANDLE(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return std::error_code(); +} + +std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { + WIN32_FIND_DATAW FindData; + if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { + DWORD LastError = ::GetLastError(); + // Check for end. + if (LastError == ERROR_NO_MORE_FILES) + return detail::directory_iterator_destruct(it); + return mapWindowsError(LastError); + } + + size_t FilenameLen = ::wcslen(FindData.cFileName); + if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || + (FilenameLen == 2 && FindData.cFileName[0] == L'.' && + FindData.cFileName[1] == L'.')) + return directory_iterator_increment(it); + + SmallString<128> directory_entry_path_utf8; + if (std::error_code ec = + UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), + directory_entry_path_utf8)) + return ec; + + it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); + return std::error_code(); +} + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + SmallVectorImpl *RealPath) { + SmallVector PathUTF16; + + if (std::error_code EC = widenPath(Name, PathUTF16)) + return EC; + + HANDLE H = + ::CreateFileW(PathUTF16.begin(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (H == INVALID_HANDLE_VALUE) { + DWORD LastError = ::GetLastError(); + std::error_code EC = mapWindowsError(LastError); + // Provide a better error message when trying to open directories. + // This only runs if we failed to open the file, so there is probably + // no performances issues. + if (LastError != ERROR_ACCESS_DENIED) + return EC; + if (is_directory(Name)) + return std::make_error_code(std::errc::is_a_directory); + return EC; + } + + int FD = ::_open_osfhandle(intptr_t(H), 0); + if (FD == -1) { + ::CloseHandle(H); + return mapWindowsError(ERROR_INVALID_HANDLE); + } + + // Fetch the real name of the file, if the user asked + if (RealPath) { + RealPath->clear(); + wchar_t RealPathUTF16[MAX_PATH]; + DWORD CountChars = + ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, + FILE_NAME_NORMALIZED); + if (CountChars > 0 && CountChars < MAX_PATH) { + // Convert the result from UTF-16 to UTF-8. + SmallString RealPathUTF8; + if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) + RealPath->append(RealPathUTF8.data(), + RealPathUTF8.data() + strlen(RealPathUTF8.data())); + } + } + + ResultFD = FD; + return std::error_code(); +} + +std::error_code openFileForWrite(const Twine &Name, int &ResultFD, + OpenFlags Flags, unsigned Mode) { + // Verify that we don't have both "append" and "excl". + assert((!(Flags & F_Excl) || !(Flags & F_Append)) && + "Cannot specify both 'excl' and 'append' file creation flags!"); + + SmallVector PathUTF16; + + if (std::error_code EC = widenPath(Name, PathUTF16)) + return EC; + + DWORD CreationDisposition; + if (Flags & F_Excl) + CreationDisposition = CREATE_NEW; + else if (Flags & F_Append) + CreationDisposition = OPEN_ALWAYS; + else + CreationDisposition = CREATE_ALWAYS; + + DWORD Access = GENERIC_WRITE; + if (Flags & F_RW) + Access |= GENERIC_READ; + + HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + + if (H == INVALID_HANDLE_VALUE) { + DWORD LastError = ::GetLastError(); + std::error_code EC = mapWindowsError(LastError); + // Provide a better error message when trying to open directories. + // This only runs if we failed to open the file, so there is probably + // no performances issues. + if (LastError != ERROR_ACCESS_DENIED) + return EC; + if (is_directory(Name)) + return std::make_error_code(std::errc::is_a_directory); + return EC; + } + + int OpenFlags = 0; + if (Flags & F_Append) + OpenFlags |= _O_APPEND; + + if (Flags & F_Text) + OpenFlags |= _O_TEXT; + + int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); + if (FD == -1) { + ::CloseHandle(H); + return mapWindowsError(ERROR_INVALID_HANDLE); + } + + ResultFD = FD; + return std::error_code(); +} + +} // end namespace fs + +namespace path { +static bool getKnownFolderPath(KNOWNFOLDERID folderId, + SmallVectorImpl &result) { + wchar_t *path = nullptr; + if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) + return false; + + bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); + ::CoTaskMemFree(path); + return ok; +} + +bool getUserCacheDir(SmallVectorImpl &Result) { + return getKnownFolderPath(FOLDERID_LocalAppData, Result); +} + +bool home_directory(SmallVectorImpl &result) { + return getKnownFolderPath(FOLDERID_Profile, result); +} + +static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { + SmallVector Buf; + size_t Size = 1024; + do { + Buf.reserve(Size); + Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); + if (Size == 0) + return false; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + return !windows::UTF16ToUTF8(Buf.data(), Size, Res); +} + +static bool getTempDirEnvVar(SmallVectorImpl &Res) { + const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; + for (auto *Env : EnvironmentVariables) { + if (getTempDirEnvVar(Env, Res)) + return true; + } + return false; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { + (void)ErasedOnReboot; + Result.clear(); + + // Check whether the temporary directory is specified by an environment var. + // This matches GetTempPath logic to some degree. GetTempPath is not used + // directly as it cannot handle evn var longer than 130 chars on Windows 7 + // (fixed on Windows 8). + if (getTempDirEnvVar(Result)) { + assert(!Result.empty() && "Unexpected empty path"); + native(Result); // Some Unix-like shells use Unix path separator in $TMP. + fs::make_absolute(Result); // Make it absolute if not already. + return; + } + + // Fall back to a system default. + const char *DefaultResult = "C:\\Temp"; + Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} +} // end namespace path + namespace windows { std::error_code UTF8ToUTF16(llvm::StringRef utf8, llvm::SmallVectorImpl &utf16) { @@ -101,270 +644,5 @@ std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, } } // end namespace windows - -using llvm::sys::windows::UTF8ToUTF16; -using llvm::sys::windows::UTF16ToUTF8; - -namespace fs { - -std::error_code current_path(SmallVectorImpl &result) { - SmallVector cur_path; - DWORD len = MAX_PATH; - - do { - cur_path.reserve(len); - len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return mapWindowsError(::GetLastError()); - - // If there's insufficient space, the len returned is larger than the len - // given. - } while (len > cur_path.capacity()); - - // On success, GetCurrentDirectoryW returns the number of characters not - // including the null-terminator. - cur_path.set_size(len); - return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); -} - -} // end namespace fs - -namespace path { - -// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the -// path is longer than CreateDirectory can tolerate, make it absolute and -// prefixed by '\\?\'. -std::error_code widenPath(const Twine &Path8, - SmallVectorImpl &Path16) { - const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. - - // Several operations would convert Path8 to SmallString; more efficient to - // do it once up front. - SmallString<128> Path8Str; - Path8.toVector(Path8Str); - - // If we made this path absolute, how much longer would it get? - size_t CurPathLen; - if (llvm::sys::path::is_absolute(Twine(Path8Str))) - CurPathLen = 0; // No contribution from current_path needed. - else { - CurPathLen = ::GetCurrentDirectoryW(0, NULL); - if (CurPathLen == 0) - return mapWindowsError(::GetLastError()); - } - - // Would the absolute path be longer than our limit? - if ((Path8Str.size() + CurPathLen) >= MaxDirLen && - !Path8Str.startswith("\\\\?\\")) { - SmallString<2*MAX_PATH> FullPath("\\\\?\\"); - if (CurPathLen) { - SmallString<80> CurPath; - if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) - return EC; - FullPath.append(CurPath); - } - // Traverse the requested path, canonicalizing . and .. as we go (because - // the \\?\ prefix is documented to treat them as real components). - // The iterators don't report separators and append() always attaches - // preferred_separator so we don't need to call native() on the result. - for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), - E = llvm::sys::path::end(Path8Str); - I != E; ++I) { - if (I->size() == 1 && *I == ".") - continue; - if (I->size() == 2 && *I == "..") - llvm::sys::path::remove_filename(FullPath); - else - llvm::sys::path::append(FullPath, *I); - } - return UTF8ToUTF16(FullPath, Path16); - } - - // Just use the caller's original path. - return UTF8ToUTF16(Path8Str, Path16); -} -} // end namespace path - -using llvm::sys::path::widenPath; - -namespace fs { - -std::error_code openFileForRead(const Twine &Name, int &ResultFD, - SmallVectorImpl *RealPath) { - SmallVector PathUTF16; - - if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; - - HANDLE H = - ::CreateFileW(PathUTF16.begin(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (H == INVALID_HANDLE_VALUE) { - DWORD LastError = ::GetLastError(); - std::error_code EC = mapWindowsError(LastError); - // Provide a better error message when trying to open directories. - // This only runs if we failed to open the file, so there is probably - // no performances issues. - //if (LastError != ERROR_ACCESS_DENIED) - // return EC; - //if (is_directory(Name)) - // return make_error_code(errc::is_a_directory); - return EC; - } - - int FD = ::_open_osfhandle(intptr_t(H), 0); - if (FD == -1) { - ::CloseHandle(H); - return mapWindowsError(ERROR_INVALID_HANDLE); - } - - // Fetch the real name of the file, if the user asked - if (RealPath) { - RealPath->clear(); - wchar_t RealPathUTF16[MAX_PATH]; - DWORD CountChars = - ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, - FILE_NAME_NORMALIZED); - if (CountChars > 0 && CountChars < MAX_PATH) { - // Convert the result from UTF-16 to UTF-8. - SmallString RealPathUTF8; - if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) - RealPath->append(RealPathUTF8.data(), - RealPathUTF8.data() + strlen(RealPathUTF8.data())); - } - } - - ResultFD = FD; - return std::error_code(); -} - -std::error_code openFileForWrite(const Twine &Name, int &ResultFD, - OpenFlags Flags, unsigned Mode) { - // Verify that we don't have both "append" and "excl". - assert((!(Flags & F_Excl) || !(Flags & F_Append)) && - "Cannot specify both 'excl' and 'append' file creation flags!"); - - SmallVector PathUTF16; - - if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; - - DWORD CreationDisposition; - if (Flags & F_Excl) - CreationDisposition = CREATE_NEW; - else if (Flags & F_Append) - CreationDisposition = OPEN_ALWAYS; - else - CreationDisposition = CREATE_ALWAYS; - - DWORD Access = GENERIC_WRITE; - if (Flags & F_RW) - Access |= GENERIC_READ; - - HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - - if (H == INVALID_HANDLE_VALUE) { - DWORD LastError = ::GetLastError(); - std::error_code EC = mapWindowsError(LastError); - // Provide a better error message when trying to open directories. - // This only runs if we failed to open the file, so there is probably - // no performances issues. - //if (LastError != ERROR_ACCESS_DENIED) - // return EC; - //if (is_directory(Name)) - // return make_error_code(errc::is_a_directory); - return EC; - } - - int OpenFlags = 0; - if (Flags & F_Append) - OpenFlags |= _O_APPEND; - - if (Flags & F_Text) - OpenFlags |= _O_TEXT; - - int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); - if (FD == -1) { - ::CloseHandle(H); - return mapWindowsError(ERROR_INVALID_HANDLE); - } - - ResultFD = FD; - return std::error_code(); -} - -} // end namespace fs - -namespace path { - -static bool getKnownFolderPath(KNOWNFOLDERID folderId, - SmallVectorImpl &result) { - wchar_t *path = nullptr; - if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) - return false; - - bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); - ::CoTaskMemFree(path); - return ok; -} - -bool getUserCacheDir(SmallVectorImpl &Result) { - return getKnownFolderPath(FOLDERID_LocalAppData, Result); -} - -bool home_directory(SmallVectorImpl &result) { - return getKnownFolderPath(FOLDERID_Profile, result); -} - -static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { - SmallVector Buf; - size_t Size = 1024; - do { - Buf.reserve(Size); - Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); - if (Size == 0) - return false; - - // Try again with larger buffer. - } while (Size > Buf.capacity()); - Buf.set_size(Size); - - return !windows::UTF16ToUTF8(Buf.data(), Size, Res); -} - -static bool getTempDirEnvVar(SmallVectorImpl &Res) { - const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; - for (auto *Env : EnvironmentVariables) { - if (getTempDirEnvVar(Env, Res)) - return true; - } - return false; -} - -void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { - (void)ErasedOnReboot; - Result.clear(); - - // Check whether the temporary directory is specified by an environment var. - // This matches GetTempPath logic to some degree. GetTempPath is not used - // directly as it cannot handle evn var longer than 130 chars on Windows 7 - // (fixed on Windows 8). - if (getTempDirEnvVar(Result)) { - assert(!Result.empty() && "Unexpected empty path"); - native(Result); // Some Unix-like shells use Unix path separator in $TMP. - //fs::make_absolute(Result); // Make it absolute if not already. - return; - } - - // Fall back to a system default. - const char *DefaultResult = "C:\\Temp"; - Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); -} -} // end namespace path } // end namespace sys } // end namespace llvm diff --git a/src/main/native/cpp/llvm/Windows/WindowsSupport.h b/src/main/native/cpp/llvm/Windows/WindowsSupport.h new file mode 100644 index 0000000000..fd820e7582 --- /dev/null +++ b/src/main/native/cpp/llvm/Windows/WindowsSupport.h @@ -0,0 +1,211 @@ +//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Windows implementations. In addition to +// providing some helpers for working with win32 APIs, this header wraps +// with some portability macros. Always include WindowsSupport.h +// instead of including directly. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H +#define LLVM_SUPPORT_WINDOWSSUPPORT_H + +// mingw-w64 tends to define it as 0x0502 in its headers. +#undef _WIN32_WINNT +#undef _WIN32_IE + +// Require at least Windows 7 API. +#define _WIN32_WINNT 0x0601 +#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed. +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include "llvm/SmallVector.h" +#include "llvm/StringExtras.h" +#include "llvm/StringRef.h" +#include "llvm/Twine.h" +#include "llvm/Compiler.h" +#include +#include +#include +#include + +/// Determines if the program is running on Windows 8 or newer. This +/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended +/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't +/// yet have VersionHelpers.h, so we have our own helper. +inline bool RunningWindows8OrGreater() { + // Windows 8 is version 6.2, service pack 0. + OSVERSIONINFOEXW osvi = {}; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + osvi.dwMajorVersion = 6; + osvi.dwMinorVersion = 2; + osvi.wServicePackMajor = 0; + + DWORDLONG Mask = 0; + Mask = VerSetConditionMask(Mask, VER_MAJORVERSION, VER_GREATER_EQUAL); + Mask = VerSetConditionMask(Mask, VER_MINORVERSION, VER_GREATER_EQUAL); + Mask = VerSetConditionMask(Mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR, + Mask) != FALSE; +} + +inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { + if (!ErrMsg) + return true; + char *buffer = NULL; + DWORD LastError = GetLastError(); + DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); + if (R) + *ErrMsg = prefix + ": " + buffer; + else + *ErrMsg = prefix + ": Unknown error"; + *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")"; + + LocalFree(buffer); + return R != 0; +} + +template +class ScopedHandle { + typedef typename HandleTraits::handle_type handle_type; + handle_type Handle; + + ScopedHandle(const ScopedHandle &other); // = delete; + void operator=(const ScopedHandle &other); // = delete; +public: + ScopedHandle() + : Handle(HandleTraits::GetInvalid()) {} + + explicit ScopedHandle(handle_type h) + : Handle(h) {} + + ~ScopedHandle() { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + } + + handle_type take() { + handle_type t = Handle; + Handle = HandleTraits::GetInvalid(); + return t; + } + + ScopedHandle &operator=(handle_type h) { + if (HandleTraits::IsValid(Handle)) + HandleTraits::Close(Handle); + Handle = h; + return *this; + } + + // True if Handle is valid. + explicit operator bool() const { + return HandleTraits::IsValid(Handle) ? true : false; + } + + operator handle_type() const { + return Handle; + } +}; + +struct CommonHandleTraits { + typedef HANDLE handle_type; + + static handle_type GetInvalid() { + return INVALID_HANDLE_VALUE; + } + + static void Close(handle_type h) { + ::CloseHandle(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct JobHandleTraits : CommonHandleTraits { + static handle_type GetInvalid() { + return NULL; + } +}; + +struct RegTraits : CommonHandleTraits { + typedef HKEY handle_type; + + static handle_type GetInvalid() { + return NULL; + } + + static void Close(handle_type h) { + ::RegCloseKey(h); + } + + static bool IsValid(handle_type h) { + return h != GetInvalid(); + } +}; + +struct FindHandleTraits : CommonHandleTraits { + static void Close(handle_type h) { + ::FindClose(h); + } +}; + +struct FileHandleTraits : CommonHandleTraits {}; + +typedef ScopedHandle ScopedCommonHandle; +typedef ScopedHandle ScopedFileHandle; +typedef ScopedHandle ScopedRegHandle; +typedef ScopedHandle ScopedFindHandle; +typedef ScopedHandle ScopedJobHandle; + +namespace llvm { +template +class SmallVectorImpl; + +template +typename SmallVectorImpl::const_pointer +c_str(SmallVectorImpl &str) { + str.push_back(0); + str.pop_back(); + return str.data(); +} + +namespace sys { +namespace path { +std::error_code widenPath(const Twine &Path8, + SmallVectorImpl &Path16); +} // end namespace path + +namespace windows { +std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl &utf16); +std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl &utf8); +/// Convert from UTF16 to the current code page used in the system +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl &utf8); +} // end namespace windows +} // end namespace sys +} // end namespace llvm. + +#endif diff --git a/src/main/native/cpp/llvm/raw_ostream.cpp b/src/main/native/cpp/llvm/raw_ostream.cpp index de5d8e7ae5..3fab800b79 100644 --- a/src/main/native/cpp/llvm/raw_ostream.cpp +++ b/src/main/native/cpp/llvm/raw_ostream.cpp @@ -50,30 +50,7 @@ #endif #if defined(_WIN32) -#include - -/// Determines if the program is running on Windows 8 or newer. This -/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended -/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't -/// yet have VersionHelpers.h, so we have our own helper. -static inline bool RunningWindows8OrGreater() { - // Windows 8 is version 6.2, service pack 0. - OSVERSIONINFOEXW osvi = {}; - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - osvi.dwMajorVersion = 6; - osvi.dwMinorVersion = 2; - osvi.wServicePackMajor = 0; - - DWORDLONG Mask = 0; - Mask = VerSetConditionMask(Mask, VER_MAJORVERSION, VER_GREATER_EQUAL); - Mask = VerSetConditionMask(Mask, VER_MINORVERSION, VER_GREATER_EQUAL); - Mask = VerSetConditionMask(Mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR, - Mask) != FALSE; -} - +#include "Windows/WindowsSupport.h" #endif using namespace llvm; diff --git a/src/main/native/include/llvm/FileSystem.h b/src/main/native/include/llvm/FileSystem.h index c3feb10bf0..c45afc877a 100644 --- a/src/main/native/include/llvm/FileSystem.h +++ b/src/main/native/include/llvm/FileSystem.h @@ -27,19 +27,388 @@ #ifndef LLVM_SUPPORT_FILESYSTEM_H #define LLVM_SUPPORT_FILESYSTEM_H +#include "llvm/IntrusiveRefCntPtr.h" +#include "llvm/SmallString.h" #include "llvm/Twine.h" + +#include + +#include +#include #include +#include +#include namespace llvm { - -template class SmallVectorImpl; - namespace sys { namespace fs { +/// An enumeration for the file system's view of the type. +enum class file_type { + status_error, + file_not_found, + regular_file, + directory_file, + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + type_unknown +}; + +enum perms { + no_perms = 0, + owner_read = 0400, + owner_write = 0200, + owner_exe = 0100, + owner_all = owner_read | owner_write | owner_exe, + group_read = 040, + group_write = 020, + group_exe = 010, + group_all = group_read | group_write | group_exe, + others_read = 04, + others_write = 02, + others_exe = 01, + others_all = others_read | others_write | others_exe, + all_read = owner_read | group_read | others_read, + all_write = owner_write | group_write | others_write, + all_exe = owner_exe | group_exe | others_exe, + all_all = owner_all | group_all | others_all, + set_uid_on_exe = 04000, + set_gid_on_exe = 02000, + sticky_bit = 01000, + perms_not_known = 0xFFFF +}; + +// Helper functions so that you can use & and | to manipulate perms bits: +inline perms operator|(perms l, perms r) { + return static_cast(static_cast(l) | + static_cast(r)); +} +inline perms operator&(perms l, perms r) { + return static_cast(static_cast(l) & + static_cast(r)); +} +inline perms &operator|=(perms &l, perms r) { + l = l | r; + return l; +} +inline perms &operator&=(perms &l, perms r) { + l = l & r; + return l; +} +inline perms operator~(perms x) { + return static_cast( + static_cast(~static_cast(x))); +} + +class UniqueID { + uint64_t Device; + uint64_t File; + +public: + UniqueID() = default; + UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} + bool operator==(const UniqueID &Other) const { + return Device == Other.Device && File == Other.File; + } + bool operator!=(const UniqueID &Other) const { return !(*this == Other); } + bool operator<(const UniqueID &Other) const { + return std::tie(Device, File) < std::tie(Other.Device, Other.File); + } + uint64_t getDevice() const { return Device; } + uint64_t getFile() const { return File; } +}; + +/// file_status - Represents the result of a call to stat and friends. It has +/// a platform-specific member to store the result. +class file_status +{ + #ifdef _WIN32 + uint32_t LastAccessedTimeHigh; + uint32_t LastAccessedTimeLow; + uint32_t LastWriteTimeHigh; + uint32_t LastWriteTimeLow; + uint32_t VolumeSerialNumber; + uint32_t FileSizeHigh; + uint32_t FileSizeLow; + uint32_t FileIndexHigh; + uint32_t FileIndexLow; + #else + dev_t fs_st_dev; + ino_t fs_st_ino; + time_t fs_st_atime; + time_t fs_st_mtime; + uid_t fs_st_uid; + gid_t fs_st_gid; + off_t fs_st_size; + #endif + friend bool equivalent(file_status A, file_status B); + file_type Type; + perms Perms; + +public: + #ifdef _WIN32 + file_status() + : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0), + LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0), + FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), + Type(file_type::status_error), Perms(perms_not_known) {} + + file_status(file_type Type) + : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0), + LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0), + FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type), + Perms(perms_not_known) {} + + file_status(file_type Type, uint32_t LastAccessTimeHigh, + uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh, + uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, + uint32_t FileSizeHigh, uint32_t FileSizeLow, + uint32_t FileIndexHigh, uint32_t FileIndexLow) + : LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow), + LastWriteTimeHigh(LastWriteTimeHigh), + LastWriteTimeLow(LastWriteTimeLow), + VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), + FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), + FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} + #else + file_status() + : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0), + fs_st_uid(0), fs_st_gid(0), fs_st_size(0), + Type(file_type::status_error), Perms(perms_not_known) {} + + file_status(file_type Type) + : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0), + fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type), + Perms(perms_not_known) {} + + file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime, + time_t MTime, uid_t UID, gid_t GID, off_t Size) + : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_atime(ATime), fs_st_mtime(MTime), + fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type), + Perms(Perms) {} + #endif + + // getters + file_type type() const { return Type; } + perms permissions() const { return Perms; } + UniqueID getUniqueID() const; + + #ifdef _WIN32 + uint32_t getUser() const { + return 9999; // Not applicable to Windows, so... + } + uint32_t getGroup() const { + return 9999; // Not applicable to Windows, so... + } + uint64_t getSize() const { + return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; + } + #else + uint32_t getUser() const { return fs_st_uid; } + uint32_t getGroup() const { return fs_st_gid; } + uint64_t getSize() const { return fs_st_size; } + #endif + + // setters + void type(file_type v) { Type = v; } + void permissions(perms p) { Perms = p; } +}; + +/// @} +/// @name Physical Operators +/// @{ + +/// @brief Make \a path an absolute path. +/// +/// Makes \a path absolute using the \a current_directory if it is not already. +/// An empty \a path will result in the \a current_directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => /relative/../path +/// +/// @param path A path that is modified to be an absolute path. +/// @returns errc::success if \a path has been made absolute, otherwise a +/// platform-specific error_code. +std::error_code make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path); + +/// @brief Make \a path an absolute path. +/// +/// Makes \a path absolute using the current directory if it is not already. An +/// empty \a path will result in the current directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => /relative/../path +/// +/// @param path A path that is modified to be an absolute path. +/// @returns errc::success if \a path has been made absolute, otherwise a +/// platform-specific error_code. +std::error_code make_absolute(SmallVectorImpl &path); + +/// @brief Get the current path. +/// +/// @param result Holds the current path on return. +/// @returns errc::success if the current path has been stored in result, +/// otherwise a platform-specific error_code. +std::error_code current_path(SmallVectorImpl &result); + +/// @} /// @name Physical Observers /// @{ +/// @brief Does file exist? +/// +/// @param status A file_status previously returned from stat. +/// @returns True if the file represented by status exists, false if it does +/// not. +bool exists(file_status status); + +enum class AccessMode { Exist, Write, Execute }; + +/// @brief Can the file be accessed? +/// +/// @param Path Input path. +/// @returns errc::success if the path can be accessed, otherwise a +/// platform-specific error_code. +std::error_code access(const Twine &Path, AccessMode Mode); + +/// @brief Does file exist? +/// +/// @param Path Input path. +/// @returns True if it exists, false otherwise. +inline bool exists(const Twine &Path) { + return !access(Path, AccessMode::Exist); +} + +/// @brief Can we write this file? +/// +/// @param Path Input path. +/// @returns True if we can write to it, false otherwise. +inline bool can_write(const Twine &Path) { + return !access(Path, AccessMode::Write); +} + +/// @brief Do file_status's represent the same thing? +/// +/// @param A Input file_status. +/// @param B Input file_status. +/// +/// assert(status_known(A) || status_known(B)); +/// +/// @returns True if A and B both represent the same file system entity, false +/// otherwise. +bool equivalent(file_status A, file_status B); + +/// @brief Do paths represent the same thing? +/// +/// assert(status_known(A) || status_known(B)); +/// +/// @param A Input path A. +/// @param B Input path B. +/// @param result Set to true if stat(A) and stat(B) have the same device and +/// inode (or equivalent). +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code equivalent(const Twine &A, const Twine &B, bool &result); + +/// @brief Simpler version of equivalent for clients that don't need to +/// differentiate between an error and false. +inline bool equivalent(const Twine &A, const Twine &B) { + bool result; + return !equivalent(A, B, result) && result; +} + +/// @brief Does status represent a directory? +/// +/// @param status A file_status previously returned from status. +/// @returns status.type() == file_type::directory_file. +bool is_directory(file_status status); + +/// @brief Is path a directory? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a directory, false if it is not. +/// Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_directory(const Twine &path, bool &result); + +/// @brief Simpler version of is_directory for clients that don't need to +/// differentiate between an error and false. +inline bool is_directory(const Twine &Path) { + bool Result; + return !is_directory(Path, Result) && Result; +} + +/// @brief Does status represent a regular file? +/// +/// @param status A file_status previously returned from status. +/// @returns status_known(status) && status.type() == file_type::regular_file. +bool is_regular_file(file_status status); + +/// @brief Is path a regular file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a regular file, false if it is not. +/// Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_regular_file(const Twine &path, bool &result); + +/// @brief Simpler version of is_regular_file for clients that don't need to +/// differentiate between an error and false. +inline bool is_regular_file(const Twine &Path) { + bool Result; + if (is_regular_file(Path, Result)) + return false; + return Result; +} + +/// @brief Does this status represent something that exists but is not a +/// directory, regular file, or symlink? +/// +/// @param status A file_status previously returned from status. +/// @returns exists(s) && !is_regular_file(s) && !is_directory(s) +bool is_other(file_status status); + +/// @brief Is path something that exists but is not a directory, +/// regular file, or symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path exists, but is not a directory, regular +/// file, or a symlink, false if it does not. Undefined otherwise. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code is_other(const Twine &path, bool &result); + +/// @brief Get file status as if by POSIX stat(). +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code status(const Twine &path, file_status &result); + +/// @brief A version for when a file descriptor is already available. +std::error_code status(int FD, file_status &Result); + +/// @brief Is status available? +/// +/// @param s Input file status. +/// @returns True if status() != status_error. +bool status_known(file_status s); + +/// @brief Is status available? +/// +/// @param path Input path. +/// @param result Set to true if status() != status_error. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform-specific error_code. +std::error_code status_known(const Twine &path, bool &result); + enum OpenFlags : unsigned { F_None = 0, @@ -74,6 +443,221 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, std::error_code openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl *RealPath = nullptr); +std::error_code getUniqueID(const Twine Path, UniqueID &Result); + +/// @} +/// @name Iterators +/// @{ + +/// directory_entry - A single entry in a directory. Caches the status either +/// from the result of the iteration syscall, or the first time status is +/// called. +class directory_entry { + std::string Path; + mutable file_status Status; + +public: + explicit directory_entry(const Twine &path, file_status st = file_status()) + : Path(path.str()) + , Status(st) {} + + directory_entry() {} + + void assign(const Twine &path, file_status st = file_status()) { + Path = path.str(); + Status = st; + } + + void replace_filename(const Twine &filename, file_status st = file_status()); + + const std::string &path() const { return Path; } + std::error_code status(file_status &result) const; + + bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } + bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } + bool operator< (const directory_entry& rhs) const; + bool operator<=(const directory_entry& rhs) const; + bool operator> (const directory_entry& rhs) const; + bool operator>=(const directory_entry& rhs) const; +}; + +namespace detail { + struct DirIterState; + + std::error_code directory_iterator_construct(DirIterState &, StringRef); + std::error_code directory_iterator_increment(DirIterState &); + std::error_code directory_iterator_destruct(DirIterState &); + + /// DirIterState - Keeps state for the directory_iterator. It is reference + /// counted in order to preserve InputIterator semantics on copy. + struct DirIterState : public RefCountedBase { + DirIterState() + : IterationHandle(0) {} + + ~DirIterState() { + directory_iterator_destruct(*this); + } + + intptr_t IterationHandle; + directory_entry CurrentEntry; + }; +} // end namespace detail + +/// directory_iterator - Iterates through the entries in path. There is no +/// operator++ because we need an error_code. If it's really needed we can make +/// it call report_fatal_error on error. +class directory_iterator { + IntrusiveRefCntPtr State; + +public: + explicit directory_iterator(const Twine &path, std::error_code &ec) { + State = new detail::DirIterState; + SmallString<128> path_storage; + ec = detail::directory_iterator_construct(*State, + path.toStringRef(path_storage)); + } + + explicit directory_iterator(const directory_entry &de, std::error_code &ec) { + State = new detail::DirIterState; + ec = detail::directory_iterator_construct(*State, de.path()); + } + + /// Construct end iterator. + directory_iterator() : State(nullptr) {} + + // No operator++ because we need error_code. + directory_iterator &increment(std::error_code &ec) { + ec = directory_iterator_increment(*State); + return *this; + } + + const directory_entry &operator*() const { return State->CurrentEntry; } + const directory_entry *operator->() const { return &State->CurrentEntry; } + + bool operator==(const directory_iterator &RHS) const { + if (State == RHS.State) + return true; + if (!RHS.State) + return State->CurrentEntry == directory_entry(); + if (!State) + return RHS.State->CurrentEntry == directory_entry(); + return State->CurrentEntry == RHS.State->CurrentEntry; + } + + bool operator!=(const directory_iterator &RHS) const { + return !(*this == RHS); + } + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; + +namespace detail { + /// RecDirIterState - Keeps state for the recursive_directory_iterator. It is + /// reference counted in order to preserve InputIterator semantics on copy. + struct RecDirIterState : public RefCountedBase { + RecDirIterState() + : Level(0) + , HasNoPushRequest(false) {} + + std::stack > Stack; + uint16_t Level; + bool HasNoPushRequest; + }; +} // end namespace detail + +/// recursive_directory_iterator - Same as directory_iterator except for it +/// recurses down into child directories. +class recursive_directory_iterator { + IntrusiveRefCntPtr State; + +public: + recursive_directory_iterator() {} + explicit recursive_directory_iterator(const Twine &path, std::error_code &ec) + : State(new detail::RecDirIterState) { + State->Stack.push(directory_iterator(path, ec)); + if (State->Stack.top() == directory_iterator()) + State.reset(); + } + // No operator++ because we need error_code. + recursive_directory_iterator &increment(std::error_code &ec) { + const directory_iterator end_itr; + + if (State->HasNoPushRequest) + State->HasNoPushRequest = false; + else { + file_status st; + if ((ec = State->Stack.top()->status(st))) return *this; + if (is_directory(st)) { + State->Stack.push(directory_iterator(*State->Stack.top(), ec)); + if (ec) return *this; + if (State->Stack.top() != end_itr) { + ++State->Level; + return *this; + } + State->Stack.pop(); + } + } + + while (!State->Stack.empty() + && State->Stack.top().increment(ec) == end_itr) { + State->Stack.pop(); + --State->Level; + } + + // Check if we are done. If so, create an end iterator. + if (State->Stack.empty()) + State.reset(); + + return *this; + } + + const directory_entry &operator*() const { return *State->Stack.top(); } + const directory_entry *operator->() const { return &*State->Stack.top(); } + + // observers + /// Gets the current level. Starting path is at level 0. + int level() const { return State->Level; } + + /// Returns true if no_push has been called for this directory_entry. + bool no_push_request() const { return State->HasNoPushRequest; } + + // modifiers + /// Goes up one level if Level > 0. + void pop() { + assert(State && "Cannot pop an end iterator!"); + assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); + + const directory_iterator end_itr; + std::error_code ec; + do { + if (ec) { + //report_fatal_error("Error incrementing directory iterator."); + while (!State->Stack.empty()) State->Stack.pop(); + break; + } + State->Stack.pop(); + --State->Level; + } while (!State->Stack.empty() + && State->Stack.top().increment(ec) == end_itr); + + // Check if we are done. If so, create an end iterator. + if (State->Stack.empty()) + State.reset(); + } + + /// Does not go down into the current directory_entry. + void no_push() { State->HasNoPushRequest = true; } + + bool operator==(const recursive_directory_iterator &RHS) const { + return State == RHS.State; + } + + bool operator!=(const recursive_directory_iterator &RHS) const { + return !(*this == RHS); + } + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; /// @} diff --git a/src/main/native/include/llvm/IntrusiveRefCntPtr.h b/src/main/native/include/llvm/IntrusiveRefCntPtr.h new file mode 100644 index 0000000000..8057ec10be --- /dev/null +++ b/src/main/native/include/llvm/IntrusiveRefCntPtr.h @@ -0,0 +1,288 @@ +//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines IntrusiveRefCntPtr, a template class that +// implements a "smart" pointer for objects that maintain their own +// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two +// generic base classes for objects that wish to have their lifetimes +// managed using reference counting. +// +// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added +// LLVM-style casting. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H +#define LLVM_ADT_INTRUSIVEREFCNTPTR_H + +#include +#include +#include + +namespace llvm { + + template + class IntrusiveRefCntPtr; + +//===----------------------------------------------------------------------===// +/// RefCountedBase - A generic base class for objects that wish to +/// have their lifetimes managed using reference counts. Classes +/// subclass RefCountedBase to obtain such functionality, and are +/// typically handled with IntrusiveRefCntPtr "smart pointers" (see below) +/// which automatically handle the management of reference counts. +/// Objects that subclass RefCountedBase should not be allocated on +/// the stack, as invoking "delete" (which is called when the +/// reference count hits 0) on such objects is an error. +//===----------------------------------------------------------------------===// + template + class RefCountedBase { + mutable unsigned ref_cnt; + + public: + RefCountedBase() : ref_cnt(0) {} + RefCountedBase(const RefCountedBase &) : ref_cnt(0) {} + + void Retain() const { ++ref_cnt; } + void Release() const { + assert (ref_cnt > 0 && "Reference count is already zero."); + if (--ref_cnt == 0) delete static_cast(this); + } + }; + +//===----------------------------------------------------------------------===// +/// RefCountedBaseVPTR - A class that has the same function as +/// RefCountedBase, but with a virtual destructor. Should be used +/// instead of RefCountedBase for classes that already have virtual +/// methods to enforce dynamic allocation via 'new'. Classes that +/// inherit from RefCountedBaseVPTR can't be allocated on stack - +/// attempting to do this will produce a compile error. +//===----------------------------------------------------------------------===// + class RefCountedBaseVPTR { + mutable unsigned ref_cnt; + virtual void anchor(); + + protected: + RefCountedBaseVPTR() : ref_cnt(0) {} + RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {} + + virtual ~RefCountedBaseVPTR() {} + + void Retain() const { ++ref_cnt; } + void Release() const { + assert (ref_cnt > 0 && "Reference count is already zero."); + if (--ref_cnt == 0) delete this; + } + + template + friend struct IntrusiveRefCntPtrInfo; + }; + + + template struct IntrusiveRefCntPtrInfo { + static void retain(T *obj) { obj->Retain(); } + static void release(T *obj) { obj->Release(); } + }; + +/// \brief A thread-safe version of \c llvm::RefCountedBase. +/// +/// A generic base class for objects that wish to have their lifetimes managed +/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to +/// obtain such functionality, and are typically handled with +/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the +/// management of reference counts. +template +class ThreadSafeRefCountedBase { + mutable std::atomic RefCount; + +protected: + ThreadSafeRefCountedBase() : RefCount(0) {} + +public: + void Retain() const { ++RefCount; } + + void Release() const { + int NewRefCount = --RefCount; + assert(NewRefCount >= 0 && "Reference count was already zero."); + if (NewRefCount == 0) + delete static_cast(this); + } +}; + +//===----------------------------------------------------------------------===// +/// IntrusiveRefCntPtr - A template class that implements a "smart pointer" +/// that assumes the wrapped object has a reference count associated +/// with it that can be managed via calls to +/// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers +/// manage reference counts via the RAII idiom: upon creation of +/// smart pointer the reference count of the wrapped object is +/// incremented and upon destruction of the smart pointer the +/// reference count is decremented. This class also safely handles +/// wrapping NULL pointers. +/// +/// Reference counting is implemented via calls to +/// Obj->Retain()/Obj->Release(). Release() is required to destroy +/// the object when the reference count reaches zero. Inheriting from +/// RefCountedBase/RefCountedBaseVPTR takes care of this +/// automatically. +//===----------------------------------------------------------------------===// + template + class IntrusiveRefCntPtr { + T* Obj; + + public: + typedef T element_type; + + explicit IntrusiveRefCntPtr() : Obj(nullptr) {} + + IntrusiveRefCntPtr(T* obj) : Obj(obj) { + retain(); + } + + IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) { + retain(); + } + + IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) { + S.Obj = nullptr; + } + + template + IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.get()) { + S.Obj = nullptr; + } + + template + IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) + : Obj(S.get()) { + retain(); + } + + IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) { + swap(S); + return *this; + } + + ~IntrusiveRefCntPtr() { release(); } + + T& operator*() const { return *Obj; } + + T* operator->() const { return Obj; } + + T* get() const { return Obj; } + + explicit operator bool() const { return Obj; } + + void swap(IntrusiveRefCntPtr& other) { + T* tmp = other.Obj; + other.Obj = Obj; + Obj = tmp; + } + + void reset() { + release(); + Obj = nullptr; + } + + void resetWithoutRelease() { + Obj = nullptr; + } + + private: + void retain() { if (Obj) IntrusiveRefCntPtrInfo::retain(Obj); } + void release() { if (Obj) IntrusiveRefCntPtrInfo::release(Obj); } + + template + friend class IntrusiveRefCntPtr; + }; + + template + inline bool operator==(const IntrusiveRefCntPtr& A, + const IntrusiveRefCntPtr& B) + { + return A.get() == B.get(); + } + + template + inline bool operator!=(const IntrusiveRefCntPtr& A, + const IntrusiveRefCntPtr& B) + { + return A.get() != B.get(); + } + + template + inline bool operator==(const IntrusiveRefCntPtr& A, + U* B) + { + return A.get() == B; + } + + template + inline bool operator!=(const IntrusiveRefCntPtr& A, + U* B) + { + return A.get() != B; + } + + template + inline bool operator==(T* A, + const IntrusiveRefCntPtr& B) + { + return A == B.get(); + } + + template + inline bool operator!=(T* A, + const IntrusiveRefCntPtr& B) + { + return A != B.get(); + } + + template + bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr &B) { + return !B; + } + + template + bool operator==(const IntrusiveRefCntPtr &A, std::nullptr_t B) { + return B == A; + } + + template + bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr &B) { + return !(A == B); + } + + template + bool operator!=(const IntrusiveRefCntPtr &A, std::nullptr_t B) { + return !(A == B); + } + +//===----------------------------------------------------------------------===// +// LLVM-style downcasting support for IntrusiveRefCntPtr objects +//===----------------------------------------------------------------------===// + + template struct simplify_type; + + template struct simplify_type > { + typedef T* SimpleType; + static SimpleType getSimplifiedValue(IntrusiveRefCntPtr& Val) { + return Val.get(); + } + }; + + template struct simplify_type > { + typedef /*const*/ T* SimpleType; + static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr& Val) { + return Val.get(); + } + }; + +} // end namespace llvm + +#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H