aboutsummaryrefslogtreecommitdiff
path: root/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/AArch64TargetParser.cpp4
-rw-r--r--lib/Support/ABIBreak.cpp24
-rw-r--r--lib/Support/APInt.cpp52
-rw-r--r--lib/Support/ARMTargetParser.cpp8
-rw-r--r--lib/Support/CRC.cpp113
-rw-r--r--lib/Support/CachePruning.cpp2
-rw-r--r--lib/Support/CodeGenCoverage.cpp4
-rw-r--r--lib/Support/CommandLine.cpp2
-rw-r--r--lib/Support/CrashRecoveryContext.cpp8
-rw-r--r--lib/Support/DataExtractor.cpp160
-rw-r--r--lib/Support/Error.cpp17
-rw-r--r--lib/Support/FileCheck.cpp356
-rw-r--r--lib/Support/FileCheckImpl.h624
-rw-r--r--lib/Support/FileCollector.cpp268
-rw-r--r--lib/Support/FileOutputBuffer.cpp6
-rw-r--r--lib/Support/FileUtilities.cpp66
-rw-r--r--lib/Support/GlobPattern.cpp23
-rw-r--r--lib/Support/Host.cpp34
-rw-r--r--lib/Support/JSON.cpp2
-rw-r--r--lib/Support/JamCRC.cpp96
-rw-r--r--lib/Support/ManagedStatic.cpp13
-rw-r--r--lib/Support/MemoryBuffer.cpp31
-rw-r--r--lib/Support/Mutex.cpp123
-rw-r--r--lib/Support/Parallel.cpp31
-rw-r--r--lib/Support/Path.cpp6
-rw-r--r--lib/Support/PrettyStackTrace.cpp64
-rw-r--r--lib/Support/RWMutex.cpp58
-rw-r--r--lib/Support/Regex.cpp39
-rw-r--r--lib/Support/Signposts.cpp2
-rw-r--r--lib/Support/SpecialCaseList.cpp4
-rw-r--r--lib/Support/Statistic.cpp27
-rw-r--r--lib/Support/StringExtras.cpp4
-rw-r--r--lib/Support/TimeProfiler.cpp63
-rw-r--r--lib/Support/Timer.cpp10
-rw-r--r--lib/Support/Unix/Memory.inc6
-rw-r--r--lib/Support/Unix/Mutex.inc42
-rw-r--r--lib/Support/Unix/Path.inc73
-rw-r--r--lib/Support/Unix/Process.inc7
-rw-r--r--lib/Support/Unix/Program.inc4
-rw-r--r--lib/Support/Unix/RWMutex.inc50
-rw-r--r--lib/Support/Unix/Signals.inc15
-rw-r--r--lib/Support/VirtualFileSystem.cpp102
-rw-r--r--lib/Support/Windows/Mutex.inc56
-rw-r--r--lib/Support/Windows/Path.inc93
-rw-r--r--lib/Support/Windows/Program.inc2
-rw-r--r--lib/Support/Windows/RWMutex.inc128
-rw-r--r--lib/Support/Windows/Signals.inc3
-rw-r--r--lib/Support/Windows/WindowsSupport.h1
-rw-r--r--lib/Support/Windows/explicit_symbols.inc6
-rw-r--r--lib/Support/YAMLTraits.cpp16
-rw-r--r--lib/Support/Z3Solver.cpp2
-rw-r--r--lib/Support/raw_ostream.cpp35
-rw-r--r--lib/Support/regcomp.c7
53 files changed, 1882 insertions, 1110 deletions
diff --git a/lib/Support/AArch64TargetParser.cpp b/lib/Support/AArch64TargetParser.cpp
index df4caa1f07fd..6f1d6d50eee2 100644
--- a/lib/Support/AArch64TargetParser.cpp
+++ b/lib/Support/AArch64TargetParser.cpp
@@ -96,8 +96,8 @@ bool AArch64::getExtensionFeatures(unsigned Extensions,
Features.push_back("+sve2-sm4");
if (Extensions & AEK_SVE2SHA3)
Features.push_back("+sve2-sha3");
- if (Extensions & AEK_BITPERM)
- Features.push_back("+bitperm");
+ if (Extensions & AEK_SVE2BITPERM)
+ Features.push_back("+sve2-bitperm");
if (Extensions & AEK_RCPC)
Features.push_back("+rcpc");
diff --git a/lib/Support/ABIBreak.cpp b/lib/Support/ABIBreak.cpp
new file mode 100644
index 000000000000..247b635e02b8
--- /dev/null
+++ b/lib/Support/ABIBreak.cpp
@@ -0,0 +1,24 @@
+//===----- lib/Support/ABIBreak.cpp - EnableABIBreakingChecks -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Config/abi-breaking.h"
+
+#ifndef _MSC_VER
+namespace llvm {
+
+// One of these two variables will be referenced by a symbol defined in
+// llvm-config.h. We provide a link-time (or load time for DSO) failure when
+// there is a mismatch in the build configuration of the API client and LLVM.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+int EnableABIBreakingChecks;
+#else
+int DisableABIBreakingChecks;
+#endif
+
+} // end namespace llvm
+#endif
diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp
index 43173311cd80..758fe8b4f866 100644
--- a/lib/Support/APInt.cpp
+++ b/lib/Support/APInt.cpp
@@ -401,6 +401,33 @@ void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
}
}
+void APInt::insertBits(uint64_t subBits, unsigned bitPosition, unsigned numBits) {
+ uint64_t maskBits = maskTrailingOnes<uint64_t>(numBits);
+ subBits &= maskBits;
+ if (isSingleWord()) {
+ U.VAL &= ~(maskBits << bitPosition);
+ U.VAL |= subBits << bitPosition;
+ return;
+ }
+
+ unsigned loBit = whichBit(bitPosition);
+ unsigned loWord = whichWord(bitPosition);
+ unsigned hiWord = whichWord(bitPosition + numBits - 1);
+ if (loWord == hiWord) {
+ U.pVal[loWord] &= ~(maskBits << loBit);
+ U.pVal[loWord] |= subBits << loBit;
+ return;
+ }
+
+ static_assert(8 * sizeof(WordType) <= 64, "This code assumes only two words affected");
+ unsigned wordBits = 8 * sizeof(WordType);
+ U.pVal[loWord] &= ~(maskBits << loBit);
+ U.pVal[loWord] |= subBits << loBit;
+
+ U.pVal[hiWord] &= ~(maskBits >> (wordBits - loBit));
+ U.pVal[hiWord] |= subBits >> (wordBits - loBit);
+}
+
APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
assert(numBits > 0 && "Can't extract zero bits");
assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth &&
@@ -438,6 +465,31 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
return Result.clearUnusedBits();
}
+uint64_t APInt::extractBitsAsZExtValue(unsigned numBits,
+ unsigned bitPosition) const {
+ assert(numBits > 0 && "Can't extract zero bits");
+ assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth &&
+ "Illegal bit extraction");
+ assert(numBits <= 64 && "Illegal bit extraction");
+
+ uint64_t maskBits = maskTrailingOnes<uint64_t>(numBits);
+ if (isSingleWord())
+ return (U.VAL >> bitPosition) & maskBits;
+
+ unsigned loBit = whichBit(bitPosition);
+ unsigned loWord = whichWord(bitPosition);
+ unsigned hiWord = whichWord(bitPosition + numBits - 1);
+ if (loWord == hiWord)
+ return (U.pVal[loWord] >> loBit) & maskBits;
+
+ static_assert(8 * sizeof(WordType) <= 64, "This code assumes only two words affected");
+ unsigned wordBits = 8 * sizeof(WordType);
+ uint64_t retBits = U.pVal[loWord] >> loBit;
+ retBits |= U.pVal[hiWord] << (wordBits - loBit);
+ retBits &= maskBits;
+ return retBits;
+}
+
unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
assert(!str.empty() && "Invalid string length");
assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 ||
diff --git a/lib/Support/ARMTargetParser.cpp b/lib/Support/ARMTargetParser.cpp
index be948cfc95d4..ce5daa7fe58c 100644
--- a/lib/Support/ARMTargetParser.cpp
+++ b/lib/Support/ARMTargetParser.cpp
@@ -176,10 +176,8 @@ bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
// exist).
{"+fpregs", "-fpregs", FPUVersion::VFPV2, FPURestriction::SP_D16},
- {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::None},
- {"+vfp2d16", "-vfp2d16", FPUVersion::VFPV2, FPURestriction::D16},
- {"+vfp2d16sp", "-vfp2d16sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
- {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::None},
+ {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::D16},
+ {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::SP_D16},
{"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None},
{"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16},
{"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16},
@@ -195,7 +193,7 @@ bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) {
{"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None},
{"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16},
{"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16},
- {"+d32", "-d32", FPUVersion::VFPV2, FPURestriction::None},
+ {"+d32", "-d32", FPUVersion::VFPV3, FPURestriction::None},
};
for (const auto &Info: FPUFeatureInfoList) {
diff --git a/lib/Support/CRC.cpp b/lib/Support/CRC.cpp
index fd98f3a24003..7c008d3b599d 100644
--- a/lib/Support/CRC.cpp
+++ b/lib/Support/CRC.cpp
@@ -6,63 +6,94 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements llvm::crc32 function.
+// This file contains implementations of CRC functions.
+//
+// The implementation technique is the one mentioned in:
+// D. V. Sarwate. 1988. Computation of cyclic redundancy checks via table
+// look-up. Commun. ACM 31, 8 (August 1988)
+//
+// See also Ross N. Williams "A Painless Guide to CRC Error Detection
+// Algorithms" (https://zlib.net/crc_v3.txt) or Hacker's Delight (2nd ed.)
+// Chapter 14 (Figure 14-7 in particular) for how the algorithm works.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/CRC.h"
+
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/Config/config.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Threading.h"
-#include <array>
using namespace llvm;
#if LLVM_ENABLE_ZLIB == 0 || !HAVE_ZLIB_H
-using CRC32Table = std::array<uint32_t, 256>;
-
-static void initCRC32Table(CRC32Table *Tbl) {
- auto Shuffle = [](uint32_t V) {
- return (V & 1) ? (V >> 1) ^ 0xEDB88320U : V >> 1;
- };
-
- for (size_t I = 0; I < Tbl->size(); ++I) {
- uint32_t V = Shuffle(I);
- V = Shuffle(V);
- V = Shuffle(V);
- V = Shuffle(V);
- V = Shuffle(V);
- V = Shuffle(V);
- V = Shuffle(V);
- (*Tbl)[I] = Shuffle(V);
- }
-}
-uint32_t llvm::crc32(uint32_t CRC, StringRef S) {
- static llvm::once_flag InitFlag;
- static CRC32Table Tbl;
- llvm::call_once(InitFlag, initCRC32Table, &Tbl);
+static const uint32_t CRCTable[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
- const uint8_t *P = reinterpret_cast<const uint8_t *>(S.data());
- size_t Len = S.size();
+uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) {
CRC ^= 0xFFFFFFFFU;
- for (; Len >= 8; Len -= 8) {
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
+ for (uint8_t Byte : Data) {
+ int TableIdx = (CRC ^ Byte) & 0xff;
+ CRC = CRCTable[TableIdx] ^ (CRC >> 8);
}
- while (Len--)
- CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8);
return CRC ^ 0xFFFFFFFFU;
}
+
#else
+
#include <zlib.h>
-uint32_t llvm::crc32(uint32_t CRC, StringRef S) {
- return ::crc32(CRC, (const Bytef *)S.data(), S.size());
+uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) {
+ return ::crc32(CRC, (const Bytef *)Data.data(), Data.size());
}
+
#endif
+
+uint32_t llvm::crc32(ArrayRef<uint8_t> Data) { return crc32(0, Data); }
+
+void JamCRC::update(ArrayRef<uint8_t> Data) {
+ CRC ^= 0xFFFFFFFFU; // Undo CRC-32 Init.
+ CRC = crc32(CRC, Data);
+ CRC ^= 0xFFFFFFFFU; // Undo CRC-32 XorOut.
+}
diff --git a/lib/Support/CachePruning.cpp b/lib/Support/CachePruning.cpp
index 9813eec0e433..7a2f6c53435a 100644
--- a/lib/Support/CachePruning.cpp
+++ b/lib/Support/CachePruning.cpp
@@ -45,7 +45,7 @@ struct FileInfo {
/// interval option.
static void writeTimestampFile(StringRef TimestampFile) {
std::error_code EC;
- raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::F_None);
+ raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::OF_None);
}
static Expected<std::chrono::seconds> parseDuration(StringRef Duration) {
diff --git a/lib/Support/CodeGenCoverage.cpp b/lib/Support/CodeGenCoverage.cpp
index f39eb7533b43..2db4193ce382 100644
--- a/lib/Support/CodeGenCoverage.cpp
+++ b/lib/Support/CodeGenCoverage.cpp
@@ -101,9 +101,9 @@ bool CodeGenCoverage::emit(StringRef CoveragePrefix,
std::string CoverageFilename = (CoveragePrefix + Pid).str();
std::error_code EC;
- sys::fs::OpenFlags OpenFlags = sys::fs::F_Append;
+ sys::fs::OpenFlags OpenFlags = sys::fs::OF_Append;
std::unique_ptr<ToolOutputFile> CoverageFile =
- llvm::make_unique<ToolOutputFile>(CoverageFilename, EC, OpenFlags);
+ std::make_unique<ToolOutputFile>(CoverageFilename, EC, OpenFlags);
if (EC)
return false;
diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp
index 25510fa58ff5..620f7ffd4c9f 100644
--- a/lib/Support/CommandLine.cpp
+++ b/lib/Support/CommandLine.cpp
@@ -692,7 +692,7 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName,
return false;
}
-static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) {
+bool llvm::cl::ProvidePositionalOption(Option *Handler, StringRef Arg, int i) {
int Dummy = i;
return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy);
}
diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp
index c2459256f8fe..9d13fce9cc52 100644
--- a/lib/Support/CrashRecoveryContext.cpp
+++ b/lib/Support/CrashRecoveryContext.cpp
@@ -10,8 +10,8 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Mutex.h"
#include "llvm/Support/ThreadLocal.h"
+#include <mutex>
#include <setjmp.h>
using namespace llvm;
@@ -71,7 +71,7 @@ public:
}
-static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
+static ManagedStatic<std::mutex> gCrashRecoveryContextMutex;
static bool gCrashRecoveryEnabled = false;
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
@@ -116,7 +116,7 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
}
void CrashRecoveryContext::Enable() {
- sys::ScopedLock L(*gCrashRecoveryContextMutex);
+ std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
// FIXME: Shouldn't this be a refcount or something?
if (gCrashRecoveryEnabled)
return;
@@ -125,7 +125,7 @@ void CrashRecoveryContext::Enable() {
}
void CrashRecoveryContext::Disable() {
- sys::ScopedLock L(*gCrashRecoveryContextMutex);
+ std::lock_guard<std::mutex> L(*gCrashRecoveryContextMutex);
if (!gCrashRecoveryEnabled)
return;
gCrashRecoveryEnabled = false;
diff --git a/lib/Support/DataExtractor.cpp b/lib/Support/DataExtractor.cpp
index 673bbb4d06f4..a98297cdb35f 100644
--- a/lib/Support/DataExtractor.cpp
+++ b/lib/Support/DataExtractor.cpp
@@ -7,111 +7,137 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/SwapByteOrder.h"
+
using namespace llvm;
+static void unexpectedEndReached(Error *E) {
+ if (E)
+ *E = createStringError(errc::illegal_byte_sequence,
+ "unexpected end of data");
+}
+
+static bool isError(Error *E) { return E && *E; }
+
template <typename T>
-static T getU(uint32_t *offset_ptr, const DataExtractor *de,
- bool isLittleEndian, const char *Data) {
+static T getU(uint64_t *offset_ptr, const DataExtractor *de,
+ bool isLittleEndian, const char *Data, llvm::Error *Err) {
+ ErrorAsOutParameter ErrAsOut(Err);
T val = 0;
- uint32_t offset = *offset_ptr;
- if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) {
- std::memcpy(&val, &Data[offset], sizeof(val));
- if (sys::IsLittleEndianHost != isLittleEndian)
- sys::swapByteOrder(val);
-
- // Advance the offset
- *offset_ptr += sizeof(val);
+ if (isError(Err))
+ return val;
+
+ uint64_t offset = *offset_ptr;
+ if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) {
+ unexpectedEndReached(Err);
+ return val;
}
+ std::memcpy(&val, &Data[offset], sizeof(val));
+ if (sys::IsLittleEndianHost != isLittleEndian)
+ sys::swapByteOrder(val);
+
+ // Advance the offset
+ *offset_ptr += sizeof(val);
return val;
}
template <typename T>
-static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count,
- const DataExtractor *de, bool isLittleEndian, const char *Data){
- uint32_t offset = *offset_ptr;
-
- if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) {
- for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
- ++value_ptr, offset += sizeof(*dst))
- *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data);
- // Advance the offset
- *offset_ptr = offset;
- // Return a non-NULL pointer to the converted data as an indicator of
- // success
- return dst;
+static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
+ const DataExtractor *de, bool isLittleEndian, const char *Data,
+ llvm::Error *Err) {
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (isError(Err))
+ return nullptr;
+
+ uint64_t offset = *offset_ptr;
+
+ if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) {
+ unexpectedEndReached(Err);
+ return nullptr;
}
- return nullptr;
+ for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
+ ++value_ptr, offset += sizeof(*dst))
+ *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err);
+ // Advance the offset
+ *offset_ptr = offset;
+ // Return a non-NULL pointer to the converted data as an indicator of
+ // success
+ return dst;
}
-uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const {
- return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data());
+uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
+ return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
}
uint8_t *
-DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const {
+DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const {
return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data());
+ Data.data(), nullptr);
}
+uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
+ return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian,
+ Data.data(), &C.Err);
+}
-uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const {
- return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data());
+uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
+ return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
}
-uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst,
+uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
uint32_t count) const {
return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data());
+ Data.data(), nullptr);
}
-uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const {
+uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const {
uint24_t ExtractedVal =
- getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data());
+ getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data(), nullptr);
// The 3 bytes are in the correct byte order for the host.
return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
}
-uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const {
- return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data());
+uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
+ return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
}
-uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst,
+uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
uint32_t count) const {
return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data());
+ Data.data(), nullptr);
}
-uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const {
- return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data());
+uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
+ return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
}
-uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst,
+uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
uint32_t count) const {
return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data());
+ Data.data(), nullptr);
}
-uint64_t
-DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const {
+uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
+ llvm::Error *Err) const {
switch (byte_size) {
case 1:
- return getU8(offset_ptr);
+ return getU8(offset_ptr, Err);
case 2:
- return getU16(offset_ptr);
+ return getU16(offset_ptr, Err);
case 4:
- return getU32(offset_ptr);
+ return getU32(offset_ptr, Err);
case 8:
- return getU64(offset_ptr);
+ return getU64(offset_ptr, Err);
}
llvm_unreachable("getUnsigned unhandled case!");
}
int64_t
-DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
+DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
switch (byte_size) {
case 1:
return (int8_t)getU8(offset_ptr);
@@ -125,8 +151,8 @@ DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
llvm_unreachable("getSigned unhandled case!");
}
-const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
- uint32_t offset = *offset_ptr;
+const char *DataExtractor::getCStr(uint64_t *offset_ptr) const {
+ uint64_t offset = *offset_ptr;
StringRef::size_type pos = Data.find('\0', offset);
if (pos != StringRef::npos) {
*offset_ptr = pos + 1;
@@ -135,31 +161,38 @@ const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
return nullptr;
}
-StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const {
- uint32_t Start = *OffsetPtr;
+StringRef DataExtractor::getCStrRef(uint64_t *offset_ptr) const {
+ uint64_t Start = *offset_ptr;
StringRef::size_type Pos = Data.find('\0', Start);
if (Pos != StringRef::npos) {
- *OffsetPtr = Pos + 1;
+ *offset_ptr = Pos + 1;
return StringRef(Data.data() + Start, Pos - Start);
}
return StringRef();
}
-uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
+uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr,
+ llvm::Error *Err) const {
assert(*offset_ptr <= Data.size());
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (isError(Err))
+ return 0;
const char *error;
unsigned bytes_read;
uint64_t result = decodeULEB128(
reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read,
reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error);
- if (error)
+ if (error) {
+ if (Err)
+ *Err = createStringError(errc::illegal_byte_sequence, error);
return 0;
+ }
*offset_ptr += bytes_read;
return result;
}
-int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
+int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const {
assert(*offset_ptr <= Data.size());
const char *error;
@@ -172,3 +205,14 @@ int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
*offset_ptr += bytes_read;
return result;
}
+
+void DataExtractor::skip(Cursor &C, uint64_t Length) const {
+ ErrorAsOutParameter ErrAsOut(&C.Err);
+ if (isError(&C.Err))
+ return;
+
+ if (isValidOffsetForDataOfSize(C.Offset, Length))
+ C.Offset += Length;
+ else
+ unexpectedEndReached(&C.Err);
+}
diff --git a/lib/Support/Error.cpp b/lib/Support/Error.cpp
index 72bc08af2ddb..9ea08c37478e 100644
--- a/lib/Support/Error.cpp
+++ b/lib/Support/Error.cpp
@@ -87,7 +87,7 @@ std::error_code FileError::convertToErrorCode() const {
Error errorCodeToError(std::error_code EC) {
if (!EC)
return Error::success();
- return Error(llvm::make_unique<ECError>(ECError(EC)));
+ return Error(std::make_unique<ECError>(ECError(EC)));
}
std::error_code errorToErrorCode(Error Err) {
@@ -167,18 +167,3 @@ void LLVMDisposeErrorMessage(char *ErrMsg) { delete[] ErrMsg; }
LLVMErrorTypeId LLVMGetStringErrorTypeId() {
return reinterpret_cast<void *>(&StringError::ID);
}
-
-#ifndef _MSC_VER
-namespace llvm {
-
-// One of these two variables will be referenced by a symbol defined in
-// llvm-config.h. We provide a link-time (or load time for DSO) failure when
-// there is a mismatch in the build configuration of the API client and LLVM.
-#if LLVM_ENABLE_ABI_BREAKING_CHECKS
-int EnableABIBreakingChecks;
-#else
-int DisableABIBreakingChecks;
-#endif
-
-} // end namespace llvm
-#endif
diff --git a/lib/Support/FileCheck.cpp b/lib/Support/FileCheck.cpp
index e0f17787bdf8..841e406a7b69 100644
--- a/lib/Support/FileCheck.cpp
+++ b/lib/Support/FileCheck.cpp
@@ -14,31 +14,22 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FileCheck.h"
+#include "FileCheckImpl.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
#include <list>
-#include <map>
#include <tuple>
#include <utility>
using namespace llvm;
-void FileCheckNumericVariable::setValue(uint64_t NewValue) {
- assert(!Value && "Overwriting numeric variable's value is not allowed");
- Value = NewValue;
-}
-
-void FileCheckNumericVariable::clearValue() {
- if (!Value)
- return;
- Value = None;
-}
-
Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
Optional<uint64_t> Value = NumericVariable->getValue();
if (Value)
return *Value;
+
return make_error<FileCheckUndefVarError>(Name);
}
@@ -109,7 +100,7 @@ FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
// StringRef holding all characters considered as horizontal whitespaces by
// FileCheck input canonicalization.
-StringRef SpaceChars = " \t";
+constexpr StringLiteral SpaceChars = " \t";
// Parsing helper function that strips the first character in S and returns it.
static char popFront(StringRef &S) {
@@ -159,7 +150,9 @@ FileCheckPattern::parseNumericVariableDefinition(
Expected<std::unique_ptr<FileCheckNumericVariableUse>>
FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
- const SourceMgr &SM) const {
+ Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context,
+ const SourceMgr &SM) {
if (IsPseudo && !Name.equals("@LINE"))
return FileCheckErrorDiagnostic::get(
SM, Name, "invalid pseudo numeric variable '" + Name + "'");
@@ -185,21 +178,25 @@ FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
return FileCheckErrorDiagnostic::get(
SM, Name,
- "numeric variable '" + Name + "' defined on the same line as used");
+ "numeric variable '" + Name +
+ "' defined earlier in the same CHECK directive");
- return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
+ return std::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
}
Expected<std::unique_ptr<FileCheckExpressionAST>>
FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
- const SourceMgr &SM) const {
+ Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context,
+ const SourceMgr &SM) {
if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
// Try to parse as a numeric variable use.
Expected<FileCheckPattern::VariableProperties> ParseVarResult =
parseVariable(Expr, SM);
if (ParseVarResult)
return parseNumericVariableUse(ParseVarResult->Name,
- ParseVarResult->IsPseudo, SM);
+ ParseVarResult->IsPseudo, LineNumber,
+ Context, SM);
if (AO == AllowedOperand::LineVar)
return ParseVarResult.takeError();
// Ignore the error and retry parsing as a literal.
@@ -209,7 +206,7 @@ FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
// Otherwise, parse it as a literal.
uint64_t LiteralValue;
if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
- return llvm::make_unique<FileCheckExpressionLiteral>(LiteralValue);
+ return std::make_unique<FileCheckExpressionLiteral>(LiteralValue);
return FileCheckErrorDiagnostic::get(SM, Expr,
"invalid operand format '" + Expr + "'");
@@ -223,10 +220,10 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
return LeftOp - RightOp;
}
-Expected<std::unique_ptr<FileCheckExpressionAST>>
-FileCheckPattern::parseBinop(StringRef &Expr,
- std::unique_ptr<FileCheckExpressionAST> LeftOp,
- bool IsLegacyLineExpr, const SourceMgr &SM) const {
+Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(
+ StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM) {
Expr = Expr.ltrim(SpaceChars);
if (Expr.empty())
return std::move(LeftOp);
@@ -257,12 +254,12 @@ FileCheckPattern::parseBinop(StringRef &Expr,
AllowedOperand AO =
IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
- parseNumericOperand(Expr, AO, SM);
+ parseNumericOperand(Expr, AO, LineNumber, Context, SM);
if (!RightOpResult)
return RightOpResult;
Expr = Expr.ltrim(SpaceChars);
- return llvm::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
+ return std::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
std::move(*RightOpResult));
}
@@ -270,56 +267,60 @@ Expected<std::unique_ptr<FileCheckExpressionAST>>
FileCheckPattern::parseNumericSubstitutionBlock(
StringRef Expr,
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
- bool IsLegacyLineExpr, const SourceMgr &SM) const {
- // Parse the numeric variable definition.
+ bool IsLegacyLineExpr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM) {
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;
+ StringRef DefExpr = StringRef();
DefinedNumericVariable = None;
+ // Save variable definition expression if any.
size_t DefEnd = Expr.find(':');
if (DefEnd != StringRef::npos) {
- StringRef DefExpr = Expr.substr(0, DefEnd);
- StringRef UseExpr = Expr.substr(DefEnd + 1);
+ DefExpr = Expr.substr(0, DefEnd);
+ Expr = Expr.substr(DefEnd + 1);
+ }
- UseExpr = UseExpr.ltrim(SpaceChars);
- if (!UseExpr.empty())
- return FileCheckErrorDiagnostic::get(
- SM, UseExpr,
- "unexpected string after variable definition: '" + UseExpr + "'");
+ // Parse the expression itself.
+ Expr = Expr.ltrim(SpaceChars);
+ if (!Expr.empty()) {
+ // The first operand in a legacy @LINE expression is always the @LINE
+ // pseudo variable.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericOperand(Expr, AO, LineNumber, Context, SM);
+ while (ParseResult && !Expr.empty()) {
+ ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,
+ LineNumber, Context, SM);
+ // Legacy @LINE expressions only allow 2 operands.
+ if (ParseResult && IsLegacyLineExpr && !Expr.empty())
+ return FileCheckErrorDiagnostic::get(
+ SM, Expr,
+ "unexpected characters at end of expression '" + Expr + "'");
+ }
+ if (!ParseResult)
+ return ParseResult;
+ ExpressionAST = std::move(*ParseResult);
+ }
+ // Parse the numeric variable definition.
+ if (DefEnd != StringRef::npos) {
DefExpr = DefExpr.ltrim(SpaceChars);
Expected<FileCheckNumericVariable *> ParseResult =
parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
+
if (!ParseResult)
return ParseResult.takeError();
DefinedNumericVariable = *ParseResult;
-
- return nullptr;
}
- // Parse the expression itself.
- Expr = Expr.ltrim(SpaceChars);
- // The first operand in a legacy @LINE expression is always the @LINE pseudo
- // variable.
- AllowedOperand AO =
- IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
- Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
- parseNumericOperand(Expr, AO, SM);
- while (ParseResult && !Expr.empty()) {
- ParseResult =
- parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);
- // Legacy @LINE expressions only allow 2 operands.
- if (ParseResult && IsLegacyLineExpr && !Expr.empty())
- return FileCheckErrorDiagnostic::get(
- SM, Expr,
- "unexpected characters at end of expression '" + Expr + "'");
- }
- if (!ParseResult)
- return ParseResult;
- return std::move(*ParseResult);
+ return std::move(ExpressionAST);
}
bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
SourceMgr &SM,
const FileCheckRequest &Req) {
bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
+ IgnoreCase = Req.IgnoreCase;
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@@ -396,14 +397,15 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
continue;
}
- // String and numeric substitution blocks. String substitution blocks come
+ // String and numeric substitution blocks. Pattern substitution blocks come
// in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
// other regex) and assigns it to the string variable 'foo'. The latter
- // substitutes foo's value. Numeric substitution blocks work the same way
- // as string ones, but start with a '#' sign after the double brackets.
- // Both string and numeric variable names must satisfy the regular
- // expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch
- // some common errors.
+ // substitutes foo's value. Numeric substitution blocks recognize the same
+ // form as string ones, but start with a '#' sign after the double
+ // brackets. They also accept a combined form which sets a numeric variable
+ // to the evaluation of an expression. Both string and numeric variable
+ // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
+ // valid, as this helps catch some common errors.
if (PatternStr.startswith("[[")) {
StringRef UnparsedPatternStr = PatternStr.substr(2);
// Find the closing bracket pair ending the match. End is going to be an
@@ -424,6 +426,7 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
PatternStr = UnparsedPatternStr.substr(End + 2);
bool IsDefinition = false;
+ bool SubstNeeded = false;
// Whether the substitution block is a legacy use of @LINE with string
// substitution block syntax.
bool IsLegacyLineExpr = false;
@@ -454,6 +457,7 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
bool IsPseudo = ParseVarResult->IsPseudo;
IsDefinition = (VarEndIdx != StringRef::npos);
+ SubstNeeded = !IsDefinition;
if (IsDefinition) {
if ((IsPseudo || !MatchStr.consume_front(":"))) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
@@ -488,22 +492,61 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
if (IsNumBlock) {
Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
- IsLegacyLineExpr, SM);
+ IsLegacyLineExpr, LineNumber, Context,
+ SM);
if (!ParseResult) {
logAllUnhandledErrors(ParseResult.takeError(), errs());
return true;
}
ExpressionAST = std::move(*ParseResult);
+ SubstNeeded = ExpressionAST != nullptr;
if (DefinedNumericVariable) {
IsDefinition = true;
DefName = (*DefinedNumericVariable)->getName();
- MatchRegexp = StringRef("[0-9]+");
- } else
+ }
+ if (SubstNeeded)
SubstStr = MatchStr;
+ else
+ MatchRegexp = "[0-9]+";
}
+ // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
+ if (IsDefinition) {
+ RegExStr += '(';
+ ++SubstInsertIdx;
+
+ if (IsNumBlock) {
+ FileCheckNumericVariableMatch NumericVariableDefinition = {
+ *DefinedNumericVariable, CurParen};
+ NumericVariableDefs[DefName] = NumericVariableDefinition;
+ // This store is done here rather than in match() to allow
+ // parseNumericVariableUse() to get the pointer to the class instance
+ // of the right variable definition corresponding to a given numeric
+ // variable use.
+ Context->GlobalNumericVariableTable[DefName] =
+ *DefinedNumericVariable;
+ } else {
+ VariableDefs[DefName] = CurParen;
+ // Mark string variable as defined to detect collisions between
+ // string and numeric variables in parseNumericVariableUse() and
+ // defineCmdlineVariables() when the latter is created later than the
+ // former. We cannot reuse GlobalVariableTable for this by populating
+ // it with an empty string since we would then lose the ability to
+ // detect the use of an undefined variable in match().
+ Context->DefinedVariableTable[DefName] = true;
+ }
+
+ ++CurParen;
+ }
+
+ if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
+ return true;
+
+ if (IsDefinition)
+ RegExStr += ')';
+
// Handle substitutions: [[foo]] and [[#<foo expr>]].
- if (!IsDefinition) {
+ if (SubstNeeded) {
// Handle substitution of string variables that were defined earlier on
// the same line by emitting a backreference. Expressions do not
// support substituting a numeric variable defined on the same line.
@@ -526,37 +569,7 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
: Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
- continue;
- }
-
- // Handle variable definitions: [[<def>:(...)]] and
- // [[#(...)<def>:(...)]].
- if (IsNumBlock) {
- FileCheckNumericVariableMatch NumericVariableDefinition = {
- *DefinedNumericVariable, CurParen};
- NumericVariableDefs[DefName] = NumericVariableDefinition;
- // This store is done here rather than in match() to allow
- // parseNumericVariableUse() to get the pointer to the class instance
- // of the right variable definition corresponding to a given numeric
- // variable use.
- Context->GlobalNumericVariableTable[DefName] = *DefinedNumericVariable;
- } else {
- VariableDefs[DefName] = CurParen;
- // Mark the string variable as defined to detect collisions between
- // string and numeric variables in parseNumericVariableUse() and
- // DefineCmdlineVariables() when the latter is created later than the
- // former. We cannot reuse GlobalVariableTable for this by populating
- // it with an empty string since we would then lose the ability to
- // detect the use of an undefined variable in match().
- Context->DefinedVariableTable[DefName] = true;
}
- RegExStr += '(';
- ++CurParen;
-
- if (AddRegExToRegEx(MatchRegexp, CurParen, SM))
- return true;
-
- RegExStr += ')';
}
// Handle fixed string matches.
@@ -607,7 +620,8 @@ Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
// If this is a fixed string pattern, just match it now.
if (!FixedStr.empty()) {
MatchLen = FixedStr.size();
- size_t Pos = Buffer.find(FixedStr);
+ size_t Pos = IgnoreCase ? Buffer.find_lower(FixedStr)
+ : Buffer.find(FixedStr);
if (Pos == StringRef::npos)
return make_error<FileCheckNotFoundError>();
return Pos;
@@ -631,10 +645,8 @@ Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
for (const auto &Substitution : Substitutions) {
// Substitute and check for failure (e.g. use of undefined variable).
Expected<std::string> Value = Substitution->getResult();
- if (!Value) {
- Context->LineVariable->clearValue();
+ if (!Value)
return Value.takeError();
- }
// Plop it into the regex at the adjusted offset.
TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
@@ -644,11 +656,13 @@ Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
// Match the newly constructed regex.
RegExToMatch = TmpStr;
- Context->LineVariable->clearValue();
}
SmallVector<StringRef, 4> MatchInfo;
- if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo))
+ unsigned int Flags = Regex::Newline;
+ if (IgnoreCase)
+ Flags |= Regex::IgnoreCase;
+ if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo))
return make_error<FileCheckNotFoundError>();
// Successful regex match.
@@ -824,7 +838,7 @@ template <class... Types>
FileCheckNumericVariable *
FileCheckPatternContext::makeNumericVariable(Types... args) {
NumericVariables.push_back(
- llvm::make_unique<FileCheckNumericVariable>(args...));
+ std::make_unique<FileCheckNumericVariable>(args...));
return NumericVariables.back().get();
}
@@ -832,14 +846,14 @@ FileCheckSubstitution *
FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
size_t InsertIdx) {
Substitutions.push_back(
- llvm::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
+ std::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
return Substitutions.back().get();
}
FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
StringRef ExpressionStr,
std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {
- Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>(
+ Substitutions.push_back(std::make_unique<FileCheckNumericSubstitution>(
this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
return Substitutions.back().get();
}
@@ -1108,16 +1122,22 @@ void FileCheckPatternContext::createLineVariable() {
GlobalNumericVariableTable[LineName] = LineVariable;
}
-bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
- std::vector<FileCheckString> &CheckStrings) {
+FileCheck::FileCheck(FileCheckRequest Req)
+ : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()),
+ CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {}
+
+FileCheck::~FileCheck() = default;
+
+bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
+ Regex &PrefixRE) {
Error DefineError =
- PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM);
+ PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
if (DefineError) {
logAllUnhandledErrors(std::move(DefineError), errs());
return true;
}
- PatternContext.createLineVariable();
+ PatternContext->createLineVariable();
std::vector<FileCheckPattern> ImplicitNegativeChecks;
for (const auto &PatternString : Req.ImplicitCheckNot) {
@@ -1133,7 +1153,7 @@ bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
ImplicitNegativeChecks.push_back(
- FileCheckPattern(Check::CheckNot, &PatternContext));
+ FileCheckPattern(Check::CheckNot, PatternContext.get()));
ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
"IMPLICIT-CHECK", SM, Req);
}
@@ -1196,7 +1216,7 @@ bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
// Parse the pattern.
- FileCheckPattern P(CheckTy, &PatternContext, LineNumber);
+ FileCheckPattern P(CheckTy, PatternContext.get(), LineNumber);
if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
return true;
@@ -1214,7 +1234,7 @@ bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
// Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
CheckTy == Check::CheckEmpty) &&
- CheckStrings.empty()) {
+ CheckStrings->empty()) {
StringRef Type = CheckTy == Check::CheckNext
? "NEXT"
: CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
@@ -1232,21 +1252,21 @@ bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
}
// Okay, add the string we captured to the output vector and move on.
- CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);
- std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
+ CheckStrings->emplace_back(P, UsedPrefix, PatternLoc);
+ std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
DagNotMatches = ImplicitNegativeChecks;
}
// Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
// prefix as a filler for the error message.
if (!DagNotMatches.empty()) {
- CheckStrings.emplace_back(
- FileCheckPattern(Check::CheckEOF, &PatternContext, LineNumber + 1),
+ CheckStrings->emplace_back(
+ FileCheckPattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),
*Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
- std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
+ std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
}
- if (CheckStrings.empty()) {
+ if (CheckStrings->empty()) {
errs() << "error: no check strings found with prefix"
<< (Req.CheckPrefixes.size() > 1 ? "es " : " ");
auto I = Req.CheckPrefixes.begin();
@@ -1704,7 +1724,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// A check prefix must contain only alphanumeric, hyphens and underscores.
static bool ValidateCheckPrefix(StringRef CheckPrefix) {
- Regex Validator("^[a-zA-Z0-9_-]*$");
+ static const Regex Validator("^[a-zA-Z0-9_-]*$");
return Validator.match(CheckPrefix);
}
@@ -1759,11 +1779,32 @@ Error FileCheckPatternContext::defineCmdlineVariables(
unsigned I = 0;
Error Errs = Error::success();
std::string CmdlineDefsDiag;
- StringRef Prefix1 = "Global define #";
- StringRef Prefix2 = ": ";
- for (StringRef CmdlineDef : CmdlineDefines)
- CmdlineDefsDiag +=
- (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();
+ SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
+ for (StringRef CmdlineDef : CmdlineDefines) {
+ std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
+ size_t EqIdx = CmdlineDef.find('=');
+ if (EqIdx == StringRef::npos) {
+ CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
+ continue;
+ }
+ // Numeric variable definition.
+ if (CmdlineDef[0] == '#') {
+ // Append a copy of the command-line definition adapted to use the same
+ // format as in the input file to be able to reuse
+ // parseNumericSubstitutionBlock.
+ CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
+ std::string SubstitutionStr = CmdlineDef;
+ SubstitutionStr[EqIdx] = ':';
+ CmdlineDefsIndices.push_back(
+ std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
+ CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
+ } else {
+ CmdlineDefsDiag += DefPrefix;
+ CmdlineDefsIndices.push_back(
+ std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
+ CmdlineDefsDiag += (CmdlineDef + "\n").str();
+ }
+ }
// Create a buffer with fake command line content in order to display
// parsing diagnostic with location information and point to the
@@ -1773,14 +1814,10 @@ Error FileCheckPatternContext::defineCmdlineVariables(
StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
- SmallVector<StringRef, 4> CmdlineDefsDiagVec;
- CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,
- false /*KeepEmpty*/);
- for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
- unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
- StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
- size_t EqIdx = CmdlineDef.find('=');
- if (EqIdx == StringRef::npos) {
+ for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
+ StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
+ CmdlineDefIndices.second);
+ if (CmdlineDef.empty()) {
Errs = joinErrors(
std::move(Errs),
FileCheckErrorDiagnostic::get(
@@ -1790,31 +1827,35 @@ Error FileCheckPatternContext::defineCmdlineVariables(
// Numeric variable definition.
if (CmdlineDef[0] == '#') {
- StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
- Expected<FileCheckNumericVariable *> ParseResult =
- FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this,
- None, SM);
- if (!ParseResult) {
- Errs = joinErrors(std::move(Errs), ParseResult.takeError());
+ // Now parse the definition both to check that the syntax is correct and
+ // to create the necessary class instance.
+ StringRef CmdlineDefExpr = CmdlineDef.substr(1);
+ Optional<FileCheckNumericVariable *> DefinedNumericVariable;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =
+ FileCheckPattern::parseNumericSubstitutionBlock(
+ CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
+ if (!ExpressionASTResult) {
+ Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());
continue;
}
-
- StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
- uint64_t Val;
- if (CmdlineVal.getAsInteger(10, Val)) {
- Errs = joinErrors(std::move(Errs),
- FileCheckErrorDiagnostic::get(
- SM, CmdlineVal,
- "invalid value in numeric variable definition '" +
- CmdlineVal + "'"));
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST =
+ std::move(*ExpressionASTResult);
+ // Now evaluate the expression whose value this variable should be set
+ // to, since the expression of a command-line variable definition should
+ // only use variables defined earlier on the command-line. If not, this
+ // is an error and we report it.
+ Expected<uint64_t> Value = ExpressionAST->eval();
+ if (!Value) {
+ Errs = joinErrors(std::move(Errs), Value.takeError());
continue;
}
- FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;
- DefinedNumericVariable->setValue(Val);
+
+ assert(DefinedNumericVariable && "No variable defined");
+ (*DefinedNumericVariable)->setValue(*Value);
// Record this variable definition.
- GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
- DefinedNumericVariable;
+ GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
+ *DefinedNumericVariable;
} else {
// String variable definition.
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
@@ -1851,7 +1892,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
}
GlobalVariableTable.insert(CmdlineNameVal);
// Mark the string variable as defined to detect collisions between
- // string and numeric variables in DefineCmdlineVariables when the latter
+ // string and numeric variables in defineCmdlineVariables when the latter
// is created later than the former. We cannot reuse GlobalVariableTable
// for this by populating it with an empty string since we would then
// lose the ability to detect the use of an undefined variable in
@@ -1887,18 +1928,17 @@ void FileCheckPatternContext::clearLocalVars() {
GlobalNumericVariableTable.erase(Var);
}
-bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
- ArrayRef<FileCheckString> CheckStrings,
+bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer,
std::vector<FileCheckDiag> *Diags) {
bool ChecksFailed = false;
- unsigned i = 0, j = 0, e = CheckStrings.size();
+ unsigned i = 0, j = 0, e = CheckStrings->size();
while (true) {
StringRef CheckRegion;
if (j == e) {
CheckRegion = Buffer;
} else {
- const FileCheckString &CheckLabelStr = CheckStrings[j];
+ const FileCheckString &CheckLabelStr = (*CheckStrings)[j];
if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
++j;
continue;
@@ -1921,10 +1961,10 @@ bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
// CHECK-LABEL and it would clear variables defined on the command-line
// before they get used.
if (i != 0 && Req.EnableVarScope)
- PatternContext.clearLocalVars();
+ PatternContext->clearLocalVars();
for (; i != j; ++i) {
- const FileCheckString &CheckStr = CheckStrings[i];
+ const FileCheckString &CheckStr = (*CheckStrings)[i];
// Check each string within the scanned region, including a second check
// of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
diff --git a/lib/Support/FileCheckImpl.h b/lib/Support/FileCheckImpl.h
new file mode 100644
index 000000000000..06ce8301cec4
--- /dev/null
+++ b/lib/Support/FileCheckImpl.h
@@ -0,0 +1,624 @@
+//===-- FileCheckImpl.h - Private FileCheck Interface ------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the private interfaces of FileCheck. Its purpose is to
+// allow unit testing of FileCheck and to separate the interface from the
+// implementation. It is only meant to be used by FileCheck.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H
+#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/SourceMgr.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+//===----------------------------------------------------------------------===//
+// Numeric substitution handling code.
+//===----------------------------------------------------------------------===//
+
+/// Base class representing the AST of a given expression.
+class FileCheckExpressionAST {
+public:
+ virtual ~FileCheckExpressionAST() = default;
+
+ /// Evaluates and \returns the value of the expression represented by this
+ /// AST or an error if evaluation fails.
+ virtual Expected<uint64_t> eval() const = 0;
+};
+
+/// Class representing an unsigned literal in the AST of an expression.
+class FileCheckExpressionLiteral : public FileCheckExpressionAST {
+private:
+ /// Actual value of the literal.
+ uint64_t Value;
+
+public:
+ /// Constructs a literal with the specified value.
+ FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}
+
+ /// \returns the literal's value.
+ Expected<uint64_t> eval() const { return Value; }
+};
+
+/// Class to represent an undefined variable error, which quotes that
+/// variable's name when printed.
+class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {
+private:
+ StringRef VarName;
+
+public:
+ static char ID;
+
+ FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
+
+ StringRef getVarName() const { return VarName; }
+
+ std::error_code convertToErrorCode() const override {
+ return inconvertibleErrorCode();
+ }
+
+ /// Print name of variable associated with this error.
+ void log(raw_ostream &OS) const override {
+ OS << "\"";
+ OS.write_escaped(VarName) << "\"";
+ }
+};
+
+/// Class representing a numeric variable and its associated current value.
+class FileCheckNumericVariable {
+private:
+ /// Name of the numeric variable.
+ StringRef Name;
+
+ /// Value of numeric variable, if defined, or None otherwise.
+ Optional<uint64_t> Value;
+
+ /// Line number where this variable is defined, or None if defined before
+ /// input is parsed. Used to determine whether a variable is defined on the
+ /// same line as a given use.
+ Optional<size_t> DefLineNumber;
+
+public:
+ /// Constructor for a variable \p Name defined at line \p DefLineNumber or
+ /// defined before input is parsed if \p DefLineNumber is None.
+ explicit FileCheckNumericVariable(StringRef Name,
+ Optional<size_t> DefLineNumber = None)
+ : Name(Name), DefLineNumber(DefLineNumber) {}
+
+ /// \returns name of this numeric variable.
+ StringRef getName() const { return Name; }
+
+ /// \returns this variable's value.
+ Optional<uint64_t> getValue() const { return Value; }
+
+ /// Sets value of this numeric variable to \p NewValue.
+ void setValue(uint64_t NewValue) { Value = NewValue; }
+
+ /// Clears value of this numeric variable, regardless of whether it is
+ /// currently defined or not.
+ void clearValue() { Value = None; }
+
+ /// \returns the line number where this variable is defined, if any, or None
+ /// if defined before input is parsed.
+ Optional<size_t> getDefLineNumber() { return DefLineNumber; }
+};
+
+/// Class representing the use of a numeric variable in the AST of an
+/// expression.
+class FileCheckNumericVariableUse : public FileCheckExpressionAST {
+private:
+ /// Name of the numeric variable.
+ StringRef Name;
+
+ /// Pointer to the class instance for the variable this use is about.
+ FileCheckNumericVariable *NumericVariable;
+
+public:
+ FileCheckNumericVariableUse(StringRef Name,
+ FileCheckNumericVariable *NumericVariable)
+ : Name(Name), NumericVariable(NumericVariable) {}
+
+ /// \returns the value of the variable referenced by this instance.
+ Expected<uint64_t> eval() const;
+};
+
+/// Type of functions evaluating a given binary operation.
+using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
+
+/// Class representing a single binary operation in the AST of an expression.
+class FileCheckASTBinop : public FileCheckExpressionAST {
+private:
+ /// Left operand.
+ std::unique_ptr<FileCheckExpressionAST> LeftOperand;
+
+ /// Right operand.
+ std::unique_ptr<FileCheckExpressionAST> RightOperand;
+
+ /// Pointer to function that can evaluate this binary operation.
+ binop_eval_t EvalBinop;
+
+public:
+ FileCheckASTBinop(binop_eval_t EvalBinop,
+ std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ std::unique_ptr<FileCheckExpressionAST> RightOp)
+ : EvalBinop(EvalBinop) {
+ LeftOperand = std::move(LeftOp);
+ RightOperand = std::move(RightOp);
+ }
+
+ /// Evaluates the value of the binary operation represented by this AST,
+ /// using EvalBinop on the result of recursively evaluating the operands.
+ /// \returns the expression value or an error if an undefined numeric
+ /// variable is used in one of the operands.
+ Expected<uint64_t> eval() const;
+};
+
+class FileCheckPatternContext;
+
+/// Class representing a substitution to perform in the RegExStr string.
+class FileCheckSubstitution {
+protected:
+ /// Pointer to a class instance holding, among other things, the table with
+ /// the values of live string variables at the start of any given CHECK line.
+ /// Used for substituting string variables with the text they were defined
+ /// as. Expressions are linked to the numeric variables they use at
+ /// parse time and directly access the value of the numeric variable to
+ /// evaluate their value.
+ FileCheckPatternContext *Context;
+
+ /// The string that needs to be substituted for something else. For a
+ /// string variable this is its name, otherwise this is the whole expression.
+ StringRef FromStr;
+
+ // Index in RegExStr of where to do the substitution.
+ size_t InsertIdx;
+
+public:
+ FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName,
+ size_t InsertIdx)
+ : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {}
+
+ virtual ~FileCheckSubstitution() = default;
+
+ /// \returns the string to be substituted for something else.
+ StringRef getFromString() const { return FromStr; }
+
+ /// \returns the index where the substitution is to be performed in RegExStr.
+ size_t getIndex() const { return InsertIdx; }
+
+ /// \returns a string containing the result of the substitution represented
+ /// by this class instance or an error if substitution failed.
+ virtual Expected<std::string> getResult() const = 0;
+};
+
+class FileCheckStringSubstitution : public FileCheckSubstitution {
+public:
+ FileCheckStringSubstitution(FileCheckPatternContext *Context,
+ StringRef VarName, size_t InsertIdx)
+ : FileCheckSubstitution(Context, VarName, InsertIdx) {}
+
+ /// \returns the text that the string variable in this substitution matched
+ /// when defined, or an error if the variable is undefined.
+ Expected<std::string> getResult() const override;
+};
+
+class FileCheckNumericSubstitution : public FileCheckSubstitution {
+private:
+ /// Pointer to the class representing the expression whose value is to be
+ /// substituted.
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
+
+public:
+ FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
+ std::unique_ptr<FileCheckExpressionAST> ExprAST,
+ size_t InsertIdx)
+ : FileCheckSubstitution(Context, Expr, InsertIdx) {
+ ExpressionAST = std::move(ExprAST);
+ }
+
+ /// \returns a string containing the result of evaluating the expression in
+ /// this substitution, or an error if evaluation failed.
+ Expected<std::string> getResult() const override;
+};
+
+//===----------------------------------------------------------------------===//
+// Pattern handling code.
+//===----------------------------------------------------------------------===//
+
+struct FileCheckDiag;
+
+/// Class holding the FileCheckPattern global state, shared by all patterns:
+/// tables holding values of variables and whether they are defined or not at
+/// any given time in the matching process.
+class FileCheckPatternContext {
+ friend class FileCheckPattern;
+
+private:
+ /// When matching a given pattern, this holds the value of all the string
+ /// variables defined in previous patterns. In a pattern, only the last
+ /// definition for a given variable is recorded in this table.
+ /// Back-references are used for uses after any the other definition.
+ StringMap<StringRef> GlobalVariableTable;
+
+ /// Map of all string variables defined so far. Used at parse time to detect
+ /// a name conflict between a numeric variable and a string variable when
+ /// the former is defined on a later line than the latter.
+ StringMap<bool> DefinedVariableTable;
+
+ /// When matching a given pattern, this holds the pointers to the classes
+ /// representing the numeric variables defined in previous patterns. When
+ /// matching a pattern all definitions for that pattern are recorded in the
+ /// NumericVariableDefs table in the FileCheckPattern instance of that
+ /// pattern.
+ StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;
+
+ /// Pointer to the class instance representing the @LINE pseudo variable for
+ /// easily updating its value.
+ FileCheckNumericVariable *LineVariable = nullptr;
+
+ /// Vector holding pointers to all parsed numeric variables. Used to
+ /// automatically free them once they are guaranteed to no longer be used.
+ std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
+
+ /// Vector holding pointers to all substitutions. Used to automatically free
+ /// them once they are guaranteed to no longer be used.
+ std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions;
+
+public:
+ /// \returns the value of string variable \p VarName or an error if no such
+ /// variable has been defined.
+ Expected<StringRef> getPatternVarValue(StringRef VarName);
+
+ /// Defines string and numeric variables from definitions given on the
+ /// command line, passed as a vector of [#]VAR=VAL strings in
+ /// \p CmdlineDefines. \returns an error list containing diagnostics against
+ /// \p SM for all definition parsing failures, if any, or Success otherwise.
+ Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
+ SourceMgr &SM);
+
+ /// Create @LINE pseudo variable. Value is set when pattern are being
+ /// matched.
+ void createLineVariable();
+
+ /// Undefines local variables (variables whose name does not start with a '$'
+ /// sign), i.e. removes them from GlobalVariableTable and from
+ /// GlobalNumericVariableTable and also clears the value of numeric
+ /// variables.
+ void clearLocalVars();
+
+private:
+ /// Makes a new numeric variable and registers it for destruction when the
+ /// context is destroyed.
+ template <class... Types>
+ FileCheckNumericVariable *makeNumericVariable(Types... args);
+
+ /// Makes a new string substitution and registers it for destruction when the
+ /// context is destroyed.
+ FileCheckSubstitution *makeStringSubstitution(StringRef VarName,
+ size_t InsertIdx);
+
+ /// Makes a new numeric substitution and registers it for destruction when
+ /// the context is destroyed.
+ FileCheckSubstitution *
+ makeNumericSubstitution(StringRef ExpressionStr,
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST,
+ size_t InsertIdx);
+};
+
+/// Class to represent an error holding a diagnostic with location information
+/// used when printing it.
+class FileCheckErrorDiagnostic : public ErrorInfo<FileCheckErrorDiagnostic> {
+private:
+ SMDiagnostic Diagnostic;
+
+public:
+ static char ID;
+
+ FileCheckErrorDiagnostic(SMDiagnostic &&Diag) : Diagnostic(Diag) {}
+
+ std::error_code convertToErrorCode() const override {
+ return inconvertibleErrorCode();
+ }
+
+ /// Print diagnostic associated with this error when printing the error.
+ void log(raw_ostream &OS) const override { Diagnostic.print(nullptr, OS); }
+
+ static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg) {
+ return make_error<FileCheckErrorDiagnostic>(
+ SM.GetMessage(Loc, SourceMgr::DK_Error, ErrMsg));
+ }
+
+ static Error get(const SourceMgr &SM, StringRef Buffer, const Twine &ErrMsg) {
+ return get(SM, SMLoc::getFromPointer(Buffer.data()), ErrMsg);
+ }
+};
+
+class FileCheckNotFoundError : public ErrorInfo<FileCheckNotFoundError> {
+public:
+ static char ID;
+
+ std::error_code convertToErrorCode() const override {
+ return inconvertibleErrorCode();
+ }
+
+ /// Print diagnostic associated with this error when printing the error.
+ void log(raw_ostream &OS) const override {
+ OS << "String not found in input";
+ }
+};
+
+class FileCheckPattern {
+ SMLoc PatternLoc;
+
+ /// A fixed string to match as the pattern or empty if this pattern requires
+ /// a regex match.
+ StringRef FixedStr;
+
+ /// A regex string to match as the pattern or empty if this pattern requires
+ /// a fixed string to match.
+ std::string RegExStr;
+
+ /// Entries in this vector represent a substitution of a string variable or
+ /// an expression in the RegExStr regex at match time. For example, in the
+ /// case of a CHECK directive with the pattern "foo[[bar]]baz[[#N+1]]",
+ /// RegExStr will contain "foobaz" and we'll get two entries in this vector
+ /// that tells us to insert the value of string variable "bar" at offset 3
+ /// and the value of expression "N+1" at offset 6.
+ std::vector<FileCheckSubstitution *> Substitutions;
+
+ /// Maps names of string variables defined in a pattern to the number of
+ /// their parenthesis group in RegExStr capturing their last definition.
+ ///
+ /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",
+ /// RegExStr will be "foo(.*)baz(\1<quux value>(.*))" where <quux value> is
+ /// the value captured for QUUX on the earlier line where it was defined, and
+ /// VariableDefs will map "bar" to the third parenthesis group which captures
+ /// the second definition of "bar".
+ ///
+ /// Note: uses std::map rather than StringMap to be able to get the key when
+ /// iterating over values.
+ std::map<StringRef, unsigned> VariableDefs;
+
+ /// Structure representing the definition of a numeric variable in a pattern.
+ /// It holds the pointer to the class representing the numeric variable whose
+ /// value is being defined and the number of the parenthesis group in
+ /// RegExStr to capture that value.
+ struct FileCheckNumericVariableMatch {
+ /// Pointer to class representing the numeric variable whose value is being
+ /// defined.
+ FileCheckNumericVariable *DefinedNumericVariable;
+
+ /// Number of the parenthesis group in RegExStr that captures the value of
+ /// this numeric variable definition.
+ unsigned CaptureParenGroup;
+ };
+
+ /// Holds the number of the parenthesis group in RegExStr and pointer to the
+ /// corresponding FileCheckNumericVariable class instance of all numeric
+ /// variable definitions. Used to set the matched value of all those
+ /// variables.
+ StringMap<FileCheckNumericVariableMatch> NumericVariableDefs;
+
+ /// Pointer to a class instance holding the global state shared by all
+ /// patterns:
+ /// - separate tables with the values of live string and numeric variables
+ /// respectively at the start of any given CHECK line;
+ /// - table holding whether a string variable has been defined at any given
+ /// point during the parsing phase.
+ FileCheckPatternContext *Context;
+
+ Check::FileCheckType CheckTy;
+
+ /// Line number for this CHECK pattern or None if it is an implicit pattern.
+ /// Used to determine whether a variable definition is made on an earlier
+ /// line to the one with this CHECK.
+ Optional<size_t> LineNumber;
+
+ /// Ignore case while matching if set to true.
+ bool IgnoreCase = false;
+
+public:
+ FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,
+ Optional<size_t> Line = None)
+ : Context(Context), CheckTy(Ty), LineNumber(Line) {}
+
+ /// \returns the location in source code.
+ SMLoc getLoc() const { return PatternLoc; }
+
+ /// \returns the pointer to the global state for all patterns in this
+ /// FileCheck instance.
+ FileCheckPatternContext *getContext() const { return Context; }
+
+ /// \returns whether \p C is a valid first character for a variable name.
+ static bool isValidVarNameStart(char C);
+
+ /// Parsing information about a variable.
+ struct VariableProperties {
+ StringRef Name;
+ bool IsPseudo;
+ };
+
+ /// Parses the string at the start of \p Str for a variable name. \returns
+ /// a VariableProperties structure holding the variable name and whether it
+ /// is the name of a pseudo variable, or an error holding a diagnostic
+ /// against \p SM if parsing fail. If parsing was successful, also strips
+ /// \p Str from the variable name.
+ static Expected<VariableProperties> parseVariable(StringRef &Str,
+ const SourceMgr &SM);
+ /// Parses \p Expr for a numeric substitution block at line \p LineNumber,
+ /// or before input is parsed if \p LineNumber is None. Parameter
+ /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
+ /// expression and \p Context points to the class instance holding the live
+ /// string and numeric variables. \returns a pointer to the class instance
+ /// representing the AST of the expression whose value must be substitued, or
+ /// an error holding a diagnostic against \p SM if parsing fails. If
+ /// substitution was successful, sets \p DefinedNumericVariable to point to
+ /// the class representing the numeric variable defined in this numeric
+ /// substitution block, or None if this block does not define any variable.
+ static Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseNumericSubstitutionBlock(
+ StringRef Expr,
+ Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
+ bool IsLegacyLineExpr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM);
+ /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
+ /// instance accordingly.
+ ///
+ /// \p Prefix provides which prefix is being matched, \p Req describes the
+ /// global options that influence the parsing such as whitespace
+ /// canonicalization, \p SM provides the SourceMgr used for error reports.
+ /// \returns true in case of an error, false otherwise.
+ bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
+ const FileCheckRequest &Req);
+ /// Matches the pattern string against the input buffer \p Buffer
+ ///
+ /// \returns the position that is matched or an error indicating why matching
+ /// failed. If there is a match, updates \p MatchLen with the size of the
+ /// matched string.
+ ///
+ /// The GlobalVariableTable StringMap in the FileCheckPatternContext class
+ /// instance provides the current values of FileCheck string variables and
+ /// is updated if this match defines new values. Likewise, the
+ /// GlobalNumericVariableTable StringMap in the same class provides the
+ /// current values of FileCheck numeric variables and is updated if this
+ /// match defines new numeric values.
+ Expected<size_t> match(StringRef Buffer, size_t &MatchLen,
+ const SourceMgr &SM) const;
+ /// Prints the value of successful substitutions or the name of the undefined
+ /// string or numeric variables preventing a successful substitution.
+ void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
+ SMRange MatchRange = None) const;
+ void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
+ std::vector<FileCheckDiag> *Diags) const;
+
+ bool hasVariable() const {
+ return !(Substitutions.empty() && VariableDefs.empty());
+ }
+
+ Check::FileCheckType getCheckTy() const { return CheckTy; }
+
+ int getCount() const { return CheckTy.getCount(); }
+
+private:
+ bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
+ void AddBackrefToRegEx(unsigned BackrefNum);
+ /// Computes an arbitrary estimate for the quality of matching this pattern
+ /// at the start of \p Buffer; a distance of zero should correspond to a
+ /// perfect match.
+ unsigned computeMatchDistance(StringRef Buffer) const;
+ /// Finds the closing sequence of a regex variable usage or definition.
+ ///
+ /// \p Str has to point in the beginning of the definition (right after the
+ /// opening sequence). \p SM holds the SourceMgr used for error repporting.
+ /// \returns the offset of the closing sequence within Str, or npos if it
+ /// was not found.
+ size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
+
+ /// Parses \p Expr for the name of a numeric variable to be defined at line
+ /// \p LineNumber, or before input is parsed if \p LineNumber is None.
+ /// \returns a pointer to the class instance representing that variable,
+ /// creating it if needed, or an error holding a diagnostic against \p SM
+ /// should defining such a variable be invalid.
+ static Expected<FileCheckNumericVariable *> parseNumericVariableDefinition(
+ StringRef &Expr, FileCheckPatternContext *Context,
+ Optional<size_t> LineNumber, const SourceMgr &SM);
+ /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use
+ /// at line \p LineNumber, or before input is parsed if \p LineNumber is
+ /// None. Parameter \p Context points to the class instance holding the live
+ /// string and numeric variables. \returns the pointer to the class instance
+ /// representing that variable if successful, or an error holding a
+ /// diagnostic against \p SM otherwise.
+ static Expected<std::unique_ptr<FileCheckNumericVariableUse>>
+ parseNumericVariableUse(StringRef Name, bool IsPseudo,
+ Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context,
+ const SourceMgr &SM);
+ enum class AllowedOperand { LineVar, Literal, Any };
+ /// Parses \p Expr for use of a numeric operand at line \p LineNumber, or
+ /// before input is parsed if \p LineNumber is None. Accepts both literal
+ /// values and numeric variables, depending on the value of \p AO. Parameter
+ /// \p Context points to the class instance holding the live string and
+ /// numeric variables. \returns the class representing that operand in the
+ /// AST of the expression or an error holding a diagnostic against \p SM
+ /// otherwise.
+ static Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+ Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM);
+ /// Parses \p Expr for a binary operation at line \p LineNumber, or before
+ /// input is parsed if \p LineNumber is None. The left operand of this binary
+ /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether
+ /// we are parsing a legacy @LINE expression. Parameter \p Context points to
+ /// the class instance holding the live string and numeric variables.
+ /// \returns the class representing the binary operation in the AST of the
+ /// expression, or an error holding a diagnostic against \p SM otherwise.
+ static Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM);
+};
+
+//===----------------------------------------------------------------------===//
+// Check Strings.
+//===----------------------------------------------------------------------===//
+
+/// A check that we found in the input file.
+struct FileCheckString {
+ /// The pattern to match.
+ FileCheckPattern Pat;
+
+ /// Which prefix name this check matched.
+ StringRef Prefix;
+
+ /// The location in the match file that the check string was specified.
+ SMLoc Loc;
+
+ /// All of the strings that are disallowed from occurring between this match
+ /// string and the previous one (or start of file).
+ std::vector<FileCheckPattern> DagNotStrings;
+
+ FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)
+ : Pat(P), Prefix(S), Loc(L) {}
+
+ /// Matches check string and its "not strings" and/or "dag strings".
+ size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
+ size_t &MatchLen, FileCheckRequest &Req,
+ std::vector<FileCheckDiag> *Diags) const;
+
+ /// Verifies that there is a single line in the given \p Buffer. Errors are
+ /// reported against \p SM.
+ bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
+ /// Verifies that there is no newline in the given \p Buffer. Errors are
+ /// reported against \p SM.
+ bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
+ /// Verifies that none of the strings in \p NotStrings are found in the given
+ /// \p Buffer. Errors are reported against \p SM and diagnostics recorded in
+ /// \p Diags according to the verbosity level set in \p Req.
+ bool CheckNot(const SourceMgr &SM, StringRef Buffer,
+ const std::vector<const FileCheckPattern *> &NotStrings,
+ const FileCheckRequest &Req,
+ std::vector<FileCheckDiag> *Diags) const;
+ /// Matches "dag strings" and their mixed "not strings".
+ size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
+ std::vector<const FileCheckPattern *> &NotStrings,
+ const FileCheckRequest &Req,
+ std::vector<FileCheckDiag> *Diags) const;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/lib/Support/FileCollector.cpp b/lib/Support/FileCollector.cpp
new file mode 100644
index 000000000000..47fca6413722
--- /dev/null
+++ b/lib/Support/FileCollector.cpp
@@ -0,0 +1,268 @@
+//===-- FileCollector.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FileCollector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm;
+
+static bool isCaseSensitivePath(StringRef Path) {
+ SmallString<256> TmpDest = Path, UpperDest, RealDest;
+
+ // Remove component traversals, links, etc.
+ if (!sys::fs::real_path(Path, TmpDest))
+ return true; // Current default value in vfs.yaml
+ Path = TmpDest;
+
+ // Change path to all upper case and ask for its real path, if the latter
+ // exists and is equal to path, it's not case sensitive. Default to case
+ // sensitive in the absence of real_path, since this is the YAMLVFSWriter
+ // default.
+ UpperDest = Path.upper();
+ if (sys::fs::real_path(UpperDest, RealDest) && Path.equals(RealDest))
+ return false;
+ return true;
+}
+
+FileCollector::FileCollector(std::string Root, std::string OverlayRoot)
+ : Root(std::move(Root)), OverlayRoot(std::move(OverlayRoot)) {
+ sys::fs::create_directories(this->Root, true);
+}
+
+bool FileCollector::getRealPath(StringRef SrcPath,
+ SmallVectorImpl<char> &Result) {
+ SmallString<256> RealPath;
+ StringRef FileName = sys::path::filename(SrcPath);
+ std::string Directory = sys::path::parent_path(SrcPath).str();
+ auto DirWithSymlink = SymlinkMap.find(Directory);
+
+ // Use real_path to fix any symbolic link component present in a path.
+ // Computing the real path is expensive, cache the search through the parent
+ // path Directory.
+ if (DirWithSymlink == SymlinkMap.end()) {
+ auto EC = sys::fs::real_path(Directory, RealPath);
+ if (EC)
+ return false;
+ SymlinkMap[Directory] = RealPath.str();
+ } else {
+ RealPath = DirWithSymlink->second;
+ }
+
+ sys::path::append(RealPath, FileName);
+ Result.swap(RealPath);
+ return true;
+}
+
+void FileCollector::addFile(const Twine &file) {
+ std::lock_guard<std::mutex> lock(Mutex);
+ std::string FileStr = file.str();
+ if (markAsSeen(FileStr))
+ addFileImpl(FileStr);
+}
+
+void FileCollector::addFileImpl(StringRef SrcPath) {
+ // We need an absolute src path to append to the root.
+ SmallString<256> AbsoluteSrc = SrcPath;
+ sys::fs::make_absolute(AbsoluteSrc);
+
+ // Canonicalize src to a native path to avoid mixed separator styles.
+ sys::path::native(AbsoluteSrc);
+
+ // Remove redundant leading "./" pieces and consecutive separators.
+ AbsoluteSrc = sys::path::remove_leading_dotslash(AbsoluteSrc);
+
+ // Canonicalize the source path by removing "..", "." components.
+ SmallString<256> VirtualPath = AbsoluteSrc;
+ sys::path::remove_dots(VirtualPath, /*remove_dot_dot=*/true);
+
+ // If a ".." component is present after a symlink component, remove_dots may
+ // lead to the wrong real destination path. Let the source be canonicalized
+ // like that but make sure we always use the real path for the destination.
+ SmallString<256> CopyFrom;
+ if (!getRealPath(AbsoluteSrc, CopyFrom))
+ CopyFrom = VirtualPath;
+
+ SmallString<256> DstPath = StringRef(Root);
+ sys::path::append(DstPath, sys::path::relative_path(CopyFrom));
+
+ // Always map a canonical src path to its real path into the YAML, by doing
+ // this we map different virtual src paths to the same entry in the VFS
+ // overlay, which is a way to emulate symlink inside the VFS; this is also
+ // needed for correctness, not doing that can lead to module redefinition
+ // errors.
+ addFileToMapping(VirtualPath, DstPath);
+}
+
+/// Set the access and modification time for the given file from the given
+/// status object.
+static std::error_code
+copyAccessAndModificationTime(StringRef Filename,
+ const sys::fs::file_status &Stat) {
+ int FD;
+
+ if (auto EC =
+ sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
+ return EC;
+
+ if (auto EC = sys::fs::setLastAccessAndModificationTime(
+ FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
+ return EC;
+
+ if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
+ return EC;
+
+ return {};
+}
+
+std::error_code FileCollector::copyFiles(bool StopOnError) {
+ for (auto &entry : VFSWriter.getMappings()) {
+ // Create directory tree.
+ if (std::error_code EC =
+ sys::fs::create_directories(sys::path::parent_path(entry.RPath),
+ /*IgnoreExisting=*/true)) {
+ if (StopOnError)
+ return EC;
+ }
+
+ // Get the status of the original file/directory.
+ sys::fs::file_status Stat;
+ if (std::error_code EC = sys::fs::status(entry.VPath, Stat)) {
+ if (StopOnError)
+ return EC;
+ continue;
+ }
+
+ if (Stat.type() == sys::fs::file_type::directory_file) {
+ // Construct a directory when it's just a directory entry.
+ if (std::error_code EC =
+ sys::fs::create_directories(entry.RPath,
+ /*IgnoreExisting=*/true)) {
+ if (StopOnError)
+ return EC;
+ }
+ continue;
+ }
+
+ // Copy file over.
+ if (std::error_code EC = sys::fs::copy_file(entry.VPath, entry.RPath)) {
+ if (StopOnError)
+ return EC;
+ }
+
+ // Copy over permissions.
+ if (auto perms = sys::fs::getPermissions(entry.VPath)) {
+ if (std::error_code EC = sys::fs::setPermissions(entry.RPath, *perms)) {
+ if (StopOnError)
+ return EC;
+ }
+ }
+
+ // Copy over modification time.
+ copyAccessAndModificationTime(entry.RPath, Stat);
+ }
+ return {};
+}
+
+std::error_code FileCollector::writeMapping(StringRef mapping_file) {
+ std::lock_guard<std::mutex> lock(Mutex);
+
+ VFSWriter.setOverlayDir(OverlayRoot);
+ VFSWriter.setCaseSensitivity(isCaseSensitivePath(OverlayRoot));
+ VFSWriter.setUseExternalNames(false);
+
+ std::error_code EC;
+ raw_fd_ostream os(mapping_file, EC, sys::fs::OF_Text);
+ if (EC)
+ return EC;
+
+ VFSWriter.write(os);
+
+ return {};
+}
+
+namespace {
+
+class FileCollectorFileSystem : public vfs::FileSystem {
+public:
+ explicit FileCollectorFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS,
+ std::shared_ptr<FileCollector> Collector)
+ : FS(std::move(FS)), Collector(std::move(Collector)) {}
+
+ llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
+ auto Result = FS->status(Path);
+ if (Result && Result->exists())
+ Collector->addFile(Path);
+ return Result;
+ }
+
+ llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+ openFileForRead(const Twine &Path) override {
+ auto Result = FS->openFileForRead(Path);
+ if (Result && *Result)
+ Collector->addFile(Path);
+ return Result;
+ }
+
+ llvm::vfs::directory_iterator dir_begin(const llvm::Twine &Dir,
+ std::error_code &EC) override {
+ auto It = FS->dir_begin(Dir, EC);
+ if (EC)
+ return It;
+ // Collect everything that's listed in case the user needs it.
+ Collector->addFile(Dir);
+ for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
+ if (It->type() == sys::fs::file_type::regular_file ||
+ It->type() == sys::fs::file_type::directory_file ||
+ It->type() == sys::fs::file_type::symlink_file) {
+ Collector->addFile(It->path());
+ }
+ }
+ if (EC)
+ return It;
+ // Return a new iterator.
+ return FS->dir_begin(Dir, EC);
+ }
+
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override {
+ auto EC = FS->getRealPath(Path, Output);
+ if (!EC) {
+ Collector->addFile(Path);
+ if (Output.size() > 0)
+ Collector->addFile(Output);
+ }
+ return EC;
+ }
+
+ std::error_code isLocal(const Twine &Path, bool &Result) override {
+ return FS->isLocal(Path, Result);
+ }
+
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return FS->getCurrentWorkingDirectory();
+ }
+
+ std::error_code setCurrentWorkingDirectory(const llvm::Twine &Path) override {
+ return FS->setCurrentWorkingDirectory(Path);
+ }
+
+private:
+ IntrusiveRefCntPtr<vfs::FileSystem> FS;
+ std::shared_ptr<FileCollector> Collector;
+};
+
+} // end anonymous namespace
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+FileCollector::createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
+ std::shared_ptr<FileCollector> Collector) {
+ return new FileCollectorFileSystem(std::move(BaseFS), std::move(Collector));
+}
diff --git a/lib/Support/FileOutputBuffer.cpp b/lib/Support/FileOutputBuffer.cpp
index 3d6b569f2993..024dd3e57a40 100644
--- a/lib/Support/FileOutputBuffer.cpp
+++ b/lib/Support/FileOutputBuffer.cpp
@@ -121,7 +121,7 @@ createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) {
Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
if (EC)
return errorCodeToError(EC);
- return llvm::make_unique<InMemoryBuffer>(Path, MB, Size, Mode);
+ return std::make_unique<InMemoryBuffer>(Path, MB, Size, Mode);
}
static Expected<std::unique_ptr<FileOutputBuffer>>
@@ -146,7 +146,7 @@ createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) {
// Mmap it.
std::error_code EC;
- auto MappedFile = llvm::make_unique<fs::mapped_file_region>(
+ auto MappedFile = std::make_unique<fs::mapped_file_region>(
fs::convertFDToNativeFile(File.FD), fs::mapped_file_region::readwrite,
Size, 0, EC);
@@ -157,7 +157,7 @@ createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) {
return createInMemoryBuffer(Path, Size, Mode);
}
- return llvm::make_unique<OnDiskBuffer>(Path, std::move(File),
+ return std::make_unique<OnDiskBuffer>(Path, std::move(File),
std::move(MappedFile));
}
diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp
index 62eb7bfda195..d11fbb54dc0d 100644
--- a/lib/Support/FileUtilities.cpp
+++ b/lib/Support/FileUtilities.cpp
@@ -12,9 +12,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FileUtilities.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cctype>
#include <cmath>
@@ -264,3 +267,66 @@ int llvm::DiffFilesWithTolerance(StringRef NameA,
return CompareFailed;
}
+
+void llvm::AtomicFileWriteError::log(raw_ostream &OS) const {
+ OS << "atomic_write_error: ";
+ switch (Error) {
+ case atomic_write_error::failed_to_create_uniq_file:
+ OS << "failed_to_create_uniq_file";
+ return;
+ case atomic_write_error::output_stream_error:
+ OS << "output_stream_error";
+ return;
+ case atomic_write_error::failed_to_rename_temp_file:
+ OS << "failed_to_rename_temp_file";
+ return;
+ }
+ llvm_unreachable("unknown atomic_write_error value in "
+ "failed_to_rename_temp_file::log()");
+}
+
+llvm::Error llvm::writeFileAtomically(StringRef TempPathModel,
+ StringRef FinalPath, StringRef Buffer) {
+ return writeFileAtomically(TempPathModel, FinalPath,
+ [&Buffer](llvm::raw_ostream &OS) {
+ OS.write(Buffer.data(), Buffer.size());
+ return llvm::Error::success();
+ });
+}
+
+llvm::Error llvm::writeFileAtomically(
+ StringRef TempPathModel, StringRef FinalPath,
+ std::function<llvm::Error(llvm::raw_ostream &)> Writer) {
+ SmallString<128> GeneratedUniqPath;
+ int TempFD;
+ if (sys::fs::createUniqueFile(TempPathModel.str(), TempFD,
+ GeneratedUniqPath)) {
+ return llvm::make_error<AtomicFileWriteError>(
+ atomic_write_error::failed_to_create_uniq_file);
+ }
+ llvm::FileRemover RemoveTmpFileOnFail(GeneratedUniqPath);
+
+ raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
+ if (llvm::Error Err = Writer(OS)) {
+ return Err;
+ }
+
+ OS.close();
+ if (OS.has_error()) {
+ OS.clear_error();
+ return llvm::make_error<AtomicFileWriteError>(
+ atomic_write_error::output_stream_error);
+ }
+
+ if (const std::error_code Error =
+ sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(),
+ /*to=*/FinalPath.str().c_str())) {
+ return llvm::make_error<AtomicFileWriteError>(
+ atomic_write_error::failed_to_rename_temp_file);
+ }
+
+ RemoveTmpFileOnFail.releaseFile();
+ return Error::success();
+}
+
+char llvm::AtomicFileWriteError::ID;
diff --git a/lib/Support/GlobPattern.cpp b/lib/Support/GlobPattern.cpp
index 6011be86d77f..8dae6941ec77 100644
--- a/lib/Support/GlobPattern.cpp
+++ b/lib/Support/GlobPattern.cpp
@@ -19,7 +19,7 @@
using namespace llvm;
static bool hasWildcard(StringRef S) {
- return S.find_first_of("?*[") != StringRef::npos;
+ return S.find_first_of("?*[\\") != StringRef::npos;
}
// Expands character ranges and returns a bitmap.
@@ -60,8 +60,9 @@ static Expected<BitVector> expand(StringRef S, StringRef Original) {
}
// This is a scanner for the glob pattern.
-// A glob pattern token is one of "*", "?", "[<chars>]", "[^<chars>]"
-// (which is a negative form of "[<chars>]"), or a non-meta character.
+// A glob pattern token is one of "*", "?", "\", "[<chars>]", "[^<chars>]"
+// (which is a negative form of "[<chars>]"), "[!<chars>]" (which is
+// equivalent to "[^<chars>]"), or a non-meta character.
// This function returns the first token in S.
static Expected<BitVector> scan(StringRef &S, StringRef Original) {
switch (S[0]) {
@@ -74,14 +75,16 @@ static Expected<BitVector> scan(StringRef &S, StringRef Original) {
S = S.substr(1);
return BitVector(256, true);
case '[': {
- size_t End = S.find(']', 1);
+ // ']' is allowed as the first character of a character class. '[]' is
+ // invalid. So, just skip the first character.
+ size_t End = S.find(']', 2);
if (End == StringRef::npos)
return make_error<StringError>("invalid glob pattern: " + Original,
errc::invalid_argument);
StringRef Chars = S.substr(1, End - 1);
S = S.substr(End + 1);
- if (Chars.startswith("^")) {
+ if (Chars.startswith("^") || Chars.startswith("!")) {
Expected<BitVector> BV = expand(Chars.substr(1), Original);
if (!BV)
return BV.takeError();
@@ -89,6 +92,11 @@ static Expected<BitVector> scan(StringRef &S, StringRef Original) {
}
return expand(Chars, Original);
}
+ case '\\':
+ // Eat this character and fall through below to treat it like a non-meta
+ // character.
+ S = S.substr(1);
+ LLVM_FALLTHROUGH;
default:
BitVector BV(256, false);
BV[(uint8_t)S[0]] = true;
@@ -107,8 +115,9 @@ Expected<GlobPattern> GlobPattern::create(StringRef S) {
return Pat;
}
- // S is something like "foo*". We can use startswith().
- if (S.endswith("*") && !hasWildcard(S.drop_back())) {
+ // S is something like "foo*", and the "* is not escaped. We can use
+ // startswith().
+ if (S.endswith("*") && !S.endswith("\\*") && !hasWildcard(S.drop_back())) {
Pat.Prefix = S.drop_back();
return Pat;
}
diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp
index d491912bdc0c..2a473a1994c2 100644
--- a/lib/Support/Host.cpp
+++ b/lib/Support/Host.cpp
@@ -316,7 +316,7 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) {
unsigned int Id;
if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) {
if (Id >= 8561 && HaveVectorSupport)
- return "arch13";
+ return "z15";
if (Id >= 3906 && HaveVectorSupport)
return "z14";
if (Id >= 2964 && HaveVectorSupport)
@@ -680,7 +680,7 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
// Skylake Xeon:
case 0x55:
*Type = X86::INTEL_COREI7;
- if (Features3 & (1 << (X86::FEATURE_AVX512BF16 - 64)))
+ if (Features2 & (1 << (X86::FEATURE_AVX512BF16 - 32)))
*Subtype = X86::INTEL_COREI7_COOPERLAKE; // "cooperlake"
else if (Features2 & (1 << (X86::FEATURE_AVX512VNNI - 32)))
*Subtype = X86::INTEL_COREI7_CASCADELAKE; // "cascadelake"
@@ -746,6 +746,13 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
break;
default: // Unknown family 6 CPU, try to guess.
+ // TODO detect tigerlake host
+ if (Features3 & (1 << (X86::FEATURE_AVX512VP2INTERSECT - 64))) {
+ *Type = X86::INTEL_COREI7;
+ *Subtype = X86::INTEL_COREI7_TIGERLAKE;
+ break;
+ }
+
if (Features & (1 << X86::FEATURE_AVX512VBMI2)) {
*Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT;
@@ -758,7 +765,7 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
break;
}
- if (Features3 & (1 << (X86::FEATURE_AVX512BF16 - 64))) {
+ if (Features2 & (1 << (X86::FEATURE_AVX512BF16 - 32))) {
*Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_COOPERLAKE;
break;
@@ -1034,7 +1041,7 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
setFeature(X86::FEATURE_BMI);
if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
setFeature(X86::FEATURE_AVX2);
- if (HasLeaf7 && ((EBX >> 9) & 1))
+ if (HasLeaf7 && ((EBX >> 8) & 1))
setFeature(X86::FEATURE_BMI2);
if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
setFeature(X86::FEATURE_AVX512F);
@@ -1078,6 +1085,13 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
setFeature(X86::FEATURE_AVX5124VNNIW);
if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
setFeature(X86::FEATURE_AVX5124FMAPS);
+ if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save)
+ setFeature(X86::FEATURE_AVX512VP2INTERSECT);
+
+ bool HasLeaf7Subleaf1 =
+ MaxLeaf >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);
+ if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save)
+ setFeature(X86::FEATURE_AVX512BF16);
unsigned MaxExtLevel;
getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
@@ -1369,7 +1383,6 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1);
Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1);
Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1);
- Features["mpx"] = HasLeaf7 && ((EBX >> 14) & 1);
// AVX512 is only supported if the OS supports the context save for it.
Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save;
Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save;
@@ -1499,6 +1512,17 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
return true;
}
+#elif defined(_WIN32) && (defined(__aarch64__) || defined(_M_ARM64))
+bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
+ if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
+ Features["neon"] = true;
+ if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
+ Features["crc"] = true;
+ if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE))
+ Features["crypto"] = true;
+
+ return true;
+}
#else
bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return false; }
#endif
diff --git a/lib/Support/JSON.cpp b/lib/Support/JSON.cpp
index 95e5ed654277..16b1d11efd08 100644
--- a/lib/Support/JSON.cpp
+++ b/lib/Support/JSON.cpp
@@ -502,7 +502,7 @@ bool Parser::parseError(const char *Msg) {
}
}
Err.emplace(
- llvm::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
+ std::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
return false;
}
} // namespace
diff --git a/lib/Support/JamCRC.cpp b/lib/Support/JamCRC.cpp
deleted file mode 100644
index e043a3c33c28..000000000000
--- a/lib/Support/JamCRC.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-//===-- JamCRC.cpp - Cyclic Redundancy Check --------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains an implementation of JamCRC.
-//
-//===----------------------------------------------------------------------===//
-//
-// The implementation technique is the one mentioned in:
-// D. V. Sarwate. 1988. Computation of cyclic redundancy checks via table
-// look-up. Commun. ACM 31, 8 (August 1988)
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/JamCRC.h"
-#include "llvm/ADT/ArrayRef.h"
-
-using namespace llvm;
-
-static const uint32_t CRCTable[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
-};
-
-void JamCRC::update(ArrayRef<char> Data) {
- for (char Byte : Data) {
- int TableIdx = (CRC ^ Byte) & 0xff;
- CRC = CRCTable[TableIdx] ^ (CRC >> 8);
- }
-}
diff --git a/lib/Support/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp
index 28ceb1a70e42..053493f72fb5 100644
--- a/lib/Support/ManagedStatic.cpp
+++ b/lib/Support/ManagedStatic.cpp
@@ -12,21 +12,20 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Config/config.h"
-#include "llvm/Support/Mutex.h"
-#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/Threading.h"
#include <cassert>
+#include <mutex>
using namespace llvm;
static const ManagedStaticBase *StaticList = nullptr;
-static sys::Mutex *ManagedStaticMutex = nullptr;
+static std::recursive_mutex *ManagedStaticMutex = nullptr;
static llvm::once_flag mutex_init_flag;
static void initializeMutex() {
- ManagedStaticMutex = new sys::Mutex();
+ ManagedStaticMutex = new std::recursive_mutex();
}
-static sys::Mutex* getManagedStaticMutex() {
+static std::recursive_mutex *getManagedStaticMutex() {
llvm::call_once(mutex_init_flag, initializeMutex);
return ManagedStaticMutex;
}
@@ -35,7 +34,7 @@ void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
void (*Deleter)(void*)) const {
assert(Creator);
if (llvm_is_multithreaded()) {
- MutexGuard Lock(*getManagedStaticMutex());
+ std::lock_guard<std::recursive_mutex> Lock(*getManagedStaticMutex());
if (!Ptr.load(std::memory_order_relaxed)) {
void *Tmp = Creator();
@@ -77,7 +76,7 @@ void ManagedStaticBase::destroy() const {
/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
void llvm::llvm_shutdown() {
- MutexGuard Lock(*getManagedStaticMutex());
+ std::lock_guard<std::recursive_mutex> Lock(*getManagedStaticMutex());
while (StaticList)
StaticList->destroy();
diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp
index d0e5bb154c1a..e4027ca7bbfd 100644
--- a/lib/Support/MemoryBuffer.cpp
+++ b/lib/Support/MemoryBuffer.cpp
@@ -211,15 +211,17 @@ static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) {
const ssize_t ChunkSize = 4096*4;
SmallString<ChunkSize> Buffer;
- size_t ReadBytes;
// Read into Buffer until we hit EOF.
- do {
+ for (;;) {
Buffer.reserve(Buffer.size() + ChunkSize);
- if (auto EC = sys::fs::readNativeFile(
- FD, makeMutableArrayRef(Buffer.end(), ChunkSize), &ReadBytes))
- return EC;
- Buffer.set_size(Buffer.size() + ReadBytes);
- } while (ReadBytes != 0);
+ Expected<size_t> ReadBytes = sys::fs::readNativeFile(
+ FD, makeMutableArrayRef(Buffer.end(), ChunkSize));
+ if (!ReadBytes)
+ return errorToErrorCode(ReadBytes.takeError());
+ if (*ReadBytes == 0)
+ break;
+ Buffer.set_size(Buffer.size() + *ReadBytes);
+ }
return getMemBufferCopyImpl(Buffer, BufferName);
}
@@ -458,7 +460,20 @@ getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
return make_error_code(errc::not_enough_memory);
}
- sys::fs::readNativeFileSlice(FD, Buf->getBuffer(), Offset);
+ // Read until EOF, zero-initialize the rest.
+ MutableArrayRef<char> ToRead = Buf->getBuffer();
+ while (!ToRead.empty()) {
+ Expected<size_t> ReadBytes =
+ sys::fs::readNativeFileSlice(FD, ToRead, Offset);
+ if (!ReadBytes)
+ return errorToErrorCode(ReadBytes.takeError());
+ if (*ReadBytes == 0) {
+ std::memset(ToRead.data(), 0, ToRead.size());
+ break;
+ }
+ ToRead = ToRead.drop_front(*ReadBytes);
+ Offset += *ReadBytes;
+ }
return std::move(Buf);
}
diff --git a/lib/Support/Mutex.cpp b/lib/Support/Mutex.cpp
deleted file mode 100644
index 69b7b8126ab1..000000000000
--- a/lib/Support/Mutex.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-//===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the llvm::sys::Mutex class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Mutex.h"
-#include "llvm/Config/config.h"
-#include "llvm/Support/ErrorHandling.h"
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only TRULY operating system
-//=== independent code.
-//===----------------------------------------------------------------------===//
-
-#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
-// Define all methods as no-ops if threading is explicitly disabled
-namespace llvm {
-using namespace sys;
-MutexImpl::MutexImpl( bool recursive) { }
-MutexImpl::~MutexImpl() { }
-bool MutexImpl::acquire() { return true; }
-bool MutexImpl::release() { return true; }
-bool MutexImpl::tryacquire() { return true; }
-}
-#else
-
-#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_LOCK)
-
-#include <cassert>
-#include <pthread.h>
-#include <stdlib.h>
-
-namespace llvm {
-using namespace sys;
-
-// Construct a Mutex using pthread calls
-MutexImpl::MutexImpl( bool recursive)
- : data_(nullptr)
-{
- // Declare the pthread_mutex data structures
- pthread_mutex_t* mutex =
- static_cast<pthread_mutex_t*>(safe_malloc(sizeof(pthread_mutex_t)));
-
- pthread_mutexattr_t attr;
-
- // Initialize the mutex attributes
- int errorcode = pthread_mutexattr_init(&attr);
- assert(errorcode == 0); (void)errorcode;
-
- // Initialize the mutex as a recursive mutex, if requested, or normal
- // otherwise.
- int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL );
- errorcode = pthread_mutexattr_settype(&attr, kind);
- assert(errorcode == 0);
-
- // Initialize the mutex
- errorcode = pthread_mutex_init(mutex, &attr);
- assert(errorcode == 0);
-
- // Destroy the attributes
- errorcode = pthread_mutexattr_destroy(&attr);
- assert(errorcode == 0);
-
- // Assign the data member
- data_ = mutex;
-}
-
-// Destruct a Mutex
-MutexImpl::~MutexImpl()
-{
- pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_);
- assert(mutex != nullptr);
- pthread_mutex_destroy(mutex);
- free(mutex);
-}
-
-bool
-MutexImpl::acquire()
-{
- pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_);
- assert(mutex != nullptr);
-
- int errorcode = pthread_mutex_lock(mutex);
- return errorcode == 0;
-}
-
-bool
-MutexImpl::release()
-{
- pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_);
- assert(mutex != nullptr);
-
- int errorcode = pthread_mutex_unlock(mutex);
- return errorcode == 0;
-}
-
-bool
-MutexImpl::tryacquire()
-{
- pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_);
- assert(mutex != nullptr);
-
- int errorcode = pthread_mutex_trylock(mutex);
- return errorcode == 0;
-}
-
-}
-
-#elif defined(LLVM_ON_UNIX)
-#include "Unix/Mutex.inc"
-#elif defined( _WIN32)
-#include "Windows/Mutex.inc"
-#else
-#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp
-#endif
-#endif
diff --git a/lib/Support/Parallel.cpp b/lib/Support/Parallel.cpp
index 621bccbf2a4c..355c64b7d079 100644
--- a/lib/Support/Parallel.cpp
+++ b/lib/Support/Parallel.cpp
@@ -32,34 +32,6 @@ public:
static Executor *getDefaultExecutor();
};
-#if defined(_MSC_VER)
-/// An Executor that runs tasks via ConcRT.
-class ConcRTExecutor : public Executor {
- struct Taskish {
- Taskish(std::function<void()> Task) : Task(Task) {}
-
- std::function<void()> Task;
-
- static void run(void *P) {
- Taskish *Self = static_cast<Taskish *>(P);
- Self->Task();
- concurrency::Free(Self);
- }
- };
-
-public:
- virtual void add(std::function<void()> F) {
- Concurrency::CurrentScheduler::ScheduleTask(
- Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
- }
-};
-
-Executor *Executor::getDefaultExecutor() {
- static ConcRTExecutor exec;
- return &exec;
-}
-
-#else
/// An implementation of an Executor that runs closures on a thread pool
/// in filo order.
class ThreadPoolExecutor : public Executor {
@@ -117,8 +89,7 @@ Executor *Executor::getDefaultExecutor() {
static ThreadPoolExecutor exec;
return &exec;
}
-#endif
-}
+} // namespace
static std::atomic<int> TaskGroupInstances;
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index c49260125dba..14def83802da 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -855,11 +855,11 @@ void make_absolute(const Twine &current_directory,
StringRef p(path.data(), path.size());
bool rootDirectory = path::has_root_directory(p);
- bool rootName =
- (real_style(Style::native) != Style::windows) || path::has_root_name(p);
+ bool rootName = path::has_root_name(p);
// Already absolute.
- if (rootName && rootDirectory)
+ if ((rootName || real_style(Style::native) != Style::windows) &&
+ rootDirectory)
return;
// All of the following conditions will need the current directory.
diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp
index aec00baec0e3..bfb238cc8539 100644
--- a/lib/Support/PrettyStackTrace.cpp
+++ b/lib/Support/PrettyStackTrace.cpp
@@ -121,31 +121,63 @@ extern "C" const char *__crashreporter_info__
asm(".desc ___crashreporter_info__, 0x10");
#endif
-/// CrashHandler - This callback is run if a fatal signal is delivered to the
-/// process, it prints the pretty stack trace.
+static void setCrashLogMessage(const char *msg) LLVM_ATTRIBUTE_UNUSED;
+static void setCrashLogMessage(const char *msg) {
+#ifdef HAVE_CRASHREPORTERCLIENT_H
+ (void)CRSetCrashLogMessage(msg);
+#elif HAVE_CRASHREPORTER_INFO
+ __crashreporter_info__ = msg;
+#endif
+ // Don't reorder subsequent operations: whatever comes after might crash and
+ // we want the system crash handling to see the message we just set.
+ std::atomic_signal_fence(std::memory_order_seq_cst);
+}
+
+#ifdef __APPLE__
+using CrashHandlerString = SmallString<2048>;
+using CrashHandlerStringStorage =
+ std::aligned_storage<sizeof(CrashHandlerString),
+ alignof(CrashHandlerString)>::type;
+static CrashHandlerStringStorage crashHandlerStringStorage;
+#endif
+
+/// This callback is run if a fatal signal is delivered to the process, it
+/// prints the pretty stack trace.
static void CrashHandler(void *) {
#ifndef __APPLE__
// On non-apple systems, just emit the crash stack trace to stderr.
PrintCurStackTrace(errs());
#else
- // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
- // put it into __crashreporter_info__.
- SmallString<2048> TmpStr;
+ // Emit the crash stack trace to a SmallString, put it where the system crash
+ // handling will find it, and also send it to stderr.
+ //
+ // The SmallString is fairly large in the hope that we don't allocate (we're
+ // handling a fatal signal, something is already pretty wrong, allocation
+ // might not work). Further, we don't use a magic static in case that's also
+ // borked. We leak any allocation that does occur because the program is about
+ // to die anyways. This is technically racy if we were handling two fatal
+ // signals, however if we're in that situation a race is the least of our
+ // worries.
+ auto &crashHandlerString =
+ *new (&crashHandlerStringStorage) CrashHandlerString;
+
+ // If we crash while trying to print the stack trace, we still want the system
+ // crash handling to have some partial information. That'll work out as long
+ // as the SmallString doesn't allocate. If it does allocate then the system
+ // crash handling will see some garbage because the inline buffer now contains
+ // a pointer.
+ setCrashLogMessage(crashHandlerString.c_str());
+
{
- raw_svector_ostream Stream(TmpStr);
+ raw_svector_ostream Stream(crashHandlerString);
PrintCurStackTrace(Stream);
}
- if (!TmpStr.empty()) {
-#ifdef HAVE_CRASHREPORTERCLIENT_H
- // Cast to void to avoid warning.
- (void)CRSetCrashLogMessage(TmpStr.c_str());
-#elif HAVE_CRASHREPORTER_INFO
- __crashreporter_info__ = strdup(TmpStr.c_str());
-#endif
- errs() << TmpStr.str();
- }
-
+ if (!crashHandlerString.empty()) {
+ setCrashLogMessage(crashHandlerString.c_str());
+ errs() << crashHandlerString.str();
+ } else
+ setCrashLogMessage("No crash information.");
#endif
}
diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp
index 7ce856b716c6..5accf73e5f94 100644
--- a/lib/Support/RWMutex.cpp
+++ b/lib/Support/RWMutex.cpp
@@ -14,24 +14,20 @@
#include "llvm/Support/RWMutex.h"
#include "llvm/Config/config.h"
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only TRULY operating system
-//=== independent code.
-//===----------------------------------------------------------------------===//
+#if defined(LLVM_USE_RW_MUTEX_IMPL)
+using namespace llvm;
+using namespace sys;
#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
// Define all methods as no-ops if threading is explicitly disabled
-using namespace llvm;
-using namespace sys;
-
RWMutexImpl::RWMutexImpl() = default;
RWMutexImpl::~RWMutexImpl() = default;
-bool RWMutexImpl::reader_acquire() { return true; }
-bool RWMutexImpl::reader_release() { return true; }
-bool RWMutexImpl::writer_acquire() { return true; }
-bool RWMutexImpl::writer_release() { return true; }
+bool RWMutexImpl::lock_shared() { return true; }
+bool RWMutexImpl::unlock_shared() { return true; }
+bool RWMutexImpl::lock() { return true; }
+bool RWMutexImpl::unlock() { return true; }
#else
@@ -41,9 +37,6 @@ bool RWMutexImpl::writer_release() { return true; }
#include <cstdlib>
#include <pthread.h>
-using namespace llvm;
-using namespace sys;
-
// Construct a RWMutex using pthread calls
RWMutexImpl::RWMutexImpl()
{
@@ -75,7 +68,7 @@ RWMutexImpl::~RWMutexImpl()
}
bool
-RWMutexImpl::reader_acquire()
+RWMutexImpl::lock_shared()
{
pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
assert(rwlock != nullptr);
@@ -85,7 +78,7 @@ RWMutexImpl::reader_acquire()
}
bool
-RWMutexImpl::reader_release()
+RWMutexImpl::unlock_shared()
{
pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
assert(rwlock != nullptr);
@@ -95,7 +88,7 @@ RWMutexImpl::reader_release()
}
bool
-RWMutexImpl::writer_acquire()
+RWMutexImpl::lock()
{
pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
assert(rwlock != nullptr);
@@ -105,7 +98,7 @@ RWMutexImpl::writer_acquire()
}
bool
-RWMutexImpl::writer_release()
+RWMutexImpl::unlock()
{
pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
assert(rwlock != nullptr);
@@ -114,11 +107,30 @@ RWMutexImpl::writer_release()
return errorcode == 0;
}
-#elif defined(LLVM_ON_UNIX)
-#include "Unix/RWMutex.inc"
-#elif defined( _WIN32)
-#include "Windows/RWMutex.inc"
#else
-#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp
+
+RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { }
+
+RWMutexImpl::~RWMutexImpl() {
+ delete static_cast<MutexImpl *>(data_);
+}
+
+bool RWMutexImpl::lock_shared() {
+ return static_cast<MutexImpl *>(data_)->acquire();
+}
+
+bool RWMutexImpl::unlock_shared() {
+ return static_cast<MutexImpl *>(data_)->release();
+}
+
+bool RWMutexImpl::lock() {
+ return static_cast<MutexImpl *>(data_)->acquire();
+}
+
+bool RWMutexImpl::unlock() {
+ return static_cast<MutexImpl *>(data_)->release();
+}
+
+#endif
#endif
#endif
diff --git a/lib/Support/Regex.cpp b/lib/Support/Regex.cpp
index 4c1b07038024..8da345d4f140 100644
--- a/lib/Support/Regex.cpp
+++ b/lib/Support/Regex.cpp
@@ -52,14 +52,24 @@ Regex::~Regex() {
}
}
-bool Regex::isValid(std::string &Error) const {
- if (!error)
- return true;
+namespace {
+/// Utility to convert a regex error code into a human-readable string.
+void RegexErrorToString(int error, struct llvm_regex *preg,
+ std::string &Error) {
size_t len = llvm_regerror(error, preg, nullptr, 0);
Error.resize(len - 1);
llvm_regerror(error, preg, &Error[0], len);
+}
+
+} // namespace
+
+bool Regex::isValid(std::string &Error) const {
+ if (!error)
+ return true;
+
+ RegexErrorToString(error, preg, Error);
return false;
}
@@ -69,8 +79,14 @@ unsigned Regex::getNumMatches() const {
return preg->re_nsub;
}
-bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){
- if (error)
+bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches,
+ std::string *Error) const {
+ // Reset error, if given.
+ if (Error && !Error->empty())
+ *Error = "";
+
+ // Check if the regex itself didn't successfully compile.
+ if (Error ? !isValid(*Error) : !isValid())
return false;
unsigned nmatch = Matches ? preg->re_nsub+1 : 0;
@@ -83,11 +99,13 @@ bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){
int rc = llvm_regexec(preg, String.data(), nmatch, pm.data(), REG_STARTEND);
+ // Failure to match is not an error, it's just a normal return value.
+ // Any other error code is considered abnormal, and is logged in the Error.
if (rc == REG_NOMATCH)
return false;
if (rc != 0) {
- // regexec can fail due to invalid pattern or running out of memory.
- error = rc;
+ if (Error)
+ RegexErrorToString(error, preg, *Error);
return false;
}
@@ -112,14 +130,11 @@ bool Regex::match(StringRef String, SmallVectorImpl<StringRef> *Matches){
}
std::string Regex::sub(StringRef Repl, StringRef String,
- std::string *Error) {
+ std::string *Error) const {
SmallVector<StringRef, 8> Matches;
- // Reset error, if given.
- if (Error && !Error->empty()) *Error = "";
-
// Return the input if there was no match.
- if (!match(String, &Matches))
+ if (!match(String, &Matches, Error))
return String;
// Otherwise splice in the replacement string, starting with the prefix before
diff --git a/lib/Support/Signposts.cpp b/lib/Support/Signposts.cpp
index d456f41d2fa6..aa159e1da2ae 100644
--- a/lib/Support/Signposts.cpp
+++ b/lib/Support/Signposts.cpp
@@ -78,6 +78,8 @@ public:
#if LLVM_SUPPORT_XCODE_SIGNPOSTS
#define HAVE_ANY_SIGNPOST_IMPL 1
+#else
+#define HAVE_ANY_SIGNPOST_IMPL 0
#endif
SignpostEmitter::SignpostEmitter() {
diff --git a/lib/Support/SpecialCaseList.cpp b/lib/Support/SpecialCaseList.cpp
index 96e09f9552bb..9bd1f18a4ee7 100644
--- a/lib/Support/SpecialCaseList.cpp
+++ b/lib/Support/SpecialCaseList.cpp
@@ -53,7 +53,7 @@ bool SpecialCaseList::Matcher::insert(std::string Regexp,
return false;
RegExes.emplace_back(
- std::make_pair(make_unique<Regex>(std::move(CheckRE)), LineNumber));
+ std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
return true;
}
@@ -175,7 +175,7 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB,
// Create this section if it has not been seen before.
if (SectionsMap.find(Section) == SectionsMap.end()) {
- std::unique_ptr<Matcher> M = make_unique<Matcher>();
+ std::unique_ptr<Matcher> M = std::make_unique<Matcher>();
std::string REError;
if (!M->insert(Section, LineNo, REError)) {
Error = (Twine("malformed section ") + Section + ": '" + REError).str();
diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp
index e4f0535d21aa..8b4177c7fba6 100644
--- a/lib/Support/Statistic.cpp
+++ b/lib/Support/Statistic.cpp
@@ -57,7 +57,7 @@ namespace {
/// This class is also used to look up statistic values from applications that
/// use LLVM.
class StatisticInfo {
- std::vector<Statistic*> Stats;
+ std::vector<TrackingStatistic *> Stats;
friend void llvm::PrintStatistics();
friend void llvm::PrintStatistics(raw_ostream &OS);
@@ -66,14 +66,12 @@ class StatisticInfo {
/// Sort statistics by debugtype,name,description.
void sort();
public:
- using const_iterator = std::vector<Statistic *>::const_iterator;
+ using const_iterator = std::vector<TrackingStatistic *>::const_iterator;
StatisticInfo();
~StatisticInfo();
- void addStatistic(Statistic *S) {
- Stats.push_back(S);
- }
+ void addStatistic(TrackingStatistic *S) { Stats.push_back(S); }
const_iterator begin() const { return Stats.begin(); }
const_iterator end() const { return Stats.end(); }
@@ -90,7 +88,7 @@ static ManagedStatic<sys::SmartMutex<true> > StatLock;
/// RegisterStatistic - The first time a statistic is bumped, this method is
/// called.
-void Statistic::RegisterStatistic() {
+void TrackingStatistic::RegisterStatistic() {
// If stats are enabled, inform StatInfo that this statistic should be
// printed.
// llvm_shutdown calls destructors while holding the ManagedStatic mutex.
@@ -135,15 +133,16 @@ bool llvm::AreStatisticsEnabled() {
}
void StatisticInfo::sort() {
- llvm::stable_sort(Stats, [](const Statistic *LHS, const Statistic *RHS) {
- if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType()))
- return Cmp < 0;
+ llvm::stable_sort(
+ Stats, [](const TrackingStatistic *LHS, const TrackingStatistic *RHS) {
+ if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType()))
+ return Cmp < 0;
- if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
- return Cmp < 0;
+ if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
+ return Cmp < 0;
- return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
- });
+ return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
+ });
}
void StatisticInfo::reset() {
@@ -207,7 +206,7 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) {
// Print all of the statistics.
OS << "{\n";
const char *delim = "";
- for (const Statistic *Stat : Stats.Stats) {
+ for (const TrackingStatistic *Stat : Stats.Stats) {
OS << delim;
assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None &&
"Statistic group/type name is simple.");
diff --git a/lib/Support/StringExtras.cpp b/lib/Support/StringExtras.cpp
index bf28b2be5657..af8dd463e125 100644
--- a/lib/Support/StringExtras.cpp
+++ b/lib/Support/StringExtras.cpp
@@ -60,7 +60,9 @@ void llvm::SplitString(StringRef Source,
void llvm::printEscapedString(StringRef Name, raw_ostream &Out) {
for (unsigned i = 0, e = Name.size(); i != e; ++i) {
unsigned char C = Name[i];
- if (isPrint(C) && C != '\\' && C != '"')
+ if (C == '\\')
+ Out << '\\' << C;
+ else if (isPrint(C) && C != '"')
Out << C;
else
Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
diff --git a/lib/Support/TimeProfiler.cpp b/lib/Support/TimeProfiler.cpp
index bc2340815645..ca9119e30b65 100644
--- a/lib/Support/TimeProfiler.cpp
+++ b/lib/Support/TimeProfiler.cpp
@@ -24,29 +24,38 @@ using namespace std::chrono;
namespace llvm {
-static cl::opt<unsigned> TimeTraceGranularity(
- "time-trace-granularity",
- cl::desc(
- "Minimum time granularity (in microseconds) traced by time profiler"),
- cl::init(500));
-
TimeTraceProfiler *TimeTraceProfilerInstance = nullptr;
typedef duration<steady_clock::rep, steady_clock::period> DurationType;
+typedef time_point<steady_clock> TimePointType;
typedef std::pair<size_t, DurationType> CountAndDurationType;
typedef std::pair<std::string, CountAndDurationType>
NameAndCountAndDurationType;
struct Entry {
- time_point<steady_clock> Start;
- DurationType Duration;
+ TimePointType Start;
+ TimePointType End;
std::string Name;
std::string Detail;
- Entry(time_point<steady_clock> &&S, DurationType &&D, std::string &&N,
- std::string &&Dt)
- : Start(std::move(S)), Duration(std::move(D)), Name(std::move(N)),
+ Entry(TimePointType &&S, TimePointType &&E, std::string &&N, std::string &&Dt)
+ : Start(std::move(S)), End(std::move(E)), Name(std::move(N)),
Detail(std::move(Dt)){};
+
+ // Calculate timings for FlameGraph. Cast time points to microsecond precision
+ // rather than casting duration. This avoid truncation issues causing inner
+ // scopes overruning outer scopes.
+ steady_clock::rep getFlameGraphStartUs(TimePointType StartTime) const {
+ return (time_point_cast<microseconds>(Start) -
+ time_point_cast<microseconds>(StartTime))
+ .count();
+ }
+
+ steady_clock::rep getFlameGraphDurUs() const {
+ return (time_point_cast<microseconds>(End) -
+ time_point_cast<microseconds>(Start))
+ .count();
+ }
};
struct TimeTraceProfiler {
@@ -55,17 +64,27 @@ struct TimeTraceProfiler {
}
void begin(std::string Name, llvm::function_ref<std::string()> Detail) {
- Stack.emplace_back(steady_clock::now(), DurationType{}, std::move(Name),
+ Stack.emplace_back(steady_clock::now(), TimePointType(), std::move(Name),
Detail());
}
void end() {
assert(!Stack.empty() && "Must call begin() first");
auto &E = Stack.back();
- E.Duration = steady_clock::now() - E.Start;
+ E.End = steady_clock::now();
+
+ // Check that end times monotonically increase.
+ assert((Entries.empty() ||
+ (E.getFlameGraphStartUs(StartTime) + E.getFlameGraphDurUs() >=
+ Entries.back().getFlameGraphStartUs(StartTime) +
+ Entries.back().getFlameGraphDurUs())) &&
+ "TimeProfiler scope ended earlier than previous scope");
- // Only include sections longer than TimeTraceGranularity msec.
- if (duration_cast<microseconds>(E.Duration).count() > TimeTraceGranularity)
+ // Calculate duration at full precision for overall counts.
+ DurationType Duration = E.End - E.Start;
+
+ // Only include sections longer or equal to TimeTraceGranularity msec.
+ if (duration_cast<microseconds>(Duration).count() >= TimeTraceGranularity)
Entries.emplace_back(E);
// Track total time taken by each "name", but only the topmost levels of
@@ -78,7 +97,7 @@ struct TimeTraceProfiler {
}) == Stack.rend()) {
auto &CountAndTotal = CountAndTotalPerName[E.Name];
CountAndTotal.first++;
- CountAndTotal.second += E.Duration;
+ CountAndTotal.second += Duration;
}
Stack.pop_back();
@@ -94,8 +113,8 @@ struct TimeTraceProfiler {
// Emit all events for the main flame graph.
for (const auto &E : Entries) {
- auto StartUs = duration_cast<microseconds>(E.Start - StartTime).count();
- auto DurUs = duration_cast<microseconds>(E.Duration).count();
+ auto StartUs = E.getFlameGraphStartUs(StartTime);
+ auto DurUs = E.getFlameGraphDurUs();
J.object([&]{
J.attribute("pid", 1);
@@ -160,13 +179,17 @@ struct TimeTraceProfiler {
SmallVector<Entry, 16> Stack;
SmallVector<Entry, 128> Entries;
StringMap<CountAndDurationType> CountAndTotalPerName;
- time_point<steady_clock> StartTime;
+ TimePointType StartTime;
+
+ // Minimum time granularity (in microseconds)
+ unsigned TimeTraceGranularity;
};
-void timeTraceProfilerInitialize() {
+void timeTraceProfilerInitialize(unsigned TimeTraceGranularity) {
assert(TimeTraceProfilerInstance == nullptr &&
"Profiler should not be initialized");
TimeTraceProfilerInstance = new TimeTraceProfiler();
+ TimeTraceProfilerInstance->TimeTraceGranularity = TimeTraceGranularity;
}
void timeTraceProfilerCleanup() {
diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp
index 2a7ff1eaaf63..10c9b8e0b329 100644
--- a/lib/Support/Timer.cpp
+++ b/lib/Support/Timer.cpp
@@ -58,23 +58,23 @@ namespace {
std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
const std::string &OutputFilename = getLibSupportInfoOutputFilename();
if (OutputFilename.empty())
- return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
+ return std::make_unique<raw_fd_ostream>(2, false); // stderr.
if (OutputFilename == "-")
- return llvm::make_unique<raw_fd_ostream>(1, false); // stdout.
+ return std::make_unique<raw_fd_ostream>(1, false); // stdout.
// Append mode is used because the info output file is opened and closed
// each time -stats or -time-passes wants to print output to it. To
// compensate for this, the test-suite Makefiles have code to delete the
// info output file before running commands which write to it.
std::error_code EC;
- auto Result = llvm::make_unique<raw_fd_ostream>(
- OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text);
+ auto Result = std::make_unique<raw_fd_ostream>(
+ OutputFilename, EC, sys::fs::OF_Append | sys::fs::OF_Text);
if (!EC)
return Result;
errs() << "Error opening info-output-file '"
<< OutputFilename << " for appending!\n";
- return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
+ return std::make_unique<raw_fd_ostream>(2, false); // stderr.
}
namespace {
diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc
index a0927da50e48..05f8e32896fa 100644
--- a/lib/Support/Unix/Memory.inc
+++ b/lib/Support/Unix/Memory.inc
@@ -176,7 +176,7 @@ Memory::releaseMappedMemory(MemoryBlock &M) {
std::error_code
Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
- static const size_t PageSize = Process::getPageSizeEstimate();
+ static const Align PageSize = Align(Process::getPageSizeEstimate());
if (M.Address == nullptr || M.AllocatedSize == 0)
return std::error_code();
@@ -184,8 +184,8 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
return std::error_code(EINVAL, std::generic_category());
int Protect = getPosixProtectionFlags(Flags);
- uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize);
- uintptr_t End = alignAddr((uint8_t *)M.Address + M.AllocatedSize, PageSize);
+ uintptr_t Start = alignAddr((const uint8_t *)M.Address - PageSize.value() + 1, PageSize);
+ uintptr_t End = alignAddr((const uint8_t *)M.Address + M.AllocatedSize, PageSize);
bool InvalidateCache = (Flags & MF_EXEC);
diff --git a/lib/Support/Unix/Mutex.inc b/lib/Support/Unix/Mutex.inc
deleted file mode 100644
index 2c982b38d6ff..000000000000
--- a/lib/Support/Unix/Mutex.inc
+++ /dev/null
@@ -1,42 +0,0 @@
-//===- llvm/Support/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Unix specific (non-pthread) Mutex class.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic UNIX code that
-//=== is guaranteed to work on *all* UNIX variants.
-//===----------------------------------------------------------------------===//
-
-namespace llvm
-{
-using namespace sys;
-
-MutexImpl::MutexImpl( bool recursive)
-{
-}
-
-MutexImpl::~MutexImpl()
-{
-}
-
-bool
-MutexImpl::release()
-{
- return true;
-}
-
-bool
-MutexImpl::tryacquire( void )
-{
- return true;
-}
-
-}
diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc
index e80880c6b3cb..a617eca3566a 100644
--- a/lib/Support/Unix/Path.inc
+++ b/lib/Support/Unix/Path.inc
@@ -186,12 +186,12 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__minix) || defined(__DragonFly__) || \
defined(__FreeBSD_kernel__) || defined(_AIX)
- StringRef curproc("/proc/curproc/file");
+ const char *curproc = "/proc/curproc/file";
char exe_path[PATH_MAX];
// /proc is not mounted by default under FreeBSD, but gives more accurate
// information than argv[0] when it is.
if (sys::fs::exists(curproc)) {
- ssize_t len = readlink(curproc.str().c_str(), exe_path, sizeof(exe_path));
+ ssize_t len = readlink(curproc, exe_path, sizeof(exe_path));
if (len > 0) {
// Null terminate the string for realpath. readlink never null
// terminates its output.
@@ -205,10 +205,10 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
return exe_path;
#elif defined(__linux__) || defined(__CYGWIN__)
char exe_path[MAXPATHLEN];
- StringRef aPath("/proc/self/exe");
+ const char *aPath = "/proc/self/exe";
if (sys::fs::exists(aPath)) {
// /proc is not always mounted under Linux (chroot for example).
- ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
+ ssize_t len = readlink(aPath, exe_path, sizeof(exe_path));
if (len < 0)
return "";
@@ -443,7 +443,7 @@ static bool is_local_impl(struct STATVFS &Vfs) {
std::unique_ptr<char[]> Buf;
int Tries = 3;
while (Tries--) {
- Buf = llvm::make_unique<char[]>(BufSize);
+ Buf = std::make_unique<char[]>(BufSize);
Ret = mntctl(MCTL_QUERY, BufSize, Buf.get());
if (Ret != 0)
break;
@@ -833,7 +833,10 @@ std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
static file_type direntType(dirent* Entry) {
// Most platforms provide the file type in the dirent: Linux/BSD/Mac.
// The DTTOIF macro lets us reuse our status -> type conversion.
-#if defined(_DIRENT_HAVE_D_TYPE) && defined(DTTOIF)
+ // Note that while glibc provides a macro to see if this is supported,
+ // _DIRENT_HAVE_D_TYPE, it's not defined on BSD/Mac, so we test for the
+ // d_type-to-mode_t conversion macro instead.
+#if defined(DTTOIF)
return typeForMode(DTTOIF(Entry->d_type));
#else
// Other platforms such as Solaris require a stat() to get the type.
@@ -884,9 +887,9 @@ static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
else if (Access == (FA_Read | FA_Write))
Result |= O_RDWR;
- // This is for compatibility with old code that assumed F_Append implied
+ // This is for compatibility with old code that assumed OF_Append implied
// would open an existing file. See Windows/Path.inc for a longer comment.
- if (Flags & F_Append)
+ if (Flags & OF_Append)
Disp = CD_OpenAlways;
if (Disp == CD_CreateNew) {
@@ -901,7 +904,7 @@ static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
// Nothing special, just don't add O_CREAT and we get these semantics.
}
- if (Flags & F_Append)
+ if (Flags & OF_Append)
Result |= O_APPEND;
#ifdef O_CLOEXEC
@@ -996,44 +999,28 @@ file_t getStdinHandle() { return 0; }
file_t getStdoutHandle() { return 1; }
file_t getStderrHandle() { return 2; }
-std::error_code readNativeFile(file_t FD, MutableArrayRef<char> Buf,
- size_t *BytesRead) {
- *BytesRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
- if (ssize_t(*BytesRead) == -1)
- return std::error_code(errno, std::generic_category());
- return std::error_code();
+Expected<size_t> readNativeFile(file_t FD, MutableArrayRef<char> Buf) {
+ ssize_t NumRead =
+ sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
+ if (ssize_t(NumRead) == -1)
+ return errorCodeToError(std::error_code(errno, std::generic_category()));
+ return NumRead;
}
-std::error_code readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
- size_t Offset) {
- char *BufPtr = Buf.data();
- size_t BytesLeft = Buf.size();
-
-#ifndef HAVE_PREAD
- // If we don't have pread, seek to Offset.
- if (lseek(FD, Offset, SEEK_SET) == -1)
- return std::error_code(errno, std::generic_category());
-#endif
-
- while (BytesLeft) {
+Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
+ uint64_t Offset) {
#ifdef HAVE_PREAD
- ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft,
- Buf.size() - BytesLeft + Offset);
+ ssize_t NumRead =
+ sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Buf.size(), Offset);
#else
- ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft);
+ if (lseek(FD, Offset, SEEK_SET) == -1)
+ return errorCodeToError(std::error_code(errno, std::generic_category()));
+ ssize_t NumRead =
+ sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size());
#endif
- if (NumRead == -1) {
- // Error while reading.
- return std::error_code(errno, std::generic_category());
- }
- if (NumRead == 0) {
- memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer.
- break;
- }
- BytesLeft -= NumRead;
- BufPtr += NumRead;
- }
- return std::error_code();
+ if (NumRead == -1)
+ return errorCodeToError(std::error_code(errno, std::generic_category()));
+ return NumRead;
}
std::error_code closeFile(file_t &F) {
@@ -1200,7 +1187,7 @@ namespace fs {
/// implementation.
std::error_code copy_file(const Twine &From, const Twine &To) {
uint32_t Flag = COPYFILE_DATA;
-#if __has_builtin(__builtin_available)
+#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE)
if (__builtin_available(macos 10.12, *)) {
bool IsSymlink;
if (std::error_code Error = is_symlink_file(From, IsSymlink))
diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc
index 4115ee396582..dfe81d7e2833 100644
--- a/lib/Support/Unix/Process.inc
+++ b/lib/Support/Unix/Process.inc
@@ -15,8 +15,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Mutex.h"
-#include "llvm/Support/MutexGuard.h"
+#include <mutex>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -327,13 +326,13 @@ extern "C" int tigetnum(char *capname);
#endif
#ifdef HAVE_TERMINFO
-static ManagedStatic<sys::Mutex> TermColorMutex;
+static ManagedStatic<std::mutex> TermColorMutex;
#endif
static bool terminalHasColors(int fd) {
#ifdef HAVE_TERMINFO
// First, acquire a global lock because these C routines are thread hostile.
- MutexGuard G(*TermColorMutex);
+ std::lock_guard<std::mutex> G(*TermColorMutex);
int errret = 0;
if (setupterm(nullptr, fd, &errret) != 0)
diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc
index c4123a64046f..520685a0e987 100644
--- a/lib/Support/Unix/Program.inc
+++ b/lib/Support/Unix/Program.inc
@@ -136,7 +136,7 @@ static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg,
if (int Err = posix_spawn_file_actions_addopen(
FileActions, FD, File,
FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))
- return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
+ return MakeErrMsg(ErrMsg, "Cannot posix_spawn_file_actions_addopen", Err);
return false;
}
#endif
@@ -444,7 +444,7 @@ std::error_code
llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
WindowsEncodingMethod Encoding /*unused*/) {
std::error_code EC;
- llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text);
+ llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::OF_Text);
if (EC)
return EC;
diff --git a/lib/Support/Unix/RWMutex.inc b/lib/Support/Unix/RWMutex.inc
deleted file mode 100644
index 8b47dfa0f85c..000000000000
--- a/lib/Support/Unix/RWMutex.inc
+++ /dev/null
@@ -1,50 +0,0 @@
-//= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Unix specific (non-pthread) RWMutex class.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic UNIX code that
-//=== is guaranteed to work on *all* UNIX variants.
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Mutex.h"
-
-namespace llvm {
-
-using namespace sys;
-
-// This naive implementation treats readers the same as writers. This
-// will therefore deadlock if a thread tries to acquire a read lock
-// multiple times.
-
-RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { }
-
-RWMutexImpl::~RWMutexImpl() {
- delete static_cast<MutexImpl *>(data_);
-}
-
-bool RWMutexImpl::reader_acquire() {
- return static_cast<MutexImpl *>(data_)->acquire();
-}
-
-bool RWMutexImpl::reader_release() {
- return static_cast<MutexImpl *>(data_)->release();
-}
-
-bool RWMutexImpl::writer_acquire() {
- return static_cast<MutexImpl *>(data_)->acquire();
-}
-
-bool RWMutexImpl::writer_release() {
- return static_cast<MutexImpl *>(data_)->release();
-}
-
-}
diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc
index 634c16aa36c7..5e0cde4a81ed 100644
--- a/lib/Support/Unix/Signals.inc
+++ b/lib/Support/Unix/Signals.inc
@@ -43,7 +43,6 @@
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/UniqueLock.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
@@ -83,12 +82,18 @@ using namespace llvm;
static RETSIGTYPE SignalHandler(int Sig); // defined below.
static RETSIGTYPE InfoSignalHandler(int Sig); // defined below.
+static void DefaultPipeSignalFunction() {
+ exit(EX_IOERR);
+}
+
using SignalHandlerFunctionType = void (*)();
/// The function to call if ctrl-c is pressed.
static std::atomic<SignalHandlerFunctionType> InterruptFunction =
ATOMIC_VAR_INIT(nullptr);
static std::atomic<SignalHandlerFunctionType> InfoSignalFunction =
ATOMIC_VAR_INIT(nullptr);
+static std::atomic<SignalHandlerFunctionType> PipeSignalFunction =
+ ATOMIC_VAR_INIT(DefaultPipeSignalFunction);
namespace {
/// Signal-safe removal of files.
@@ -364,7 +369,8 @@ static RETSIGTYPE SignalHandler(int Sig) {
// Send a special return code that drivers can check for, from sysexits.h.
if (Sig == SIGPIPE)
- exit(EX_IOERR);
+ if (SignalHandlerFunctionType CurrentPipeFunction = PipeSignalFunction)
+ CurrentPipeFunction();
raise(Sig); // Execute the default handler.
return;
@@ -404,6 +410,11 @@ void llvm::sys::SetInfoSignalFunction(void (*Handler)()) {
RegisterHandlers();
}
+void llvm::sys::SetPipeSignalFunction(void (*Handler)()) {
+ PipeSignalFunction.exchange(Handler);
+ RegisterHandlers();
+}
+
// The public API
bool llvm::sys::RemoveFileOnSignal(StringRef Filename,
std::string* ErrMsg) {
diff --git a/lib/Support/VirtualFileSystem.cpp b/lib/Support/VirtualFileSystem.cpp
index 5d3480e97148..c390cb1b2227 100644
--- a/lib/Support/VirtualFileSystem.cpp
+++ b/lib/Support/VirtualFileSystem.cpp
@@ -176,9 +176,9 @@ class RealFile : public File {
Status S;
std::string RealName;
- RealFile(file_t FD, StringRef NewName, StringRef NewRealPathName)
- : FD(FD), S(NewName, {}, {}, {}, {}, {},
- llvm::sys::fs::file_type::status_error, {}),
+ RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
+ : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
+ llvm::sys::fs::file_type::status_error, {}),
RealName(NewRealPathName.str()) {
assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
}
@@ -349,7 +349,7 @@ IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
}
std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
- return llvm::make_unique<RealFileSystem>(false);
+ return std::make_unique<RealFileSystem>(false);
}
namespace {
@@ -754,7 +754,7 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file,
NewDirectoryPerms);
Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
- Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
+ Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
continue;
}
@@ -989,6 +989,16 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
// RedirectingFileSystem implementation
//===-----------------------------------------------------------------------===/
+RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
+ : ExternalFS(std::move(FS)) {
+ if (ExternalFS)
+ if (auto ExternalWorkingDirectory =
+ ExternalFS->getCurrentWorkingDirectory()) {
+ WorkingDirectory = *ExternalWorkingDirectory;
+ ExternalFSValidWD = true;
+ }
+}
+
// FIXME: reuse implementation common with OverlayFSDirIterImpl as these
// iterators are conceptually similar.
class llvm::vfs::VFSFromYamlDirIterImpl
@@ -1035,12 +1045,27 @@ public:
llvm::ErrorOr<std::string>
RedirectingFileSystem::getCurrentWorkingDirectory() const {
- return ExternalFS->getCurrentWorkingDirectory();
+ return WorkingDirectory;
}
std::error_code
RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
- return ExternalFS->setCurrentWorkingDirectory(Path);
+ // Don't change the working directory if the path doesn't exist.
+ if (!exists(Path))
+ return errc::no_such_file_or_directory;
+
+ // Always change the external FS but ignore its result.
+ if (ExternalFS) {
+ auto EC = ExternalFS->setCurrentWorkingDirectory(Path);
+ ExternalFSValidWD = !static_cast<bool>(EC);
+ }
+
+ SmallString<128> AbsolutePath;
+ Path.toVector(AbsolutePath);
+ if (std::error_code EC = makeAbsolute(AbsolutePath))
+ return EC;
+ WorkingDirectory = AbsolutePath.str();
+ return {};
}
std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
@@ -1053,7 +1078,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir);
if (!E) {
EC = E.getError();
- if (IsFallthrough && EC == errc::no_such_file_or_directory)
+ if (shouldUseExternalFS() && EC == errc::no_such_file_or_directory)
return ExternalFS->dir_begin(Dir, EC);
return {};
}
@@ -1071,7 +1096,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E);
return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
Dir, D->contents_begin(), D->contents_end(),
- /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
+ /*IterateExternalFS=*/shouldUseExternalFS(), *ExternalFS, EC));
}
void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
@@ -1082,20 +1107,19 @@ StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
return ExternalContentsPrefixDir;
}
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const {
+void RedirectingFileSystem::dump(raw_ostream &OS) const {
for (const auto &Root : Roots)
- dumpEntry(Root.get());
+ dumpEntry(OS, Root.get());
}
-LLVM_DUMP_METHOD void
-RedirectingFileSystem::dumpEntry(RedirectingFileSystem::Entry *E,
- int NumSpaces) const {
+void RedirectingFileSystem::dumpEntry(raw_ostream &OS,
+ RedirectingFileSystem::Entry *E,
+ int NumSpaces) const {
StringRef Name = E->getName();
for (int i = 0, e = NumSpaces; i < e; ++i)
- dbgs() << " ";
- dbgs() << "'" << Name.str().c_str() << "'"
- << "\n";
+ OS << " ";
+ OS << "'" << Name.str().c_str() << "'"
+ << "\n";
if (E->getKind() == RedirectingFileSystem::EK_Directory) {
auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(E);
@@ -1103,9 +1127,12 @@ RedirectingFileSystem::dumpEntry(RedirectingFileSystem::Entry *E,
for (std::unique_ptr<Entry> &SubEntry :
llvm::make_range(DE->contents_begin(), DE->contents_end()))
- dumpEntry(SubEntry.get(), NumSpaces + 2);
+ dumpEntry(OS, SubEntry.get(), NumSpaces + 2);
}
}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const { dump(dbgs()); }
#endif
/// A helper class to hold the common YAML parsing state.
@@ -1209,7 +1236,7 @@ class llvm::vfs::RedirectingFileSystemParser {
// ... or create a new one
std::unique_ptr<RedirectingFileSystem::Entry> E =
- llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
+ std::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
Name, Status("", getNextVirtualUniqueID(),
std::chrono::system_clock::now(), 0, 0, 0,
file_type::directory_file, sys::fs::all_all));
@@ -1221,7 +1248,7 @@ class llvm::vfs::RedirectingFileSystemParser {
}
auto *DE =
- dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
+ cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
DE->addContent(std::move(E));
return DE->getLastContent();
}
@@ -1232,9 +1259,7 @@ class llvm::vfs::RedirectingFileSystemParser {
StringRef Name = SrcE->getName();
switch (SrcE->getKind()) {
case RedirectingFileSystem::EK_Directory: {
- auto *DE =
- dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
- assert(DE && "Must be a directory");
+ auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
// Empty directories could be present in the YAML as a way to
// describe a file for a current directory after some of its subdir
// is parsed. This only leads to redundant walks, ignore it.
@@ -1246,13 +1271,12 @@ class llvm::vfs::RedirectingFileSystemParser {
break;
}
case RedirectingFileSystem::EK_File: {
- auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
- assert(FE && "Must be a file");
assert(NewParentE && "Parent entry must exist");
- auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
- NewParentE);
+ auto *FE = cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
+ auto *DE =
+ cast<RedirectingFileSystem::RedirectingDirectoryEntry>(NewParentE);
DE->addContent(
- llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
+ std::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
Name, FE->getExternalContentsPath(), FE->getUseName()));
break;
}
@@ -1423,12 +1447,12 @@ class llvm::vfs::RedirectingFileSystemParser {
std::unique_ptr<RedirectingFileSystem::Entry> Result;
switch (Kind) {
case RedirectingFileSystem::EK_File:
- Result = llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
+ Result = std::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
LastComponent, std::move(ExternalContentsPath), UseExternalName);
break;
case RedirectingFileSystem::EK_Directory:
Result =
- llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
+ std::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
LastComponent, std::move(EntryArrayContents),
Status("", getNextVirtualUniqueID(),
std::chrono::system_clock::now(), 0, 0, 0,
@@ -1447,7 +1471,7 @@ class llvm::vfs::RedirectingFileSystemParser {
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
Entries.push_back(std::move(Result));
Result =
- llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
+ std::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
*I, std::move(Entries),
Status("", getNextVirtualUniqueID(),
std::chrono::system_clock::now(), 0, 0, 0,
@@ -1573,7 +1597,7 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
RedirectingFileSystemParser P(Stream);
std::unique_ptr<RedirectingFileSystem> FS(
- new RedirectingFileSystem(std::move(ExternalFS)));
+ new RedirectingFileSystem(ExternalFS));
if (!YAMLFilePath.empty()) {
// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
@@ -1702,7 +1726,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
- if (IsFallthrough &&
+ if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->status(Path);
}
@@ -1740,7 +1764,7 @@ ErrorOr<std::unique_ptr<File>>
RedirectingFileSystem::openFileForRead(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
if (!E) {
- if (IsFallthrough &&
+ if (shouldUseExternalFS() &&
E.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->openFileForRead(Path);
}
@@ -1763,7 +1787,7 @@ RedirectingFileSystem::openFileForRead(const Twine &Path) {
Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
*ExternalStatus);
return std::unique_ptr<File>(
- llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
+ std::make_unique<FileWithFixedStatus>(std::move(*Result), S));
}
std::error_code
@@ -1771,7 +1795,7 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) const {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
- if (IsFallthrough &&
+ if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->getRealPath(Path, Output);
}
@@ -1784,8 +1808,8 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
}
// Even if there is a directory entry, fall back to ExternalFS if allowed,
// because directories don't have a single external contents path.
- return IsFallthrough ? ExternalFS->getRealPath(Path, Output)
- : llvm::errc::invalid_argument;
+ return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
+ : llvm::errc::invalid_argument;
}
IntrusiveRefCntPtr<FileSystem>
diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc
deleted file mode 100644
index b55b14febf2c..000000000000
--- a/lib/Support/Windows/Mutex.inc
+++ /dev/null
@@ -1,56 +0,0 @@
-//===- llvm/Support/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Win32 specific (non-pthread) Mutex class.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Win32 code that
-//=== is guaranteed to work on *all* Win32 variants.
-//===----------------------------------------------------------------------===//
-
-#include "WindowsSupport.h"
-#include "llvm/Support/Mutex.h"
-
-namespace llvm {
-
-sys::MutexImpl::MutexImpl(bool /*recursive*/)
-{
- data_ = new CRITICAL_SECTION;
- InitializeCriticalSection((LPCRITICAL_SECTION)data_);
-}
-
-sys::MutexImpl::~MutexImpl()
-{
- DeleteCriticalSection((LPCRITICAL_SECTION)data_);
- delete (LPCRITICAL_SECTION)data_;
- data_ = 0;
-}
-
-bool
-sys::MutexImpl::acquire()
-{
- EnterCriticalSection((LPCRITICAL_SECTION)data_);
- return true;
-}
-
-bool
-sys::MutexImpl::release()
-{
- LeaveCriticalSection((LPCRITICAL_SECTION)data_);
- return true;
-}
-
-bool
-sys::MutexImpl::tryacquire()
-{
- return TryEnterCriticalSection((LPCRITICAL_SECTION)data_);
-}
-
-}
diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc
index 5704930aeecc..c3b13abef5de 100644
--- a/lib/Support/Windows/Path.inc
+++ b/lib/Support/Windows/Path.inc
@@ -371,13 +371,19 @@ static std::error_code realPathFromHandle(HANDLE H,
if (std::error_code EC = realPathFromHandle(H, Buffer))
return EC;
- const wchar_t *Data = Buffer.data();
+ // Strip the \\?\ prefix. We don't want it ending up in output, and such
+ // paths don't get canonicalized by file APIs.
+ wchar_t *Data = Buffer.data();
DWORD CountChars = Buffer.size();
- if (CountChars >= 4) {
- if (0 == ::memcmp(Data, L"\\\\?\\", 8)) {
- CountChars -= 4;
- Data += 4;
- }
+ if (CountChars >= 8 && ::memcmp(Data, L"\\\\?\\UNC\\", 16) == 0) {
+ // Convert \\?\UNC\foo\bar to \\foo\bar
+ CountChars -= 6;
+ Data += 6;
+ Data[0] = '\\';
+ } else if (CountChars >= 4 && ::memcmp(Data, L"\\\\?\\", 8) == 0) {
+ // Convert \\?\c:\foo to c:\foo
+ CountChars -= 4;
+ Data += 4;
}
// Convert the result from UTF-16 to UTF-8.
@@ -1217,57 +1223,34 @@ file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); }
file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); }
file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); }
-std::error_code readNativeFileImpl(file_t FileHandle, char *BufPtr, size_t BytesToRead,
- size_t *BytesRead, OVERLAPPED *Overlap) {
+Expected<size_t> readNativeFileImpl(file_t FileHandle,
+ MutableArrayRef<char> Buf,
+ OVERLAPPED *Overlap) {
// ReadFile can only read 2GB at a time. The caller should check the number of
// bytes and read in a loop until termination.
- DWORD BytesToRead32 =
- std::min(size_t(std::numeric_limits<DWORD>::max()), BytesToRead);
- DWORD BytesRead32 = 0;
- bool Success =
- ::ReadFile(FileHandle, BufPtr, BytesToRead32, &BytesRead32, Overlap);
- *BytesRead = BytesRead32;
- if (!Success) {
- DWORD Err = ::GetLastError();
- // Pipe EOF is not an error.
- if (Err == ERROR_BROKEN_PIPE)
- return std::error_code();
- return mapWindowsError(Err);
- }
- return std::error_code();
-}
-
-std::error_code readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf,
- size_t *BytesRead) {
- return readNativeFileImpl(FileHandle, Buf.data(), Buf.size(), BytesRead,
- /*Overlap=*/nullptr);
-}
-
-std::error_code readNativeFileSlice(file_t FileHandle,
- MutableArrayRef<char> Buf, size_t Offset) {
- char *BufPtr = Buf.data();
- size_t BytesLeft = Buf.size();
-
- while (BytesLeft) {
- uint64_t CurOff = Buf.size() - BytesLeft + Offset;
- OVERLAPPED Overlapped = {};
- Overlapped.Offset = uint32_t(CurOff);
- Overlapped.OffsetHigh = uint32_t(uint64_t(CurOff) >> 32);
-
- size_t BytesRead = 0;
- if (auto EC = readNativeFileImpl(FileHandle, BufPtr, BytesLeft, &BytesRead,
- &Overlapped))
- return EC;
-
- // Once we reach EOF, zero the remaining bytes in the buffer.
- if (BytesRead == 0) {
- memset(BufPtr, 0, BytesLeft);
- break;
- }
- BytesLeft -= BytesRead;
- BufPtr += BytesRead;
- }
- return std::error_code();
+ DWORD BytesToRead =
+ std::min(size_t(std::numeric_limits<DWORD>::max()), Buf.size());
+ DWORD BytesRead = 0;
+ if (::ReadFile(FileHandle, Buf.data(), BytesToRead, &BytesRead, Overlap))
+ return BytesRead;
+ DWORD Err = ::GetLastError();
+ // EOF is not an error.
+ if (Err == ERROR_BROKEN_PIPE || Err == ERROR_HANDLE_EOF)
+ return BytesRead;
+ return errorCodeToError(mapWindowsError(Err));
+}
+
+Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf) {
+ return readNativeFileImpl(FileHandle, Buf, /*Overlap=*/nullptr);
+}
+
+Expected<size_t> readNativeFileSlice(file_t FileHandle,
+ MutableArrayRef<char> Buf,
+ uint64_t Offset) {
+ OVERLAPPED Overlapped = {};
+ Overlapped.Offset = uint32_t(Offset);
+ Overlapped.OffsetHigh = uint32_t(Offset >> 32);
+ return readNativeFileImpl(FileHandle, Buf, &Overlapped);
}
std::error_code closeFile(file_t &F) {
diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc
index 0f54e59ee55b..a23ed95fc390 100644
--- a/lib/Support/Windows/Program.inc
+++ b/lib/Support/Windows/Program.inc
@@ -470,7 +470,7 @@ std::error_code
llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
WindowsEncodingMethod Encoding) {
std::error_code EC;
- llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OF_Text);
if (EC)
return EC;
diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc
deleted file mode 100644
index 8df9bc394160..000000000000
--- a/lib/Support/Windows/RWMutex.inc
+++ /dev/null
@@ -1,128 +0,0 @@
-//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Win32 specific (non-pthread) RWMutex class.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Win32 code that
-//=== is guaranteed to work on *all* Win32 variants.
-//===----------------------------------------------------------------------===//
-
-#include "WindowsSupport.h"
-
-namespace llvm {
-
-// Windows has slim read-writer lock support on Vista and higher, so we
-// will attempt to load the APIs. If they exist, we will use them, and
-// if not, we will fall back on critical sections. When we drop support
-// for XP, we can stop lazy-loading these APIs and just use them directly.
-#if defined(__MINGW32__)
- // Taken from WinNT.h
- typedef struct _RTL_SRWLOCK {
- PVOID Ptr;
- } RTL_SRWLOCK, *PRTL_SRWLOCK;
-
- // Taken from WinBase.h
- typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
-#endif
-
-static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
-static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
-static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
-static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
-static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
-
-static bool sHasSRW = false;
-
-static bool loadSRW() {
- static bool sChecked = false;
- if (!sChecked) {
- sChecked = true;
-
- if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
- fpInitializeSRWLock =
- (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
- "InitializeSRWLock");
- fpAcquireSRWLockExclusive =
- (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
- "AcquireSRWLockExclusive");
- fpAcquireSRWLockShared =
- (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
- "AcquireSRWLockShared");
- fpReleaseSRWLockExclusive =
- (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
- "ReleaseSRWLockExclusive");
- fpReleaseSRWLockShared =
- (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
- "ReleaseSRWLockShared");
-
- if (fpInitializeSRWLock != NULL) {
- sHasSRW = true;
- }
- }
- }
- return sHasSRW;
-}
-
-sys::RWMutexImpl::RWMutexImpl() {
- if (loadSRW()) {
- data_ = safe_calloc(1, sizeof(SRWLOCK));
- fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
- } else {
- data_ = safe_calloc(1, sizeof(CRITICAL_SECTION));
- InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- }
-}
-
-sys::RWMutexImpl::~RWMutexImpl() {
- if (!sHasSRW)
- DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- // Nothing to do in the case of slim reader/writers except free the memory.
- free(data_);
-}
-
-bool sys::RWMutexImpl::reader_acquire() {
- if (sHasSRW) {
- fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
- } else {
- EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- }
- return true;
-}
-
-bool sys::RWMutexImpl::reader_release() {
- if (sHasSRW) {
- fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
- } else {
- LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- }
- return true;
-}
-
-bool sys::RWMutexImpl::writer_acquire() {
- if (sHasSRW) {
- fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
- } else {
- EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- }
- return true;
-}
-
-bool sys::RWMutexImpl::writer_release() {
- if (sHasSRW) {
- fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
- } else {
- LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
- }
- return true;
-}
-
-
-}
diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc
index 6a820ef22b1e..d962daf79348 100644
--- a/lib/Support/Windows/Signals.inc
+++ b/lib/Support/Windows/Signals.inc
@@ -560,6 +560,9 @@ void llvm::sys::SetInfoSignalFunction(void (*Handler)()) {
// Unimplemented.
}
+void llvm::sys::SetPipeSignalFunction(void (*Handler)()) {
+ // Unimplemented.
+}
/// Add a function to be called when a signal is delivered to the process. The
/// handler can have a cookie passed to it to identify what instance of the
diff --git a/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h
index fed9b2f462ef..2e2e97430b76 100644
--- a/lib/Support/Windows/WindowsSupport.h
+++ b/lib/Support/Windows/WindowsSupport.h
@@ -38,6 +38,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h" // Get build system configuration settings
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/VersionTuple.h"
diff --git a/lib/Support/Windows/explicit_symbols.inc b/lib/Support/Windows/explicit_symbols.inc
index bbbf7ea6a777..0a4fda1d4e8c 100644
--- a/lib/Support/Windows/explicit_symbols.inc
+++ b/lib/Support/Windows/explicit_symbols.inc
@@ -90,12 +90,6 @@
INLINE_DEF_FLOAT_SYMBOL(tanf, 1)
INLINE_DEF_FLOAT_SYMBOL(tanhf, 1)
- // These were added in VS 2013.
-#if (1800 <= _MSC_VER && _MSC_VER < 1900)
- INLINE_DEF_FLOAT_SYMBOL(copysignf, 2)
- INLINE_DEF_FLOAT_SYMBOL(fminf, 2)
- INLINE_DEF_FLOAT_SYMBOL(fmaxf, 2)
-#endif
#undef INLINE_DEF_FLOAT_SYMBOL
#endif
diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp
index 09eb36943de9..eba22fd14725 100644
--- a/lib/Support/YAMLTraits.cpp
+++ b/lib/Support/YAMLTraits.cpp
@@ -40,7 +40,7 @@ IO::IO(void *Context) : Ctxt(Context) {}
IO::~IO() = default;
-void *IO::getContext() {
+void *IO::getContext() const {
return Ctxt;
}
@@ -79,7 +79,7 @@ void Input::ScalarHNode::anchor() {}
void Input::MapHNode::anchor() {}
void Input::SequenceHNode::anchor() {}
-bool Input::outputting() {
+bool Input::outputting() const {
return false;
}
@@ -377,12 +377,12 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
// Copy string to permanent storage
KeyStr = StringStorage.str().copy(StringAllocator);
}
- return llvm::make_unique<ScalarHNode>(N, KeyStr);
+ return std::make_unique<ScalarHNode>(N, KeyStr);
} else if (BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N)) {
StringRef ValueCopy = BSN->getValue().copy(StringAllocator);
- return llvm::make_unique<ScalarHNode>(N, ValueCopy);
+ return std::make_unique<ScalarHNode>(N, ValueCopy);
} else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) {
- auto SQHNode = llvm::make_unique<SequenceHNode>(N);
+ auto SQHNode = std::make_unique<SequenceHNode>(N);
for (Node &SN : *SQ) {
auto Entry = createHNodes(&SN);
if (EC)
@@ -391,7 +391,7 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
}
return std::move(SQHNode);
} else if (MappingNode *Map = dyn_cast<MappingNode>(N)) {
- auto mapHNode = llvm::make_unique<MapHNode>(N);
+ auto mapHNode = std::make_unique<MapHNode>(N);
for (KeyValueNode &KVN : *Map) {
Node *KeyNode = KVN.getKey();
ScalarNode *Key = dyn_cast<ScalarNode>(KeyNode);
@@ -416,7 +416,7 @@ std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
}
return std::move(mapHNode);
} else if (isa<NullNode>(N)) {
- return llvm::make_unique<EmptyHNode>(N);
+ return std::make_unique<EmptyHNode>(N);
} else {
setError(N, "unknown node kind");
return nullptr;
@@ -440,7 +440,7 @@ Output::Output(raw_ostream &yout, void *context, int WrapColumn)
Output::~Output() = default;
-bool Output::outputting() {
+bool Output::outputting() const {
return true;
}
diff --git a/lib/Support/Z3Solver.cpp b/lib/Support/Z3Solver.cpp
index f1a6fdf87cf2..a83d0f441a4b 100644
--- a/lib/Support/Z3Solver.cpp
+++ b/lib/Support/Z3Solver.cpp
@@ -886,7 +886,7 @@ public:
llvm::SMTSolverRef llvm::CreateZ3Solver() {
#if LLVM_WITH_Z3
- return llvm::make_unique<Z3Solver>();
+ return std::make_unique<Z3Solver>();
#else
llvm::report_fatal_error("LLVM was not compiled with Z3 support, rebuild "
"with -DLLVM_ENABLE_Z3_SOLVER=ON",
diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp
index 2baccaa0cbd7..b9989371f5ea 100644
--- a/lib/Support/raw_ostream.cpp
+++ b/lib/Support/raw_ostream.cpp
@@ -65,6 +65,17 @@
using namespace llvm;
+const raw_ostream::Colors raw_ostream::BLACK;
+const raw_ostream::Colors raw_ostream::RED;
+const raw_ostream::Colors raw_ostream::GREEN;
+const raw_ostream::Colors raw_ostream::YELLOW;
+const raw_ostream::Colors raw_ostream::BLUE;
+const raw_ostream::Colors raw_ostream::MAGENTA;
+const raw_ostream::Colors raw_ostream::CYAN;
+const raw_ostream::Colors raw_ostream::WHITE;
+const raw_ostream::Colors raw_ostream::SAVEDCOLOR;
+const raw_ostream::Colors raw_ostream::RESET;
+
raw_ostream::~raw_ostream() {
// raw_ostream's subclasses should take care to flush the buffer
// in their destructors.
@@ -133,6 +144,14 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) {
return *this;
}
+raw_ostream &raw_ostream::operator<<(Colors C) {
+ if (C == Colors::RESET)
+ resetColor();
+ else
+ changeColor(C);
+ return *this;
+}
+
raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) {
for (int Idx = 0; Idx < 16; ++Idx) {
*this << format("%02" PRIX32, UUID[Idx]);
@@ -784,11 +803,15 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
bool bg) {
+ if (!ColorEnabled)
+ return *this;
+
if (sys::Process::ColorNeedsFlush())
flush();
const char *colorcode =
- (colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg)
- : sys::Process::OutputColor(colors, bold, bg);
+ (colors == SAVEDCOLOR)
+ ? sys::Process::OutputBold(bg)
+ : sys::Process::OutputColor(static_cast<char>(colors), bold, bg);
if (colorcode) {
size_t len = strlen(colorcode);
write(colorcode, len);
@@ -799,6 +822,9 @@ raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
}
raw_ostream &raw_fd_ostream::resetColor() {
+ if (!ColorEnabled)
+ return *this;
+
if (sys::Process::ColorNeedsFlush())
flush();
const char *colorcode = sys::Process::ResetColor();
@@ -812,6 +838,9 @@ raw_ostream &raw_fd_ostream::resetColor() {
}
raw_ostream &raw_fd_ostream::reverseColor() {
+ if (!ColorEnabled)
+ return *this;
+
if (sys::Process::ColorNeedsFlush())
flush();
const char *colorcode = sys::Process::OutputReverse();
@@ -843,7 +872,7 @@ void raw_fd_ostream::anchor() {}
raw_ostream &llvm::outs() {
// Set buffer settings to model stdout behavior.
std::error_code EC;
- static raw_fd_ostream S("-", EC, sys::fs::F_None);
+ static raw_fd_ostream S("-", EC, sys::fs::OF_None);
assert(!EC);
return S;
}
diff --git a/lib/Support/regcomp.c b/lib/Support/regcomp.c
index 12669ab75d1a..ee2a1d87a267 100644
--- a/lib/Support/regcomp.c
+++ b/lib/Support/regcomp.c
@@ -48,6 +48,7 @@
#include "regex2.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
/* character-class table */
static struct cclass {
@@ -537,7 +538,7 @@ p_ere_exp(struct parse *p)
break;
case '{': /* okay as ordinary except if digit follows */
REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
- /* FALLTHROUGH */
+ LLVM_FALLTHROUGH;
default:
ordinary(p, c);
break;
@@ -733,7 +734,7 @@ p_simp_re(struct parse *p,
break;
case '*':
REQUIRE(starordinary, REG_BADRPT);
- /* FALLTHROUGH */
+ LLVM_FALLTHROUGH;
default:
ordinary(p, (char)c);
break;
@@ -1635,7 +1636,7 @@ findmust(struct parse *p, struct re_guts *g)
return;
}
} while (OP(s) != O_QUEST && OP(s) != O_CH);
- /* fallthrough */
+ LLVM_FALLTHROUGH;
default: /* things that break a sequence */
if (newlen > g->mlen) { /* ends one */
start = newstart;