Initial check in
Bug: 137197907
diff --git a/src/llvm-project/llvm/unittests/Support/ARMAttributeParser.cpp b/src/llvm-project/llvm/unittests/Support/ARMAttributeParser.cpp
new file mode 100644
index 0000000..9940118
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ARMAttributeParser.cpp
@@ -0,0 +1,384 @@
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+struct AttributeSection {
+ unsigned Tag;
+ unsigned Value;
+
+ AttributeSection(unsigned tag, unsigned value) : Tag(tag), Value(value) { }
+
+ void write(raw_ostream &OS) {
+ OS.flush();
+ // length = length + "aeabi\0" + TagFile + ByteSize + Tag + Value;
+ // length = 17 bytes
+
+ OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << "aeabi" << '\0';
+ OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+ OS << (uint8_t)Tag << (uint8_t)Value;
+
+ }
+};
+
+bool testBuildAttr(unsigned Tag, unsigned Value,
+ unsigned ExpectedTag, unsigned ExpectedValue) {
+ std::string buffer;
+ raw_string_ostream OS(buffer);
+ AttributeSection Section(Tag, Value);
+ Section.write(OS);
+ ArrayRef<uint8_t> Bytes(
+ reinterpret_cast<const uint8_t*>(OS.str().c_str()), OS.str().size());
+
+ ARMAttributeParser Parser;
+ Parser.Parse(Bytes, true);
+
+ return (Parser.hasAttribute(ExpectedTag) &&
+ Parser.getAttributeValue(ExpectedTag) == ExpectedValue);
+}
+
+bool testTagString(unsigned Tag, const char *name) {
+ return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name;
+}
+
+TEST(CPUArchBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(6, "Tag_CPU_arch"));
+
+ EXPECT_TRUE(testBuildAttr(6, 0, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::Pre_v4));
+ EXPECT_TRUE(testBuildAttr(6, 1, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v4));
+ EXPECT_TRUE(testBuildAttr(6, 2, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v4T));
+ EXPECT_TRUE(testBuildAttr(6, 3, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5T));
+ EXPECT_TRUE(testBuildAttr(6, 4, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5TE));
+ EXPECT_TRUE(testBuildAttr(6, 5, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v5TEJ));
+ EXPECT_TRUE(testBuildAttr(6, 6, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6));
+ EXPECT_TRUE(testBuildAttr(6, 7, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6KZ));
+ EXPECT_TRUE(testBuildAttr(6, 8, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6T2));
+ EXPECT_TRUE(testBuildAttr(6, 9, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6K));
+ EXPECT_TRUE(testBuildAttr(6, 10, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v7));
+ EXPECT_TRUE(testBuildAttr(6, 11, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6_M));
+ EXPECT_TRUE(testBuildAttr(6, 12, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v6S_M));
+ EXPECT_TRUE(testBuildAttr(6, 13, ARMBuildAttrs::CPU_arch,
+ ARMBuildAttrs::v7E_M));
+}
+
+TEST(CPUArchProfileBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(7, "Tag_CPU_arch_profile"));
+ EXPECT_TRUE(testBuildAttr(7, 'A', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::ApplicationProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'R', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::RealTimeProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'M', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::MicroControllerProfile));
+ EXPECT_TRUE(testBuildAttr(7, 'S', ARMBuildAttrs::CPU_arch_profile,
+ ARMBuildAttrs::SystemProfile));
+}
+
+TEST(ARMISABuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(8, "Tag_ARM_ISA_use"));
+ EXPECT_TRUE(testBuildAttr(8, 0, ARMBuildAttrs::ARM_ISA_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(8, 1, ARMBuildAttrs::ARM_ISA_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(ThumbISABuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(9, "Tag_THUMB_ISA_use"));
+ EXPECT_TRUE(testBuildAttr(9, 0, ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(9, 1, ARMBuildAttrs::THUMB_ISA_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(FPArchBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(10, "Tag_FP_arch"));
+ EXPECT_TRUE(testBuildAttr(10, 0, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(10, 1, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::Allowed));
+ EXPECT_TRUE(testBuildAttr(10, 2, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv2));
+ EXPECT_TRUE(testBuildAttr(10, 3, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv3A));
+ EXPECT_TRUE(testBuildAttr(10, 4, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv3B));
+ EXPECT_TRUE(testBuildAttr(10, 5, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv4A));
+ EXPECT_TRUE(testBuildAttr(10, 6, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPv4B));
+ EXPECT_TRUE(testBuildAttr(10, 7, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPARMv8A));
+ EXPECT_TRUE(testBuildAttr(10, 8, ARMBuildAttrs::FP_arch,
+ ARMBuildAttrs::AllowFPARMv8B));
+}
+
+TEST(WMMXBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(11, "Tag_WMMX_arch"));
+ EXPECT_TRUE(testBuildAttr(11, 0, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(11, 1, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::AllowWMMXv1));
+ EXPECT_TRUE(testBuildAttr(11, 2, ARMBuildAttrs::WMMX_arch,
+ ARMBuildAttrs::AllowWMMXv2));
+}
+
+TEST(SIMDBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(12, "Tag_Advanced_SIMD_arch"));
+ EXPECT_TRUE(testBuildAttr(12, 0, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(12, 1, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon));
+ EXPECT_TRUE(testBuildAttr(12, 2, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeon2));
+ EXPECT_TRUE(testBuildAttr(12, 3, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8));
+ EXPECT_TRUE(testBuildAttr(12, 4, ARMBuildAttrs::Advanced_SIMD_arch,
+ ARMBuildAttrs::AllowNeonARMv8_1a));
+}
+
+TEST(FPHPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(36, "Tag_FP_HP_extension"));
+ EXPECT_TRUE(testBuildAttr(36, 0, ARMBuildAttrs::FP_HP_extension,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(36, 1, ARMBuildAttrs::FP_HP_extension,
+ ARMBuildAttrs::AllowHPFP));
+}
+
+TEST(CPUAlignBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(34, "Tag_CPU_unaligned_access"));
+ EXPECT_TRUE(testBuildAttr(34, 0, ARMBuildAttrs::CPU_unaligned_access,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(34, 1, ARMBuildAttrs::CPU_unaligned_access,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(T2EEBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(66, "Tag_T2EE_use"));
+ EXPECT_TRUE(testBuildAttr(66, 0, ARMBuildAttrs::T2EE_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(66, 1, ARMBuildAttrs::T2EE_use,
+ ARMBuildAttrs::Allowed));
+}
+
+TEST(VirtualizationBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(68, "Tag_Virtualization_use"));
+ EXPECT_TRUE(testBuildAttr(68, 0, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(68, 1, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowTZ));
+ EXPECT_TRUE(testBuildAttr(68, 2, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowVirtualization));
+ EXPECT_TRUE(testBuildAttr(68, 3, ARMBuildAttrs::Virtualization_use,
+ ARMBuildAttrs::AllowTZVirtualization));
+}
+
+TEST(MPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(42, "Tag_MPextension_use"));
+ EXPECT_TRUE(testBuildAttr(42, 0, ARMBuildAttrs::MPextension_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(42, 1, ARMBuildAttrs::MPextension_use,
+ ARMBuildAttrs::AllowMP));
+}
+
+TEST(DivBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(44, "Tag_DIV_use"));
+ EXPECT_TRUE(testBuildAttr(44, 0, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::AllowDIVIfExists));
+ EXPECT_TRUE(testBuildAttr(44, 1, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::DisallowDIV));
+ EXPECT_TRUE(testBuildAttr(44, 2, ARMBuildAttrs::DIV_use,
+ ARMBuildAttrs::AllowDIVExt));
+}
+
+TEST(PCS_ConfigBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(13, "Tag_PCS_config"));
+ EXPECT_TRUE(testBuildAttr(13, 0, ARMBuildAttrs::PCS_config, 0));
+ EXPECT_TRUE(testBuildAttr(13, 1, ARMBuildAttrs::PCS_config, 1));
+ EXPECT_TRUE(testBuildAttr(13, 2, ARMBuildAttrs::PCS_config, 2));
+ EXPECT_TRUE(testBuildAttr(13, 3, ARMBuildAttrs::PCS_config, 3));
+ EXPECT_TRUE(testBuildAttr(13, 4, ARMBuildAttrs::PCS_config, 4));
+ EXPECT_TRUE(testBuildAttr(13, 5, ARMBuildAttrs::PCS_config, 5));
+ EXPECT_TRUE(testBuildAttr(13, 6, ARMBuildAttrs::PCS_config, 6));
+ EXPECT_TRUE(testBuildAttr(13, 7, ARMBuildAttrs::PCS_config, 7));
+}
+
+TEST(PCS_R9BuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(14, "Tag_ABI_PCS_R9_use"));
+ EXPECT_TRUE(testBuildAttr(14, 0, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsGPR));
+ EXPECT_TRUE(testBuildAttr(14, 1, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsSB));
+ EXPECT_TRUE(testBuildAttr(14, 2, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsTLSPointer));
+ EXPECT_TRUE(testBuildAttr(14, 3, ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9Reserved));
+}
+
+TEST(PCS_RWBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(15, "Tag_ABI_PCS_RW_data"));
+ EXPECT_TRUE(testBuildAttr(15, 0, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(15, 1, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWPCRel));
+ EXPECT_TRUE(testBuildAttr(15, 2, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWSBRel));
+ EXPECT_TRUE(testBuildAttr(15, 3, ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWNone));
+}
+
+TEST(PCS_ROBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(16, "Tag_ABI_PCS_RO_data"));
+ EXPECT_TRUE(testBuildAttr(16, 0, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(16, 1, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::AddressROPCRel));
+ EXPECT_TRUE(testBuildAttr(16, 2, ARMBuildAttrs::ABI_PCS_RO_data,
+ ARMBuildAttrs::AddressRONone));
+}
+
+TEST(PCS_GOTBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(17, "Tag_ABI_PCS_GOT_use"));
+ EXPECT_TRUE(testBuildAttr(17, 0, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(17, 1, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::AddressDirect));
+ EXPECT_TRUE(testBuildAttr(17, 2, ARMBuildAttrs::ABI_PCS_GOT_use,
+ ARMBuildAttrs::AddressGOT));
+}
+
+TEST(PCS_WCharBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(18, "Tag_ABI_PCS_wchar_t"));
+ EXPECT_TRUE(testBuildAttr(18, 0, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharProhibited));
+ EXPECT_TRUE(testBuildAttr(18, 2, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharWidth2Bytes));
+ EXPECT_TRUE(testBuildAttr(18, 4, ARMBuildAttrs::ABI_PCS_wchar_t,
+ ARMBuildAttrs::WCharWidth4Bytes));
+}
+
+TEST(EnumSizeBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(26, "Tag_ABI_enum_size"));
+ EXPECT_TRUE(testBuildAttr(26, 0, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::EnumProhibited));
+ EXPECT_TRUE(testBuildAttr(26, 1, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::EnumSmallest));
+ EXPECT_TRUE(testBuildAttr(26, 2, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::Enum32Bit));
+ EXPECT_TRUE(testBuildAttr(26, 3, ARMBuildAttrs::ABI_enum_size,
+ ARMBuildAttrs::Enum32BitABI));
+}
+
+TEST(AlignNeededBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(24, "Tag_ABI_align_needed"));
+ EXPECT_TRUE(testBuildAttr(24, 0, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(24, 1, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Align8Byte));
+ EXPECT_TRUE(testBuildAttr(24, 2, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::Align4Byte));
+ EXPECT_TRUE(testBuildAttr(24, 3, ARMBuildAttrs::ABI_align_needed,
+ ARMBuildAttrs::AlignReserved));
+}
+
+TEST(AlignPreservedBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(25, "Tag_ABI_align_preserved"));
+ EXPECT_TRUE(testBuildAttr(25, 0, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignNotPreserved));
+ EXPECT_TRUE(testBuildAttr(25, 1, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignPreserve8Byte));
+ EXPECT_TRUE(testBuildAttr(25, 2, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignPreserveAll));
+ EXPECT_TRUE(testBuildAttr(25, 3, ARMBuildAttrs::ABI_align_preserved,
+ ARMBuildAttrs::AlignReserved));
+}
+
+TEST(FPRoundingBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(19, "Tag_ABI_FP_rounding"));
+ EXPECT_TRUE(testBuildAttr(19, 0, ARMBuildAttrs::ABI_FP_rounding, 0));
+ EXPECT_TRUE(testBuildAttr(19, 1, ARMBuildAttrs::ABI_FP_rounding, 1));
+}
+
+TEST(FPDenormalBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(20, "Tag_ABI_FP_denormal"));
+ EXPECT_TRUE(testBuildAttr(20, 0, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PositiveZero));
+ EXPECT_TRUE(testBuildAttr(20, 1, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::IEEEDenormals));
+ EXPECT_TRUE(testBuildAttr(20, 2, ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PreserveFPSign));
+}
+
+TEST(FPExceptionsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(21, "Tag_ABI_FP_exceptions"));
+ EXPECT_TRUE(testBuildAttr(21, 0, ARMBuildAttrs::ABI_FP_exceptions, 0));
+ EXPECT_TRUE(testBuildAttr(21, 1, ARMBuildAttrs::ABI_FP_exceptions, 1));
+}
+
+TEST(FPUserExceptionsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(22, "Tag_ABI_FP_user_exceptions"));
+ EXPECT_TRUE(testBuildAttr(22, 0, ARMBuildAttrs::ABI_FP_user_exceptions, 0));
+ EXPECT_TRUE(testBuildAttr(22, 1, ARMBuildAttrs::ABI_FP_user_exceptions, 1));
+}
+
+TEST(FPNumberModelBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(23, "Tag_ABI_FP_number_model"));
+ EXPECT_TRUE(testBuildAttr(23, 0, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(23, 1, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowIEEENormal));
+ EXPECT_TRUE(testBuildAttr(23, 2, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowRTABI));
+ EXPECT_TRUE(testBuildAttr(23, 3, ARMBuildAttrs::ABI_FP_number_model,
+ ARMBuildAttrs::AllowIEEE754));
+}
+
+TEST(FP16BuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(38, "Tag_ABI_FP_16bit_format"));
+ EXPECT_TRUE(testBuildAttr(38, 0, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::Not_Allowed));
+ EXPECT_TRUE(testBuildAttr(38, 1, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::FP16FormatIEEE));
+ EXPECT_TRUE(testBuildAttr(38, 2, ARMBuildAttrs::ABI_FP_16bit_format,
+ ARMBuildAttrs::FP16VFP3));
+}
+
+TEST(HardFPBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(27, "Tag_ABI_HardFP_use"));
+ EXPECT_TRUE(testBuildAttr(27, 0, ARMBuildAttrs::ABI_HardFP_use,
+ ARMBuildAttrs::HardFPImplied));
+ EXPECT_TRUE(testBuildAttr(27, 1, ARMBuildAttrs::ABI_HardFP_use,
+ ARMBuildAttrs::HardFPSinglePrecision));
+ EXPECT_TRUE(testBuildAttr(27, 2, ARMBuildAttrs::ABI_HardFP_use, 2));
+}
+
+TEST(VFPArgsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(28, "Tag_ABI_VFP_args"));
+ EXPECT_TRUE(testBuildAttr(28, 0, ARMBuildAttrs::ABI_VFP_args,
+ ARMBuildAttrs::BaseAAPCS));
+ EXPECT_TRUE(testBuildAttr(28, 1, ARMBuildAttrs::ABI_VFP_args,
+ ARMBuildAttrs::HardFPAAPCS));
+ EXPECT_TRUE(testBuildAttr(28, 2, ARMBuildAttrs::ABI_VFP_args, 2));
+ EXPECT_TRUE(testBuildAttr(28, 3, ARMBuildAttrs::ABI_VFP_args, 3));
+}
+
+TEST(WMMXArgsBuildAttr, testBuildAttr) {
+ EXPECT_TRUE(testTagString(29, "Tag_ABI_WMMX_args"));
+ EXPECT_TRUE(testBuildAttr(29, 0, ARMBuildAttrs::ABI_WMMX_args, 0));
+ EXPECT_TRUE(testBuildAttr(29, 1, ARMBuildAttrs::ABI_WMMX_args, 1));
+ EXPECT_TRUE(testBuildAttr(29, 2, ARMBuildAttrs::ABI_WMMX_args, 2));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/AlignOfTest.cpp b/src/llvm-project/llvm/unittests/Support/AlignOfTest.cpp
new file mode 100644
index 0000000..388ca11
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/AlignOfTest.cpp
@@ -0,0 +1,249 @@
+//=== - llvm/unittest/Support/AlignOfTest.cpp - Alignment utility tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef _MSC_VER
+// Disable warnings about alignment-based structure padding.
+// This must be above the includes to suppress warnings in included templates.
+#pragma warning(disable:4324)
+#endif
+
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+// Disable warnings about questionable type definitions.
+// We're testing that even questionable types work with the alignment utilities.
+#ifdef _MSC_VER
+#pragma warning(disable:4584)
+#endif
+
+// Suppress direct base '{anonymous}::S1' inaccessible in '{anonymous}::D9'
+// due to ambiguity warning.
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Winaccessible-base"
+#elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
+// Pragma based warning suppression was introduced in GGC 4.2. Additionally
+// this warning is "enabled by default". The warning still appears if -Wall is
+// suppressed. Apparently GCC suppresses it when -w is specifed, which is odd.
+#pragma GCC diagnostic warning "-w"
+#endif
+
+// Define some fixed alignment types to use in these tests.
+struct LLVM_ALIGNAS(1) A1 {};
+struct LLVM_ALIGNAS(2) A2 {};
+struct LLVM_ALIGNAS(4) A4 {};
+struct LLVM_ALIGNAS(8) A8 {};
+
+struct S1 {};
+struct S2 { char a; };
+struct S3 { int x; };
+struct S4 { double y; };
+struct S5 { A1 a1; A2 a2; A4 a4; A8 a8; };
+struct S6 { double f(); };
+struct D1 : S1 {};
+struct D2 : S6 { float g(); };
+struct D3 : S2 {};
+struct D4 : S2 { int x; };
+struct D5 : S3 { char c; };
+struct D6 : S2, S3 {};
+struct D7 : S1, S3 {};
+struct D8 : S1, D4, D5 { double x[2]; };
+struct D9 : S1, D1 { S1 s1; };
+struct V1 { virtual ~V1(); };
+struct V2 { int x; virtual ~V2(); };
+struct V3 : V1 {
+ ~V3() override;
+};
+struct V4 : virtual V2 { int y;
+ ~V4() override;
+};
+struct V5 : V4, V3 { double z;
+ ~V5() override;
+};
+struct V6 : S1 { virtual ~V6(); };
+struct V7 : virtual V2, virtual V6 {
+ ~V7() override;
+};
+struct V8 : V5, virtual V6, V7 { double zz;
+ ~V8() override;
+};
+
+double S6::f() { return 0.0; }
+float D2::g() { return 0.0f; }
+V1::~V1() {}
+V2::~V2() {}
+V3::~V3() {}
+V4::~V4() {}
+V5::~V5() {}
+V6::~V6() {}
+V7::~V7() {}
+V8::~V8() {}
+
+template <typename M> struct T { M m; };
+
+TEST(AlignOfTest, BasicAlignedArray) {
+ EXPECT_LE(1u, alignof(AlignedCharArrayUnion<A1>));
+ EXPECT_LE(2u, alignof(AlignedCharArrayUnion<A2>));
+ EXPECT_LE(4u, alignof(AlignedCharArrayUnion<A4>));
+ EXPECT_LE(8u, alignof(AlignedCharArrayUnion<A8>));
+
+ EXPECT_LE(1u, sizeof(AlignedCharArrayUnion<A1>));
+ EXPECT_LE(2u, sizeof(AlignedCharArrayUnion<A2>));
+ EXPECT_LE(4u, sizeof(AlignedCharArrayUnion<A4>));
+ EXPECT_LE(8u, sizeof(AlignedCharArrayUnion<A8>));
+
+ EXPECT_EQ(1u, (alignof(AlignedCharArrayUnion<A1>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArrayUnion<A1, A2>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArrayUnion<A1, A2, A4>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArrayUnion<A1, A2, A4, A8>)));
+
+ EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1>));
+ EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1, A2>));
+ EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<A1, A2, A4>));
+ EXPECT_EQ(8u, sizeof(AlignedCharArrayUnion<A1, A2, A4, A8>));
+
+ EXPECT_EQ(1u, (alignof(AlignedCharArrayUnion<A1[1]>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArrayUnion<A1[2], A2[1]>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArrayUnion<A1[42], A2[55], A4[13]>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArrayUnion<A1[2], A2[1], A4, A8>)));
+
+ EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1[1]>));
+ EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1[2], A2[1]>));
+ EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<A1[3], A2[2], A4>));
+ EXPECT_EQ(16u, sizeof(AlignedCharArrayUnion<A1, A2[3],
+ A4[3], A8>));
+
+ // For other tests we simply assert that the alignment of the union mathes
+ // that of the fundamental type and hope that we have any weird type
+ // productions that would trigger bugs.
+ EXPECT_EQ(alignof(T<char>), alignof(AlignedCharArrayUnion<char>));
+ EXPECT_EQ(alignof(T<short>), alignof(AlignedCharArrayUnion<short>));
+ EXPECT_EQ(alignof(T<int>), alignof(AlignedCharArrayUnion<int>));
+ EXPECT_EQ(alignof(T<long>), alignof(AlignedCharArrayUnion<long>));
+ EXPECT_EQ(alignof(T<long long>), alignof(AlignedCharArrayUnion<long long>));
+ EXPECT_EQ(alignof(T<float>), alignof(AlignedCharArrayUnion<float>));
+ EXPECT_EQ(alignof(T<double>), alignof(AlignedCharArrayUnion<double>));
+ EXPECT_EQ(alignof(T<long double>),
+ alignof(AlignedCharArrayUnion<long double>));
+ EXPECT_EQ(alignof(T<void *>), alignof(AlignedCharArrayUnion<void *>));
+ EXPECT_EQ(alignof(T<int *>), alignof(AlignedCharArrayUnion<int *>));
+ EXPECT_EQ(alignof(T<double (*)(double)>),
+ alignof(AlignedCharArrayUnion<double (*)(double)>));
+ EXPECT_EQ(alignof(T<double (S6::*)()>),
+ alignof(AlignedCharArrayUnion<double (S6::*)()>));
+ EXPECT_EQ(alignof(S1), alignof(AlignedCharArrayUnion<S1>));
+ EXPECT_EQ(alignof(S2), alignof(AlignedCharArrayUnion<S2>));
+ EXPECT_EQ(alignof(S3), alignof(AlignedCharArrayUnion<S3>));
+ EXPECT_EQ(alignof(S4), alignof(AlignedCharArrayUnion<S4>));
+ EXPECT_EQ(alignof(S5), alignof(AlignedCharArrayUnion<S5>));
+ EXPECT_EQ(alignof(S6), alignof(AlignedCharArrayUnion<S6>));
+ EXPECT_EQ(alignof(D1), alignof(AlignedCharArrayUnion<D1>));
+ EXPECT_EQ(alignof(D2), alignof(AlignedCharArrayUnion<D2>));
+ EXPECT_EQ(alignof(D3), alignof(AlignedCharArrayUnion<D3>));
+ EXPECT_EQ(alignof(D4), alignof(AlignedCharArrayUnion<D4>));
+ EXPECT_EQ(alignof(D5), alignof(AlignedCharArrayUnion<D5>));
+ EXPECT_EQ(alignof(D6), alignof(AlignedCharArrayUnion<D6>));
+ EXPECT_EQ(alignof(D7), alignof(AlignedCharArrayUnion<D7>));
+ EXPECT_EQ(alignof(D8), alignof(AlignedCharArrayUnion<D8>));
+ EXPECT_EQ(alignof(D9), alignof(AlignedCharArrayUnion<D9>));
+ EXPECT_EQ(alignof(V1), alignof(AlignedCharArrayUnion<V1>));
+ EXPECT_EQ(alignof(V2), alignof(AlignedCharArrayUnion<V2>));
+ EXPECT_EQ(alignof(V3), alignof(AlignedCharArrayUnion<V3>));
+ EXPECT_EQ(alignof(V4), alignof(AlignedCharArrayUnion<V4>));
+ EXPECT_EQ(alignof(V5), alignof(AlignedCharArrayUnion<V5>));
+ EXPECT_EQ(alignof(V6), alignof(AlignedCharArrayUnion<V6>));
+ EXPECT_EQ(alignof(V7), alignof(AlignedCharArrayUnion<V7>));
+
+ // Some versions of MSVC get this wrong somewhat disturbingly. The failure
+ // appears to be benign: alignof(V8) produces a preposterous value: 12
+#ifndef _MSC_VER
+ EXPECT_EQ(alignof(V8), alignof(AlignedCharArrayUnion<V8>));
+#endif
+
+ EXPECT_EQ(sizeof(char), sizeof(AlignedCharArrayUnion<char>));
+ EXPECT_EQ(sizeof(char[1]), sizeof(AlignedCharArrayUnion<char[1]>));
+ EXPECT_EQ(sizeof(char[2]), sizeof(AlignedCharArrayUnion<char[2]>));
+ EXPECT_EQ(sizeof(char[3]), sizeof(AlignedCharArrayUnion<char[3]>));
+ EXPECT_EQ(sizeof(char[4]), sizeof(AlignedCharArrayUnion<char[4]>));
+ EXPECT_EQ(sizeof(char[5]), sizeof(AlignedCharArrayUnion<char[5]>));
+ EXPECT_EQ(sizeof(char[8]), sizeof(AlignedCharArrayUnion<char[8]>));
+ EXPECT_EQ(sizeof(char[13]), sizeof(AlignedCharArrayUnion<char[13]>));
+ EXPECT_EQ(sizeof(char[16]), sizeof(AlignedCharArrayUnion<char[16]>));
+ EXPECT_EQ(sizeof(char[21]), sizeof(AlignedCharArrayUnion<char[21]>));
+ EXPECT_EQ(sizeof(char[32]), sizeof(AlignedCharArrayUnion<char[32]>));
+ EXPECT_EQ(sizeof(short), sizeof(AlignedCharArrayUnion<short>));
+ EXPECT_EQ(sizeof(int), sizeof(AlignedCharArrayUnion<int>));
+ EXPECT_EQ(sizeof(long), sizeof(AlignedCharArrayUnion<long>));
+ EXPECT_EQ(sizeof(long long),
+ sizeof(AlignedCharArrayUnion<long long>));
+ EXPECT_EQ(sizeof(float), sizeof(AlignedCharArrayUnion<float>));
+ EXPECT_EQ(sizeof(double), sizeof(AlignedCharArrayUnion<double>));
+ EXPECT_EQ(sizeof(long double),
+ sizeof(AlignedCharArrayUnion<long double>));
+ EXPECT_EQ(sizeof(void *), sizeof(AlignedCharArrayUnion<void *>));
+ EXPECT_EQ(sizeof(int *), sizeof(AlignedCharArrayUnion<int *>));
+ EXPECT_EQ(sizeof(double (*)(double)),
+ sizeof(AlignedCharArrayUnion<double (*)(double)>));
+ EXPECT_EQ(sizeof(double (S6::*)()),
+ sizeof(AlignedCharArrayUnion<double (S6::*)()>));
+ EXPECT_EQ(sizeof(S1), sizeof(AlignedCharArrayUnion<S1>));
+ EXPECT_EQ(sizeof(S2), sizeof(AlignedCharArrayUnion<S2>));
+ EXPECT_EQ(sizeof(S3), sizeof(AlignedCharArrayUnion<S3>));
+ EXPECT_EQ(sizeof(S4), sizeof(AlignedCharArrayUnion<S4>));
+ EXPECT_EQ(sizeof(S5), sizeof(AlignedCharArrayUnion<S5>));
+ EXPECT_EQ(sizeof(S6), sizeof(AlignedCharArrayUnion<S6>));
+ EXPECT_EQ(sizeof(D1), sizeof(AlignedCharArrayUnion<D1>));
+ EXPECT_EQ(sizeof(D2), sizeof(AlignedCharArrayUnion<D2>));
+ EXPECT_EQ(sizeof(D3), sizeof(AlignedCharArrayUnion<D3>));
+ EXPECT_EQ(sizeof(D4), sizeof(AlignedCharArrayUnion<D4>));
+ EXPECT_EQ(sizeof(D5), sizeof(AlignedCharArrayUnion<D5>));
+ EXPECT_EQ(sizeof(D6), sizeof(AlignedCharArrayUnion<D6>));
+ EXPECT_EQ(sizeof(D7), sizeof(AlignedCharArrayUnion<D7>));
+ EXPECT_EQ(sizeof(D8), sizeof(AlignedCharArrayUnion<D8>));
+ EXPECT_EQ(sizeof(D9), sizeof(AlignedCharArrayUnion<D9>));
+ EXPECT_EQ(sizeof(D9[1]), sizeof(AlignedCharArrayUnion<D9[1]>));
+ EXPECT_EQ(sizeof(D9[2]), sizeof(AlignedCharArrayUnion<D9[2]>));
+ EXPECT_EQ(sizeof(D9[3]), sizeof(AlignedCharArrayUnion<D9[3]>));
+ EXPECT_EQ(sizeof(D9[4]), sizeof(AlignedCharArrayUnion<D9[4]>));
+ EXPECT_EQ(sizeof(D9[5]), sizeof(AlignedCharArrayUnion<D9[5]>));
+ EXPECT_EQ(sizeof(D9[8]), sizeof(AlignedCharArrayUnion<D9[8]>));
+ EXPECT_EQ(sizeof(D9[13]), sizeof(AlignedCharArrayUnion<D9[13]>));
+ EXPECT_EQ(sizeof(D9[16]), sizeof(AlignedCharArrayUnion<D9[16]>));
+ EXPECT_EQ(sizeof(D9[21]), sizeof(AlignedCharArrayUnion<D9[21]>));
+ EXPECT_EQ(sizeof(D9[32]), sizeof(AlignedCharArrayUnion<D9[32]>));
+ EXPECT_EQ(sizeof(V1), sizeof(AlignedCharArrayUnion<V1>));
+ EXPECT_EQ(sizeof(V2), sizeof(AlignedCharArrayUnion<V2>));
+ EXPECT_EQ(sizeof(V3), sizeof(AlignedCharArrayUnion<V3>));
+ EXPECT_EQ(sizeof(V4), sizeof(AlignedCharArrayUnion<V4>));
+ EXPECT_EQ(sizeof(V5), sizeof(AlignedCharArrayUnion<V5>));
+ EXPECT_EQ(sizeof(V6), sizeof(AlignedCharArrayUnion<V6>));
+ EXPECT_EQ(sizeof(V7), sizeof(AlignedCharArrayUnion<V7>));
+
+ // Some versions of MSVC also get this wrong. The failure again appears to be
+ // benign: sizeof(V8) is only 52 bytes, but our array reserves 56.
+#ifndef _MSC_VER
+ EXPECT_EQ(sizeof(V8), sizeof(AlignedCharArrayUnion<V8>));
+#endif
+
+ EXPECT_EQ(1u, (alignof(AlignedCharArray<1, 1>)));
+ EXPECT_EQ(2u, (alignof(AlignedCharArray<2, 1>)));
+ EXPECT_EQ(4u, (alignof(AlignedCharArray<4, 1>)));
+ EXPECT_EQ(8u, (alignof(AlignedCharArray<8, 1>)));
+ EXPECT_EQ(16u, (alignof(AlignedCharArray<16, 1>)));
+
+ EXPECT_EQ(1u, sizeof(AlignedCharArray<1, 1>));
+ EXPECT_EQ(7u, sizeof(AlignedCharArray<1, 7>));
+ EXPECT_EQ(2u, sizeof(AlignedCharArray<2, 2>));
+ EXPECT_EQ(16u, sizeof(AlignedCharArray<2, 16>));
+}
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/AllocatorTest.cpp b/src/llvm-project/llvm/unittests/Support/AllocatorTest.cpp
new file mode 100644
index 0000000..74b394f
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/AllocatorTest.cpp
@@ -0,0 +1,188 @@
+//===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Allocator.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+namespace {
+
+TEST(AllocatorTest, Basics) {
+ BumpPtrAllocator Alloc;
+ int *a = (int*)Alloc.Allocate(sizeof(int), alignof(int));
+ int *b = (int*)Alloc.Allocate(sizeof(int) * 10, alignof(int));
+ int *c = (int*)Alloc.Allocate(sizeof(int), alignof(int));
+ *a = 1;
+ b[0] = 2;
+ b[9] = 2;
+ *c = 3;
+ EXPECT_EQ(1, *a);
+ EXPECT_EQ(2, b[0]);
+ EXPECT_EQ(2, b[9]);
+ EXPECT_EQ(3, *c);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+
+ BumpPtrAllocator Alloc2 = std::move(Alloc);
+ EXPECT_EQ(0U, Alloc.GetNumSlabs());
+ EXPECT_EQ(1U, Alloc2.GetNumSlabs());
+
+ // Make sure the old pointers still work. These are especially interesting
+ // under ASan or Valgrind.
+ EXPECT_EQ(1, *a);
+ EXPECT_EQ(2, b[0]);
+ EXPECT_EQ(2, b[9]);
+ EXPECT_EQ(3, *c);
+
+ Alloc = std::move(Alloc2);
+ EXPECT_EQ(0U, Alloc2.GetNumSlabs());
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+}
+
+// Allocate enough bytes to create three slabs.
+TEST(AllocatorTest, ThreeSlabs) {
+ BumpPtrAllocator Alloc;
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(2U, Alloc.GetNumSlabs());
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(3U, Alloc.GetNumSlabs());
+}
+
+// Allocate enough bytes to create two slabs, reset the allocator, and do it
+// again.
+TEST(AllocatorTest, TestReset) {
+ BumpPtrAllocator Alloc;
+
+ // Allocate something larger than the SizeThreshold=4096.
+ (void)Alloc.Allocate(5000, 1);
+ Alloc.Reset();
+ // Calling Reset should free all CustomSizedSlabs.
+ EXPECT_EQ(0u, Alloc.GetNumSlabs());
+
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(2U, Alloc.GetNumSlabs());
+ Alloc.Reset();
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+ Alloc.Allocate(3000, 1);
+ EXPECT_EQ(2U, Alloc.GetNumSlabs());
+}
+
+// Test some allocations at varying alignments.
+TEST(AllocatorTest, TestAlignment) {
+ BumpPtrAllocator Alloc;
+ uintptr_t a;
+ a = (uintptr_t)Alloc.Allocate(1, 2);
+ EXPECT_EQ(0U, a & 1);
+ a = (uintptr_t)Alloc.Allocate(1, 4);
+ EXPECT_EQ(0U, a & 3);
+ a = (uintptr_t)Alloc.Allocate(1, 8);
+ EXPECT_EQ(0U, a & 7);
+ a = (uintptr_t)Alloc.Allocate(1, 16);
+ EXPECT_EQ(0U, a & 15);
+ a = (uintptr_t)Alloc.Allocate(1, 32);
+ EXPECT_EQ(0U, a & 31);
+ a = (uintptr_t)Alloc.Allocate(1, 64);
+ EXPECT_EQ(0U, a & 63);
+ a = (uintptr_t)Alloc.Allocate(1, 128);
+ EXPECT_EQ(0U, a & 127);
+}
+
+// Test allocating just over the slab size. This tests a bug where before the
+// allocator incorrectly calculated the buffer end pointer.
+TEST(AllocatorTest, TestOverflow) {
+ BumpPtrAllocator Alloc;
+
+ // Fill the slab right up until the end pointer.
+ Alloc.Allocate(4096, 1);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+
+ // If we don't allocate a new slab, then we will have overflowed.
+ Alloc.Allocate(1, 1);
+ EXPECT_EQ(2U, Alloc.GetNumSlabs());
+}
+
+// Test allocating with a size larger than the initial slab size.
+TEST(AllocatorTest, TestSmallSlabSize) {
+ BumpPtrAllocator Alloc;
+
+ Alloc.Allocate(8000, 1);
+ EXPECT_EQ(1U, Alloc.GetNumSlabs());
+}
+
+// Test requesting alignment that goes past the end of the current slab.
+TEST(AllocatorTest, TestAlignmentPastSlab) {
+ BumpPtrAllocator Alloc;
+ Alloc.Allocate(4095, 1);
+
+ // Aligning the current slab pointer is likely to move it past the end of the
+ // slab, which would confuse any unsigned comparisons with the difference of
+ // the end pointer and the aligned pointer.
+ Alloc.Allocate(1024, 8192);
+
+ EXPECT_EQ(2U, Alloc.GetNumSlabs());
+}
+
+// Mock slab allocator that returns slabs aligned on 4096 bytes. There is no
+// easy portable way to do this, so this is kind of a hack.
+class MockSlabAllocator {
+ static size_t LastSlabSize;
+
+public:
+ ~MockSlabAllocator() { }
+
+ void *Allocate(size_t Size, size_t /*Alignment*/) {
+ // Allocate space for the alignment, the slab, and a void* that goes right
+ // before the slab.
+ size_t Alignment = 4096;
+ void *MemBase = safe_malloc(Size + Alignment - 1 + sizeof(void*));
+
+ // Find the slab start.
+ void *Slab = (void *)alignAddr((char*)MemBase + sizeof(void *), Alignment);
+
+ // Hold a pointer to the base so we can free the whole malloced block.
+ ((void**)Slab)[-1] = MemBase;
+
+ LastSlabSize = Size;
+ return Slab;
+ }
+
+ void Deallocate(void *Slab, size_t Size) {
+ free(((void**)Slab)[-1]);
+ }
+
+ static size_t GetLastSlabSize() { return LastSlabSize; }
+};
+
+size_t MockSlabAllocator::LastSlabSize = 0;
+
+// Allocate a large-ish block with a really large alignment so that the
+// allocator will think that it has space, but after it does the alignment it
+// will not.
+TEST(AllocatorTest, TestBigAlignment) {
+ BumpPtrAllocatorImpl<MockSlabAllocator> Alloc;
+
+ // First allocate a tiny bit to ensure we have to re-align things.
+ (void)Alloc.Allocate(1, 1);
+
+ // Now the big chunk with a big alignment.
+ (void)Alloc.Allocate(3000, 2048);
+
+ // We test that the last slab size is not the default 4096 byte slab, but
+ // rather a custom sized slab that is larger.
+ EXPECT_GT(MockSlabAllocator::GetLastSlabSize(), 4096u);
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ArrayRecyclerTest.cpp b/src/llvm-project/llvm/unittests/Support/ArrayRecyclerTest.cpp
new file mode 100644
index 0000000..1ff97ba
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ArrayRecyclerTest.cpp
@@ -0,0 +1,109 @@
+//===--- unittest/Support/ArrayRecyclerTest.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ArrayRecycler.h"
+#include "llvm/Support/Allocator.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+namespace {
+
+struct Object {
+ int Num;
+ Object *Other;
+};
+typedef ArrayRecycler<Object> ARO;
+
+TEST(ArrayRecyclerTest, Capacity) {
+ // Capacity size should never be 0.
+ ARO::Capacity Cap = ARO::Capacity::get(0);
+ EXPECT_LT(0u, Cap.getSize());
+
+ size_t PrevSize = Cap.getSize();
+ for (unsigned N = 1; N != 100; ++N) {
+ Cap = ARO::Capacity::get(N);
+ EXPECT_LE(N, Cap.getSize());
+ if (PrevSize >= N)
+ EXPECT_EQ(PrevSize, Cap.getSize());
+ else
+ EXPECT_LT(PrevSize, Cap.getSize());
+ PrevSize = Cap.getSize();
+ }
+
+ // Check that the buckets are monotonically increasing.
+ Cap = ARO::Capacity::get(0);
+ PrevSize = Cap.getSize();
+ for (unsigned N = 0; N != 20; ++N) {
+ Cap = Cap.getNext();
+ EXPECT_LT(PrevSize, Cap.getSize());
+ PrevSize = Cap.getSize();
+ }
+}
+
+TEST(ArrayRecyclerTest, Basics) {
+ BumpPtrAllocator Allocator;
+ ArrayRecycler<Object> DUT;
+
+ ARO::Capacity Cap = ARO::Capacity::get(8);
+ Object *A1 = DUT.allocate(Cap, Allocator);
+ A1[0].Num = 21;
+ A1[7].Num = 17;
+
+ Object *A2 = DUT.allocate(Cap, Allocator);
+ A2[0].Num = 121;
+ A2[7].Num = 117;
+
+ Object *A3 = DUT.allocate(Cap, Allocator);
+ A3[0].Num = 221;
+ A3[7].Num = 217;
+
+ EXPECT_EQ(21, A1[0].Num);
+ EXPECT_EQ(17, A1[7].Num);
+ EXPECT_EQ(121, A2[0].Num);
+ EXPECT_EQ(117, A2[7].Num);
+ EXPECT_EQ(221, A3[0].Num);
+ EXPECT_EQ(217, A3[7].Num);
+
+ DUT.deallocate(Cap, A2);
+
+ // Check that deallocation didn't clobber anything.
+ EXPECT_EQ(21, A1[0].Num);
+ EXPECT_EQ(17, A1[7].Num);
+ EXPECT_EQ(221, A3[0].Num);
+ EXPECT_EQ(217, A3[7].Num);
+
+ // Verify recycling.
+ Object *A2x = DUT.allocate(Cap, Allocator);
+ EXPECT_EQ(A2, A2x);
+
+ DUT.deallocate(Cap, A2x);
+ DUT.deallocate(Cap, A1);
+ DUT.deallocate(Cap, A3);
+
+ // Objects are not required to be recycled in reverse deallocation order, but
+ // that is what the current implementation does.
+ Object *A3x = DUT.allocate(Cap, Allocator);
+ EXPECT_EQ(A3, A3x);
+ Object *A1x = DUT.allocate(Cap, Allocator);
+ EXPECT_EQ(A1, A1x);
+ Object *A2y = DUT.allocate(Cap, Allocator);
+ EXPECT_EQ(A2, A2y);
+
+ // Back to allocation from the BumpPtrAllocator.
+ Object *A4 = DUT.allocate(Cap, Allocator);
+ EXPECT_NE(A1, A4);
+ EXPECT_NE(A2, A4);
+ EXPECT_NE(A3, A4);
+
+ DUT.clear(Allocator);
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/BinaryStreamTest.cpp b/src/llvm-project/llvm/unittests/Support/BinaryStreamTest.cpp
new file mode 100644
index 0000000..35a010e
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/BinaryStreamTest.cpp
@@ -0,0 +1,836 @@
+//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryItemStream.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+
+using namespace llvm;
+using namespace llvm::support;
+
+namespace {
+
+class BrokenStream : public WritableBinaryStream {
+public:
+ BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian,
+ uint32_t Align)
+ : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)),
+ Endian(Endian) {}
+
+ endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForRead(Offset, Size))
+ return EC;
+ uint32_t S = startIndex(Offset);
+ auto Ref = Data.drop_front(S);
+ if (Ref.size() >= Size) {
+ Buffer = Ref.take_front(Size);
+ return Error::success();
+ }
+
+ uint32_t BytesLeft = Size - Ref.size();
+ uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size);
+ ::memcpy(Ptr, Ref.data(), Ref.size());
+ ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft);
+ Buffer = makeArrayRef<uint8_t>(Ptr, Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForRead(Offset, 1))
+ return EC;
+ uint32_t S = startIndex(Offset);
+ Buffer = Data.drop_front(S);
+ return Error::success();
+ }
+
+ uint32_t getLength() override { return Data.size(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
+ if (auto EC = checkOffsetForWrite(Offset, SrcData.size()))
+ return EC;
+ if (SrcData.empty())
+ return Error::success();
+
+ uint32_t S = startIndex(Offset);
+ MutableArrayRef<uint8_t> Ref(Data);
+ Ref = Ref.drop_front(S);
+ if (Ref.size() >= SrcData.size()) {
+ ::memcpy(Ref.data(), SrcData.data(), SrcData.size());
+ return Error::success();
+ }
+
+ uint32_t BytesLeft = SrcData.size() - Ref.size();
+ ::memcpy(Ref.data(), SrcData.data(), Ref.size());
+ ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft);
+ return Error::success();
+ }
+ Error commit() override { return Error::success(); }
+
+private:
+ uint32_t startIndex(uint32_t Offset) const {
+ return (Offset + PartitionIndex) % Data.size();
+ }
+
+ uint32_t endIndex(uint32_t Offset, uint32_t Size) const {
+ return (startIndex(Offset) + Size - 1) % Data.size();
+ }
+
+ // Buffer is organized like this:
+ // -------------------------------------------------
+ // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N/2-1 |
+ // -------------------------------------------------
+ // So reads from the beginning actually come from the middle.
+ MutableArrayRef<uint8_t> Data;
+ uint32_t PartitionIndex = 0;
+ endianness Endian;
+ BumpPtrAllocator Allocator;
+};
+
+constexpr endianness Endians[] = {big, little, native};
+constexpr uint32_t NumEndians = llvm::array_lengthof(Endians);
+constexpr uint32_t NumStreams = 2 * NumEndians;
+
+class BinaryStreamTest : public testing::Test {
+
+public:
+ BinaryStreamTest() {}
+
+ void SetUp() override {
+ Streams.clear();
+ Streams.resize(NumStreams);
+ for (uint32_t I = 0; I < NumStreams; ++I)
+ Streams[I].IsContiguous = (I % 2 == 0);
+
+ InputData.clear();
+ OutputData.clear();
+ }
+
+protected:
+ struct StreamPair {
+ bool IsContiguous;
+ std::unique_ptr<BinaryStream> Input;
+ std::unique_ptr<WritableBinaryStream> Output;
+ };
+
+ void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) {
+ InputData = Input;
+
+ BrokenInputData.resize(InputData.size());
+ if (!Input.empty()) {
+ uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align);
+ uint32_t RightBytes = InputData.size() - PartitionIndex;
+ uint32_t LeftBytes = PartitionIndex;
+ if (RightBytes > 0)
+ ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes);
+ if (LeftBytes > 0)
+ ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes);
+ }
+
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ auto InByteStream =
+ llvm::make_unique<BinaryByteStream>(InputData, Endians[I]);
+ auto InBrokenStream = llvm::make_unique<BrokenStream>(
+ BrokenInputData, Endians[I], Align);
+
+ Streams[I * 2].Input = std::move(InByteStream);
+ Streams[I * 2 + 1].Input = std::move(InBrokenStream);
+ }
+ }
+
+ void initializeOutput(uint32_t Size, uint32_t Align) {
+ OutputData.resize(Size);
+ BrokenOutputData.resize(Size);
+
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Output =
+ llvm::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]);
+ Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>(
+ BrokenOutputData, Endians[I], Align);
+ }
+ }
+
+ void initializeOutputFromInput(uint32_t Align) {
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Output =
+ llvm::make_unique<MutableBinaryByteStream>(InputData, Endians[I]);
+ Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>(
+ BrokenInputData, Endians[I], Align);
+ }
+ }
+
+ void initializeInputFromOutput(uint32_t Align) {
+ for (uint32_t I = 0; I < NumEndians; ++I) {
+ Streams[I * 2].Input =
+ llvm::make_unique<BinaryByteStream>(OutputData, Endians[I]);
+ Streams[I * 2 + 1].Input = llvm::make_unique<BrokenStream>(
+ BrokenOutputData, Endians[I], Align);
+ }
+ }
+
+ std::vector<uint8_t> InputData;
+ std::vector<uint8_t> BrokenInputData;
+
+ std::vector<uint8_t> OutputData;
+ std::vector<uint8_t> BrokenOutputData;
+
+ std::vector<StreamPair> Streams;
+};
+
+// Tests that a we can read from a BinaryByteStream without a StreamReader.
+TEST_F(BinaryStreamTest, BinaryByteStreamBounds) {
+ std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
+ initializeInput(InputData, 1);
+
+ for (auto &Stream : Streams) {
+ ArrayRef<uint8_t> Buffer;
+
+ // 1. If the read fits it should work.
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+ ASSERT_THAT_ERROR(Stream.Input->readBytes(2, 1, Buffer), Succeeded());
+ EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
+ ASSERT_THAT_ERROR(Stream.Input->readBytes(0, 4, Buffer), Succeeded());
+ EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer);
+
+ // 2. Reading past the bounds of the input should fail.
+ EXPECT_THAT_ERROR(Stream.Input->readBytes(4, 2, Buffer), Failed());
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamRefBounds) {
+ std::vector<uint8_t> InputData = {1, 2, 3, 4, 5};
+ initializeInput(InputData, 1);
+
+ for (const auto &Stream : Streams) {
+ ArrayRef<uint8_t> Buffer;
+ BinaryStreamRef Ref(*Stream.Input);
+
+ // Read 1 byte from offset 2 should work
+ ASSERT_EQ(InputData.size(), Ref.getLength());
+ ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded());
+ EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer);
+
+ // Reading everything from offset 2 on.
+ ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading 6 bytes from offset 0 is too big.
+ EXPECT_THAT_ERROR(Ref.readBytes(0, 6, Buffer), Failed());
+ EXPECT_THAT_ERROR(Ref.readLongestContiguousChunk(6, Buffer), Failed());
+
+ // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading
+ // 1 byte from offset 3.
+ Ref = Ref.drop_front(1);
+ ASSERT_THAT_ERROR(Ref.readBytes(2, 1, Buffer), Succeeded());
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading everything from offset 2 on after dropping 1 byte.
+ ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
+ if (Stream.IsContiguous)
+ EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer);
+ else
+ EXPECT_FALSE(Buffer.empty());
+
+ // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as
+ // reading 2 bytes from offset 4, and should fail.
+ Ref = Ref.drop_front(1);
+ EXPECT_THAT_ERROR(Ref.readBytes(2, 2, Buffer), Failed());
+
+ // But if we read the longest contiguous chunk instead, we should still
+ // get the 1 byte at the end.
+ ASSERT_THAT_ERROR(Ref.readLongestContiguousChunk(2, Buffer), Succeeded());
+ EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamRefDynamicSize) {
+ StringRef Strings[] = {"1", "2", "3", "4"};
+ AppendingBinaryByteStream Stream(support::little);
+
+ BinaryStreamWriter Writer(Stream);
+ BinaryStreamReader Reader(Stream);
+ const uint8_t *Byte;
+ StringRef Str;
+
+ // When the stream is empty, it should report a 0 length and we should get an
+ // error trying to read even 1 byte from it.
+ BinaryStreamRef ConstRef(Stream);
+ EXPECT_EQ(0U, ConstRef.getLength());
+ EXPECT_THAT_ERROR(Reader.readObject(Byte), Failed());
+
+ // But if we write to it, its size should increase and we should be able to
+ // read not just a byte, but the string that was written.
+ EXPECT_THAT_ERROR(Writer.writeCString(Strings[0]), Succeeded());
+ EXPECT_EQ(2U, ConstRef.getLength());
+ EXPECT_THAT_ERROR(Reader.readObject(Byte), Succeeded());
+
+ Reader.setOffset(0);
+ EXPECT_THAT_ERROR(Reader.readCString(Str), Succeeded());
+ EXPECT_EQ(Str, Strings[0]);
+
+ // If we drop some bytes from the front, we should still track the length as
+ // the
+ // underlying stream grows.
+ BinaryStreamRef Dropped = ConstRef.drop_front(1);
+ EXPECT_EQ(1U, Dropped.getLength());
+
+ EXPECT_THAT_ERROR(Writer.writeCString(Strings[1]), Succeeded());
+ EXPECT_EQ(4U, ConstRef.getLength());
+ EXPECT_EQ(3U, Dropped.getLength());
+
+ // If we drop zero bytes from the back, we should continue tracking the
+ // length.
+ Dropped = Dropped.drop_back(0);
+ EXPECT_THAT_ERROR(Writer.writeCString(Strings[2]), Succeeded());
+ EXPECT_EQ(6U, ConstRef.getLength());
+ EXPECT_EQ(5U, Dropped.getLength());
+
+ // If we drop non-zero bytes from the back, we should stop tracking the
+ // length.
+ Dropped = Dropped.drop_back(1);
+ EXPECT_THAT_ERROR(Writer.writeCString(Strings[3]), Succeeded());
+ EXPECT_EQ(8U, ConstRef.getLength());
+ EXPECT_EQ(4U, Dropped.getLength());
+}
+
+TEST_F(BinaryStreamTest, DropOperations) {
+ std::vector<uint8_t> InputData = {1, 2, 3, 4, 5, 4, 3, 2, 1};
+ auto RefData = makeArrayRef(InputData);
+ initializeInput(InputData, 1);
+
+ ArrayRef<uint8_t> Result;
+ BinaryStreamRef Original(InputData, support::little);
+ ASSERT_EQ(InputData.size(), Original.getLength());
+
+ EXPECT_THAT_ERROR(Original.readBytes(0, InputData.size(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData, Result);
+
+ auto Dropped = Original.drop_front(2);
+ EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData.drop_front(2), Result);
+
+ Dropped = Original.drop_back(2);
+ EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData.drop_back(2), Result);
+
+ Dropped = Original.keep_front(2);
+ EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData.take_front(2), Result);
+
+ Dropped = Original.keep_back(2);
+ EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData.take_back(2), Result);
+
+ Dropped = Original.drop_symmetric(2);
+ EXPECT_THAT_ERROR(Dropped.readBytes(0, Dropped.getLength(), Result),
+ Succeeded());
+ EXPECT_EQ(RefData.drop_front(2).drop_back(2), Result);
+}
+
+// Test that we can write to a BinaryStream without a StreamWriter.
+TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) {
+ std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'};
+ initializeInput(InputData, 1);
+ initializeOutput(InputData.size(), 1);
+
+ // For every combination of input stream and output stream.
+ for (auto &Stream : Streams) {
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+
+ // 1. Try two reads that are supposed to work. One from offset 0, and one
+ // from the middle.
+ uint32_t Offsets[] = {0, 3};
+ for (auto Offset : Offsets) {
+ uint32_t ExpectedSize = Stream.Input->getLength() - Offset;
+
+ // Read everything from Offset until the end of the input data.
+ ArrayRef<uint8_t> Data;
+ ASSERT_THAT_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data),
+ Succeeded());
+ ASSERT_EQ(ExpectedSize, Data.size());
+
+ // Then write it to the destination.
+ ASSERT_THAT_ERROR(Stream.Output->writeBytes(0, Data), Succeeded());
+
+ // Then we read back what we wrote, it should match the corresponding
+ // slice of the original input data.
+ ArrayRef<uint8_t> Data2;
+ ASSERT_THAT_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2),
+ Succeeded());
+ EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2);
+ }
+
+ std::vector<uint8_t> BigData = {0, 1, 2, 3, 4};
+ // 2. If the write is too big, it should fail.
+ EXPECT_THAT_ERROR(Stream.Output->writeBytes(3, BigData), Failed());
+ }
+}
+
+TEST_F(BinaryStreamTest, AppendingStream) {
+ AppendingBinaryByteStream Stream(llvm::support::little);
+ EXPECT_EQ(0U, Stream.getLength());
+
+ std::vector<uint8_t> InputData = {'T', 'e', 's', 't', 'T', 'e', 's', 't'};
+ auto Test = makeArrayRef(InputData).take_front(4);
+ // Writing past the end of the stream is an error.
+ EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Failed());
+
+ // Writing exactly at the end of the stream is ok.
+ EXPECT_THAT_ERROR(Stream.writeBytes(0, Test), Succeeded());
+ EXPECT_EQ(Test, Stream.data());
+
+ // And now that the end of the stream is where we couldn't write before, now
+ // we can write.
+ EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Succeeded());
+ EXPECT_EQ(MutableArrayRef<uint8_t>(InputData), Stream.data());
+}
+
+// Test that FixedStreamArray works correctly.
+TEST_F(BinaryStreamTest, FixedStreamArray) {
+ std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823};
+ ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()),
+ Ints.size() * sizeof(uint32_t));
+
+ initializeInput(IntBytes, alignof(uint32_t));
+
+ for (auto &Stream : Streams) {
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+
+ FixedStreamArray<uint32_t> Array(*Stream.Input);
+ auto Iter = Array.begin();
+ ASSERT_EQ(Ints[0], *Iter++);
+ ASSERT_EQ(Ints[1], *Iter++);
+ ASSERT_EQ(Ints[2], *Iter++);
+ ASSERT_EQ(Ints[3], *Iter++);
+ ASSERT_EQ(Array.end(), Iter);
+ }
+}
+
+// Ensure FixedStreamArrayIterator::operator-> works.
+// Added for coverage of r302257.
+TEST_F(BinaryStreamTest, FixedStreamArrayIteratorArrow) {
+ std::vector<std::pair<uint32_t, uint32_t>> Pairs = {{867, 5309}, {555, 1212}};
+ ArrayRef<uint8_t> PairBytes(reinterpret_cast<uint8_t *>(Pairs.data()),
+ Pairs.size() * sizeof(Pairs[0]));
+
+ initializeInput(PairBytes, alignof(uint32_t));
+
+ for (auto &Stream : Streams) {
+ ASSERT_EQ(InputData.size(), Stream.Input->getLength());
+
+ const FixedStreamArray<std::pair<uint32_t, uint32_t>> Array(*Stream.Input);
+ auto Iter = Array.begin();
+ ASSERT_EQ(Pairs[0].first, Iter->first);
+ ASSERT_EQ(Pairs[0].second, Iter->second);
+ ++Iter;
+ ASSERT_EQ(Pairs[1].first, Iter->first);
+ ASSERT_EQ(Pairs[1].second, Iter->second);
+ ++Iter;
+ ASSERT_EQ(Array.end(), Iter);
+ }
+}
+
+// Test that VarStreamArray works correctly.
+TEST_F(BinaryStreamTest, VarStreamArray) {
+ StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super "
+ "Extra Longest Test Of All");
+ ArrayRef<uint8_t> StringBytes(
+ reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size());
+ initializeInput(StringBytes, 1);
+
+ struct StringExtractor {
+ public:
+ Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) {
+ if (Index == 0)
+ Len = strlen("1. Test");
+ else if (Index == 1)
+ Len = strlen("2. Longer Test");
+ else if (Index == 2)
+ Len = strlen("3. Really Long Test");
+ else
+ Len = strlen("4. Super Extra Longest Test Of All");
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = Stream.readBytes(0, Len, Bytes))
+ return EC;
+ Item =
+ StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ ++Index;
+ return Error::success();
+ }
+
+ uint32_t Index = 0;
+ };
+
+ for (auto &Stream : Streams) {
+ VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input);
+ auto Iter = Array.begin();
+ ASSERT_EQ("1. Test", *Iter++);
+ ASSERT_EQ("2. Longer Test", *Iter++);
+ ASSERT_EQ("3. Really Long Test", *Iter++);
+ ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++);
+ ASSERT_EQ(Array.end(), Iter);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderBounds) {
+ std::vector<uint8_t> Bytes;
+
+ initializeInput(Bytes, 1);
+ for (auto &Stream : Streams) {
+ StringRef S;
+ BinaryStreamReader Reader(*Stream.Input);
+ EXPECT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_THAT_ERROR(Reader.readFixedString(S, 1), Failed());
+ }
+
+ Bytes.resize(5);
+ initializeInput(Bytes, 1);
+ for (auto &Stream : Streams) {
+ StringRef S;
+ BinaryStreamReader Reader(*Stream.Input);
+ EXPECT_EQ(Bytes.size(), Reader.bytesRemaining());
+ EXPECT_THAT_ERROR(Reader.readFixedString(S, 5), Succeeded());
+ EXPECT_THAT_ERROR(Reader.readFixedString(S, 6), Failed());
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderIntegers) {
+ support::ulittle64_t Little{908234};
+ support::ubig32_t Big{28907823};
+ short NS = 2897;
+ int NI = -89723;
+ unsigned long NUL = 902309023UL;
+ constexpr uint32_t Size =
+ sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL);
+
+ initializeOutput(Size, alignof(support::ulittle64_t));
+ initializeInputFromOutput(alignof(support::ulittle64_t));
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ ASSERT_THAT_ERROR(Writer.writeObject(Little), Succeeded());
+ ASSERT_THAT_ERROR(Writer.writeObject(Big), Succeeded());
+ ASSERT_THAT_ERROR(Writer.writeInteger(NS), Succeeded());
+ ASSERT_THAT_ERROR(Writer.writeInteger(NI), Succeeded());
+ ASSERT_THAT_ERROR(Writer.writeInteger(NUL), Succeeded());
+
+ const support::ulittle64_t *Little2;
+ const support::ubig32_t *Big2;
+ short NS2;
+ int NI2;
+ unsigned long NUL2;
+
+ // 1. Reading fields individually.
+ BinaryStreamReader Reader(*Stream.Input);
+ ASSERT_THAT_ERROR(Reader.readObject(Little2), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readObject(Big2), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readInteger(NS2), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readInteger(NI2), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readInteger(NUL2), Succeeded());
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ(Little, *Little2);
+ EXPECT_EQ(Big, *Big2);
+ EXPECT_EQ(NS, NS2);
+ EXPECT_EQ(NI, NI2);
+ EXPECT_EQ(NUL, NUL2);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderIntegerArray) {
+ // 1. Arrays of integers
+ std::vector<int> Ints = {1, 2, 3, 4, 5};
+ ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]),
+ Ints.size() * sizeof(int));
+
+ initializeInput(IntBytes, alignof(int));
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+ ArrayRef<int> IntsRef;
+ ASSERT_THAT_ERROR(Reader.readArray(IntsRef, Ints.size()), Succeeded());
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_EQ(makeArrayRef(Ints), IntsRef);
+
+ Reader.setOffset(0);
+ FixedStreamArray<int> FixedIntsRef;
+ ASSERT_THAT_ERROR(Reader.readArray(FixedIntsRef, Ints.size()), Succeeded());
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end()));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderEnum) {
+ enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 };
+
+ std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo};
+
+ initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum));
+ initializeInputFromOutput(alignof(MyEnum));
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ for (auto Value : Enums)
+ ASSERT_THAT_ERROR(Writer.writeEnum(Value), Succeeded());
+
+ BinaryStreamReader Reader(*Stream.Input);
+
+ FixedStreamArray<MyEnum> FSA;
+
+ for (size_t I = 0; I < Enums.size(); ++I) {
+ MyEnum Value;
+ ASSERT_THAT_ERROR(Reader.readEnum(Value), Succeeded());
+ EXPECT_EQ(Enums[I], Value);
+ }
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderObject) {
+ struct Foo {
+ int X;
+ double Y;
+ char Z;
+
+ bool operator==(const Foo &Other) const {
+ return X == Other.X && Y == Other.Y && Z == Other.Z;
+ }
+ };
+
+ std::vector<Foo> Foos;
+ Foos.push_back({-42, 42.42, 42});
+ Foos.push_back({100, 3.1415, static_cast<char>(-89)});
+ Foos.push_back({200, 2.718, static_cast<char>(-12) });
+
+ const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]);
+
+ initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo));
+
+ for (auto &Stream : Streams) {
+ // 1. Reading object pointers.
+ BinaryStreamReader Reader(*Stream.Input);
+ const Foo *FPtrOut = nullptr;
+ const Foo *GPtrOut = nullptr;
+ const Foo *HPtrOut = nullptr;
+ ASSERT_THAT_ERROR(Reader.readObject(FPtrOut), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readObject(GPtrOut), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readObject(HPtrOut), Succeeded());
+ EXPECT_EQ(0U, Reader.bytesRemaining());
+ EXPECT_EQ(Foos[0], *FPtrOut);
+ EXPECT_EQ(Foos[1], *GPtrOut);
+ EXPECT_EQ(Foos[2], *HPtrOut);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamReaderStrings) {
+ std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o',
+ '\0', 'T', 'h', 'r', 'e', 'e', '\0',
+ 'F', 'o', 'u', 'r', '\0'};
+ initializeInput(Bytes, 1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+
+ StringRef S1;
+ StringRef S2;
+ StringRef S3;
+ StringRef S4;
+ ASSERT_THAT_ERROR(Reader.readCString(S1), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readCString(S2), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readCString(S3), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readCString(S4), Succeeded());
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ("One", S1);
+ EXPECT_EQ("Two", S2);
+ EXPECT_EQ("Three", S3);
+ EXPECT_EQ("Four", S4);
+
+ S1 = S2 = S3 = S4 = "";
+ Reader.setOffset(0);
+ ASSERT_THAT_ERROR(Reader.readFixedString(S1, 3), Succeeded());
+ ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readFixedString(S2, 3), Succeeded());
+ ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readFixedString(S3, 5), Succeeded());
+ ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
+ ASSERT_THAT_ERROR(Reader.readFixedString(S4, 4), Succeeded());
+ ASSERT_THAT_ERROR(Reader.skip(1), Succeeded());
+ ASSERT_EQ(0U, Reader.bytesRemaining());
+
+ EXPECT_EQ("One", S1);
+ EXPECT_EQ("Two", S2);
+ EXPECT_EQ("Three", S3);
+ EXPECT_EQ("Four", S4);
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamWriterBounds) {
+ initializeOutput(5, 1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+
+ // 1. Can write a string that exactly fills the buffer.
+ EXPECT_EQ(5U, Writer.bytesRemaining());
+ EXPECT_THAT_ERROR(Writer.writeFixedString("abcde"), Succeeded());
+ EXPECT_EQ(0U, Writer.bytesRemaining());
+
+ // 2. Can write an empty string even when you're full
+ EXPECT_THAT_ERROR(Writer.writeFixedString(""), Succeeded());
+ EXPECT_THAT_ERROR(Writer.writeFixedString("a"), Failed());
+
+ // 3. Can't write a string that is one character too long.
+ Writer.setOffset(0);
+ EXPECT_THAT_ERROR(Writer.writeFixedString("abcdef"), Failed());
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) {
+ // 3. Arrays of integers
+ std::vector<int> SourceInts = {1, 2, 3, 4, 5};
+ ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]),
+ SourceInts.size() * sizeof(int));
+
+ initializeInput(SourceBytes, alignof(int));
+ initializeOutputFromInput(alignof(int));
+
+ for (auto &Stream : Streams) {
+ BinaryStreamReader Reader(*Stream.Input);
+ BinaryStreamWriter Writer(*Stream.Output);
+ ArrayRef<int> Ints;
+ ArrayRef<int> Ints2;
+ // First read them, then write them, then read them back.
+ ASSERT_THAT_ERROR(Reader.readArray(Ints, SourceInts.size()), Succeeded());
+ ASSERT_THAT_ERROR(Writer.writeArray(Ints), Succeeded());
+
+ BinaryStreamReader ReaderBacker(*Stream.Output);
+ ASSERT_THAT_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size()),
+ Succeeded());
+
+ EXPECT_EQ(makeArrayRef(SourceInts), Ints2);
+ }
+}
+
+TEST_F(BinaryStreamTest, StringWriterStrings) {
+ StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
+
+ size_t Length = 0;
+ for (auto S : Strings)
+ Length += S.size() + 1;
+ initializeOutput(Length, 1);
+ initializeInputFromOutput(1);
+
+ for (auto &Stream : Streams) {
+ BinaryStreamWriter Writer(*Stream.Output);
+ for (auto S : Strings)
+ ASSERT_THAT_ERROR(Writer.writeCString(S), Succeeded());
+ std::vector<StringRef> InStrings;
+ BinaryStreamReader Reader(*Stream.Input);
+ while (!Reader.empty()) {
+ StringRef S;
+ ASSERT_THAT_ERROR(Reader.readCString(S), Succeeded());
+ InStrings.push_back(S);
+ }
+ EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings));
+ }
+}
+
+TEST_F(BinaryStreamTest, StreamWriterAppend) {
+ StringRef Strings[] = {"First", "Second", "Third", "Fourth"};
+ AppendingBinaryByteStream Stream(support::little);
+ BinaryStreamWriter Writer(Stream);
+
+ for (auto &Str : Strings) {
+ EXPECT_THAT_ERROR(Writer.writeCString(Str), Succeeded());
+ }
+
+ BinaryStreamReader Reader(Stream);
+ for (auto &Str : Strings) {
+ StringRef S;
+ EXPECT_THAT_ERROR(Reader.readCString(S), Succeeded());
+ EXPECT_EQ(Str, S);
+ }
+}
+}
+
+namespace {
+struct BinaryItemStreamObject {
+ explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {}
+
+ ArrayRef<uint8_t> Bytes;
+};
+}
+
+namespace llvm {
+template <> struct BinaryItemTraits<BinaryItemStreamObject> {
+ static size_t length(const BinaryItemStreamObject &Item) {
+ return Item.Bytes.size();
+ }
+
+ static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) {
+ return Item.Bytes;
+ }
+};
+}
+
+namespace {
+
+TEST_F(BinaryStreamTest, BinaryItemStream) {
+ std::vector<BinaryItemStreamObject> Objects;
+
+ struct Foo {
+ int X;
+ double Y;
+ };
+ std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}};
+ BumpPtrAllocator Allocator;
+ for (const auto &F : Foos) {
+ uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo),
+ alignof(Foo)));
+ MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo));
+ MutableBinaryByteStream Stream(Buffer, llvm::support::big);
+ BinaryStreamWriter Writer(Stream);
+ ASSERT_THAT_ERROR(Writer.writeObject(F), Succeeded());
+ Objects.push_back(BinaryItemStreamObject(Buffer));
+ }
+
+ BinaryItemStream<BinaryItemStreamObject> ItemStream(big);
+ ItemStream.setItems(Objects);
+ BinaryStreamReader Reader(ItemStream);
+
+ for (const auto &F : Foos) {
+ const Foo *F2;
+ ASSERT_THAT_ERROR(Reader.readObject(F2), Succeeded());
+
+ EXPECT_EQ(F.X, F2->X);
+ EXPECT_DOUBLE_EQ(F.Y, F2->Y);
+ }
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/BlockFrequencyTest.cpp b/src/llvm-project/llvm/unittests/Support/BlockFrequencyTest.cpp
new file mode 100644
index 0000000..c1f5671
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/BlockFrequencyTest.cpp
@@ -0,0 +1,128 @@
+//===- unittests/Support/BlockFrequencyTest.cpp - BlockFrequency tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BlockFrequency.h"
+#include "llvm/Support/BranchProbability.h"
+#include "llvm/Support/DataTypes.h"
+#include "gtest/gtest.h"
+#include <climits>
+
+using namespace llvm;
+
+namespace {
+
+TEST(BlockFrequencyTest, OneToZero) {
+ BlockFrequency Freq(1);
+ BranchProbability Prob(UINT32_MAX / 3, UINT32_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 0u);
+
+ Freq = BlockFrequency(1);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 0u);
+}
+
+TEST(BlockFrequencyTest, OneToOne) {
+ BlockFrequency Freq(1);
+ BranchProbability Prob(UINT32_MAX, UINT32_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 1u);
+
+ Freq = BlockFrequency(1);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 1u);
+}
+
+TEST(BlockFrequencyTest, ThreeToOne) {
+ BlockFrequency Freq(3);
+ BranchProbability Prob(3000000, 9000000);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 1u);
+
+ Freq = BlockFrequency(3);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 1u);
+}
+
+TEST(BlockFrequencyTest, MaxToHalfMax) {
+ BlockFrequency Freq(UINT64_MAX);
+ BranchProbability Prob(UINT32_MAX / 2, UINT32_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 9223372036854775807ULL);
+
+ Freq = BlockFrequency(UINT64_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), 9223372036854775807ULL);
+}
+
+TEST(BlockFrequencyTest, BigToBig) {
+ const uint64_t Big = 387246523487234346LL;
+ const uint32_t P = 123456789;
+ BlockFrequency Freq(Big);
+ BranchProbability Prob(P, P);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), Big);
+
+ Freq = BlockFrequency(Big);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), Big);
+}
+
+TEST(BlockFrequencyTest, MaxToMax) {
+ BlockFrequency Freq(UINT64_MAX);
+ BranchProbability Prob(UINT32_MAX, UINT32_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), UINT64_MAX);
+
+ // This additionally makes sure if we have a value equal to our saturating
+ // value, we do not signal saturation if the result equals said value, but
+ // saturating does not occur.
+ Freq = BlockFrequency(UINT64_MAX);
+ Freq *= Prob;
+ EXPECT_EQ(Freq.getFrequency(), UINT64_MAX);
+}
+
+TEST(BlockFrequencyTest, Subtract) {
+ BlockFrequency Freq1(0), Freq2(1);
+ EXPECT_EQ((Freq1 - Freq2).getFrequency(), 0u);
+ EXPECT_EQ((Freq2 - Freq1).getFrequency(), 1u);
+}
+
+TEST(BlockFrequency, Divide) {
+ BlockFrequency Freq(0x3333333333333333ULL);
+ Freq /= BranchProbability(1, 2);
+ EXPECT_EQ(Freq.getFrequency(), 0x6666666666666666ULL);
+}
+
+TEST(BlockFrequencyTest, Saturate) {
+ BlockFrequency Freq(0x3333333333333333ULL);
+ Freq /= BranchProbability(100, 300);
+ EXPECT_EQ(Freq.getFrequency(), 0x9999999866666668ULL);
+ Freq /= BranchProbability(1, 2);
+ EXPECT_EQ(Freq.getFrequency(), UINT64_MAX);
+
+ Freq = 0x1000000000000000ULL;
+ Freq /= BranchProbability(10000, 170000);
+ EXPECT_EQ(Freq.getFrequency(), UINT64_MAX);
+
+ // Try to cheat the multiplication overflow check.
+ Freq = 0x00000001f0000001ull;
+ Freq /= BranchProbability(1000, 0xf000000f);
+ EXPECT_EQ(33527736066704712ULL, Freq.getFrequency());
+}
+
+TEST(BlockFrequencyTest, SaturatingRightShift) {
+ BlockFrequency Freq(0x10080ULL);
+ Freq >>= 2;
+ EXPECT_EQ(Freq.getFrequency(), 0x4020ULL);
+ Freq >>= 20;
+ EXPECT_EQ(Freq.getFrequency(), 0x1ULL);
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/BranchProbabilityTest.cpp b/src/llvm-project/llvm/unittests/Support/BranchProbabilityTest.cpp
new file mode 100644
index 0000000..54948ba
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/BranchProbabilityTest.cpp
@@ -0,0 +1,406 @@
+//===- unittest/Support/BranchProbabilityTest.cpp - BranchProbability tests -=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/BranchProbability.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace llvm {
+void PrintTo(BranchProbability P, ::std::ostream *os) {
+ *os << P.getNumerator() << "/" << P.getDenominator();
+}
+}
+namespace {
+
+typedef BranchProbability BP;
+TEST(BranchProbabilityTest, Accessors) {
+ EXPECT_EQ(306783378u, BP(1, 7).getNumerator());
+ EXPECT_EQ(1u << 31, BP(1, 7).getDenominator());
+ EXPECT_EQ(0u, BP::getZero().getNumerator());
+ EXPECT_EQ(1u << 31, BP::getZero().getDenominator());
+ EXPECT_EQ(1u << 31, BP::getOne().getNumerator());
+ EXPECT_EQ(1u << 31, BP::getOne().getDenominator());
+}
+
+TEST(BranchProbabilityTest, Operators) {
+ EXPECT_TRUE(BP(1, 7) < BP(2, 7));
+ EXPECT_TRUE(BP(1, 7) < BP(1, 4));
+ EXPECT_TRUE(BP(5, 7) < BP(3, 4));
+ EXPECT_FALSE(BP(1, 7) < BP(1, 7));
+ EXPECT_FALSE(BP(1, 7) < BP(2, 14));
+ EXPECT_FALSE(BP(4, 7) < BP(1, 2));
+ EXPECT_FALSE(BP(4, 7) < BP(3, 7));
+
+ EXPECT_FALSE(BP(1, 7) > BP(2, 7));
+ EXPECT_FALSE(BP(1, 7) > BP(1, 4));
+ EXPECT_FALSE(BP(5, 7) > BP(3, 4));
+ EXPECT_FALSE(BP(1, 7) > BP(1, 7));
+ EXPECT_FALSE(BP(1, 7) > BP(2, 14));
+ EXPECT_TRUE(BP(4, 7) > BP(1, 2));
+ EXPECT_TRUE(BP(4, 7) > BP(3, 7));
+
+ EXPECT_TRUE(BP(1, 7) <= BP(2, 7));
+ EXPECT_TRUE(BP(1, 7) <= BP(1, 4));
+ EXPECT_TRUE(BP(5, 7) <= BP(3, 4));
+ EXPECT_TRUE(BP(1, 7) <= BP(1, 7));
+ EXPECT_TRUE(BP(1, 7) <= BP(2, 14));
+ EXPECT_FALSE(BP(4, 7) <= BP(1, 2));
+ EXPECT_FALSE(BP(4, 7) <= BP(3, 7));
+
+ EXPECT_FALSE(BP(1, 7) >= BP(2, 7));
+ EXPECT_FALSE(BP(1, 7) >= BP(1, 4));
+ EXPECT_FALSE(BP(5, 7) >= BP(3, 4));
+ EXPECT_TRUE(BP(1, 7) >= BP(1, 7));
+ EXPECT_TRUE(BP(1, 7) >= BP(2, 14));
+ EXPECT_TRUE(BP(4, 7) >= BP(1, 2));
+ EXPECT_TRUE(BP(4, 7) >= BP(3, 7));
+
+ EXPECT_FALSE(BP(1, 7) == BP(2, 7));
+ EXPECT_FALSE(BP(1, 7) == BP(1, 4));
+ EXPECT_FALSE(BP(5, 7) == BP(3, 4));
+ EXPECT_TRUE(BP(1, 7) == BP(1, 7));
+ EXPECT_TRUE(BP(1, 7) == BP(2, 14));
+ EXPECT_FALSE(BP(4, 7) == BP(1, 2));
+ EXPECT_FALSE(BP(4, 7) == BP(3, 7));
+
+ EXPECT_TRUE(BP(1, 7) != BP(2, 7));
+ EXPECT_TRUE(BP(1, 7) != BP(1, 4));
+ EXPECT_TRUE(BP(5, 7) != BP(3, 4));
+ EXPECT_FALSE(BP(1, 7) != BP(1, 7));
+ EXPECT_FALSE(BP(1, 7) != BP(2, 14));
+ EXPECT_TRUE(BP(4, 7) != BP(1, 2));
+ EXPECT_TRUE(BP(4, 7) != BP(3, 7));
+
+ EXPECT_TRUE(BP(1, 7) == BP(2, 14));
+ EXPECT_TRUE(BP(1, 7) == BP(3, 21));
+ EXPECT_TRUE(BP(5, 7) == BP(25, 35));
+ EXPECT_TRUE(BP(99999998, 100000000) < BP(99999999, 100000000));
+ EXPECT_TRUE(BP(4, 8) == BP(400000000, 800000000));
+}
+
+TEST(BranchProbabilityTest, MoreOperators) {
+ BP A(4, 5);
+ BP B(4U << 29, 5U << 29);
+ BP C(3, 4);
+
+ EXPECT_TRUE(A == B);
+ EXPECT_FALSE(A != B);
+ EXPECT_FALSE(A < B);
+ EXPECT_FALSE(A > B);
+ EXPECT_TRUE(A <= B);
+ EXPECT_TRUE(A >= B);
+
+ EXPECT_FALSE(B == C);
+ EXPECT_TRUE(B != C);
+ EXPECT_FALSE(B < C);
+ EXPECT_TRUE(B > C);
+ EXPECT_FALSE(B <= C);
+ EXPECT_TRUE(B >= C);
+
+ BP BigZero(0, UINT32_MAX);
+ BP BigOne(UINT32_MAX, UINT32_MAX);
+ EXPECT_FALSE(BigZero == BigOne);
+ EXPECT_TRUE(BigZero != BigOne);
+ EXPECT_TRUE(BigZero < BigOne);
+ EXPECT_FALSE(BigZero > BigOne);
+ EXPECT_TRUE(BigZero <= BigOne);
+ EXPECT_FALSE(BigZero >= BigOne);
+}
+
+TEST(BranchProbabilityTest, ArithmeticOperators) {
+ BP Z(0, 1);
+ BP O(1, 1);
+ BP H(1, 2);
+ BP Q(1, 4);
+ BP Q3(3, 4);
+
+ EXPECT_EQ(Z + O, O);
+ EXPECT_EQ(H + Z, H);
+ EXPECT_EQ(H + H, O);
+ EXPECT_EQ(Q + H, Q3);
+ EXPECT_EQ(Q + Q3, O);
+ EXPECT_EQ(H + Q3, O);
+ EXPECT_EQ(Q3 + Q3, O);
+
+ EXPECT_EQ(Z - O, Z);
+ EXPECT_EQ(O - Z, O);
+ EXPECT_EQ(O - H, H);
+ EXPECT_EQ(O - Q, Q3);
+ EXPECT_EQ(Q3 - H, Q);
+ EXPECT_EQ(Q - H, Z);
+ EXPECT_EQ(Q - Q3, Z);
+
+ EXPECT_EQ(Z * O, Z);
+ EXPECT_EQ(H * H, Q);
+ EXPECT_EQ(Q * O, Q);
+ EXPECT_EQ(O * O, O);
+ EXPECT_EQ(Z * Z, Z);
+
+ EXPECT_EQ(Z * 3, Z);
+ EXPECT_EQ(Q * 3, Q3);
+ EXPECT_EQ(H * 3, O);
+ EXPECT_EQ(Q3 * 2, O);
+ EXPECT_EQ(O * UINT32_MAX, O);
+
+ EXPECT_EQ(Z / 4, Z);
+ EXPECT_EQ(O / 4, Q);
+ EXPECT_EQ(Q3 / 3, Q);
+ EXPECT_EQ(H / 2, Q);
+ EXPECT_EQ(O / 2, H);
+ EXPECT_EQ(H / UINT32_MAX, Z);
+
+ BP Min(1, 1u << 31);
+
+ EXPECT_EQ(O / UINT32_MAX, Z);
+ EXPECT_EQ(Min * UINT32_MAX, O);
+}
+
+TEST(BranchProbabilityTest, getCompl) {
+ EXPECT_EQ(BP(5, 7), BP(2, 7).getCompl());
+ EXPECT_EQ(BP(2, 7), BP(5, 7).getCompl());
+ EXPECT_EQ(BP::getZero(), BP(7, 7).getCompl());
+ EXPECT_EQ(BP::getOne(), BP(0, 7).getCompl());
+}
+
+TEST(BranchProbabilityTest, scale) {
+ // Multiply by 1.0.
+ EXPECT_EQ(UINT64_MAX, BP(1, 1).scale(UINT64_MAX));
+ EXPECT_EQ(UINT64_MAX, BP(7, 7).scale(UINT64_MAX));
+ EXPECT_EQ(UINT32_MAX, BP(1, 1).scale(UINT32_MAX));
+ EXPECT_EQ(UINT32_MAX, BP(7, 7).scale(UINT32_MAX));
+ EXPECT_EQ(0u, BP(1, 1).scale(0));
+ EXPECT_EQ(0u, BP(7, 7).scale(0));
+
+ // Multiply by 0.0.
+ EXPECT_EQ(0u, BP(0, 1).scale(UINT64_MAX));
+ EXPECT_EQ(0u, BP(0, 1).scale(UINT64_MAX));
+ EXPECT_EQ(0u, BP(0, 1).scale(0));
+
+ auto Two63 = UINT64_C(1) << 63;
+ auto Two31 = UINT64_C(1) << 31;
+
+ // Multiply by 0.5.
+ EXPECT_EQ(Two63 - 1, BP(1, 2).scale(UINT64_MAX));
+
+ // Big fractions.
+ EXPECT_EQ(1u, BP(Two31, UINT32_MAX).scale(2));
+ EXPECT_EQ(Two31, BP(Two31, UINT32_MAX).scale(Two31 * 2));
+ EXPECT_EQ(9223372036854775807ULL, BP(Two31, UINT32_MAX).scale(UINT64_MAX));
+
+ // High precision.
+ EXPECT_EQ(UINT64_C(9223372045444710399),
+ BP(Two31 + 1, UINT32_MAX - 2).scale(UINT64_MAX));
+}
+
+TEST(BranchProbabilityTest, scaleByInverse) {
+ // Divide by 1.0.
+ EXPECT_EQ(UINT64_MAX, BP(1, 1).scaleByInverse(UINT64_MAX));
+ EXPECT_EQ(UINT64_MAX, BP(7, 7).scaleByInverse(UINT64_MAX));
+ EXPECT_EQ(UINT32_MAX, BP(1, 1).scaleByInverse(UINT32_MAX));
+ EXPECT_EQ(UINT32_MAX, BP(7, 7).scaleByInverse(UINT32_MAX));
+ EXPECT_EQ(0u, BP(1, 1).scaleByInverse(0));
+ EXPECT_EQ(0u, BP(7, 7).scaleByInverse(0));
+
+ auto MAX_DENOMINATOR = BP::getDenominator();
+
+ // Divide by something very small.
+ EXPECT_EQ(UINT64_MAX, BP(1, UINT32_MAX).scaleByInverse(UINT64_MAX));
+ EXPECT_EQ(uint64_t(UINT32_MAX) * MAX_DENOMINATOR,
+ BP(1, MAX_DENOMINATOR).scaleByInverse(UINT32_MAX));
+ EXPECT_EQ(MAX_DENOMINATOR, BP(1, MAX_DENOMINATOR).scaleByInverse(1));
+
+ auto Two63 = UINT64_C(1) << 63;
+ auto Two31 = UINT64_C(1) << 31;
+
+ // Divide by 0.5.
+ EXPECT_EQ(UINT64_MAX - 1, BP(1, 2).scaleByInverse(Two63 - 1));
+ EXPECT_EQ(UINT64_MAX, BP(1, 2).scaleByInverse(Two63));
+
+ // Big fractions.
+ EXPECT_EQ(2u, BP(Two31, UINT32_MAX).scaleByInverse(1));
+ EXPECT_EQ(2u, BP(Two31 - 1, UINT32_MAX).scaleByInverse(1));
+ EXPECT_EQ(Two31 * 2, BP(Two31, UINT32_MAX).scaleByInverse(Two31));
+ EXPECT_EQ(Two31 * 2, BP(Two31 - 1, UINT32_MAX).scaleByInverse(Two31));
+ EXPECT_EQ(UINT64_MAX, BP(Two31, UINT32_MAX).scaleByInverse(Two63 + Two31));
+
+ // High precision. The exact answers to these are close to the successors of
+ // the floor. If we were rounding, these would round up.
+ EXPECT_EQ(UINT64_C(18446744060824649767),
+ BP(Two31 + 2, UINT32_MAX - 2)
+ .scaleByInverse(UINT64_C(9223372047592194056)));
+ EXPECT_EQ(UINT64_C(18446744060824649739),
+ BP(Two31 + 1, UINT32_MAX).scaleByInverse(Two63 + Two31));
+}
+
+TEST(BranchProbabilityTest, scaleBruteForce) {
+ struct {
+ uint64_t Num;
+ uint32_t Prob[2];
+ uint64_t Result;
+ } Tests[] = {
+ // Data for scaling that results in <= 64 bit division.
+ { 0x1423e2a50ULL, { 0x64819521, 0x7765dd13 }, 0x10f418888ULL },
+ { 0x35ef14ceULL, { 0x28ade3c7, 0x304532ae }, 0x2d73c33bULL },
+ { 0xd03dbfbe24ULL, { 0x790079, 0xe419f3 }, 0x6e776fc2c4ULL },
+ { 0x21d67410bULL, { 0x302a9dc2, 0x3ddb4442 }, 0x1a5948fd4ULL },
+ { 0x8664aeadULL, { 0x3d523513, 0x403523b1 }, 0x805a04cfULL },
+ { 0x201db0cf4ULL, { 0x35112a7b, 0x79fc0c74 }, 0xdf8b07f8ULL },
+ { 0x13f1e4430aULL, { 0x21c92bf, 0x21e63aae }, 0x13e0cba26ULL },
+ { 0x16c83229ULL, { 0x3793f66f, 0x53180dea }, 0xf3ce7b6ULL },
+ { 0xc62415be8ULL, { 0x9cc4a63, 0x4327ae9b }, 0x1ce8b71c1ULL },
+ { 0x6fac5e434ULL, { 0xe5f9170, 0x1115e10b }, 0x5df23dd4cULL },
+ { 0x1929375f2ULL, { 0x3a851375, 0x76c08456 }, 0xc662b083ULL },
+ { 0x243c89db6ULL, { 0x354ebfc0, 0x450ef197 }, 0x1bf8c1663ULL },
+ { 0x310e9b31aULL, { 0x1b1b8acf, 0x2d3629f0 }, 0x1d69c93f9ULL },
+ { 0xa1fae921dULL, { 0xa7a098c, 0x10469f44 }, 0x684413d6eULL },
+ { 0xc1582d957ULL, { 0x498e061, 0x59856bc }, 0x9edc5f4ecULL },
+ { 0x57cfee75ULL, { 0x1d061dc3, 0x7c8bfc17 }, 0x1476a220ULL },
+ { 0x139220080ULL, { 0x294a6c71, 0x2a2b07c9 }, 0x1329e1c75ULL },
+ { 0x1665d353cULL, { 0x7080db5, 0xde0d75c }, 0xb590d9faULL },
+ { 0xe8f14541ULL, { 0x5188e8b2, 0x736527ef }, 0xa4971be5ULL },
+ { 0x2f4775f29ULL, { 0x254ef0fe, 0x435fcf50 }, 0x1a2e449c1ULL },
+ { 0x27b85d8d7ULL, { 0x304c8220, 0x5de678f2 }, 0x146e3befbULL },
+ { 0x1d362e36bULL, { 0x36c85b12, 0x37a66f55 }, 0x1cc19b8e7ULL },
+ { 0x155fd48c7ULL, { 0xf5894d, 0x1256108 }, 0x11e383604ULL },
+ { 0xb5db2d15ULL, { 0x39bb26c5, 0x5bdcda3e }, 0x72499259ULL },
+ { 0x153990298ULL, { 0x48921c09, 0x706eb817 }, 0xdb3268e7ULL },
+ { 0x28a7c3ed7ULL, { 0x1f776fd7, 0x349f7a70 }, 0x184f73ae2ULL },
+ { 0x724dbeabULL, { 0x1bd149f5, 0x253a085e }, 0x5569c0b3ULL },
+ { 0xd8f0c513ULL, { 0x18c8cc4c, 0x1b72bad0 }, 0xc3e30642ULL },
+ { 0x17ce3dcbULL, { 0x1e4c6260, 0x233b359e }, 0x1478f4afULL },
+ { 0x1ce036ce0ULL, { 0x29e3c8af, 0x5318dd4a }, 0xe8e76195ULL },
+ { 0x1473ae2aULL, { 0x29b897ba, 0x2be29378 }, 0x13718185ULL },
+ { 0x1dd41aa68ULL, { 0x3d0a4441, 0x5a0e8f12 }, 0x1437b6bbfULL },
+ { 0x1b49e4a53ULL, { 0x3430c1fe, 0x5a204aed }, 0xfcd6852fULL },
+ { 0x217941b19ULL, { 0x12ced2bd, 0x21b68310 }, 0x12aca65b1ULL },
+ { 0xac6a4dc8ULL, { 0x3ed68da8, 0x6fdca34c }, 0x60da926dULL },
+ { 0x1c503a4e7ULL, { 0xfcbbd32, 0x11e48d17 }, 0x18fec7d37ULL },
+ { 0x1c885855ULL, { 0x213e919d, 0x25941897 }, 0x193de742ULL },
+ { 0x29b9c168eULL, { 0x2b644aea, 0x45725ee7 }, 0x1a122e5d4ULL },
+ { 0x806a33f2ULL, { 0x30a80a23, 0x5063733a }, 0x4db9a264ULL },
+ { 0x282afc96bULL, { 0x143ae554, 0x1a9863ff }, 0x1e8de5204ULL },
+ // Data for scaling that results in > 64 bit division.
+ { 0x23ca5f2f672ca41cULL, { 0xecbc641, 0x111373f7 }, 0x1f0301e5c76869c6ULL },
+ { 0x5e4f2468142265e3ULL, { 0x1ddf5837, 0x32189233 }, 0x383ca7bad6053ac9ULL },
+ { 0x277a1a6f6b266bf6ULL, { 0x415d81a8, 0x61eb5e1e }, 0x1a5a3e1d1c9e8540ULL },
+ { 0x1bdbb49a237035cbULL, { 0xea5bf17, 0x1d25ffb3 }, 0xdffc51c5cb51cf1ULL },
+ { 0x2bce6d29b64fb8ULL, { 0x3bfd5631, 0x7525c9bb }, 0x166ebedd9581fdULL },
+ { 0x3a02116103df5013ULL, { 0x2ee18a83, 0x3299aea8 }, 0x35be89227276f105ULL },
+ { 0x7b5762390799b18cULL, { 0x12f8e5b9, 0x2563bcd4 }, 0x3e960077695655a3ULL },
+ { 0x69cfd72537021579ULL, { 0x4c35f468, 0x6a40feee }, 0x4be4cb38695a4f30ULL },
+ { 0x49dfdf835120f1c1ULL, { 0x8cb3759, 0x559eb891 }, 0x79663f6e3c8d8f6ULL },
+ { 0x74b5be5c27676381ULL, { 0x47e4c5e0, 0x7c7b19ff }, 0x4367d2dfb22b3265ULL },
+ { 0x4f50f97075e7f431ULL, { 0x9a50a17, 0x11cd1185 }, 0x2af952b30374f382ULL },
+ { 0x2f8b0d712e393be4ULL, { 0x1487e386, 0x15aa356e }, 0x2d0df3649b2b19fcULL },
+ { 0x224c1c75999d3deULL, { 0x3b2df0ea, 0x4523b100 }, 0x1d5b481d160dd8bULL },
+ { 0x2bcbcea22a399a76ULL, { 0x28b58212, 0x48dd013e }, 0x187814d0610c8a56ULL },
+ { 0x1dbfca91257cb2d1ULL, { 0x1a8c04d9, 0x5e92502c }, 0x859cf7d19e83ad0ULL },
+ { 0x7f20039b57cda935ULL, { 0xeccf651, 0x323f476e }, 0x25720cd9054634bdULL },
+ { 0x40512c6a586aa087ULL, { 0x113b0423, 0x398c9eab }, 0x1341c03dbb662054ULL },
+ { 0x63d802693f050a11ULL, { 0xf50cdd6, 0xfce2a44 }, 0x60c0177b667a4feaULL },
+ { 0x2d956b422838de77ULL, { 0xb2d345b, 0x1321e557 }, 0x1aa0ed16b094575cULL },
+ { 0x5a1cdf0c1657bc91ULL, { 0x1d77bb0c, 0x1f991ff1 }, 0x54097ee9907290eaULL },
+ { 0x3801b26d7e00176bULL, { 0xeed25da, 0x1a819d8b }, 0x1f89e96a616b9abeULL },
+ { 0x37655e74338e1e45ULL, { 0x300e170a, 0x5a1595fe }, 0x1d8cfb55ff6a6dbcULL },
+ { 0x7b38703f2a84e6ULL, { 0x66d9053, 0xc79b6b9 }, 0x3f7d4c91b9afb9ULL },
+ { 0x2245063c0acb3215ULL, { 0x30ce2f5b, 0x610e7271 }, 0x113b916455fe2560ULL },
+ { 0x6bc195877b7b8a7eULL, { 0x392004aa, 0x4a24e60c }, 0x530594fabfc81cc3ULL },
+ { 0x40a3fde23c7b43dbULL, { 0x4e712195, 0x6553e56e }, 0x320a799bc205c78dULL },
+ { 0x1d3dfc2866fbccbaULL, { 0x5075b517, 0x5fc42245 }, 0x18917f00745cb781ULL },
+ { 0x19aeb14045a61121ULL, { 0x1bf6edec, 0x707e2f4b }, 0x6626672aa2ba10aULL },
+ { 0x44ff90486c531e9fULL, { 0x66598a, 0x8a90dc }, 0x32f6f2b097001598ULL },
+ { 0x3f3e7121092c5bcbULL, { 0x1c754df7, 0x5951a1b9 }, 0x14267f50d4971583ULL },
+ { 0x60e2dafb7e50a67eULL, { 0x4d96c66e, 0x65bd878d }, 0x49e317155d75e883ULL },
+ { 0x656286667e0e6e29ULL, { 0x9d971a2, 0xacda23b }, 0x5c6ee3159e1deac3ULL },
+ { 0x1114e0974255d507ULL, { 0x1c693, 0x2d6ff }, 0xaae42e4be5f9f8dULL },
+ { 0x508c8baf3a70ff5aULL, { 0x3b26b779, 0x6ad78745 }, 0x2c983876178ed5b1ULL },
+ { 0x5b47bc666bf1f9cfULL, { 0x10a87ed6, 0x187d358a }, 0x3e1767153bea720aULL },
+ { 0x50954e3744460395ULL, { 0x7a42263, 0xcdaa048 }, 0x2fe739f0944a023cULL },
+ { 0x20020b406550dd8fULL, { 0x3318539, 0x42eead0 }, 0x186f326307c0d985ULL },
+ { 0x5bcb0b872439ffd5ULL, { 0x6f61fb2, 0x9af7344 }, 0x41fa1e3c47f0f80dULL },
+ { 0x7a670f365db87a53ULL, { 0x417e102, 0x3bb54c67 }, 0x8642a551d0f41b0ULL },
+ { 0x1ef0db1e7bab1cd0ULL, { 0x2b60cf38, 0x4188f78f }, 0x147ae0d63fc0575aULL }
+ };
+
+ for (const auto &T : Tests) {
+ EXPECT_EQ(T.Result, BP(T.Prob[0], T.Prob[1]).scale(T.Num));
+ }
+}
+
+TEST(BranchProbabilityTest, NormalizeProbabilities) {
+ const auto UnknownProb = BranchProbability::getUnknown();
+ {
+ SmallVector<BranchProbability, 2> Probs{{0, 1}, {0, 1}};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{0, 1}, {1, 1}};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(0u, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator(), Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{1, 100}, {1, 100}};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{1, 1}, {1, 1}};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 3> Probs{{1, 1}, {1, 1}, {1, 1}};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[1].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[2].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{0, 1}, UnknownProb};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(0U, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator(), Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{1, 1}, UnknownProb};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator(), Probs[0].getNumerator());
+ EXPECT_EQ(0U, Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 2> Probs{{1, 2}, UnknownProb};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 2, Probs[1].getNumerator());
+ }
+ {
+ SmallVector<BranchProbability, 4> Probs{
+ {1, 2}, {1, 2}, {1, 2}, UnknownProb};
+ BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[0].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[1].getNumerator());
+ EXPECT_EQ(BranchProbability::getDenominator() / 3 + 1,
+ Probs[2].getNumerator());
+ EXPECT_EQ(0U, Probs[3].getNumerator());
+ }
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/CMakeLists.txt b/src/llvm-project/llvm/unittests/Support/CMakeLists.txt
new file mode 100644
index 0000000..f9c877f
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CMakeLists.txt
@@ -0,0 +1,91 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_llvm_unittest(SupportTests
+ AlignOfTest.cpp
+ AllocatorTest.cpp
+ ARMAttributeParser.cpp
+ ArrayRecyclerTest.cpp
+ BinaryStreamTest.cpp
+ BlockFrequencyTest.cpp
+ BranchProbabilityTest.cpp
+ CachePruningTest.cpp
+ CrashRecoveryTest.cpp
+ Casting.cpp
+ CheckedArithmeticTest.cpp
+ Chrono.cpp
+ CommandLineTest.cpp
+ CompressionTest.cpp
+ ConvertUTFTest.cpp
+ DataExtractorTest.cpp
+ DebugTest.cpp
+ DebugCounterTest.cpp
+ DJBTest.cpp
+ EndianStreamTest.cpp
+ EndianTest.cpp
+ ErrnoTest.cpp
+ ErrorOrTest.cpp
+ ErrorTest.cpp
+ FileOutputBufferTest.cpp
+ FormatVariadicTest.cpp
+ GlobPatternTest.cpp
+ Host.cpp
+ ItaniumManglingCanonicalizerTest.cpp
+ JSONTest.cpp
+ LEB128Test.cpp
+ LineIteratorTest.cpp
+ LockFileManagerTest.cpp
+ MD5Test.cpp
+ ManagedStatic.cpp
+ MathExtrasTest.cpp
+ MemoryBufferTest.cpp
+ MemoryTest.cpp
+ NativeFormatTests.cpp
+ ParallelTest.cpp
+ Path.cpp
+ ProcessTest.cpp
+ ProgramTest.cpp
+ RegexTest.cpp
+ ReverseIterationTest.cpp
+ ReplaceFileTest.cpp
+ ScaledNumberTest.cpp
+ SourceMgrTest.cpp
+ SpecialCaseListTest.cpp
+ StringPool.cpp
+ SwapByteOrderTest.cpp
+ SymbolRemappingReaderTest.cpp
+ TarWriterTest.cpp
+ TargetParserTest.cpp
+ TaskQueueTest.cpp
+ ThreadLocalTest.cpp
+ ThreadPool.cpp
+ Threading.cpp
+ TimerTest.cpp
+ TypeNameTest.cpp
+ TypeTraitsTest.cpp
+ TrailingObjectsTest.cpp
+ TrigramIndexTest.cpp
+ UnicodeTest.cpp
+ VersionTupleTest.cpp
+ VirtualFileSystemTest.cpp
+ YAMLIOTest.cpp
+ YAMLParserTest.cpp
+ formatted_raw_ostream_test.cpp
+ raw_ostream_test.cpp
+ raw_pwrite_stream_test.cpp
+ raw_sha1_ostream_test.cpp
+ xxhashTest.cpp
+ )
+
+target_link_libraries(SupportTests PRIVATE LLVMTestingSupport)
+
+# Disable all warning for AlignOfTest.cpp,
+# as it does things intentionally, and there is no reliable way of
+# disabling all warnings for all the compilers by using pragmas.
+set_source_files_properties(AlignOfTest.cpp PROPERTIES COMPILE_FLAGS -w)
+
+# ManagedStatic.cpp uses <pthread>.
+target_link_libraries(SupportTests PRIVATE LLVMTestingSupport ${LLVM_PTHREAD_LIB})
+
+add_subdirectory(DynamicLibrary)
diff --git a/src/llvm-project/llvm/unittests/Support/CachePruningTest.cpp b/src/llvm-project/llvm/unittests/Support/CachePruningTest.cpp
new file mode 100644
index 0000000..4bc2ad1
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CachePruningTest.cpp
@@ -0,0 +1,97 @@
+//===- CachePruningTest.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(CachePruningPolicyParser, Empty) {
+ auto P = parseCachePruningPolicy("");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
+ EXPECT_EQ(std::chrono::hours(7 * 24), P->Expiration);
+ EXPECT_EQ(75u, P->MaxSizePercentageOfAvailableSpace);
+}
+
+TEST(CachePruningPolicyParser, Interval) {
+ auto P = parseCachePruningPolicy("prune_interval=1s");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1), P->Interval);
+ P = parseCachePruningPolicy("prune_interval=2m");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::minutes(2), *P->Interval);
+ P = parseCachePruningPolicy("prune_interval=3h");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::hours(3), *P->Interval);
+}
+
+TEST(CachePruningPolicyParser, Expiration) {
+ auto P = parseCachePruningPolicy("prune_after=1s");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
+}
+
+TEST(CachePruningPolicyParser, MaxSizePercentageOfAvailableSpace) {
+ auto P = parseCachePruningPolicy("cache_size=100%");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(100u, P->MaxSizePercentageOfAvailableSpace);
+ EXPECT_EQ(0u, P->MaxSizeBytes);
+}
+
+TEST(CachePruningPolicyParser, MaxSizeBytes) {
+ auto P = parseCachePruningPolicy("cache_size_bytes=1");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(75u, P->MaxSizePercentageOfAvailableSpace);
+ EXPECT_EQ(1u, P->MaxSizeBytes);
+ P = parseCachePruningPolicy("cache_size_bytes=2k");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(75u, P->MaxSizePercentageOfAvailableSpace);
+ EXPECT_EQ(2u * 1024u, P->MaxSizeBytes);
+ P = parseCachePruningPolicy("cache_size_bytes=3m");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(75u, P->MaxSizePercentageOfAvailableSpace);
+ EXPECT_EQ(3u * 1024u * 1024u, P->MaxSizeBytes);
+ P = parseCachePruningPolicy("cache_size_bytes=4G");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(75u, P->MaxSizePercentageOfAvailableSpace);
+ EXPECT_EQ(4ull * 1024ull * 1024ull * 1024ull, P->MaxSizeBytes);
+}
+
+TEST(CachePruningPolicyParser, Multiple) {
+ auto P = parseCachePruningPolicy("prune_after=1s:cache_size=50%");
+ ASSERT_TRUE(bool(P));
+ EXPECT_EQ(std::chrono::seconds(1200), P->Interval);
+ EXPECT_EQ(std::chrono::seconds(1), P->Expiration);
+ EXPECT_EQ(50u, P->MaxSizePercentageOfAvailableSpace);
+}
+
+TEST(CachePruningPolicyParser, Errors) {
+ EXPECT_EQ("Duration must not be empty",
+ toString(parseCachePruningPolicy("prune_interval=").takeError()));
+ EXPECT_EQ("'foo' not an integer",
+ toString(parseCachePruningPolicy("prune_interval=foos").takeError()));
+ EXPECT_EQ("'24x' must end with one of 's', 'm' or 'h'",
+ toString(parseCachePruningPolicy("prune_interval=24x").takeError()));
+ EXPECT_EQ("'foo' must be a percentage",
+ toString(parseCachePruningPolicy("cache_size=foo").takeError()));
+ EXPECT_EQ("'foo' not an integer",
+ toString(parseCachePruningPolicy("cache_size=foo%").takeError()));
+ EXPECT_EQ("'101' must be between 0 and 100",
+ toString(parseCachePruningPolicy("cache_size=101%").takeError()));
+ EXPECT_EQ(
+ "'foo' not an integer",
+ toString(parseCachePruningPolicy("cache_size_bytes=foo").takeError()));
+ EXPECT_EQ(
+ "'foo' not an integer",
+ toString(parseCachePruningPolicy("cache_size_bytes=foom").takeError()));
+ EXPECT_EQ("Unknown key: 'foo'",
+ toString(parseCachePruningPolicy("foo=bar").takeError()));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/Casting.cpp b/src/llvm-project/llvm/unittests/Support/Casting.cpp
new file mode 100644
index 0000000..9a818f6
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/Casting.cpp
@@ -0,0 +1,405 @@
+//===---------- llvm/unittest/Support/Casting.cpp - Casting tests ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Casting.h"
+#include "llvm/IR/User.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+namespace llvm {
+// Used to test illegal cast. If a cast doesn't match any of the "real" ones,
+// it will match this one.
+struct IllegalCast;
+template <typename T> IllegalCast *cast(...) { return nullptr; }
+
+// set up two example classes
+// with conversion facility
+//
+struct bar {
+ bar() {}
+ struct foo *baz();
+ struct foo *caz();
+ struct foo *daz();
+ struct foo *naz();
+private:
+ bar(const bar &);
+};
+struct foo {
+ void ext() const;
+ /* static bool classof(const bar *X) {
+ cerr << "Classof: " << X << "\n";
+ return true;
+ }*/
+};
+
+struct base {
+ virtual ~base() {}
+};
+
+struct derived : public base {
+ static bool classof(const base *B) { return true; }
+};
+
+template <> struct isa_impl<foo, bar> {
+ static inline bool doit(const bar &Val) {
+ dbgs() << "Classof: " << &Val << "\n";
+ return true;
+ }
+};
+
+template <typename T> struct isa_impl<foo, T> {
+ static inline bool doit(const T &Val) { return false; }
+};
+
+foo *bar::baz() {
+ return cast<foo>(this);
+}
+
+foo *bar::caz() {
+ return cast_or_null<foo>(this);
+}
+
+foo *bar::daz() {
+ return dyn_cast<foo>(this);
+}
+
+foo *bar::naz() {
+ return dyn_cast_or_null<foo>(this);
+}
+
+
+bar *fub();
+
+template <> struct simplify_type<foo> {
+ typedef int SimpleType;
+ static SimpleType getSimplifiedValue(foo &Val) { return 0; }
+};
+
+} // End llvm namespace
+
+using namespace llvm;
+
+
+// Test the peculiar behavior of Use in simplify_type.
+static_assert(std::is_same<simplify_type<Use>::SimpleType, Value *>::value,
+ "Use doesn't simplify correctly!");
+static_assert(std::is_same<simplify_type<Use *>::SimpleType, Value *>::value,
+ "Use doesn't simplify correctly!");
+
+// Test that a regular class behaves as expected.
+static_assert(std::is_same<simplify_type<foo>::SimpleType, int>::value,
+ "Unexpected simplify_type result!");
+static_assert(std::is_same<simplify_type<foo *>::SimpleType, foo *>::value,
+ "Unexpected simplify_type result!");
+
+namespace {
+
+const foo *null_foo = nullptr;
+
+bar B;
+extern bar &B1;
+bar &B1 = B;
+extern const bar *B2;
+// test various configurations of const
+const bar &B3 = B1;
+const bar *const B4 = B2;
+
+TEST(CastingTest, isa) {
+ EXPECT_TRUE(isa<foo>(B1));
+ EXPECT_TRUE(isa<foo>(B2));
+ EXPECT_TRUE(isa<foo>(B3));
+ EXPECT_TRUE(isa<foo>(B4));
+}
+
+TEST(CastingTest, cast) {
+ foo &F1 = cast<foo>(B1);
+ EXPECT_NE(&F1, null_foo);
+ const foo *F3 = cast<foo>(B2);
+ EXPECT_NE(F3, null_foo);
+ const foo *F4 = cast<foo>(B2);
+ EXPECT_NE(F4, null_foo);
+ const foo &F5 = cast<foo>(B3);
+ EXPECT_NE(&F5, null_foo);
+ const foo *F6 = cast<foo>(B4);
+ EXPECT_NE(F6, null_foo);
+ // Can't pass null pointer to cast<>.
+ // foo *F7 = cast<foo>(fub());
+ // EXPECT_EQ(F7, null_foo);
+ foo *F8 = B1.baz();
+ EXPECT_NE(F8, null_foo);
+
+ std::unique_ptr<const bar> BP(B2);
+ auto FP = cast<foo>(std::move(BP));
+ static_assert(std::is_same<std::unique_ptr<const foo>, decltype(FP)>::value,
+ "Incorrect deduced return type!");
+ EXPECT_NE(FP.get(), null_foo);
+ FP.release();
+}
+
+TEST(CastingTest, cast_or_null) {
+ const foo *F11 = cast_or_null<foo>(B2);
+ EXPECT_NE(F11, null_foo);
+ const foo *F12 = cast_or_null<foo>(B2);
+ EXPECT_NE(F12, null_foo);
+ const foo *F13 = cast_or_null<foo>(B4);
+ EXPECT_NE(F13, null_foo);
+ const foo *F14 = cast_or_null<foo>(fub()); // Shouldn't print.
+ EXPECT_EQ(F14, null_foo);
+ foo *F15 = B1.caz();
+ EXPECT_NE(F15, null_foo);
+
+ std::unique_ptr<const bar> BP(fub());
+ auto FP = cast_or_null<foo>(std::move(BP));
+ EXPECT_EQ(FP.get(), null_foo);
+}
+
+TEST(CastingTest, dyn_cast) {
+ const foo *F1 = dyn_cast<foo>(B2);
+ EXPECT_NE(F1, null_foo);
+ const foo *F2 = dyn_cast<foo>(B2);
+ EXPECT_NE(F2, null_foo);
+ const foo *F3 = dyn_cast<foo>(B4);
+ EXPECT_NE(F3, null_foo);
+ // Can't pass null pointer to dyn_cast<>.
+ // foo *F4 = dyn_cast<foo>(fub());
+ // EXPECT_EQ(F4, null_foo);
+ foo *F5 = B1.daz();
+ EXPECT_NE(F5, null_foo);
+}
+
+TEST(CastingTest, dyn_cast_or_null) {
+ const foo *F1 = dyn_cast_or_null<foo>(B2);
+ EXPECT_NE(F1, null_foo);
+ const foo *F2 = dyn_cast_or_null<foo>(B2);
+ EXPECT_NE(F2, null_foo);
+ const foo *F3 = dyn_cast_or_null<foo>(B4);
+ EXPECT_NE(F3, null_foo);
+ foo *F4 = dyn_cast_or_null<foo>(fub());
+ EXPECT_EQ(F4, null_foo);
+ foo *F5 = B1.naz();
+ EXPECT_NE(F5, null_foo);
+}
+
+std::unique_ptr<derived> newd() { return llvm::make_unique<derived>(); }
+std::unique_ptr<base> newb() { return llvm::make_unique<derived>(); }
+
+TEST(CastingTest, unique_dyn_cast) {
+ derived *OrigD = nullptr;
+ auto D = llvm::make_unique<derived>();
+ OrigD = D.get();
+
+ // Converting from D to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewD = unique_dyn_cast<derived>(D);
+ ASSERT_EQ(OrigD, NewD.get());
+ ASSERT_EQ(nullptr, D);
+
+ // Converting from D to B is valid, B should have a value and D should be
+ // nullptr.
+ auto B = unique_dyn_cast<base>(NewD);
+ ASSERT_EQ(OrigD, B.get());
+ ASSERT_EQ(nullptr, NewD);
+
+ // Converting from B to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewB = unique_dyn_cast<base>(B);
+ ASSERT_EQ(OrigD, NewB.get());
+ ASSERT_EQ(nullptr, B);
+
+ // Converting from B to D is valid, D should have a value and B should be
+ // nullptr;
+ D = unique_dyn_cast<derived>(NewB);
+ ASSERT_EQ(OrigD, D.get());
+ ASSERT_EQ(nullptr, NewB);
+
+ // Converting between unrelated types should fail. The original value should
+ // remain unchanged and it should return nullptr.
+ auto F = unique_dyn_cast<foo>(D);
+ ASSERT_EQ(nullptr, F);
+ ASSERT_EQ(OrigD, D.get());
+
+ // All of the above should also hold for temporaries.
+ auto D2 = unique_dyn_cast<derived>(newd());
+ EXPECT_NE(nullptr, D2);
+
+ auto B2 = unique_dyn_cast<derived>(newb());
+ EXPECT_NE(nullptr, B2);
+
+ auto B3 = unique_dyn_cast<base>(newb());
+ EXPECT_NE(nullptr, B3);
+
+ auto F2 = unique_dyn_cast<foo>(newb());
+ EXPECT_EQ(nullptr, F2);
+}
+
+// These lines are errors...
+//foo *F20 = cast<foo>(B2); // Yields const foo*
+//foo &F21 = cast<foo>(B3); // Yields const foo&
+//foo *F22 = cast<foo>(B4); // Yields const foo*
+//foo &F23 = cast_or_null<foo>(B1);
+//const foo &F24 = cast_or_null<foo>(B3);
+
+const bar *B2 = &B;
+} // anonymous namespace
+
+bar *llvm::fub() { return nullptr; }
+
+namespace {
+namespace inferred_upcasting {
+// This test case verifies correct behavior of inferred upcasts when the
+// types are statically known to be OK to upcast. This is the case when,
+// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.
+
+// Note: This test will actually fail to compile without inferred
+// upcasting.
+
+class Base {
+public:
+ // No classof. We are testing that the upcast is inferred.
+ Base() {}
+};
+
+class Derived : public Base {
+public:
+ Derived() {}
+};
+
+// Even with no explicit classof() in Base, we should still be able to cast
+// Derived to its base class.
+TEST(CastingTest, UpcastIsInferred) {
+ Derived D;
+ EXPECT_TRUE(isa<Base>(D));
+ Base *BP = dyn_cast<Base>(&D);
+ EXPECT_TRUE(BP != nullptr);
+}
+
+
+// This test verifies that the inferred upcast takes precedence over an
+// explicitly written one. This is important because it verifies that the
+// dynamic check gets optimized away.
+class UseInferredUpcast {
+public:
+ int Dummy;
+ static bool classof(const UseInferredUpcast *) {
+ return false;
+ }
+};
+
+TEST(CastingTest, InferredUpcastTakesPrecedence) {
+ UseInferredUpcast UIU;
+ // Since the explicit classof() returns false, this will fail if the
+ // explicit one is used.
+ EXPECT_TRUE(isa<UseInferredUpcast>(&UIU));
+}
+
+} // end namespace inferred_upcasting
+} // end anonymous namespace
+// Test that we reject casts of temporaries (and so the illegal cast gets used).
+namespace TemporaryCast {
+struct pod {};
+IllegalCast *testIllegalCast() { return cast<foo>(pod()); }
+}
+
+namespace {
+namespace pointer_wrappers {
+
+struct Base {
+ bool IsDerived;
+ Base(bool IsDerived = false) : IsDerived(IsDerived) {}
+};
+
+struct Derived : Base {
+ Derived() : Base(true) {}
+ static bool classof(const Base *B) { return B->IsDerived; }
+};
+
+class PTy {
+ Base *B;
+public:
+ PTy(Base *B) : B(B) {}
+ explicit operator bool() const { return get(); }
+ Base *get() const { return B; }
+};
+
+} // end namespace pointer_wrappers
+} // end namespace
+
+namespace llvm {
+
+template <> struct simplify_type<pointer_wrappers::PTy> {
+ typedef pointer_wrappers::Base *SimpleType;
+ static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {
+ return P.get();
+ }
+};
+template <> struct simplify_type<const pointer_wrappers::PTy> {
+ typedef pointer_wrappers::Base *SimpleType;
+ static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {
+ return P.get();
+ }
+};
+
+} // end namespace llvm
+
+namespace {
+namespace pointer_wrappers {
+
+// Some objects.
+pointer_wrappers::Base B;
+pointer_wrappers::Derived D;
+
+// Mutable "smart" pointers.
+pointer_wrappers::PTy MN(nullptr);
+pointer_wrappers::PTy MB(&B);
+pointer_wrappers::PTy MD(&D);
+
+// Const "smart" pointers.
+const pointer_wrappers::PTy CN(nullptr);
+const pointer_wrappers::PTy CB(&B);
+const pointer_wrappers::PTy CD(&D);
+
+TEST(CastingTest, smart_isa) {
+ EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));
+ EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));
+ EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));
+ EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));
+}
+
+TEST(CastingTest, smart_cast) {
+ EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_cast_or_null) {
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_dyn_cast) {
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_dyn_cast_or_null) {
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D);
+}
+
+} // end namespace pointer_wrappers
+} // end namespace
diff --git a/src/llvm-project/llvm/unittests/Support/CheckedArithmeticTest.cpp b/src/llvm-project/llvm/unittests/Support/CheckedArithmeticTest.cpp
new file mode 100644
index 0000000..18eee4c
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CheckedArithmeticTest.cpp
@@ -0,0 +1,84 @@
+#include "llvm/Support/CheckedArithmetic.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(CheckedArithmetic, CheckedAdd) {
+ const int64_t Max = std::numeric_limits<int64_t>::max();
+ const int64_t Min = std::numeric_limits<int64_t>::min();
+ EXPECT_EQ(checkedAdd<int64_t>(Max, Max), None);
+ EXPECT_EQ(checkedAdd<int64_t>(Min, -1), None);
+ EXPECT_EQ(checkedAdd<int64_t>(Max, 1), None);
+ EXPECT_EQ(checkedAdd<int64_t>(10, 1), Optional<int64_t>(11));
+}
+
+TEST(CheckedArithmetic, CheckedAddSmall) {
+ const int16_t Max = std::numeric_limits<int16_t>::max();
+ const int16_t Min = std::numeric_limits<int16_t>::min();
+ EXPECT_EQ(checkedAdd<int16_t>(Max, Max), None);
+ EXPECT_EQ(checkedAdd<int16_t>(Min, -1), None);
+ EXPECT_EQ(checkedAdd<int16_t>(Max, 1), None);
+ EXPECT_EQ(checkedAdd<int16_t>(10, 1), Optional<int64_t>(11));
+}
+
+TEST(CheckedArithmetic, CheckedMul) {
+ const int64_t Max = std::numeric_limits<int64_t>::max();
+ const int64_t Min = std::numeric_limits<int64_t>::min();
+ EXPECT_EQ(checkedMul<int64_t>(Max, 2), None);
+ EXPECT_EQ(checkedMul<int64_t>(Max, Max), None);
+ EXPECT_EQ(checkedMul<int64_t>(Min, 2), None);
+ EXPECT_EQ(checkedMul<int64_t>(10, 2), Optional<int64_t>(20));
+}
+
+TEST(CheckedArithmetic, CheckedMulAdd) {
+ const int64_t Max = std::numeric_limits<int64_t>::max();
+ const int64_t Min = std::numeric_limits<int64_t>::min();
+ EXPECT_EQ(checkedMulAdd<int64_t>(Max, 1, 2), None);
+ EXPECT_EQ(checkedMulAdd<int64_t>(1, 1, Max), None);
+ EXPECT_EQ(checkedMulAdd<int64_t>(1, -1, Min), None);
+ EXPECT_EQ(checkedMulAdd<int64_t>(10, 2, 3), Optional<int64_t>(23));
+}
+
+TEST(CheckedArithmetic, CheckedMulSmall) {
+ const int16_t Max = std::numeric_limits<int16_t>::max();
+ const int16_t Min = std::numeric_limits<int16_t>::min();
+ EXPECT_EQ(checkedMul<int16_t>(Max, 2), None);
+ EXPECT_EQ(checkedMul<int16_t>(Max, Max), None);
+ EXPECT_EQ(checkedMul<int16_t>(Min, 2), None);
+ EXPECT_EQ(checkedMul<int16_t>(10, 2), Optional<int16_t>(20));
+}
+
+TEST(CheckedArithmetic, CheckedMulAddSmall) {
+ const int16_t Max = std::numeric_limits<int16_t>::max();
+ const int16_t Min = std::numeric_limits<int16_t>::min();
+ EXPECT_EQ(checkedMulAdd<int16_t>(Max, 1, 2), None);
+ EXPECT_EQ(checkedMulAdd<int16_t>(1, 1, Max), None);
+ EXPECT_EQ(checkedMulAdd<int16_t>(1, -1, Min), None);
+ EXPECT_EQ(checkedMulAdd<int16_t>(10, 2, 3), Optional<int16_t>(23));
+}
+
+TEST(CheckedArithmetic, CheckedAddUnsigned) {
+ const uint64_t Max = std::numeric_limits<uint64_t>::max();
+ EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, Max), None);
+ EXPECT_EQ(checkedAddUnsigned<uint64_t>(Max, 1), None);
+ EXPECT_EQ(checkedAddUnsigned<uint64_t>(10, 1), Optional<uint64_t>(11));
+}
+
+TEST(CheckedArithmetic, CheckedMulUnsigned) {
+ const uint64_t Max = std::numeric_limits<uint64_t>::max();
+ EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, 2), llvm::None);
+ EXPECT_EQ(checkedMulUnsigned<uint64_t>(Max, Max), llvm::None);
+ EXPECT_EQ(checkedMulUnsigned<uint64_t>(10, 2), Optional<uint64_t>(20));
+}
+
+TEST(CheckedArithmetic, CheckedMulAddUnsigned) {
+ const uint64_t Max = std::numeric_limits<uint64_t>::max();
+ EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(Max, 1, 2), None);
+ EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(1, 1, Max), None);
+ EXPECT_EQ(checkedMulAddUnsigned<uint64_t>(10, 2, 3), Optional<uint64_t>(23));
+}
+
+
+} // namespace
diff --git a/src/llvm-project/llvm/unittests/Support/Chrono.cpp b/src/llvm-project/llvm/unittests/Support/Chrono.cpp
new file mode 100644
index 0000000..a6b76c8
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/Chrono.cpp
@@ -0,0 +1,112 @@
+//===- llvm/unittest/Support/Chrono.cpp - Time utilities tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Chrono.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace std::chrono;
+
+namespace {
+
+TEST(Chrono, TimeTConversion) {
+ EXPECT_EQ(time_t(0), toTimeT(toTimePoint(time_t(0))));
+ EXPECT_EQ(time_t(1), toTimeT(toTimePoint(time_t(1))));
+ EXPECT_EQ(time_t(47), toTimeT(toTimePoint(time_t(47))));
+
+ TimePoint<> TP;
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+ TP += seconds(1);
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+ TP += hours(47);
+ EXPECT_EQ(TP, toTimePoint(toTimeT(TP)));
+}
+
+TEST(Chrono, TimePointFormat) {
+ using namespace std::chrono;
+ struct tm TM {};
+ TM.tm_year = 106;
+ TM.tm_mon = 0;
+ TM.tm_mday = 2;
+ TM.tm_hour = 15;
+ TM.tm_min = 4;
+ TM.tm_sec = 5;
+ TM.tm_isdst = -1;
+ TimePoint<> T =
+ system_clock::from_time_t(mktime(&TM)) + nanoseconds(123456789);
+
+ // operator<< uses the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN
+ std::string S;
+ raw_string_ostream OS(S);
+ OS << T;
+ EXPECT_EQ("2006-01-02 15:04:05.123456789", OS.str());
+
+ // formatv default style matches operator<<.
+ EXPECT_EQ("2006-01-02 15:04:05.123456789", formatv("{0}", T).str());
+ // formatv supports strftime-style format strings.
+ EXPECT_EQ("15:04:05", formatv("{0:%H:%M:%S}", T).str());
+ // formatv supports our strftime extensions for sub-second precision.
+ EXPECT_EQ("123", formatv("{0:%L}", T).str());
+ EXPECT_EQ("123456", formatv("{0:%f}", T).str());
+ EXPECT_EQ("123456789", formatv("{0:%N}", T).str());
+ // our extensions don't interfere with %% escaping.
+ EXPECT_EQ("%foo", formatv("{0:%%foo}", T).str());
+}
+
+// Test that toTimePoint and toTimeT can be called with a arguments with varying
+// precisions.
+TEST(Chrono, ImplicitConversions) {
+ std::time_t TimeT = 47;
+ TimePoint<seconds> Sec = toTimePoint(TimeT);
+ TimePoint<milliseconds> Milli = toTimePoint(TimeT);
+ TimePoint<microseconds> Micro = toTimePoint(TimeT);
+ TimePoint<nanoseconds> Nano = toTimePoint(TimeT);
+ EXPECT_EQ(Sec, Milli);
+ EXPECT_EQ(Sec, Micro);
+ EXPECT_EQ(Sec, Nano);
+ EXPECT_EQ(TimeT, toTimeT(Sec));
+ EXPECT_EQ(TimeT, toTimeT(Milli));
+ EXPECT_EQ(TimeT, toTimeT(Micro));
+ EXPECT_EQ(TimeT, toTimeT(Nano));
+}
+
+TEST(Chrono, DurationFormat) {
+ EXPECT_EQ("1 h", formatv("{0}", hours(1)).str());
+ EXPECT_EQ("1 m", formatv("{0}", minutes(1)).str());
+ EXPECT_EQ("1 s", formatv("{0}", seconds(1)).str());
+ EXPECT_EQ("1 ms", formatv("{0}", milliseconds(1)).str());
+ EXPECT_EQ("1 us", formatv("{0}", microseconds(1)).str());
+ EXPECT_EQ("1 ns", formatv("{0}", nanoseconds(1)).str());
+
+ EXPECT_EQ("1 s", formatv("{0:+}", seconds(1)).str());
+ EXPECT_EQ("1", formatv("{0:-}", seconds(1)).str());
+
+ EXPECT_EQ("1000 ms", formatv("{0:ms}", seconds(1)).str());
+ EXPECT_EQ("1000000 us", formatv("{0:us}", seconds(1)).str());
+ EXPECT_EQ("1000", formatv("{0:ms-}", seconds(1)).str());
+
+ EXPECT_EQ("1,000 ms", formatv("{0:+n}", milliseconds(1000)).str());
+ EXPECT_EQ("0x3e8", formatv("{0:-x}", milliseconds(1000)).str());
+ EXPECT_EQ("010", formatv("{0:-3}", milliseconds(10)).str());
+ EXPECT_EQ("10,000", formatv("{0:ms-n}", seconds(10)).str());
+
+ EXPECT_EQ("1.00 s", formatv("{0}", duration<float>(1)).str());
+ EXPECT_EQ("0.123 s", formatv("{0:+3}", duration<float>(0.123f)).str());
+ EXPECT_EQ("1.230e-01 s", formatv("{0:+e3}", duration<float>(0.123f)).str());
+
+ typedef duration<float, std::ratio<60 * 60 * 24 * 14, 1000000>>
+ microfortnights;
+ EXPECT_EQ("1.00", formatv("{0:-}", microfortnights(1)).str());
+ EXPECT_EQ("1209.60 ms", formatv("{0:ms}", microfortnights(1)).str());
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/CommandLineTest.cpp b/src/llvm-project/llvm/unittests/Support/CommandLineTest.cpp
new file mode 100644
index 0000000..9d06f72
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CommandLineTest.cpp
@@ -0,0 +1,917 @@
+//===- llvm/unittest/Support/CommandLineTest.cpp - CommandLine tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/StringSaver.h"
+#include "gtest/gtest.h"
+#include <fstream>
+#include <stdlib.h>
+#include <string>
+
+using namespace llvm;
+
+namespace {
+
+class TempEnvVar {
+ public:
+ TempEnvVar(const char *name, const char *value)
+ : name(name) {
+ const char *old_value = getenv(name);
+ EXPECT_EQ(nullptr, old_value) << old_value;
+#if HAVE_SETENV
+ setenv(name, value, true);
+#else
+# define SKIP_ENVIRONMENT_TESTS
+#endif
+ }
+
+ ~TempEnvVar() {
+#if HAVE_SETENV
+ // Assume setenv and unsetenv come together.
+ unsetenv(name);
+#else
+ (void)name; // Suppress -Wunused-private-field.
+#endif
+ }
+
+ private:
+ const char *const name;
+};
+
+template <typename T, typename Base = cl::opt<T>>
+class StackOption : public Base {
+public:
+ template <class... Ts>
+ explicit StackOption(Ts &&... Ms) : Base(std::forward<Ts>(Ms)...) {}
+
+ ~StackOption() override { this->removeArgument(); }
+
+ template <class DT> StackOption<T> &operator=(const DT &V) {
+ this->setValue(V);
+ return *this;
+ }
+};
+
+class StackSubCommand : public cl::SubCommand {
+public:
+ StackSubCommand(StringRef Name,
+ StringRef Description = StringRef())
+ : SubCommand(Name, Description) {}
+
+ StackSubCommand() : SubCommand() {}
+
+ ~StackSubCommand() { unregisterSubCommand(); }
+};
+
+
+cl::OptionCategory TestCategory("Test Options", "Description");
+TEST(CommandLineTest, ModifyExisitingOption) {
+ StackOption<int> TestOption("test-option", cl::desc("old description"));
+
+ static const char Description[] = "New description";
+ static const char ArgString[] = "new-test-option";
+ static const char ValueString[] = "Integer";
+
+ StringMap<cl::Option *> &Map =
+ cl::getRegisteredOptions(*cl::TopLevelSubCommand);
+
+ ASSERT_TRUE(Map.count("test-option") == 1) <<
+ "Could not find option in map.";
+
+ cl::Option *Retrieved = Map["test-option"];
+ ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
+
+ ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) <<
+ "Incorrect default option category.";
+
+ Retrieved->setCategory(TestCategory);
+ ASSERT_EQ(&TestCategory,Retrieved->Category) <<
+ "Failed to modify option's option category.";
+
+ Retrieved->setDescription(Description);
+ ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
+ << "Changing option description failed.";
+
+ Retrieved->setArgStr(ArgString);
+ ASSERT_STREQ(ArgString, Retrieved->ArgStr.data())
+ << "Failed to modify option's Argument string.";
+
+ Retrieved->setValueStr(ValueString);
+ ASSERT_STREQ(Retrieved->ValueStr.data(), ValueString)
+ << "Failed to modify option's Value string.";
+
+ Retrieved->setHiddenFlag(cl::Hidden);
+ ASSERT_EQ(cl::Hidden, TestOption.getOptionHiddenFlag()) <<
+ "Failed to modify option's hidden flag.";
+}
+#ifndef SKIP_ENVIRONMENT_TESTS
+
+const char test_env_var[] = "LLVM_TEST_COMMAND_LINE_FLAGS";
+
+cl::opt<std::string> EnvironmentTestOption("env-test-opt");
+TEST(CommandLineTest, ParseEnvironment) {
+ TempEnvVar TEV(test_env_var, "-env-test-opt=hello");
+ EXPECT_EQ("", EnvironmentTestOption);
+ cl::ParseEnvironmentOptions("CommandLineTest", test_env_var);
+ EXPECT_EQ("hello", EnvironmentTestOption);
+}
+
+// This test used to make valgrind complain
+// ("Conditional jump or move depends on uninitialised value(s)")
+//
+// Warning: Do not run any tests after this one that try to gain access to
+// registered command line options because this will likely result in a
+// SEGFAULT. This can occur because the cl::opt in the test below is declared
+// on the stack which will be destroyed after the test completes but the
+// command line system will still hold a pointer to a deallocated cl::Option.
+TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
+ // Put cl::opt on stack to check for proper initialization of fields.
+ StackOption<std::string> EnvironmentTestOptionLocal("env-test-opt-local");
+ TempEnvVar TEV(test_env_var, "-env-test-opt-local=hello-local");
+ EXPECT_EQ("", EnvironmentTestOptionLocal);
+ cl::ParseEnvironmentOptions("CommandLineTest", test_env_var);
+ EXPECT_EQ("hello-local", EnvironmentTestOptionLocal);
+}
+
+#endif // SKIP_ENVIRONMENT_TESTS
+
+TEST(CommandLineTest, UseOptionCategory) {
+ StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
+
+ ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
+ "Category.";
+}
+
+typedef void ParserFunction(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs);
+
+void testCommandLineTokenizer(ParserFunction *parse, StringRef Input,
+ const char *const Output[], size_t OutputSize) {
+ SmallVector<const char *, 0> Actual;
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ parse(Input, Saver, Actual, /*MarkEOLs=*/false);
+ EXPECT_EQ(OutputSize, Actual.size());
+ for (unsigned I = 0, E = Actual.size(); I != E; ++I) {
+ if (I < OutputSize) {
+ EXPECT_STREQ(Output[I], Actual[I]);
+ }
+ }
+}
+
+TEST(CommandLineTest, TokenizeGNUCommandLine) {
+ const char Input[] =
+ "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) "
+ "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\"";
+ const char *const Output[] = {
+ "foo bar", "foo bar", "foo bar", "foo\\bar",
+ "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"};
+ testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeWindowsCommandLine) {
+ const char Input[] = "a\\b c\\\\d e\\\\\"f g\" h\\\"i j\\\\\\\"k \"lmn\" o pqr "
+ "\"st \\\"u\" \\v";
+ const char *const Output[] = { "a\\b", "c\\\\d", "e\\f g", "h\"i", "j\\\"k",
+ "lmn", "o", "pqr", "st \"u", "\\v" };
+ testCommandLineTokenizer(cl::TokenizeWindowsCommandLine, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile1) {
+ const char *Input = "\\";
+ const char *const Output[] = { "\\" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile2) {
+ const char *Input = "\\abc";
+ const char *const Output[] = { "abc" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile3) {
+ const char *Input = "abc\\";
+ const char *const Output[] = { "abc\\" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile4) {
+ const char *Input = "abc\\\n123";
+ const char *const Output[] = { "abc123" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile5) {
+ const char *Input = "abc\\\r\n123";
+ const char *const Output[] = { "abc123" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile6) {
+ const char *Input = "abc\\\n";
+ const char *const Output[] = { "abc" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile7) {
+ const char *Input = "abc\\\r\n";
+ const char *const Output[] = { "abc" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile8) {
+ SmallVector<const char *, 0> Actual;
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ cl::tokenizeConfigFile("\\\n", Saver, Actual, /*MarkEOLs=*/false);
+ EXPECT_TRUE(Actual.empty());
+}
+
+TEST(CommandLineTest, TokenizeConfigFile9) {
+ SmallVector<const char *, 0> Actual;
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ cl::tokenizeConfigFile("\\\r\n", Saver, Actual, /*MarkEOLs=*/false);
+ EXPECT_TRUE(Actual.empty());
+}
+
+TEST(CommandLineTest, TokenizeConfigFile10) {
+ const char *Input = "\\\nabc";
+ const char *const Output[] = { "abc" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, TokenizeConfigFile11) {
+ const char *Input = "\\\r\nabc";
+ const char *const Output[] = { "abc" };
+ testCommandLineTokenizer(cl::tokenizeConfigFile, Input, Output,
+ array_lengthof(Output));
+}
+
+TEST(CommandLineTest, AliasesWithArguments) {
+ static const size_t ARGC = 3;
+ const char *const Inputs[][ARGC] = {
+ { "-tool", "-actual=x", "-extra" },
+ { "-tool", "-actual", "x" },
+ { "-tool", "-alias=x", "-extra" },
+ { "-tool", "-alias", "x" }
+ };
+
+ for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) {
+ StackOption<std::string> Actual("actual");
+ StackOption<bool> Extra("extra");
+ StackOption<std::string> Input(cl::Positional);
+
+ cl::alias Alias("alias", llvm::cl::aliasopt(Actual));
+
+ cl::ParseCommandLineOptions(ARGC, Inputs[i]);
+ EXPECT_EQ("x", Actual);
+ EXPECT_EQ(0, Input.getNumOccurrences());
+
+ Alias.removeArgument();
+ }
+}
+
+void testAliasRequired(int argc, const char *const *argv) {
+ StackOption<std::string> Option("option", cl::Required);
+ cl::alias Alias("o", llvm::cl::aliasopt(Option));
+
+ cl::ParseCommandLineOptions(argc, argv);
+ EXPECT_EQ("x", Option);
+ EXPECT_EQ(1, Option.getNumOccurrences());
+
+ Alias.removeArgument();
+}
+
+TEST(CommandLineTest, AliasRequired) {
+ const char *opts1[] = { "-tool", "-option=x" };
+ const char *opts2[] = { "-tool", "-o", "x" };
+ testAliasRequired(array_lengthof(opts1), opts1);
+ testAliasRequired(array_lengthof(opts2), opts2);
+}
+
+TEST(CommandLineTest, HideUnrelatedOptions) {
+ StackOption<int> TestOption1("hide-option-1");
+ StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory));
+
+ cl::HideUnrelatedOptions(TestCategory);
+
+ ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
+ << "Failed to hide extra option.";
+ ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+
+ StringMap<cl::Option *> &Map =
+ cl::getRegisteredOptions(*cl::TopLevelSubCommand);
+ ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
+ << "Hid default option that should be visable.";
+}
+
+cl::OptionCategory TestCategory2("Test Options set 2", "Description");
+
+TEST(CommandLineTest, HideUnrelatedOptionsMulti) {
+ StackOption<int> TestOption1("multi-hide-option-1");
+ StackOption<int> TestOption2("multi-hide-option-2", cl::cat(TestCategory));
+ StackOption<int> TestOption3("multi-hide-option-3", cl::cat(TestCategory2));
+
+ const cl::OptionCategory *VisibleCategories[] = {&TestCategory,
+ &TestCategory2};
+
+ cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
+
+ ASSERT_EQ(cl::ReallyHidden, TestOption1.getOptionHiddenFlag())
+ << "Failed to hide extra option.";
+ ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+ ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
+ << "Hid extra option that should be visable.";
+
+ StringMap<cl::Option *> &Map =
+ cl::getRegisteredOptions(*cl::TopLevelSubCommand);
+ ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
+ << "Hid default option that should be visable.";
+}
+
+TEST(CommandLineTest, SetValueInSubcategories) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First subcommand");
+ StackSubCommand SC2("sc2", "Second subcommand");
+
+ StackOption<bool> TopLevelOpt("top-level", cl::init(false));
+ StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
+ StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
+
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_FALSE(SC1Opt);
+ EXPECT_FALSE(SC2Opt);
+ const char *args[] = {"prog", "-top-level"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(TopLevelOpt);
+ EXPECT_FALSE(SC1Opt);
+ EXPECT_FALSE(SC2Opt);
+
+ TopLevelOpt = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_FALSE(SC1Opt);
+ EXPECT_FALSE(SC2Opt);
+ const char *args2[] = {"prog", "sc1", "-sc1"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_TRUE(SC1Opt);
+ EXPECT_FALSE(SC2Opt);
+
+ SC1Opt = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_FALSE(SC1Opt);
+ EXPECT_FALSE(SC2Opt);
+ const char *args3[] = {"prog", "sc2", "-sc2"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls()));
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_FALSE(SC1Opt);
+ EXPECT_TRUE(SC2Opt);
+}
+
+TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First subcommand");
+ StackSubCommand SC2("sc2", "Second subcommand");
+
+ StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
+ StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
+
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
+ const char *args[] = {"prog", "sc1", "-sc2"};
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
+ OS.flush();
+ EXPECT_FALSE(Errs.empty());
+}
+
+TEST(CommandLineTest, AddToAllSubCommands) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First subcommand");
+ StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),
+ cl::init(false));
+ StackSubCommand SC2("sc2", "Second subcommand");
+
+ const char *args[] = {"prog", "-everywhere"};
+ const char *args2[] = {"prog", "sc1", "-everywhere"};
+ const char *args3[] = {"prog", "sc2", "-everywhere"};
+
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
+ EXPECT_FALSE(AllOpt);
+ EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
+ EXPECT_TRUE(AllOpt);
+
+ AllOpt = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(AllOpt);
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS));
+ EXPECT_TRUE(AllOpt);
+
+ AllOpt = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(AllOpt);
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS));
+ EXPECT_TRUE(AllOpt);
+
+ // Since all parsing succeeded, the error message should be empty.
+ OS.flush();
+ EXPECT_TRUE(Errs.empty());
+}
+
+TEST(CommandLineTest, ReparseCommandLineOptions) {
+ cl::ResetCommandLineParser();
+
+ StackOption<bool> TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand),
+ cl::init(false));
+
+ const char *args[] = {"prog", "-top-level"};
+
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(TopLevelOpt);
+
+ TopLevelOpt = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(TopLevelOpt);
+}
+
+TEST(CommandLineTest, RemoveFromRegularSubCommand) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC("sc", "Subcommand");
+ StackOption<bool> RemoveOption("remove-option", cl::sub(SC), cl::init(false));
+ StackOption<bool> KeepOption("keep-option", cl::sub(SC), cl::init(false));
+
+ const char *args[] = {"prog", "sc", "-remove-option"};
+
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+
+ EXPECT_FALSE(RemoveOption);
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
+ EXPECT_TRUE(RemoveOption);
+ OS.flush();
+ EXPECT_TRUE(Errs.empty());
+
+ RemoveOption.removeArgument();
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS));
+ OS.flush();
+ EXPECT_FALSE(Errs.empty());
+}
+
+TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
+ cl::ResetCommandLineParser();
+
+ StackOption<bool> TopLevelRemove(
+ "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
+ StackOption<bool> TopLevelKeep(
+ "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false));
+
+ const char *args[] = {"prog", "-top-level-remove"};
+
+ EXPECT_FALSE(TopLevelRemove);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(TopLevelRemove);
+
+ TopLevelRemove.removeArgument();
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+}
+
+TEST(CommandLineTest, RemoveFromAllSubCommands) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First Subcommand");
+ StackSubCommand SC2("sc2", "Second Subcommand");
+ StackOption<bool> RemoveOption("remove-option", cl::sub(*cl::AllSubCommands),
+ cl::init(false));
+ StackOption<bool> KeepOption("keep-option", cl::sub(*cl::AllSubCommands),
+ cl::init(false));
+
+ const char *args0[] = {"prog", "-remove-option"};
+ const char *args1[] = {"prog", "sc1", "-remove-option"};
+ const char *args2[] = {"prog", "sc2", "-remove-option"};
+
+ // It should work for all subcommands including the top-level.
+ EXPECT_FALSE(RemoveOption);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(RemoveOption);
+
+ RemoveOption = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(RemoveOption);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(RemoveOption);
+
+ RemoveOption = false;
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(RemoveOption);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(RemoveOption);
+
+ RemoveOption.removeArgument();
+
+ // It should not work for any subcommands including the top-level.
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
+ cl::ResetAllOptionOccurrences();
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+}
+
+TEST(CommandLineTest, GetRegisteredSubcommands) {
+ cl::ResetCommandLineParser();
+
+ StackSubCommand SC1("sc1", "First Subcommand");
+ StackOption<bool> Opt1("opt1", cl::sub(SC1), cl::init(false));
+ StackSubCommand SC2("sc2", "Second subcommand");
+ StackOption<bool> Opt2("opt2", cl::sub(SC2), cl::init(false));
+
+ const char *args0[] = {"prog", "sc1"};
+ const char *args1[] = {"prog", "sc2"};
+
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls()));
+ EXPECT_FALSE(Opt1);
+ EXPECT_FALSE(Opt2);
+ for (auto *S : cl::getRegisteredSubcommands()) {
+ if (*S) {
+ EXPECT_EQ("sc1", S->getName());
+ }
+ }
+
+ cl::ResetAllOptionOccurrences();
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
+ EXPECT_FALSE(Opt1);
+ EXPECT_FALSE(Opt2);
+ for (auto *S : cl::getRegisteredSubcommands()) {
+ if (*S) {
+ EXPECT_EQ("sc2", S->getName());
+ }
+ }
+}
+
+TEST(CommandLineTest, ArgumentLimit) {
+ std::string args(32 * 4096, 'a');
+ EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data()));
+}
+
+TEST(CommandLineTest, ResponseFileWindows) {
+ if (!Triple(sys::getProcessTriple()).isOSWindows())
+ return;
+
+ StackOption<std::string, cl::list<std::string>> InputFilenames(
+ cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
+ StackOption<bool> TopLevelOpt("top-level", cl::init(false));
+
+ // Create response file.
+ int FileDescriptor;
+ SmallString<64> TempPath;
+ std::error_code EC =
+ llvm::sys::fs::createTemporaryFile("resp-", ".txt", FileDescriptor, TempPath);
+ EXPECT_TRUE(!EC);
+
+ std::ofstream RspFile(TempPath.c_str());
+ EXPECT_TRUE(RspFile.is_open());
+ RspFile << "-top-level\npath\\dir\\file1\npath/dir/file2";
+ RspFile.close();
+
+ llvm::SmallString<128> RspOpt;
+ RspOpt.append(1, '@');
+ RspOpt.append(TempPath.c_str());
+ const char *args[] = {"prog", RspOpt.c_str()};
+ EXPECT_FALSE(TopLevelOpt);
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(TopLevelOpt);
+ EXPECT_TRUE(InputFilenames[0] == "path\\dir\\file1");
+ EXPECT_TRUE(InputFilenames[1] == "path/dir/file2");
+
+ llvm::sys::fs::remove(TempPath.c_str());
+}
+
+TEST(CommandLineTest, ResponseFiles) {
+ llvm::SmallString<128> TestDir;
+ std::error_code EC =
+ llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
+ EXPECT_TRUE(!EC);
+
+ // Create included response file of first level.
+ llvm::SmallString<128> IncludedFileName;
+ llvm::sys::path::append(IncludedFileName, TestDir, "resp1");
+ std::ofstream IncludedFile(IncludedFileName.c_str());
+ EXPECT_TRUE(IncludedFile.is_open());
+ IncludedFile << "-option_1 -option_2\n"
+ "@incdir/resp2\n"
+ "-option_3=abcd\n";
+ IncludedFile.close();
+
+ // Directory for included file.
+ llvm::SmallString<128> IncDir;
+ llvm::sys::path::append(IncDir, TestDir, "incdir");
+ EC = llvm::sys::fs::create_directory(IncDir);
+ EXPECT_TRUE(!EC);
+
+ // Create included response file of second level.
+ llvm::SmallString<128> IncludedFileName2;
+ llvm::sys::path::append(IncludedFileName2, IncDir, "resp2");
+ std::ofstream IncludedFile2(IncludedFileName2.c_str());
+ EXPECT_TRUE(IncludedFile2.is_open());
+ IncludedFile2 << "-option_21 -option_22\n";
+ IncludedFile2 << "-option_23=abcd\n";
+ IncludedFile2.close();
+
+ // Prepare 'file' with reference to response file.
+ SmallString<128> IncRef;
+ IncRef.append(1, '@');
+ IncRef.append(IncludedFileName.c_str());
+ llvm::SmallVector<const char *, 4> Argv =
+ { "test/test", "-flag_1", IncRef.c_str(), "-flag_2" };
+
+ // Expand response files.
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ bool Res = llvm::cl::ExpandResponseFiles(
+ Saver, llvm::cl::TokenizeGNUCommandLine, Argv, false, true);
+ EXPECT_TRUE(Res);
+ EXPECT_EQ(Argv.size(), 9U);
+ EXPECT_STREQ(Argv[0], "test/test");
+ EXPECT_STREQ(Argv[1], "-flag_1");
+ EXPECT_STREQ(Argv[2], "-option_1");
+ EXPECT_STREQ(Argv[3], "-option_2");
+ EXPECT_STREQ(Argv[4], "-option_21");
+ EXPECT_STREQ(Argv[5], "-option_22");
+ EXPECT_STREQ(Argv[6], "-option_23=abcd");
+ EXPECT_STREQ(Argv[7], "-option_3=abcd");
+ EXPECT_STREQ(Argv[8], "-flag_2");
+
+ llvm::sys::fs::remove(IncludedFileName2);
+ llvm::sys::fs::remove(IncDir);
+ llvm::sys::fs::remove(IncludedFileName);
+ llvm::sys::fs::remove(TestDir);
+}
+
+TEST(CommandLineTest, SetDefautValue) {
+ cl::ResetCommandLineParser();
+
+ StackOption<std::string> Opt1("opt1", cl::init("true"));
+ StackOption<bool> Opt2("opt2", cl::init(true));
+ cl::alias Alias("alias", llvm::cl::aliasopt(Opt2));
+ StackOption<int> Opt3("opt3", cl::init(3));
+
+ const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"};
+
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+
+ EXPECT_TRUE(Opt1 == "false");
+ EXPECT_TRUE(Opt2);
+ EXPECT_TRUE(Opt3 == 3);
+
+ Opt2 = false;
+ Opt3 = 1;
+
+ cl::ResetAllOptionOccurrences();
+
+ for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) {
+ cl::Option *O = OM.second;
+ if (O->ArgStr == "opt2") {
+ continue;
+ }
+ O->setDefault();
+ }
+
+ EXPECT_TRUE(Opt1 == "true");
+ EXPECT_TRUE(Opt2);
+ EXPECT_TRUE(Opt3 == 3);
+ Alias.removeArgument();
+}
+
+TEST(CommandLineTest, ReadConfigFile) {
+ llvm::SmallVector<const char *, 1> Argv;
+
+ llvm::SmallString<128> TestDir;
+ std::error_code EC =
+ llvm::sys::fs::createUniqueDirectory("unittest", TestDir);
+ EXPECT_TRUE(!EC);
+
+ llvm::SmallString<128> TestCfg;
+ llvm::sys::path::append(TestCfg, TestDir, "foo");
+ std::ofstream ConfigFile(TestCfg.c_str());
+ EXPECT_TRUE(ConfigFile.is_open());
+ ConfigFile << "# Comment\n"
+ "-option_1\n"
+ "@subconfig\n"
+ "-option_3=abcd\n"
+ "-option_4=\\\n"
+ "cdef\n";
+ ConfigFile.close();
+
+ llvm::SmallString<128> TestCfg2;
+ llvm::sys::path::append(TestCfg2, TestDir, "subconfig");
+ std::ofstream ConfigFile2(TestCfg2.c_str());
+ EXPECT_TRUE(ConfigFile2.is_open());
+ ConfigFile2 << "-option_2\n"
+ "\n"
+ " # comment\n";
+ ConfigFile2.close();
+
+ // Make sure the current directory is not the directory where config files
+ // resides. In this case the code that expands response files will not find
+ // 'subconfig' unless it resolves nested inclusions relative to the including
+ // file.
+ llvm::SmallString<128> CurrDir;
+ EC = llvm::sys::fs::current_path(CurrDir);
+ EXPECT_TRUE(!EC);
+ EXPECT_TRUE(StringRef(CurrDir) != StringRef(TestDir));
+
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ bool Result = llvm::cl::readConfigFile(TestCfg, Saver, Argv);
+
+ EXPECT_TRUE(Result);
+ EXPECT_EQ(Argv.size(), 4U);
+ EXPECT_STREQ(Argv[0], "-option_1");
+ EXPECT_STREQ(Argv[1], "-option_2");
+ EXPECT_STREQ(Argv[2], "-option_3=abcd");
+ EXPECT_STREQ(Argv[3], "-option_4=cdef");
+
+ llvm::sys::fs::remove(TestCfg2);
+ llvm::sys::fs::remove(TestCfg);
+ llvm::sys::fs::remove(TestDir);
+}
+
+TEST(CommandLineTest, PositionalEatArgsError) {
+ StackOption<std::string, cl::list<std::string>> PosEatArgs(
+ "positional-eat-args", cl::Positional, cl::desc("<arguments>..."),
+ cl::ZeroOrMore, cl::PositionalEatsArgs);
+
+ const char *args[] = {"prog", "-positional-eat-args=XXXX"};
+ const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"};
+ const char *args3[] = {"prog", "-positional-eat-args", "-foo"};
+
+ std::string Errs;
+ raw_string_ostream OS(Errs);
+ EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush();
+ EXPECT_FALSE(Errs.empty()); Errs.clear();
+ EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush();
+ EXPECT_FALSE(Errs.empty()); Errs.clear();
+ EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush();
+ EXPECT_TRUE(Errs.empty());
+}
+
+#ifdef _WIN32
+TEST(CommandLineTest, GetCommandLineArguments) {
+ int argc = __argc;
+ char **argv = __argv;
+
+ // GetCommandLineArguments is called in InitLLVM.
+ llvm::InitLLVM X(argc, argv);
+
+ EXPECT_EQ(llvm::sys::path::is_absolute(argv[0]),
+ llvm::sys::path::is_absolute(__argv[0]));
+
+ EXPECT_TRUE(llvm::sys::path::filename(argv[0])
+ .equals_lower("supporttests.exe"))
+ << "Filename of test executable is "
+ << llvm::sys::path::filename(argv[0]);
+}
+#endif
+
+TEST(CommandLineTest, PrefixOptions) {
+ cl::ResetCommandLineParser();
+
+ StackOption<std::string, cl::list<std::string>> IncludeDirs(
+ "I", cl::Prefix, cl::desc("Declare an include directory"));
+
+ // Test non-prefixed variant works with cl::Prefix options.
+ EXPECT_TRUE(IncludeDirs.empty());
+ const char *args[] = {"prog", "-I=/usr/include"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(IncludeDirs.size() == 1);
+ EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
+
+ IncludeDirs.erase(IncludeDirs.begin());
+ cl::ResetAllOptionOccurrences();
+
+ // Test non-prefixed variant works with cl::Prefix options when value is
+ // passed in following argument.
+ EXPECT_TRUE(IncludeDirs.empty());
+ const char *args2[] = {"prog", "-I", "/usr/include"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(IncludeDirs.size() == 1);
+ EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
+
+ IncludeDirs.erase(IncludeDirs.begin());
+ cl::ResetAllOptionOccurrences();
+
+ // Test prefixed variant works with cl::Prefix options.
+ EXPECT_TRUE(IncludeDirs.empty());
+ const char *args3[] = {"prog", "-I/usr/include"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(IncludeDirs.size() == 1);
+ EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
+
+ StackOption<std::string, cl::list<std::string>> MacroDefs(
+ "D", cl::AlwaysPrefix, cl::desc("Define a macro"),
+ cl::value_desc("MACRO[=VALUE]"));
+
+ cl::ResetAllOptionOccurrences();
+
+ // Test non-prefixed variant does not work with cl::AlwaysPrefix options:
+ // equal sign is part of the value.
+ EXPECT_TRUE(MacroDefs.empty());
+ const char *args4[] = {"prog", "-D=HAVE_FOO"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(MacroDefs.size() == 1);
+ EXPECT_TRUE(MacroDefs.front().compare("=HAVE_FOO") == 0);
+
+ MacroDefs.erase(MacroDefs.begin());
+ cl::ResetAllOptionOccurrences();
+
+ // Test non-prefixed variant does not allow value to be passed in following
+ // argument with cl::AlwaysPrefix options.
+ EXPECT_TRUE(MacroDefs.empty());
+ const char *args5[] = {"prog", "-D", "HAVE_FOO"};
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(MacroDefs.empty());
+
+ cl::ResetAllOptionOccurrences();
+
+ // Test prefixed variant works with cl::AlwaysPrefix options.
+ EXPECT_TRUE(MacroDefs.empty());
+ const char *args6[] = {"prog", "-DHAVE_FOO"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(MacroDefs.size() == 1);
+ EXPECT_TRUE(MacroDefs.front().compare("HAVE_FOO") == 0);
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/CompressionTest.cpp b/src/llvm-project/llvm/unittests/Support/CompressionTest.cpp
new file mode 100644
index 0000000..e9f36c5
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CompressionTest.cpp
@@ -0,0 +1,77 @@
+//===- llvm/unittest/Support/CompressionTest.cpp - Compression tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unit tests for the Compression functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compression.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
+
+void TestZlibCompression(StringRef Input, int Level) {
+ SmallString<32> Compressed;
+ SmallString<32> Uncompressed;
+
+ Error E = zlib::compress(Input, Compressed, Level);
+ EXPECT_FALSE(E);
+ consumeError(std::move(E));
+
+ // Check that uncompressed buffer is the same as original.
+ E = zlib::uncompress(Compressed, Uncompressed, Input.size());
+ EXPECT_FALSE(E);
+ consumeError(std::move(E));
+
+ EXPECT_EQ(Input, Uncompressed);
+ if (Input.size() > 0) {
+ // Uncompression fails if expected length is too short.
+ E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1);
+ EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E)));
+ }
+}
+
+TEST(CompressionTest, Zlib) {
+ TestZlibCompression("", zlib::DefaultCompression);
+
+ TestZlibCompression("hello, world!", zlib::NoCompression);
+ TestZlibCompression("hello, world!", zlib::BestSizeCompression);
+ TestZlibCompression("hello, world!", zlib::BestSpeedCompression);
+ TestZlibCompression("hello, world!", zlib::DefaultCompression);
+
+ const size_t kSize = 1024;
+ char BinaryData[kSize];
+ for (size_t i = 0; i < kSize; ++i) {
+ BinaryData[i] = i & 255;
+ }
+ StringRef BinaryDataStr(BinaryData, kSize);
+
+ TestZlibCompression(BinaryDataStr, zlib::NoCompression);
+ TestZlibCompression(BinaryDataStr, zlib::BestSizeCompression);
+ TestZlibCompression(BinaryDataStr, zlib::BestSpeedCompression);
+ TestZlibCompression(BinaryDataStr, zlib::DefaultCompression);
+}
+
+TEST(CompressionTest, ZlibCRC32) {
+ EXPECT_EQ(
+ 0x414FA339U,
+ zlib::crc32(StringRef("The quick brown fox jumps over the lazy dog")));
+}
+
+#endif
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ConvertUTFTest.cpp b/src/llvm-project/llvm/unittests/Support/ConvertUTFTest.cpp
new file mode 100644
index 0000000..dd6e0df
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ConvertUTFTest.cpp
@@ -0,0 +1,1712 @@
+//===- llvm/unittest/Support/ConvertUTFTest.cpp - ConvertUTF tests --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "gtest/gtest.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+TEST(ConvertUTFTest, ConvertUTF16LittleEndianToUTF8String) {
+ // Src is the look of disapproval.
+ static const char Src[] = "\xff\xfe\xa0\x0c_\x00\xa0\x0c";
+ ArrayRef<char> Ref(Src, sizeof(Src) - 1);
+ std::string Result;
+ bool Success = convertUTF16ToUTF8String(Ref, Result);
+ EXPECT_TRUE(Success);
+ std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST(ConvertUTFTest, ConvertUTF16BigEndianToUTF8String) {
+ // Src is the look of disapproval.
+ static const char Src[] = "\xfe\xff\x0c\xa0\x00_\x0c\xa0";
+ ArrayRef<char> Ref(Src, sizeof(Src) - 1);
+ std::string Result;
+ bool Success = convertUTF16ToUTF8String(Ref, Result);
+ EXPECT_TRUE(Success);
+ std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST(ConvertUTFTest, ConvertUTF8ToUTF16String) {
+ // Src is the look of disapproval.
+ static const char Src[] = "\xe0\xb2\xa0_\xe0\xb2\xa0";
+ StringRef Ref(Src, sizeof(Src) - 1);
+ SmallVector<UTF16, 5> Result;
+ bool Success = convertUTF8ToUTF16String(Ref, Result);
+ EXPECT_TRUE(Success);
+ static const UTF16 Expected[] = {0x0CA0, 0x005f, 0x0CA0, 0};
+ ASSERT_EQ(3u, Result.size());
+ for (int I = 0, E = 3; I != E; ++I)
+ EXPECT_EQ(Expected[I], Result[I]);
+}
+
+TEST(ConvertUTFTest, OddLengthInput) {
+ std::string Result;
+ bool Success = convertUTF16ToUTF8String(makeArrayRef("xxxxx", 5), Result);
+ EXPECT_FALSE(Success);
+}
+
+TEST(ConvertUTFTest, Empty) {
+ std::string Result;
+ bool Success = convertUTF16ToUTF8String(llvm::ArrayRef<char>(None), Result);
+ EXPECT_TRUE(Success);
+ EXPECT_TRUE(Result.empty());
+}
+
+TEST(ConvertUTFTest, HasUTF16BOM) {
+ bool HasBOM = hasUTF16ByteOrderMark(makeArrayRef("\xff\xfe", 2));
+ EXPECT_TRUE(HasBOM);
+ HasBOM = hasUTF16ByteOrderMark(makeArrayRef("\xfe\xff", 2));
+ EXPECT_TRUE(HasBOM);
+ HasBOM = hasUTF16ByteOrderMark(makeArrayRef("\xfe\xff ", 3));
+ EXPECT_TRUE(HasBOM); // Don't care about odd lengths.
+ HasBOM = hasUTF16ByteOrderMark(makeArrayRef("\xfe\xff\x00asdf", 6));
+ EXPECT_TRUE(HasBOM);
+
+ HasBOM = hasUTF16ByteOrderMark(None);
+ EXPECT_FALSE(HasBOM);
+ HasBOM = hasUTF16ByteOrderMark(makeArrayRef("\xfe", 1));
+ EXPECT_FALSE(HasBOM);
+}
+
+TEST(ConvertUTFTest, UTF16WrappersForConvertUTF16ToUTF8String) {
+ // Src is the look of disapproval.
+ static const char Src[] = "\xff\xfe\xa0\x0c_\x00\xa0\x0c";
+ ArrayRef<UTF16> SrcRef = makeArrayRef((const UTF16 *)Src, 4);
+ std::string Result;
+ bool Success = convertUTF16ToUTF8String(SrcRef, Result);
+ EXPECT_TRUE(Success);
+ std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST(ConvertUTFTest, ConvertUTF8toWide) {
+ // Src is the look of disapproval.
+ static const char Src[] = "\xe0\xb2\xa0_\xe0\xb2\xa0";
+ std::wstring Result;
+ bool Success = ConvertUTF8toWide((const char*)Src, Result);
+ EXPECT_TRUE(Success);
+ std::wstring Expected(L"\x0ca0_\x0ca0");
+ EXPECT_EQ(Expected, Result);
+ Result.clear();
+ Success = ConvertUTF8toWide(StringRef(Src, 7), Result);
+ EXPECT_TRUE(Success);
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST(ConvertUTFTest, convertWideToUTF8) {
+ // Src is the look of disapproval.
+ static const wchar_t Src[] = L"\x0ca0_\x0ca0";
+ std::string Result;
+ bool Success = convertWideToUTF8(Src, Result);
+ EXPECT_TRUE(Success);
+ std::string Expected("\xe0\xb2\xa0_\xe0\xb2\xa0");
+ EXPECT_EQ(Expected, Result);
+}
+
+struct ConvertUTFResultContainer {
+ ConversionResult ErrorCode;
+ std::vector<unsigned> UnicodeScalars;
+
+ ConvertUTFResultContainer(ConversionResult ErrorCode)
+ : ErrorCode(ErrorCode) {}
+
+ ConvertUTFResultContainer
+ withScalars(unsigned US0 = 0x110000, unsigned US1 = 0x110000,
+ unsigned US2 = 0x110000, unsigned US3 = 0x110000,
+ unsigned US4 = 0x110000, unsigned US5 = 0x110000,
+ unsigned US6 = 0x110000, unsigned US7 = 0x110000) {
+ ConvertUTFResultContainer Result(*this);
+ if (US0 != 0x110000)
+ Result.UnicodeScalars.push_back(US0);
+ if (US1 != 0x110000)
+ Result.UnicodeScalars.push_back(US1);
+ if (US2 != 0x110000)
+ Result.UnicodeScalars.push_back(US2);
+ if (US3 != 0x110000)
+ Result.UnicodeScalars.push_back(US3);
+ if (US4 != 0x110000)
+ Result.UnicodeScalars.push_back(US4);
+ if (US5 != 0x110000)
+ Result.UnicodeScalars.push_back(US5);
+ if (US6 != 0x110000)
+ Result.UnicodeScalars.push_back(US6);
+ if (US7 != 0x110000)
+ Result.UnicodeScalars.push_back(US7);
+ return Result;
+ }
+};
+
+std::pair<ConversionResult, std::vector<unsigned>>
+ConvertUTF8ToUnicodeScalarsLenient(StringRef S) {
+ const UTF8 *SourceStart = reinterpret_cast<const UTF8 *>(S.data());
+
+ const UTF8 *SourceNext = SourceStart;
+ std::vector<UTF32> Decoded(S.size(), 0);
+ UTF32 *TargetStart = Decoded.data();
+
+ auto ErrorCode =
+ ConvertUTF8toUTF32(&SourceNext, SourceStart + S.size(), &TargetStart,
+ Decoded.data() + Decoded.size(), lenientConversion);
+
+ Decoded.resize(TargetStart - Decoded.data());
+
+ return std::make_pair(ErrorCode, Decoded);
+}
+
+std::pair<ConversionResult, std::vector<unsigned>>
+ConvertUTF8ToUnicodeScalarsPartialLenient(StringRef S) {
+ const UTF8 *SourceStart = reinterpret_cast<const UTF8 *>(S.data());
+
+ const UTF8 *SourceNext = SourceStart;
+ std::vector<UTF32> Decoded(S.size(), 0);
+ UTF32 *TargetStart = Decoded.data();
+
+ auto ErrorCode = ConvertUTF8toUTF32Partial(
+ &SourceNext, SourceStart + S.size(), &TargetStart,
+ Decoded.data() + Decoded.size(), lenientConversion);
+
+ Decoded.resize(TargetStart - Decoded.data());
+
+ return std::make_pair(ErrorCode, Decoded);
+}
+
+::testing::AssertionResult
+CheckConvertUTF8ToUnicodeScalars(ConvertUTFResultContainer Expected,
+ StringRef S, bool Partial = false) {
+ ConversionResult ErrorCode;
+ std::vector<unsigned> Decoded;
+ if (!Partial)
+ std::tie(ErrorCode, Decoded) = ConvertUTF8ToUnicodeScalarsLenient(S);
+ else
+ std::tie(ErrorCode, Decoded) = ConvertUTF8ToUnicodeScalarsPartialLenient(S);
+
+ if (Expected.ErrorCode != ErrorCode)
+ return ::testing::AssertionFailure() << "Expected error code "
+ << Expected.ErrorCode << ", actual "
+ << ErrorCode;
+
+ if (Expected.UnicodeScalars != Decoded)
+ return ::testing::AssertionFailure()
+ << "Expected lenient decoded result:\n"
+ << ::testing::PrintToString(Expected.UnicodeScalars) << "\n"
+ << "Actual result:\n" << ::testing::PrintToString(Decoded);
+
+ return ::testing::AssertionSuccess();
+}
+
+TEST(ConvertUTFTest, UTF8ToUTF32Lenient) {
+
+ //
+ // 1-byte sequences
+ //
+
+ // U+0041 LATIN CAPITAL LETTER A
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0041), "\x41"));
+
+ //
+ // 2-byte sequences
+ //
+
+ // U+0283 LATIN SMALL LETTER ESH
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0283),
+ "\xca\x83"));
+
+ // U+03BA GREEK SMALL LETTER KAPPA
+ // U+1F79 GREEK SMALL LETTER OMICRON WITH OXIA
+ // U+03C3 GREEK SMALL LETTER SIGMA
+ // U+03BC GREEK SMALL LETTER MU
+ // U+03B5 GREEK SMALL LETTER EPSILON
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK)
+ .withScalars(0x03ba, 0x1f79, 0x03c3, 0x03bc, 0x03b5),
+ "\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5"));
+
+ //
+ // 3-byte sequences
+ //
+
+ // U+4F8B CJK UNIFIED IDEOGRAPH-4F8B
+ // U+6587 CJK UNIFIED IDEOGRAPH-6587
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x4f8b, 0x6587),
+ "\xe4\xbe\x8b\xe6\x96\x87"));
+
+ // U+D55C HANGUL SYLLABLE HAN
+ // U+AE00 HANGUL SYLLABLE GEUL
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xd55c, 0xae00),
+ "\xed\x95\x9c\xea\xb8\x80"));
+
+ // U+1112 HANGUL CHOSEONG HIEUH
+ // U+1161 HANGUL JUNGSEONG A
+ // U+11AB HANGUL JONGSEONG NIEUN
+ // U+1100 HANGUL CHOSEONG KIYEOK
+ // U+1173 HANGUL JUNGSEONG EU
+ // U+11AF HANGUL JONGSEONG RIEUL
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK)
+ .withScalars(0x1112, 0x1161, 0x11ab, 0x1100, 0x1173, 0x11af),
+ "\xe1\x84\x92\xe1\x85\xa1\xe1\x86\xab\xe1\x84\x80\xe1\x85\xb3"
+ "\xe1\x86\xaf"));
+
+ //
+ // 4-byte sequences
+ //
+
+ // U+E0100 VARIATION SELECTOR-17
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x000E0100),
+ "\xf3\xa0\x84\x80"));
+
+ //
+ // First possible sequence of a certain length
+ //
+
+ // U+0000 NULL
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0000),
+ StringRef("\x00", 1)));
+
+ // U+0080 PADDING CHARACTER
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0080),
+ "\xc2\x80"));
+
+ // U+0800 SAMARITAN LETTER ALAF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0800),
+ "\xe0\xa0\x80"));
+
+ // U+10000 LINEAR B SYLLABLE B008 A
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x10000),
+ "\xf0\x90\x80\x80"));
+
+ // U+200000 (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x88\x80\x80\x80"));
+
+ // U+4000000 (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x84\x80\x80\x80\x80"));
+
+ //
+ // Last possible sequence of a certain length
+ //
+
+ // U+007F DELETE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x007f), "\x7f"));
+
+ // U+07FF (unassigned)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x07ff),
+ "\xdf\xbf"));
+
+ // U+FFFF (noncharacter)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xffff),
+ "\xef\xbf\xbf"));
+
+ // U+1FFFFF (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf7\xbf\xbf\xbf"));
+
+ // U+3FFFFFF (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfb\xbf\xbf\xbf\xbf"));
+
+ // U+7FFFFFFF (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfd\xbf\xbf\xbf\xbf\xbf"));
+
+ //
+ // Other boundary conditions
+ //
+
+ // U+D7FF (unassigned)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xd7ff),
+ "\xed\x9f\xbf"));
+
+ // U+E000 (private use)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xe000),
+ "\xee\x80\x80"));
+
+ // U+FFFD REPLACEMENT CHARACTER
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfffd),
+ "\xef\xbf\xbd"));
+
+ // U+10FFFF (noncharacter)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x10ffff),
+ "\xf4\x8f\xbf\xbf"));
+
+ // U+110000 (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf4\x90\x80\x80"));
+
+ //
+ // Unexpected continuation bytes
+ //
+
+ // A sequence of unexpected continuation bytes that don't follow a first
+ // byte, every byte is a maximal subpart.
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\x80\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xbf\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\x80\xbf\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\x80\xbf\x80\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\x80\xbf\x82\xbf\xaa"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xaa\xb0\xbb\xbf\xaa\xa0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xaa\xb0\xbb\xbf\xaa\xa0\x8f"));
+
+ // All continuation bytes (0x80--0xbf).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"));
+
+ //
+ // Lonely start bytes
+ //
+
+ // Start bytes of 2-byte sequences (0xc0--0xdf).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xc0\x20\xc1\x20\xc2\x20\xc3\x20\xc4\x20\xc5\x20\xc6\x20\xc7\x20"
+ "\xc8\x20\xc9\x20\xca\x20\xcb\x20\xcc\x20\xcd\x20\xce\x20\xcf\x20"
+ "\xd0\x20\xd1\x20\xd2\x20\xd3\x20\xd4\x20\xd5\x20\xd6\x20\xd7\x20"
+ "\xd8\x20\xd9\x20\xda\x20\xdb\x20\xdc\x20\xdd\x20\xde\x20\xdf\x20"));
+
+ // Start bytes of 3-byte sequences (0xe0--0xef).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xe0\x20\xe1\x20\xe2\x20\xe3\x20\xe4\x20\xe5\x20\xe6\x20\xe7\x20"
+ "\xe8\x20\xe9\x20\xea\x20\xeb\x20\xec\x20\xed\x20\xee\x20\xef\x20"));
+
+ // Start bytes of 4-byte sequences (0xf0--0xf7).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd,
+ 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xf0\x20\xf1\x20\xf2\x20\xf3\x20\xf4\x20\xf5\x20\xf6\x20\xf7\x20"));
+
+ // Start bytes of 5-byte sequences (0xf8--0xfb).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\xf9\xfa\xfb"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xf8\x20\xf9\x20\xfa\x20\xfb\x20"));
+
+ // Start bytes of 6-byte sequences (0xfc--0xfd).
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfc\xfd"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xfc\x20\xfd\x20"));
+
+ //
+ // Other bytes (0xc0--0xc1, 0xfe--0xff).
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xc0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xc1"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfe"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xff"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xc0\xc1\xfe\xff"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfe\xfe\xff\xff"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfe\x80\x80\x80\x80\x80"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xff\x80\x80\x80\x80\x80"));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0x0020, 0xfffd, 0x0020,
+ 0xfffd, 0x0020, 0xfffd, 0x0020),
+ "\xc0\x20\xc1\x20\xfe\x20\xff\x20"));
+
+ //
+ // Sequences with one continuation byte missing
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xc2"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xdf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xe0\xa0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xe0\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xe1\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xec\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xed\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xed\x9f"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xee\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xef\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf0\x90\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf0\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf1\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf3\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf4\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf4\x8f\xbf"));
+
+ // Overlong sequences with one trailing byte missing.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xc0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xc1"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xe0\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xe0\x9f"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x8f\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x80\x80\x80\x80"));
+
+ // Sequences that represent surrogates with one trailing byte missing.
+ // High surrogates
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xa0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xac"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xaf"));
+ // Low surrogates
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xb0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xb4"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xed\xbf"));
+
+ // Ill-formed 4-byte sequences.
+ // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+1100xx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf4\x90\x80"));
+ // U+13FBxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf4\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf5\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf6\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf7\x80\x80"));
+ // U+1FFBxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf7\xbf\xbf"));
+
+ // Ill-formed 5-byte sequences.
+ // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+2000xx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x88\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\xbf\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf9\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfa\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfb\x80\x80\x80"));
+ // U+3FFFFxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfb\xbf\xbf\xbf"));
+
+ // Ill-formed 6-byte sequences.
+ // 1111110u 10uuuuuu 10uzzzzz 10zzzyyyy 10yyyyxx 10xxxxxx
+ // U+40000xx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x84\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\xbf\xbf\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfd\x80\x80\x80\x80"));
+ // U+7FFFFFxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfd\xbf\xbf\xbf\xbf"));
+
+ //
+ // Sequences with two continuation bytes missing
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf0\x90"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf0\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf1\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf3\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf4\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd),
+ "\xf4\x8f"));
+
+ // Overlong sequences with two trailing byte missing.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xe0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf0\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf0\x8f"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x80\x80\x80"));
+
+ // Sequences that represent surrogates with two trailing bytes missing.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xed"));
+
+ // Ill-formed 4-byte sequences.
+ // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+110yxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf4\x90"));
+ // U+13Fyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf4\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf5\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf6\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf7\x80"));
+ // U+1FFyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf7\xbf"));
+
+ // Ill-formed 5-byte sequences.
+ // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+200yxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x88\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf8\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xf9\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfa\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfb\x80\x80"));
+ // U+3FFFyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfb\xbf\xbf"));
+
+ // Ill-formed 6-byte sequences.
+ // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+4000yxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x84\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\xbf\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfd\x80\x80\x80"));
+ // U+7FFFFyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfd\xbf\xbf\xbf"));
+
+ //
+ // Sequences with three continuation bytes missing
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf1"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf2"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf3"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf4"));
+
+ // Broken overlong sequences.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf0"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf8\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x80\x80"));
+
+ // Ill-formed 4-byte sequences.
+ // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+14yyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf5"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf6"));
+ // U+1Cyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf7"));
+
+ // Ill-formed 5-byte sequences.
+ // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+20yyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf8\x88"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf8\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xf9\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfa\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfb\x80"));
+ // U+3FCyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfb\xbf"));
+
+ // Ill-formed 6-byte sequences.
+ // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+400yyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x84\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfc\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfd\x80\x80"));
+ // U+7FFCyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xfd\xbf\xbf"));
+
+ //
+ // Sequences with four continuation bytes missing
+ //
+
+ // Ill-formed 5-byte sequences.
+ // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+uzyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf8"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf9"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfa"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfb"));
+ // U+3zyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfb"));
+
+ // Broken overlong sequences.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xf8"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfc\x80"));
+
+ // Ill-formed 6-byte sequences.
+ // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+uzzyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfc\x84"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfc\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfd\x80"));
+ // U+7Fzzyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xfd\xbf"));
+
+ //
+ // Sequences with five continuation bytes missing
+ //
+
+ // Ill-formed 6-byte sequences.
+ // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx
+ // U+uzzyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfc"));
+ // U+uuzzyyxx (invalid)
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd), "\xfd"));
+
+ //
+ // Consecutive sequences with trailing bytes missing
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, /**/ 0xfffd, 0xfffd, /**/ 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, /**/ 0xfffd, /**/ 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xc0" "\xe0\x80" "\xf0\x80\x80"
+ "\xf8\x80\x80\x80"
+ "\xfc\x80\x80\x80\x80"
+ "\xdf" "\xef\xbf" "\xf7\xbf\xbf"
+ "\xfb\xbf\xbf\xbf"
+ "\xfd\xbf\xbf\xbf\xbf"));
+
+ //
+ // Overlong UTF-8 sequences
+ //
+
+ // U+002F SOLIDUS
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x002f), "\x2f"));
+
+ // Overlong sequences of the above.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xc0\xaf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xe0\x80\xaf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x80\x80\xaf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x80\x80\x80\xaf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x80\x80\x80\x80\xaf"));
+
+ // U+0000 NULL
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0000),
+ StringRef("\x00", 1)));
+
+ // Overlong sequences of the above.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xc0\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xe0\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x80\x80\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x80\x80\x80\x80\x80"));
+
+ // Other overlong sequences.
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xc0\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xc1\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal).withScalars(0xfffd, 0xfffd),
+ "\xc1\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xe0\x9f\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xa0\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x8f\x80\x80"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf0\x8f\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xf8\x87\xbf\xbf\xbf"));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xfc\x83\xbf\xbf\xbf\xbf"));
+
+ //
+ // Isolated surrogates
+ //
+
+ // Unicode 6.3.0:
+ //
+ // D71. High-surrogate code point: A Unicode code point in the range
+ // U+D800 to U+DBFF.
+ //
+ // D73. Low-surrogate code point: A Unicode code point in the range
+ // U+DC00 to U+DFFF.
+
+ // Note: U+E0100 is <DB40 DD00> in UTF16.
+
+ // High surrogates
+
+ // U+D800
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xa0\x80"));
+
+ // U+DB40
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xac\xa0"));
+
+ // U+DBFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xaf\xbf"));
+
+ // Low surrogates
+
+ // U+DC00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xb0\x80"));
+
+ // U+DD00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xb4\x80"));
+
+ // U+DFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd),
+ "\xed\xbf\xbf"));
+
+ // Surrogate pairs
+
+ // U+D800 U+DC00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xa0\x80\xed\xb0\x80"));
+
+ // U+D800 U+DD00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xa0\x80\xed\xb4\x80"));
+
+ // U+D800 U+DFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xa0\x80\xed\xbf\xbf"));
+
+ // U+DB40 U+DC00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xac\xa0\xed\xb0\x80"));
+
+ // U+DB40 U+DD00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xac\xa0\xed\xb4\x80"));
+
+ // U+DB40 U+DFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xac\xa0\xed\xbf\xbf"));
+
+ // U+DBFF U+DC00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xaf\xbf\xed\xb0\x80"));
+
+ // U+DBFF U+DD00
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xaf\xbf\xed\xb4\x80"));
+
+ // U+DBFF U+DFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceIllegal)
+ .withScalars(0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd),
+ "\xed\xaf\xbf\xed\xbf\xbf"));
+
+ //
+ // Noncharacters
+ //
+
+ // Unicode 6.3.0:
+ //
+ // D14. Noncharacter: A code point that is permanently reserved for
+ // internal use and that should never be interchanged. Noncharacters
+ // consist of the values U+nFFFE and U+nFFFF (where n is from 0 to 1016)
+ // and the values U+FDD0..U+FDEF.
+
+ // U+FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfffe),
+ "\xef\xbf\xbe"));
+
+ // U+FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xffff),
+ "\xef\xbf\xbf"));
+
+ // U+1FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x1fffe),
+ "\xf0\x9f\xbf\xbe"));
+
+ // U+1FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x1ffff),
+ "\xf0\x9f\xbf\xbf"));
+
+ // U+2FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x2fffe),
+ "\xf0\xaf\xbf\xbe"));
+
+ // U+2FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x2ffff),
+ "\xf0\xaf\xbf\xbf"));
+
+ // U+3FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x3fffe),
+ "\xf0\xbf\xbf\xbe"));
+
+ // U+3FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x3ffff),
+ "\xf0\xbf\xbf\xbf"));
+
+ // U+4FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x4fffe),
+ "\xf1\x8f\xbf\xbe"));
+
+ // U+4FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x4ffff),
+ "\xf1\x8f\xbf\xbf"));
+
+ // U+5FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x5fffe),
+ "\xf1\x9f\xbf\xbe"));
+
+ // U+5FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x5ffff),
+ "\xf1\x9f\xbf\xbf"));
+
+ // U+6FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x6fffe),
+ "\xf1\xaf\xbf\xbe"));
+
+ // U+6FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x6ffff),
+ "\xf1\xaf\xbf\xbf"));
+
+ // U+7FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x7fffe),
+ "\xf1\xbf\xbf\xbe"));
+
+ // U+7FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x7ffff),
+ "\xf1\xbf\xbf\xbf"));
+
+ // U+8FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x8fffe),
+ "\xf2\x8f\xbf\xbe"));
+
+ // U+8FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x8ffff),
+ "\xf2\x8f\xbf\xbf"));
+
+ // U+9FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x9fffe),
+ "\xf2\x9f\xbf\xbe"));
+
+ // U+9FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x9ffff),
+ "\xf2\x9f\xbf\xbf"));
+
+ // U+AFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xafffe),
+ "\xf2\xaf\xbf\xbe"));
+
+ // U+AFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xaffff),
+ "\xf2\xaf\xbf\xbf"));
+
+ // U+BFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xbfffe),
+ "\xf2\xbf\xbf\xbe"));
+
+ // U+BFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xbffff),
+ "\xf2\xbf\xbf\xbf"));
+
+ // U+CFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xcfffe),
+ "\xf3\x8f\xbf\xbe"));
+
+ // U+CFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xcfffF),
+ "\xf3\x8f\xbf\xbf"));
+
+ // U+DFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xdfffe),
+ "\xf3\x9f\xbf\xbe"));
+
+ // U+DFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xdffff),
+ "\xf3\x9f\xbf\xbf"));
+
+ // U+EFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xefffe),
+ "\xf3\xaf\xbf\xbe"));
+
+ // U+EFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xeffff),
+ "\xf3\xaf\xbf\xbf"));
+
+ // U+FFFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xffffe),
+ "\xf3\xbf\xbf\xbe"));
+
+ // U+FFFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfffff),
+ "\xf3\xbf\xbf\xbf"));
+
+ // U+10FFFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x10fffe),
+ "\xf4\x8f\xbf\xbe"));
+
+ // U+10FFFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x10ffff),
+ "\xf4\x8f\xbf\xbf"));
+
+ // U+FDD0
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd0),
+ "\xef\xb7\x90"));
+
+ // U+FDD1
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd1),
+ "\xef\xb7\x91"));
+
+ // U+FDD2
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd2),
+ "\xef\xb7\x92"));
+
+ // U+FDD3
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd3),
+ "\xef\xb7\x93"));
+
+ // U+FDD4
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd4),
+ "\xef\xb7\x94"));
+
+ // U+FDD5
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd5),
+ "\xef\xb7\x95"));
+
+ // U+FDD6
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd6),
+ "\xef\xb7\x96"));
+
+ // U+FDD7
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd7),
+ "\xef\xb7\x97"));
+
+ // U+FDD8
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd8),
+ "\xef\xb7\x98"));
+
+ // U+FDD9
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdd9),
+ "\xef\xb7\x99"));
+
+ // U+FDDA
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdda),
+ "\xef\xb7\x9a"));
+
+ // U+FDDB
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfddb),
+ "\xef\xb7\x9b"));
+
+ // U+FDDC
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfddc),
+ "\xef\xb7\x9c"));
+
+ // U+FDDD
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfddd),
+ "\xef\xb7\x9d"));
+
+ // U+FDDE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdde),
+ "\xef\xb7\x9e"));
+
+ // U+FDDF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfddf),
+ "\xef\xb7\x9f"));
+
+ // U+FDE0
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde0),
+ "\xef\xb7\xa0"));
+
+ // U+FDE1
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde1),
+ "\xef\xb7\xa1"));
+
+ // U+FDE2
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde2),
+ "\xef\xb7\xa2"));
+
+ // U+FDE3
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde3),
+ "\xef\xb7\xa3"));
+
+ // U+FDE4
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde4),
+ "\xef\xb7\xa4"));
+
+ // U+FDE5
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde5),
+ "\xef\xb7\xa5"));
+
+ // U+FDE6
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde6),
+ "\xef\xb7\xa6"));
+
+ // U+FDE7
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde7),
+ "\xef\xb7\xa7"));
+
+ // U+FDE8
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde8),
+ "\xef\xb7\xa8"));
+
+ // U+FDE9
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfde9),
+ "\xef\xb7\xa9"));
+
+ // U+FDEA
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdea),
+ "\xef\xb7\xaa"));
+
+ // U+FDEB
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdeb),
+ "\xef\xb7\xab"));
+
+ // U+FDEC
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdec),
+ "\xef\xb7\xac"));
+
+ // U+FDED
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfded),
+ "\xef\xb7\xad"));
+
+ // U+FDEE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdee),
+ "\xef\xb7\xae"));
+
+ // U+FDEF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdef),
+ "\xef\xb7\xaf"));
+
+ // U+FDF0
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf0),
+ "\xef\xb7\xb0"));
+
+ // U+FDF1
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf1),
+ "\xef\xb7\xb1"));
+
+ // U+FDF2
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf2),
+ "\xef\xb7\xb2"));
+
+ // U+FDF3
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf3),
+ "\xef\xb7\xb3"));
+
+ // U+FDF4
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf4),
+ "\xef\xb7\xb4"));
+
+ // U+FDF5
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf5),
+ "\xef\xb7\xb5"));
+
+ // U+FDF6
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf6),
+ "\xef\xb7\xb6"));
+
+ // U+FDF7
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf7),
+ "\xef\xb7\xb7"));
+
+ // U+FDF8
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf8),
+ "\xef\xb7\xb8"));
+
+ // U+FDF9
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdf9),
+ "\xef\xb7\xb9"));
+
+ // U+FDFA
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdfa),
+ "\xef\xb7\xba"));
+
+ // U+FDFB
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdfb),
+ "\xef\xb7\xbb"));
+
+ // U+FDFC
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdfc),
+ "\xef\xb7\xbc"));
+
+ // U+FDFD
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdfd),
+ "\xef\xb7\xbd"));
+
+ // U+FDFE
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdfe),
+ "\xef\xb7\xbe"));
+
+ // U+FDFF
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0xfdff),
+ "\xef\xb7\xbf"));
+}
+
+TEST(ConvertUTFTest, UTF8ToUTF32PartialLenient) {
+ // U+0041 LATIN CAPITAL LETTER A
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(conversionOK).withScalars(0x0041),
+ "\x41", true));
+
+ //
+ // Sequences with one continuation byte missing
+ //
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xc2", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xdf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xe0\xa0", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xe0\xbf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xe1\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xec\xbf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xed\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xed\x9f", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xee\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xef\xbf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf0\x90\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf0\xbf\xbf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf1\x80\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf3\xbf\xbf", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf4\x80\x80", true));
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted),
+ "\xf4\x8f\xbf", true));
+
+ EXPECT_TRUE(CheckConvertUTF8ToUnicodeScalars(
+ ConvertUTFResultContainer(sourceExhausted).withScalars(0x0041),
+ "\x41\xc2", true));
+}
+
diff --git a/src/llvm-project/llvm/unittests/Support/CrashRecoveryTest.cpp b/src/llvm-project/llvm/unittests/Support/CrashRecoveryTest.cpp
new file mode 100644
index 0000000..ac531b2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/CrashRecoveryTest.cpp
@@ -0,0 +1,83 @@
+//===- llvm/unittest/Support/CrashRecoveryTest.cpp ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "gtest/gtest.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define NOGDI
+#include <windows.h>
+#endif
+
+using namespace llvm;
+using namespace llvm::sys;
+
+static int GlobalInt = 0;
+static void nullDeref() { *(volatile int *)0x10 = 0; }
+static void incrementGlobal() { ++GlobalInt; }
+static void llvmTrap() { LLVM_BUILTIN_TRAP; }
+
+TEST(CrashRecoveryTest, Basic) {
+ llvm::CrashRecoveryContext::Enable();
+ GlobalInt = 0;
+ EXPECT_TRUE(CrashRecoveryContext().RunSafely(incrementGlobal));
+ EXPECT_EQ(1, GlobalInt);
+ EXPECT_FALSE(CrashRecoveryContext().RunSafely(nullDeref));
+ EXPECT_FALSE(CrashRecoveryContext().RunSafely(llvmTrap));
+}
+
+struct IncrementGlobalCleanup : CrashRecoveryContextCleanup {
+ IncrementGlobalCleanup(CrashRecoveryContext *CRC)
+ : CrashRecoveryContextCleanup(CRC) {}
+ virtual void recoverResources() { ++GlobalInt; }
+};
+
+static void noop() {}
+
+TEST(CrashRecoveryTest, Cleanup) {
+ llvm::CrashRecoveryContext::Enable();
+ GlobalInt = 0;
+ {
+ CrashRecoveryContext CRC;
+ CRC.registerCleanup(new IncrementGlobalCleanup(&CRC));
+ EXPECT_TRUE(CRC.RunSafely(noop));
+ } // run cleanups
+ EXPECT_EQ(1, GlobalInt);
+
+ GlobalInt = 0;
+ {
+ CrashRecoveryContext CRC;
+ CRC.registerCleanup(new IncrementGlobalCleanup(&CRC));
+ EXPECT_FALSE(CRC.RunSafely(nullDeref));
+ } // run cleanups
+ EXPECT_EQ(1, GlobalInt);
+}
+
+#ifdef _WIN32
+static void raiseIt() {
+ RaiseException(123, EXCEPTION_NONCONTINUABLE, 0, NULL);
+}
+
+TEST(CrashRecoveryTest, RaiseException) {
+ llvm::CrashRecoveryContext::Enable();
+ EXPECT_FALSE(CrashRecoveryContext().RunSafely(raiseIt));
+}
+
+static void outputString() {
+ OutputDebugStringA("output for debugger\n");
+}
+
+TEST(CrashRecoveryTest, CallOutputDebugString) {
+ llvm::CrashRecoveryContext::Enable();
+ EXPECT_TRUE(CrashRecoveryContext().RunSafely(outputString));
+}
+
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/DJBTest.cpp b/src/llvm-project/llvm/unittests/Support/DJBTest.cpp
new file mode 100644
index 0000000..b157b96
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DJBTest.cpp
@@ -0,0 +1,96 @@
+//===---------- llvm/unittest/Support/DJBTest.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DJB.h"
+#include "llvm/ADT/Twine.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(DJBTest, caseFolding) {
+ struct TestCase {
+ StringLiteral One;
+ StringLiteral Two;
+ };
+
+ static constexpr TestCase Tests[] = {
+ {{"ASDF"}, {"asdf"}},
+ {{"qWeR"}, {"QwEr"}},
+ {{"qqqqqqqqqqqqqqqqqqqq"}, {"QQQQQQQQQQQQQQQQQQQQ"}},
+
+ {{"I"}, {"i"}},
+ // Latin Small Letter Dotless I
+ {{u8"\u0130"}, {"i"}},
+ // Latin Capital Letter I With Dot Above
+ {{u8"\u0131"}, {"i"}},
+
+ // Latin Capital Letter A With Grave
+ {{u8"\u00c0"}, {u8"\u00e0"}},
+ // Latin Capital Letter A With Macron
+ {{u8"\u0100"}, {u8"\u0101"}},
+ // Latin Capital Letter L With Acute
+ {{u8"\u0139"}, {u8"\u013a"}},
+ // Cyrillic Capital Letter Ie
+ {{u8"\u0415"}, {u8"\u0435"}},
+ // Latin Capital Letter A With Circumflex And Grave
+ {{u8"\u1ea6"}, {u8"\u1ea7"}},
+ // Kelvin Sign
+ {{u8"\u212a"}, {u8"\u006b"}},
+ // Glagolitic Capital Letter Chrivi
+ {{u8"\u2c1d"}, {u8"\u2c4d"}},
+ // Fullwidth Latin Capital Letter M
+ {{u8"\uff2d"}, {u8"\uff4d"}},
+ // Old Hungarian Capital Letter Ej
+ {{u8"\U00010c92"}, {u8"\U00010cd2"}},
+ };
+
+ for (const TestCase &T : Tests) {
+ SCOPED_TRACE("Comparing '" + T.One + "' and '" + T.Two + "'");
+ EXPECT_EQ(caseFoldingDjbHash(T.One), caseFoldingDjbHash(T.Two));
+ }
+}
+
+TEST(DJBTest, knownValuesLowerCase) {
+ struct TestCase {
+ StringLiteral Text;
+ uint32_t Hash;
+ };
+ static constexpr TestCase Tests[] = {
+ {{""}, 5381u},
+ {{"f"}, 177675u},
+ {{"fo"}, 5863386u},
+ {{"foo"}, 193491849u},
+ {{"foob"}, 2090263819u},
+ {{"fooba"}, 259229388u},
+ {{"foobar"}, 4259602622u},
+ {{"pneumonoultramicroscopicsilicovolcanoconiosis"}, 3999417781u},
+ };
+
+ for (const TestCase &T : Tests) {
+ SCOPED_TRACE("Text: '" + T.Text + "'");
+ EXPECT_EQ(T.Hash, djbHash(T.Text));
+ EXPECT_EQ(T.Hash, caseFoldingDjbHash(T.Text));
+ EXPECT_EQ(T.Hash, caseFoldingDjbHash(T.Text.upper()));
+ }
+}
+
+TEST(DJBTest, knownValuesUnicode) {
+ EXPECT_EQ(5866553u, djbHash(u8"\u0130"));
+ EXPECT_EQ(177678u, caseFoldingDjbHash(u8"\u0130"));
+ EXPECT_EQ(
+ 1302161417u,
+ djbHash(
+ u8"\u0130\u0131\u00c0\u00e0\u0100\u0101\u0139\u013a\u0415\u0435\u1ea6"
+ u8"\u1ea7\u212a\u006b\u2c1d\u2c4d\uff2d\uff4d\U00010c92\U00010cd2"));
+ EXPECT_EQ(
+ 1145571043u,
+ caseFoldingDjbHash(
+ u8"\u0130\u0131\u00c0\u00e0\u0100\u0101\u0139\u013a\u0415\u0435\u1ea6"
+ u8"\u1ea7\u212a\u006b\u2c1d\u2c4d\uff2d\uff4d\U00010c92\U00010cd2"));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/DataExtractorTest.cpp b/src/llvm-project/llvm/unittests/Support/DataExtractorTest.cpp
new file mode 100644
index 0000000..8b64552
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DataExtractorTest.cpp
@@ -0,0 +1,120 @@
+//===- llvm/unittest/Support/DataExtractorTest.cpp - DataExtractor tests --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DataExtractor.h"
+#include "gtest/gtest.h"
+using namespace llvm;
+
+namespace {
+
+const char numberData[] = "\x80\x90\xFF\xFF\x80\x00\x00\x00";
+const char stringData[] = "hellohello\0hello";
+const char leb128data[] = "\xA6\x49";
+const char bigleb128data[] = "\xAA\xA9\xFF\xAA\xFF\xAA\xFF\x4A";
+
+TEST(DataExtractorTest, OffsetOverflow) {
+ DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
+ EXPECT_FALSE(DE.isValidOffsetForDataOfSize(-2U, 5));
+}
+
+TEST(DataExtractorTest, UnsignedNumbers) {
+ DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
+ uint32_t offset = 0;
+
+ EXPECT_EQ(0x80U, DE.getU8(&offset));
+ EXPECT_EQ(1U, offset);
+ offset = 0;
+ EXPECT_EQ(0x8090U, DE.getU16(&offset));
+ EXPECT_EQ(2U, offset);
+ offset = 0;
+ EXPECT_EQ(0x8090FFFFU, DE.getU32(&offset));
+ EXPECT_EQ(4U, offset);
+ offset = 0;
+ EXPECT_EQ(0x8090FFFF80000000ULL, DE.getU64(&offset));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+ EXPECT_EQ(0x8090FFFF80000000ULL, DE.getAddress(&offset));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+
+ uint32_t data[2];
+ EXPECT_EQ(data, DE.getU32(&offset, data, 2));
+ EXPECT_EQ(0x8090FFFFU, data[0]);
+ EXPECT_EQ(0x80000000U, data[1]);
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+
+ // Now for little endian.
+ DE = DataExtractor(StringRef(numberData, sizeof(numberData)-1), true, 4);
+ EXPECT_EQ(0x9080U, DE.getU16(&offset));
+ EXPECT_EQ(2U, offset);
+ offset = 0;
+ EXPECT_EQ(0xFFFF9080U, DE.getU32(&offset));
+ EXPECT_EQ(4U, offset);
+ offset = 0;
+ EXPECT_EQ(0x80FFFF9080ULL, DE.getU64(&offset));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+ EXPECT_EQ(0xFFFF9080U, DE.getAddress(&offset));
+ EXPECT_EQ(4U, offset);
+ offset = 0;
+
+ EXPECT_EQ(data, DE.getU32(&offset, data, 2));
+ EXPECT_EQ(0xFFFF9080U, data[0]);
+ EXPECT_EQ(0x80U, data[1]);
+ EXPECT_EQ(8U, offset);
+}
+
+TEST(DataExtractorTest, SignedNumbers) {
+ DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8);
+ uint32_t offset = 0;
+
+ EXPECT_EQ(-128, DE.getSigned(&offset, 1));
+ EXPECT_EQ(1U, offset);
+ offset = 0;
+ EXPECT_EQ(-32624, DE.getSigned(&offset, 2));
+ EXPECT_EQ(2U, offset);
+ offset = 0;
+ EXPECT_EQ(-2137980929, DE.getSigned(&offset, 4));
+ EXPECT_EQ(4U, offset);
+ offset = 0;
+ EXPECT_EQ(-9182558167379214336LL, DE.getSigned(&offset, 8));
+ EXPECT_EQ(8U, offset);
+}
+
+TEST(DataExtractorTest, Strings) {
+ DataExtractor DE(StringRef(stringData, sizeof(stringData)-1), false, 8);
+ uint32_t offset = 0;
+
+ EXPECT_EQ(stringData, DE.getCStr(&offset));
+ EXPECT_EQ(11U, offset);
+ EXPECT_EQ(nullptr, DE.getCStr(&offset));
+ EXPECT_EQ(11U, offset);
+}
+
+TEST(DataExtractorTest, LEB128) {
+ DataExtractor DE(StringRef(leb128data, sizeof(leb128data)-1), false, 8);
+ uint32_t offset = 0;
+
+ EXPECT_EQ(9382ULL, DE.getULEB128(&offset));
+ EXPECT_EQ(2U, offset);
+ offset = 0;
+ EXPECT_EQ(-7002LL, DE.getSLEB128(&offset));
+ EXPECT_EQ(2U, offset);
+
+ DataExtractor BDE(StringRef(bigleb128data, sizeof(bigleb128data)-1), false,8);
+ offset = 0;
+ EXPECT_EQ(42218325750568106ULL, BDE.getULEB128(&offset));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+ EXPECT_EQ(-29839268287359830LL, BDE.getSLEB128(&offset));
+ EXPECT_EQ(8U, offset);
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/DebugCounterTest.cpp b/src/llvm-project/llvm/unittests/Support/DebugCounterTest.cpp
new file mode 100644
index 0000000..32bf56c
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DebugCounterTest.cpp
@@ -0,0 +1,41 @@
+//===- llvm/unittest/Support/DebugCounterTest.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DebugCounter.h"
+#include "gtest/gtest.h"
+
+#include <string>
+using namespace llvm;
+
+#ifndef NDEBUG
+TEST(DebugCounterTest, CounterCheck) {
+ DEBUG_COUNTER(TestCounter, "test-counter", "Counter used for unit test");
+
+ EXPECT_FALSE(DebugCounter::isCounterSet(TestCounter));
+
+ auto DC = &DebugCounter::instance();
+ DC->push_back("test-counter-skip=1");
+ DC->push_back("test-counter-count=3");
+
+ EXPECT_TRUE(DebugCounter::isCounterSet(TestCounter));
+
+ EXPECT_EQ(0, DebugCounter::getCounterValue(TestCounter));
+ EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
+
+ EXPECT_EQ(1, DebugCounter::getCounterValue(TestCounter));
+ EXPECT_TRUE(DebugCounter::shouldExecute(TestCounter));
+
+ DebugCounter::setCounterValue(TestCounter, 3);
+ EXPECT_TRUE(DebugCounter::shouldExecute(TestCounter));
+ EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
+
+ DebugCounter::setCounterValue(TestCounter, 100);
+ EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter));
+}
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/DebugTest.cpp b/src/llvm-project/llvm/unittests/Support/DebugTest.cpp
new file mode 100644
index 0000000..7db91ff
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DebugTest.cpp
@@ -0,0 +1,34 @@
+//===- llvm/unittest/Support/DebugTest.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <string>
+using namespace llvm;
+
+#ifndef NDEBUG
+TEST(DebugTest, Basic) {
+ std::string s1, s2;
+ raw_string_ostream os1(s1), os2(s2);
+ static const char *DT[] = {"A", "B"};
+
+ llvm::DebugFlag = true;
+ setCurrentDebugTypes(DT, 2);
+ DEBUG_WITH_TYPE("A", os1 << "A");
+ DEBUG_WITH_TYPE("B", os1 << "B");
+ EXPECT_EQ("AB", os1.str());
+
+ setCurrentDebugType("A");
+ DEBUG_WITH_TYPE("A", os2 << "A");
+ DEBUG_WITH_TYPE("B", os2 << "B");
+ EXPECT_EQ("A", os2.str());
+}
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt
new file mode 100644
index 0000000..1ea9826
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Needed by LLVM's CMake checks because this file defines multiple targets.
+set(LLVM_OPTIONAL_SOURCES ExportedFuncs.cpp PipSqueak.cpp)
+
+set(LLVM_LINK_COMPONENTS Support)
+
+add_library(DynamicLibraryLib STATIC
+ ExportedFuncs.cpp
+ )
+set_target_properties(DynamicLibraryLib PROPERTIES FOLDER "Tests")
+
+# extract_symbols.py relies on all its library arguments being in the same
+# directory, so we must set the output directory in the same way as if
+# add_llvm_library was used.
+set_output_directory(DynamicLibraryLib
+ LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}
+ )
+
+add_llvm_unittest(DynamicLibraryTests
+ DynamicLibraryTest.cpp
+ )
+target_link_libraries(DynamicLibraryTests PRIVATE DynamicLibraryLib)
+export_executable_symbols(DynamicLibraryTests)
+
+function(dynlib_add_module NAME)
+ add_library(${NAME} SHARED
+ PipSqueak.cpp
+ )
+ set_target_properties(${NAME} PROPERTIES FOLDER "Tests")
+
+ set_output_directory(${NAME}
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+ LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+ )
+
+ set_target_properties(${NAME}
+ PROPERTIES PREFIX ""
+ SUFFIX ${LTDL_SHLIB_EXT}
+ )
+
+ add_dependencies(DynamicLibraryTests ${NAME})
+endfunction(dynlib_add_module)
+
+# Revert -Wl,-z,nodelete on this test since it relies on the file
+# being unloaded.
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ string(REPLACE "-Wl,-z,nodelete" "" CMAKE_SHARED_LINKER_FLAGS
+ ${CMAKE_SHARED_LINKER_FLAGS})
+endif()
+
+dynlib_add_module(PipSqueak)
+dynlib_add_module(SecondLib)
diff --git a/src/llvm-project/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
new file mode 100644
index 0000000..50a0f1e
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
@@ -0,0 +1,178 @@
+//===- llvm/unittest/Support/DynamicLibrary/DynamicLibraryTest.cpp --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+
+#include "PipSqueak.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+std::string LibPath(const std::string Name = "PipSqueak") {
+ const std::vector<testing::internal::string> &Argvs =
+ testing::internal::GetArgvs();
+ const char *Argv0 =
+ Argvs.size() > 0 ? Argvs[0].c_str() : "DynamicLibraryTests";
+ void *Ptr = (void*)(intptr_t)TestA;
+ std::string Path = fs::getMainExecutable(Argv0, Ptr);
+ llvm::SmallString<256> Buf(path::parent_path(Path));
+ path::append(Buf, (Name + LTDL_SHLIB_EXT).c_str());
+ return Buf.str();
+}
+
+#if defined(_WIN32) || (defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN))
+
+typedef void (*SetStrings)(std::string &GStr, std::string &LStr);
+typedef void (*TestOrder)(std::vector<std::string> &V);
+typedef const char *(*GetString)();
+
+template <class T> static T FuncPtr(void *Ptr) {
+ union {
+ T F;
+ void *P;
+ } Tmp;
+ Tmp.P = Ptr;
+ return Tmp.F;
+}
+template <class T> static void* PtrFunc(T *Func) {
+ union {
+ T *F;
+ void *P;
+ } Tmp;
+ Tmp.F = Func;
+ return Tmp.P;
+}
+
+static const char *OverloadTestA() { return "OverloadCall"; }
+
+std::string StdString(const char *Ptr) { return Ptr ? Ptr : ""; }
+
+TEST(DynamicLibrary, Overload) {
+ {
+ std::string Err;
+ llvm_shutdown_obj Shutdown;
+ DynamicLibrary DL =
+ DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
+ EXPECT_TRUE(DL.isValid());
+ EXPECT_TRUE(Err.empty());
+
+ GetString GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS != &TestA);
+ EXPECT_EQ(StdString(GS()), "LibCall");
+
+ GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS != &TestA);
+ EXPECT_EQ(StdString(GS()), "LibCall");
+
+ DL = DynamicLibrary::getPermanentLibrary(nullptr, &Err);
+ EXPECT_TRUE(DL.isValid());
+ EXPECT_TRUE(Err.empty());
+
+ // Test overloading local symbols does not occur by default
+ GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS == &TestA);
+ EXPECT_EQ(StdString(GS()), "ProcessCall");
+
+ GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS == &TestA);
+ EXPECT_EQ(StdString(GS()), "ProcessCall");
+
+ // Test overloading by forcing library priority when searching for a symbol
+ DynamicLibrary::SearchOrder = DynamicLibrary::SO_LoadedFirst;
+ GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS != &TestA);
+ EXPECT_EQ(StdString(GS()), "LibCall");
+
+ DynamicLibrary::AddSymbol("TestA", PtrFunc(&OverloadTestA));
+ GS = FuncPtr<GetString>(DL.getAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS != &OverloadTestA);
+
+ GS = FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol("TestA"));
+ EXPECT_TRUE(GS != nullptr && GS == &OverloadTestA);
+ EXPECT_EQ(StdString(GS()), "OverloadCall");
+ }
+ EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol(
+ "TestA")) == nullptr);
+
+ // Check serach ordering is reset to default after call to llvm_shutdown
+ EXPECT_TRUE(DynamicLibrary::SearchOrder == DynamicLibrary::SO_Linker);
+}
+
+TEST(DynamicLibrary, Shutdown) {
+ std::string A("PipSqueak"), B, C("SecondLib");
+ std::vector<std::string> Order;
+ {
+ std::string Err;
+ llvm_shutdown_obj Shutdown;
+ DynamicLibrary DL =
+ DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err);
+ EXPECT_TRUE(DL.isValid());
+ EXPECT_TRUE(Err.empty());
+
+ SetStrings SS_0 = FuncPtr<SetStrings>(
+ DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
+ EXPECT_TRUE(SS_0 != nullptr);
+
+ SS_0(A, B);
+ EXPECT_EQ(B, "Local::Local(PipSqueak)");
+
+ TestOrder TO_0 = FuncPtr<TestOrder>(
+ DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
+ EXPECT_TRUE(TO_0 != nullptr);
+
+ DynamicLibrary DL2 =
+ DynamicLibrary::getPermanentLibrary(LibPath(C).c_str(), &Err);
+ EXPECT_TRUE(DL2.isValid());
+ EXPECT_TRUE(Err.empty());
+
+ // Should find latest version of symbols in SecondLib
+ SetStrings SS_1 = FuncPtr<SetStrings>(
+ DynamicLibrary::SearchForAddressOfSymbol("SetStrings"));
+ EXPECT_TRUE(SS_1 != nullptr);
+ EXPECT_TRUE(SS_0 != SS_1);
+
+ TestOrder TO_1 = FuncPtr<TestOrder>(
+ DynamicLibrary::SearchForAddressOfSymbol("TestOrder"));
+ EXPECT_TRUE(TO_1 != nullptr);
+ EXPECT_TRUE(TO_0 != TO_1);
+
+ B.clear();
+ SS_1(C, B);
+ EXPECT_EQ(B, "Local::Local(SecondLib)");
+
+ TO_0(Order);
+ TO_1(Order);
+ }
+ EXPECT_EQ(A, "Global::~Global");
+ EXPECT_EQ(B, "Local::~Local");
+ EXPECT_TRUE(FuncPtr<SetStrings>(DynamicLibrary::SearchForAddressOfSymbol(
+ "SetStrings")) == nullptr);
+
+ // Test unload/destruction ordering
+ EXPECT_EQ(Order.size(), 2UL);
+ EXPECT_EQ(Order.front(), "SecondLib");
+ EXPECT_EQ(Order.back(), "PipSqueak");
+}
+
+#else
+
+TEST(DynamicLibrary, Unsupported) {
+ std::string Err;
+ DynamicLibrary DL =
+ DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
+ EXPECT_FALSE(DL.isValid());
+ EXPECT_EQ(Err, "dlopen() not supported on this platform");
+}
+
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/DynamicLibrary/ExportedFuncs.cpp b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/ExportedFuncs.cpp
new file mode 100644
index 0000000..370c8cb
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/ExportedFuncs.cpp
@@ -0,0 +1,16 @@
+//===- llvm/unittest/Support/DynamicLibrary/ExportedFuncs.cpp -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PipSqueak.h"
+
+#ifndef PIPSQUEAK_TESTA_RETURN
+#define PIPSQUEAK_TESTA_RETURN "ProcessCall"
+#endif
+
+extern "C" PIPSQUEAK_EXPORT const char *TestA() { return PIPSQUEAK_TESTA_RETURN; }
diff --git a/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.cpp b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.cpp
new file mode 100644
index 0000000..e2f1cf7
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.cpp
@@ -0,0 +1,49 @@
+//===- llvm/unittest/Support/DynamicLibrary/PipSqueak.cpp -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PipSqueak.h"
+
+struct Global {
+ std::string *Str;
+ std::vector<std::string> *Vec;
+ Global() : Str(nullptr), Vec(nullptr) {}
+ ~Global() {
+ if (Str) {
+ if (Vec)
+ Vec->push_back(*Str);
+ *Str = "Global::~Global";
+ }
+ }
+};
+
+static Global Glb;
+
+struct Local {
+ std::string &Str;
+ Local(std::string &S) : Str(S) {
+ Str = "Local::Local";
+ if (Glb.Str && !Glb.Str->empty())
+ Str += std::string("(") + *Glb.Str + std::string(")");
+ }
+ ~Local() { Str = "Local::~Local"; }
+};
+
+
+extern "C" PIPSQUEAK_EXPORT void SetStrings(std::string &GStr,
+ std::string &LStr) {
+ Glb.Str = &GStr;
+ static Local Lcl(LStr);
+}
+
+extern "C" PIPSQUEAK_EXPORT void TestOrder(std::vector<std::string> &V) {
+ Glb.Vec = &V;
+}
+
+#define PIPSQUEAK_TESTA_RETURN "LibCall"
+#include "ExportedFuncs.cpp"
diff --git a/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.h b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.h
new file mode 100644
index 0000000..b44c61d
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/DynamicLibrary/PipSqueak.h
@@ -0,0 +1,34 @@
+//===- llvm/unittest/Support/DynamicLibrary/PipSqueak.h -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PIPSQUEAK_H
+#define LLVM_PIPSQUEAK_H
+
+#if defined(_WIN32) && !defined(__GNUC__)
+// Disable warnings from inclusion of xlocale & exception
+#pragma warning(push)
+#pragma warning(disable: 4530)
+#pragma warning(disable: 4577)
+#include <string>
+#include <vector>
+#pragma warning(pop)
+#else
+#include <string>
+#include <vector>
+#endif
+
+#ifdef _WIN32
+#define PIPSQUEAK_EXPORT __declspec(dllexport)
+#else
+#define PIPSQUEAK_EXPORT
+#endif
+
+extern "C" PIPSQUEAK_EXPORT const char *TestA();
+
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/EndianStreamTest.cpp b/src/llvm-project/llvm/unittests/Support/EndianStreamTest.cpp
new file mode 100644
index 0000000..9f938ee
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/EndianStreamTest.cpp
@@ -0,0 +1,208 @@
+//===- unittests/Support/EndianStreamTest.cpp - EndianStream.h tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/EndianStream.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/DataTypes.h"
+#include "gtest/gtest.h"
+using namespace llvm;
+using namespace support;
+
+namespace {
+
+TEST(EndianStream, WriteInt32LE) {
+ SmallString<16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer LE(OS, little);
+ LE.write(static_cast<int32_t>(-1362446643));
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xCD);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xB6);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xCA);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xAE);
+}
+
+TEST(EndianStream, WriteInt32BE) {
+ SmallVector<char, 16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer BE(OS, big);
+ BE.write(static_cast<int32_t>(-1362446643));
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xAE);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xCA);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xB6);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xCD);
+}
+
+
+TEST(EndianStream, WriteFloatLE) {
+ SmallString<16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer LE(OS, little);
+ LE.write(12345.0f);
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x00);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xE4);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0x40);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x46);
+}
+
+TEST(EndianStream, WriteFloatBE) {
+ SmallVector<char, 16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer BE(OS, big);
+ BE.write(12345.0f);
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x46);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x40);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xE4);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x00);
+}
+
+TEST(EndianStream, WriteInt64LE) {
+ SmallString<16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer LE(OS, little);
+ LE.write(static_cast<int64_t>(-136244664332342323));
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xCD);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xAB);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xED);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x1B);
+ EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x33);
+ EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xF6);
+ EXPECT_EQ(static_cast<uint8_t>(data[6]), 0x1B);
+ EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xFE);
+}
+
+TEST(EndianStream, WriteInt64BE) {
+ SmallVector<char, 16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer BE(OS, big);
+ BE.write(static_cast<int64_t>(-136244664332342323));
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xFE);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x1B);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xF6);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x33);
+ EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x1B);
+ EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xED);
+ EXPECT_EQ(static_cast<uint8_t>(data[6]), 0xAB);
+ EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xCD);
+}
+
+TEST(EndianStream, WriteDoubleLE) {
+ SmallString<16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer LE(OS, little);
+ LE.write(-2349214918.58107);
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0x20);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0x98);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0xD2);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0x98);
+ EXPECT_EQ(static_cast<uint8_t>(data[4]), 0xC5);
+ EXPECT_EQ(static_cast<uint8_t>(data[5]), 0x80);
+ EXPECT_EQ(static_cast<uint8_t>(data[6]), 0xE1);
+ EXPECT_EQ(static_cast<uint8_t>(data[7]), 0xC1);
+}
+
+TEST(EndianStream, WriteDoubleBE) {
+ SmallVector<char, 16> data;
+
+ {
+ raw_svector_ostream OS(data);
+ endian::Writer BE(OS, big);
+ BE.write(-2349214918.58107);
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(data[0]), 0xC1);
+ EXPECT_EQ(static_cast<uint8_t>(data[1]), 0xE1);
+ EXPECT_EQ(static_cast<uint8_t>(data[2]), 0x80);
+ EXPECT_EQ(static_cast<uint8_t>(data[3]), 0xC5);
+ EXPECT_EQ(static_cast<uint8_t>(data[4]), 0x98);
+ EXPECT_EQ(static_cast<uint8_t>(data[5]), 0xD2);
+ EXPECT_EQ(static_cast<uint8_t>(data[6]), 0x98);
+ EXPECT_EQ(static_cast<uint8_t>(data[7]), 0x20);
+}
+
+TEST(EndianStream, WriteArrayLE) {
+ SmallString<16> Data;
+
+ {
+ raw_svector_ostream OS(Data);
+ endian::Writer LE(OS, little);
+ LE.write<uint16_t>({0x1234, 0x5678});
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(Data[0]), 0x34);
+ EXPECT_EQ(static_cast<uint8_t>(Data[1]), 0x12);
+ EXPECT_EQ(static_cast<uint8_t>(Data[2]), 0x78);
+ EXPECT_EQ(static_cast<uint8_t>(Data[3]), 0x56);
+}
+
+TEST(EndianStream, WriteVectorLE) {
+ SmallString<16> Data;
+
+ {
+ raw_svector_ostream OS(Data);
+ endian::Writer LE(OS, little);
+ std::vector<uint16_t> Vec{0x1234, 0x5678};
+ LE.write<uint16_t>(Vec);
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(Data[0]), 0x34);
+ EXPECT_EQ(static_cast<uint8_t>(Data[1]), 0x12);
+ EXPECT_EQ(static_cast<uint8_t>(Data[2]), 0x78);
+ EXPECT_EQ(static_cast<uint8_t>(Data[3]), 0x56);
+}
+
+TEST(EndianStream, WriteFloatArrayLE) {
+ SmallString<16> Data;
+
+ {
+ raw_svector_ostream OS(Data);
+ endian::Writer LE(OS, little);
+ LE.write<float>({12345.0f, 12346.0f});
+ }
+
+ EXPECT_EQ(static_cast<uint8_t>(Data[0]), 0x00);
+ EXPECT_EQ(static_cast<uint8_t>(Data[1]), 0xE4);
+ EXPECT_EQ(static_cast<uint8_t>(Data[2]), 0x40);
+ EXPECT_EQ(static_cast<uint8_t>(Data[3]), 0x46);
+
+ EXPECT_EQ(static_cast<uint8_t>(Data[4]), 0x00);
+ EXPECT_EQ(static_cast<uint8_t>(Data[5]), 0xE8);
+ EXPECT_EQ(static_cast<uint8_t>(Data[6]), 0x40);
+ EXPECT_EQ(static_cast<uint8_t>(Data[7]), 0x46);
+}
+
+
+} // end anon namespace
diff --git a/src/llvm-project/llvm/unittests/Support/EndianTest.cpp b/src/llvm-project/llvm/unittests/Support/EndianTest.cpp
new file mode 100644
index 0000000..c2b5572
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/EndianTest.cpp
@@ -0,0 +1,204 @@
+//===- unittests/Support/EndianTest.cpp - Endian.h tests ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/DataTypes.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <ctime>
+using namespace llvm;
+using namespace support;
+
+#undef max
+
+namespace {
+
+TEST(Endian, Read) {
+ // These are 5 bytes so we can be sure at least one of the reads is unaligned.
+ unsigned char bigval[] = {0x00, 0x01, 0x02, 0x03, 0x04};
+ unsigned char littleval[] = {0x00, 0x04, 0x03, 0x02, 0x01};
+ int32_t BigAsHost = 0x00010203;
+ EXPECT_EQ(BigAsHost, (endian::read<int32_t, big, unaligned>(bigval)));
+ int32_t LittleAsHost = 0x02030400;
+ EXPECT_EQ(LittleAsHost,(endian::read<int32_t, little, unaligned>(littleval)));
+
+ EXPECT_EQ((endian::read<int32_t, big, unaligned>(bigval + 1)),
+ (endian::read<int32_t, little, unaligned>(littleval + 1)));
+}
+
+TEST(Endian, ReadBitAligned) {
+ // Simple test to make sure we properly pull out the 0x0 word.
+ unsigned char littleval[] = {0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff};
+ unsigned char bigval[] = {0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0};
+ EXPECT_EQ(
+ (endian::readAtBitAlignment<int, little, unaligned>(&littleval[0], 6)),
+ 0x0);
+ EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval[0], 6)),
+ 0x0);
+ // Test to make sure that signed right shift of 0xf0000000 is masked
+ // properly.
+ unsigned char littleval2[] = {0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00};
+ unsigned char bigval2[] = {0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ EXPECT_EQ(
+ (endian::readAtBitAlignment<int, little, unaligned>(&littleval2[0], 4)),
+ 0x0f000000);
+ EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval2[0], 4)),
+ 0x0f000000);
+ // Test to make sure left shift of start bit doesn't overflow.
+ EXPECT_EQ(
+ (endian::readAtBitAlignment<int, little, unaligned>(&littleval2[0], 1)),
+ 0x78000000);
+ EXPECT_EQ((endian::readAtBitAlignment<int, big, unaligned>(&bigval2[0], 1)),
+ 0x78000000);
+ // Test to make sure 64-bit int doesn't overflow.
+ unsigned char littleval3[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char bigval3[] = {0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ EXPECT_EQ((endian::readAtBitAlignment<int64_t, little, unaligned>(
+ &littleval3[0], 4)),
+ 0x0f00000000000000);
+ EXPECT_EQ(
+ (endian::readAtBitAlignment<int64_t, big, unaligned>(&bigval3[0], 4)),
+ 0x0f00000000000000);
+}
+
+TEST(Endian, WriteBitAligned) {
+ // This test ensures that signed right shift of 0xffffaa is masked
+ // properly.
+ unsigned char bigval[8] = {0x00};
+ endian::writeAtBitAlignment<int32_t, big, unaligned>(bigval, (int)0xffffaaaa,
+ 4);
+ EXPECT_EQ(bigval[0], 0xff);
+ EXPECT_EQ(bigval[1], 0xfa);
+ EXPECT_EQ(bigval[2], 0xaa);
+ EXPECT_EQ(bigval[3], 0xa0);
+ EXPECT_EQ(bigval[4], 0x00);
+ EXPECT_EQ(bigval[5], 0x00);
+ EXPECT_EQ(bigval[6], 0x00);
+ EXPECT_EQ(bigval[7], 0x0f);
+
+ unsigned char littleval[8] = {0x00};
+ endian::writeAtBitAlignment<int32_t, little, unaligned>(littleval,
+ (int)0xffffaaaa, 4);
+ EXPECT_EQ(littleval[0], 0xa0);
+ EXPECT_EQ(littleval[1], 0xaa);
+ EXPECT_EQ(littleval[2], 0xfa);
+ EXPECT_EQ(littleval[3], 0xff);
+ EXPECT_EQ(littleval[4], 0x0f);
+ EXPECT_EQ(littleval[5], 0x00);
+ EXPECT_EQ(littleval[6], 0x00);
+ EXPECT_EQ(littleval[7], 0x00);
+
+ // This test makes sure 1<<31 doesn't overflow.
+ // Test to make sure left shift of start bit doesn't overflow.
+ unsigned char bigval2[8] = {0x00};
+ endian::writeAtBitAlignment<int32_t, big, unaligned>(bigval2, (int)0xffffffff,
+ 1);
+ EXPECT_EQ(bigval2[0], 0xff);
+ EXPECT_EQ(bigval2[1], 0xff);
+ EXPECT_EQ(bigval2[2], 0xff);
+ EXPECT_EQ(bigval2[3], 0xfe);
+ EXPECT_EQ(bigval2[4], 0x00);
+ EXPECT_EQ(bigval2[5], 0x00);
+ EXPECT_EQ(bigval2[6], 0x00);
+ EXPECT_EQ(bigval2[7], 0x01);
+
+ unsigned char littleval2[8] = {0x00};
+ endian::writeAtBitAlignment<int32_t, little, unaligned>(littleval2,
+ (int)0xffffffff, 1);
+ EXPECT_EQ(littleval2[0], 0xfe);
+ EXPECT_EQ(littleval2[1], 0xff);
+ EXPECT_EQ(littleval2[2], 0xff);
+ EXPECT_EQ(littleval2[3], 0xff);
+ EXPECT_EQ(littleval2[4], 0x01);
+ EXPECT_EQ(littleval2[5], 0x00);
+ EXPECT_EQ(littleval2[6], 0x00);
+ EXPECT_EQ(littleval2[7], 0x00);
+
+ // Test to make sure 64-bit int doesn't overflow.
+ unsigned char bigval64[16] = {0x00};
+ endian::writeAtBitAlignment<int64_t, big, unaligned>(
+ bigval64, (int64_t)0xffffffffffffffff, 1);
+ EXPECT_EQ(bigval64[0], 0xff);
+ EXPECT_EQ(bigval64[1], 0xff);
+ EXPECT_EQ(bigval64[2], 0xff);
+ EXPECT_EQ(bigval64[3], 0xff);
+ EXPECT_EQ(bigval64[4], 0xff);
+ EXPECT_EQ(bigval64[5], 0xff);
+ EXPECT_EQ(bigval64[6], 0xff);
+ EXPECT_EQ(bigval64[7], 0xfe);
+ EXPECT_EQ(bigval64[8], 0x00);
+ EXPECT_EQ(bigval64[9], 0x00);
+ EXPECT_EQ(bigval64[10], 0x00);
+ EXPECT_EQ(bigval64[11], 0x00);
+ EXPECT_EQ(bigval64[12], 0x00);
+ EXPECT_EQ(bigval64[13], 0x00);
+ EXPECT_EQ(bigval64[14], 0x00);
+ EXPECT_EQ(bigval64[15], 0x01);
+
+ unsigned char littleval64[16] = {0x00};
+ endian::writeAtBitAlignment<int64_t, little, unaligned>(
+ littleval64, (int64_t)0xffffffffffffffff, 1);
+ EXPECT_EQ(littleval64[0], 0xfe);
+ EXPECT_EQ(littleval64[1], 0xff);
+ EXPECT_EQ(littleval64[2], 0xff);
+ EXPECT_EQ(littleval64[3], 0xff);
+ EXPECT_EQ(littleval64[4], 0xff);
+ EXPECT_EQ(littleval64[5], 0xff);
+ EXPECT_EQ(littleval64[6], 0xff);
+ EXPECT_EQ(littleval64[7], 0xff);
+ EXPECT_EQ(littleval64[8], 0x01);
+ EXPECT_EQ(littleval64[9], 0x00);
+ EXPECT_EQ(littleval64[10], 0x00);
+ EXPECT_EQ(littleval64[11], 0x00);
+ EXPECT_EQ(littleval64[12], 0x00);
+ EXPECT_EQ(littleval64[13], 0x00);
+ EXPECT_EQ(littleval64[14], 0x00);
+ EXPECT_EQ(littleval64[15], 0x00);
+}
+
+TEST(Endian, Write) {
+ unsigned char data[5];
+ endian::write<int32_t, big, unaligned>(data, -1362446643);
+ EXPECT_EQ(data[0], 0xAE);
+ EXPECT_EQ(data[1], 0xCA);
+ EXPECT_EQ(data[2], 0xB6);
+ EXPECT_EQ(data[3], 0xCD);
+ endian::write<int32_t, big, unaligned>(data + 1, -1362446643);
+ EXPECT_EQ(data[1], 0xAE);
+ EXPECT_EQ(data[2], 0xCA);
+ EXPECT_EQ(data[3], 0xB6);
+ EXPECT_EQ(data[4], 0xCD);
+
+ endian::write<int32_t, little, unaligned>(data, -1362446643);
+ EXPECT_EQ(data[0], 0xCD);
+ EXPECT_EQ(data[1], 0xB6);
+ EXPECT_EQ(data[2], 0xCA);
+ EXPECT_EQ(data[3], 0xAE);
+ endian::write<int32_t, little, unaligned>(data + 1, -1362446643);
+ EXPECT_EQ(data[1], 0xCD);
+ EXPECT_EQ(data[2], 0xB6);
+ EXPECT_EQ(data[3], 0xCA);
+ EXPECT_EQ(data[4], 0xAE);
+}
+
+TEST(Endian, PackedEndianSpecificIntegral) {
+ // These are 5 bytes so we can be sure at least one of the reads is unaligned.
+ unsigned char big[] = {0x00, 0x01, 0x02, 0x03, 0x04};
+ unsigned char little[] = {0x00, 0x04, 0x03, 0x02, 0x01};
+ big32_t *big_val =
+ reinterpret_cast<big32_t *>(big + 1);
+ little32_t *little_val =
+ reinterpret_cast<little32_t *>(little + 1);
+
+ EXPECT_EQ(*big_val, *little_val);
+}
+
+} // end anon namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ErrnoTest.cpp b/src/llvm-project/llvm/unittests/Support/ErrnoTest.cpp
new file mode 100644
index 0000000..701ac96
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ErrnoTest.cpp
@@ -0,0 +1,39 @@
+//===- ErrnoTest.cpp - Error handling unit tests --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Errno.h"
+#include "gtest/gtest.h"
+
+using namespace llvm::sys;
+
+TEST(ErrnoTest, RetryAfterSignal) {
+ EXPECT_EQ(1, RetryAfterSignal(-1, [] { return 1; }));
+
+ EXPECT_EQ(-1, RetryAfterSignal(-1, [] {
+ errno = EAGAIN;
+ return -1;
+ }));
+ EXPECT_EQ(EAGAIN, errno);
+
+ unsigned calls = 0;
+ EXPECT_EQ(1, RetryAfterSignal(-1, [&calls] {
+ errno = EINTR;
+ ++calls;
+ return calls == 1 ? -1 : 1;
+ }));
+ EXPECT_EQ(2u, calls);
+
+ EXPECT_EQ(1, RetryAfterSignal(-1, [](int x) { return x; }, 1));
+
+ std::unique_ptr<int> P(RetryAfterSignal(nullptr, [] { return new int(47); }));
+ EXPECT_EQ(47, *P);
+
+ errno = EINTR;
+ EXPECT_EQ(-1, RetryAfterSignal(-1, [] { return -1; }));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ErrorOrTest.cpp b/src/llvm-project/llvm/unittests/Support/ErrorOrTest.cpp
new file mode 100644
index 0000000..2ffc6e5
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ErrorOrTest.cpp
@@ -0,0 +1,140 @@
+//===- unittests/ErrorOrTest.cpp - ErrorOr.h tests ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Errc.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+ErrorOr<int> t1() { return 1; }
+ErrorOr<int> t2() { return errc::invalid_argument; }
+
+TEST(ErrorOr, SimpleValue) {
+ ErrorOr<int> a = t1();
+ // FIXME: This is probably a bug in gtest. EXPECT_TRUE should expand to
+ // include the !! to make it friendly to explicit bool operators.
+ EXPECT_TRUE(!!a);
+ EXPECT_EQ(1, *a);
+
+ ErrorOr<int> b = a;
+ EXPECT_EQ(1, *b);
+
+ a = t2();
+ EXPECT_FALSE(a);
+ EXPECT_EQ(a.getError(), errc::invalid_argument);
+#ifdef EXPECT_DEBUG_DEATH
+ EXPECT_DEBUG_DEATH(*a, "Cannot get value when an error exists");
+#endif
+}
+
+ErrorOr<std::unique_ptr<int> > t3() {
+ return std::unique_ptr<int>(new int(3));
+}
+
+TEST(ErrorOr, Types) {
+ int x;
+ ErrorOr<int&> a(x);
+ *a = 42;
+ EXPECT_EQ(42, x);
+
+ // Move only types.
+ EXPECT_EQ(3, **t3());
+}
+
+struct B {};
+struct D : B {};
+
+TEST(ErrorOr, Covariant) {
+ ErrorOr<B*> b(ErrorOr<D*>(nullptr));
+ b = ErrorOr<D*>(nullptr);
+
+ ErrorOr<std::unique_ptr<B> > b1(ErrorOr<std::unique_ptr<D> >(nullptr));
+ b1 = ErrorOr<std::unique_ptr<D> >(nullptr);
+
+ ErrorOr<std::unique_ptr<int>> b2(ErrorOr<int *>(nullptr));
+ ErrorOr<int *> b3(nullptr);
+ ErrorOr<std::unique_ptr<int>> b4(b3);
+}
+
+TEST(ErrorOr, Comparison) {
+ ErrorOr<int> x(errc::no_such_file_or_directory);
+ EXPECT_EQ(x, errc::no_such_file_or_directory);
+}
+
+TEST(ErrorOr, ImplicitConversion) {
+ ErrorOr<std::string> x("string literal");
+ EXPECT_TRUE(!!x);
+}
+
+TEST(ErrorOr, ImplicitConversionCausesMove) {
+ struct Source {};
+ struct Destination {
+ Destination(const Source&) {}
+ Destination(Source&&) = delete;
+ };
+ Source s;
+ ErrorOr<Destination> x = s;
+ EXPECT_TRUE(!!x);
+}
+
+TEST(ErrorOr, ImplicitConversionNoAmbiguity) {
+ struct CastsToErrorCode {
+ CastsToErrorCode() = default;
+ CastsToErrorCode(std::error_code) {}
+ operator std::error_code() { return errc::invalid_argument; }
+ } casts_to_error_code;
+ ErrorOr<CastsToErrorCode> x1(casts_to_error_code);
+ ErrorOr<CastsToErrorCode> x2 = casts_to_error_code;
+ ErrorOr<CastsToErrorCode> x3 = {casts_to_error_code};
+ ErrorOr<CastsToErrorCode> x4{casts_to_error_code};
+ ErrorOr<CastsToErrorCode> x5(errc::no_such_file_or_directory);
+ ErrorOr<CastsToErrorCode> x6 = errc::no_such_file_or_directory;
+ ErrorOr<CastsToErrorCode> x7 = {errc::no_such_file_or_directory};
+ ErrorOr<CastsToErrorCode> x8{errc::no_such_file_or_directory};
+ EXPECT_TRUE(!!x1);
+ EXPECT_TRUE(!!x2);
+ EXPECT_TRUE(!!x3);
+ EXPECT_TRUE(!!x4);
+ EXPECT_FALSE(x5);
+ EXPECT_FALSE(x6);
+ EXPECT_FALSE(x7);
+ EXPECT_FALSE(x8);
+}
+
+// ErrorOr<int*> x(nullptr);
+// ErrorOr<std::unique_ptr<int>> y = x; // invalid conversion
+static_assert(
+ !std::is_convertible<const ErrorOr<int *> &,
+ ErrorOr<std::unique_ptr<int>>>::value,
+ "do not invoke explicit ctors in implicit conversion from lvalue");
+
+// ErrorOr<std::unique_ptr<int>> y = ErrorOr<int*>(nullptr); // invalid
+// // conversion
+static_assert(
+ !std::is_convertible<ErrorOr<int *> &&,
+ ErrorOr<std::unique_ptr<int>>>::value,
+ "do not invoke explicit ctors in implicit conversion from rvalue");
+
+// ErrorOr<int*> x(nullptr);
+// ErrorOr<std::unique_ptr<int>> y;
+// y = x; // invalid conversion
+static_assert(!std::is_assignable<ErrorOr<std::unique_ptr<int>>&,
+ const ErrorOr<int *> &>::value,
+ "do not invoke explicit ctors in assignment");
+
+// ErrorOr<std::unique_ptr<int>> x;
+// x = ErrorOr<int*>(nullptr); // invalid conversion
+static_assert(!std::is_assignable<ErrorOr<std::unique_ptr<int>>&,
+ ErrorOr<int *> &&>::value,
+ "do not invoke explicit ctors in assignment");
+} // end anon namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ErrorTest.cpp b/src/llvm-project/llvm/unittests/Support/ErrorTest.cpp
new file mode 100644
index 0000000..eee2fe2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ErrorTest.cpp
@@ -0,0 +1,979 @@
+//===----- unittests/ErrorTest.cpp - Error.h tests ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Error.h"
+#include "llvm-c/Error.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+// Custom error class with a default base class and some random 'info' attached.
+class CustomError : public ErrorInfo<CustomError> {
+public:
+ // Create an error with some info attached.
+ CustomError(int Info) : Info(Info) {}
+
+ // Get the info attached to this error.
+ int getInfo() const { return Info; }
+
+ // Log this error to a stream.
+ void log(raw_ostream &OS) const override {
+ OS << "CustomError {" << getInfo() << "}";
+ }
+
+ std::error_code convertToErrorCode() const override {
+ llvm_unreachable("CustomError doesn't support ECError conversion");
+ }
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+protected:
+ // This error is subclassed below, but we can't use inheriting constructors
+ // yet, so we can't propagate the constructors through ErrorInfo. Instead
+ // we have to have a default constructor and have the subclass initialize all
+ // fields.
+ CustomError() : Info(0) {}
+
+ int Info;
+};
+
+char CustomError::ID = 0;
+
+// Custom error class with a custom base class and some additional random
+// 'info'.
+class CustomSubError : public ErrorInfo<CustomSubError, CustomError> {
+public:
+ // Create a sub-error with some info attached.
+ CustomSubError(int Info, int ExtraInfo) : ExtraInfo(ExtraInfo) {
+ this->Info = Info;
+ }
+
+ // Get the extra info attached to this error.
+ int getExtraInfo() const { return ExtraInfo; }
+
+ // Log this error to a stream.
+ void log(raw_ostream &OS) const override {
+ OS << "CustomSubError { " << getInfo() << ", " << getExtraInfo() << "}";
+ }
+
+ std::error_code convertToErrorCode() const override {
+ llvm_unreachable("CustomSubError doesn't support ECError conversion");
+ }
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+protected:
+ int ExtraInfo;
+};
+
+char CustomSubError::ID = 0;
+
+static Error handleCustomError(const CustomError &CE) {
+ return Error::success();
+}
+
+static void handleCustomErrorVoid(const CustomError &CE) {}
+
+static Error handleCustomErrorUP(std::unique_ptr<CustomError> CE) {
+ return Error::success();
+}
+
+static void handleCustomErrorUPVoid(std::unique_ptr<CustomError> CE) {}
+
+// Test that success values implicitly convert to false, and don't cause crashes
+// once they've been implicitly converted.
+TEST(Error, CheckedSuccess) {
+ Error E = Error::success();
+ EXPECT_FALSE(E) << "Unexpected error while testing Error 'Success'";
+}
+
+// Test that unchecked success values cause an abort.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UncheckedSuccess) {
+ EXPECT_DEATH({ Error E = Error::success(); },
+ "Program aborted due to an unhandled Error:")
+ << "Unchecked Error Succes value did not cause abort()";
+}
+#endif
+
+// ErrorAsOutParameter tester.
+void errAsOutParamHelper(Error &Err) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ // Verify that checked flag is raised - assignment should not crash.
+ Err = Error::success();
+ // Raise the checked bit manually - caller should still have to test the
+ // error.
+ (void)!!Err;
+}
+
+// Test that ErrorAsOutParameter sets the checked flag on construction.
+TEST(Error, ErrorAsOutParameterChecked) {
+ Error E = Error::success();
+ errAsOutParamHelper(E);
+ (void)!!E;
+}
+
+// Test that ErrorAsOutParameter clears the checked flag on destruction.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, ErrorAsOutParameterUnchecked) {
+ EXPECT_DEATH({ Error E = Error::success(); errAsOutParamHelper(E); },
+ "Program aborted due to an unhandled Error:")
+ << "ErrorAsOutParameter did not clear the checked flag on destruction.";
+}
+#endif
+
+// Check that we abort on unhandled failure cases. (Force conversion to bool
+// to make sure that we don't accidentally treat checked errors as handled).
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UncheckedError) {
+ auto DropUnhandledError = []() {
+ Error E = make_error<CustomError>(42);
+ (void)!E;
+ };
+ EXPECT_DEATH(DropUnhandledError(),
+ "Program aborted due to an unhandled Error:")
+ << "Unhandled Error failure value did not cause abort()";
+}
+#endif
+
+// Check 'Error::isA<T>' method handling.
+TEST(Error, IsAHandling) {
+ // Check 'isA' handling.
+ Error E = make_error<CustomError>(1);
+ Error F = make_error<CustomSubError>(1, 2);
+ Error G = Error::success();
+
+ EXPECT_TRUE(E.isA<CustomError>());
+ EXPECT_FALSE(E.isA<CustomSubError>());
+ EXPECT_TRUE(F.isA<CustomError>());
+ EXPECT_TRUE(F.isA<CustomSubError>());
+ EXPECT_FALSE(G.isA<CustomError>());
+
+ consumeError(std::move(E));
+ consumeError(std::move(F));
+ consumeError(std::move(G));
+}
+
+// Check that we can handle a custom error.
+TEST(Error, HandleCustomError) {
+ int CaughtErrorInfo = 0;
+ handleAllErrors(make_error<CustomError>(42), [&](const CustomError &CE) {
+ CaughtErrorInfo = CE.getInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42) << "Wrong result from CustomError handler";
+}
+
+// Check that handler type deduction also works for handlers
+// of the following types:
+// void (const Err&)
+// Error (const Err&) mutable
+// void (const Err&) mutable
+// Error (Err&)
+// void (Err&)
+// Error (Err&) mutable
+// void (Err&) mutable
+// Error (unique_ptr<Err>)
+// void (unique_ptr<Err>)
+// Error (unique_ptr<Err>) mutable
+// void (unique_ptr<Err>) mutable
+TEST(Error, HandlerTypeDeduction) {
+
+ handleAllErrors(make_error<CustomError>(42), [](const CustomError &CE) {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](const CustomError &CE) mutable -> Error { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](const CustomError &CE) mutable {});
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](CustomError &CE) -> Error { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) {});
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](CustomError &CE) mutable -> Error { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42), [](CustomError &CE) mutable {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) -> Error { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) {});
+
+ handleAllErrors(
+ make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) mutable -> Error { return Error::success(); });
+
+ handleAllErrors(make_error<CustomError>(42),
+ [](std::unique_ptr<CustomError> CE) mutable {});
+
+ // Check that named handlers of type 'Error (const Err&)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomError);
+
+ // Check that named handlers of type 'void (const Err&)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorVoid);
+
+ // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorUP);
+
+ // Check that named handlers of type 'Error (std::unique_ptr<Err>)' work.
+ handleAllErrors(make_error<CustomError>(42), handleCustomErrorUPVoid);
+}
+
+// Test that we can handle errors with custom base classes.
+TEST(Error, HandleCustomErrorWithCustomBaseClass) {
+ int CaughtErrorInfo = 0;
+ int CaughtErrorExtraInfo = 0;
+ handleAllErrors(make_error<CustomSubError>(42, 7),
+ [&](const CustomSubError &SE) {
+ CaughtErrorInfo = SE.getInfo();
+ CaughtErrorExtraInfo = SE.getExtraInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7)
+ << "Wrong result from CustomSubError handler";
+}
+
+// Check that we trigger only the first handler that applies.
+TEST(Error, FirstHandlerOnly) {
+ int DummyInfo = 0;
+ int CaughtErrorInfo = 0;
+ int CaughtErrorExtraInfo = 0;
+
+ handleAllErrors(make_error<CustomSubError>(42, 7),
+ [&](const CustomSubError &SE) {
+ CaughtErrorInfo = SE.getInfo();
+ CaughtErrorExtraInfo = SE.getExtraInfo();
+ },
+ [&](const CustomError &CE) { DummyInfo = CE.getInfo(); });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42 && CaughtErrorExtraInfo == 7 &&
+ DummyInfo == 0)
+ << "Activated the wrong Error handler(s)";
+}
+
+// Check that general handlers shadow specific ones.
+TEST(Error, HandlerShadowing) {
+ int CaughtErrorInfo = 0;
+ int DummyInfo = 0;
+ int DummyExtraInfo = 0;
+
+ handleAllErrors(
+ make_error<CustomSubError>(42, 7),
+ [&](const CustomError &CE) { CaughtErrorInfo = CE.getInfo(); },
+ [&](const CustomSubError &SE) {
+ DummyInfo = SE.getInfo();
+ DummyExtraInfo = SE.getExtraInfo();
+ });
+
+ EXPECT_TRUE(CaughtErrorInfo == 42 && DummyInfo == 0 && DummyExtraInfo == 0)
+ << "General Error handler did not shadow specific handler";
+}
+
+// Test joinErrors.
+TEST(Error, CheckJoinErrors) {
+ int CustomErrorInfo1 = 0;
+ int CustomErrorInfo2 = 0;
+ int CustomErrorExtraInfo = 0;
+ Error E =
+ joinErrors(make_error<CustomError>(7), make_error<CustomSubError>(42, 7));
+
+ handleAllErrors(std::move(E),
+ [&](const CustomSubError &SE) {
+ CustomErrorInfo2 = SE.getInfo();
+ CustomErrorExtraInfo = SE.getExtraInfo();
+ },
+ [&](const CustomError &CE) {
+ // Assert that the CustomError instance above is handled
+ // before the
+ // CustomSubError - joinErrors should preserve error
+ // ordering.
+ EXPECT_EQ(CustomErrorInfo2, 0)
+ << "CustomErrorInfo2 should be 0 here. "
+ "joinErrors failed to preserve ordering.\n";
+ CustomErrorInfo1 = CE.getInfo();
+ });
+
+ EXPECT_TRUE(CustomErrorInfo1 == 7 && CustomErrorInfo2 == 42 &&
+ CustomErrorExtraInfo == 7)
+ << "Failed handling compound Error.";
+
+ // Test appending a single item to a list.
+ {
+ int Sum = 0;
+ handleAllErrors(
+ joinErrors(
+ joinErrors(make_error<CustomError>(7),
+ make_error<CustomError>(7)),
+ make_error<CustomError>(7)),
+ [&](const CustomError &CE) {
+ Sum += CE.getInfo();
+ });
+ EXPECT_EQ(Sum, 21) << "Failed to correctly append error to error list.";
+ }
+
+ // Test prepending a single item to a list.
+ {
+ int Sum = 0;
+ handleAllErrors(
+ joinErrors(
+ make_error<CustomError>(7),
+ joinErrors(make_error<CustomError>(7),
+ make_error<CustomError>(7))),
+ [&](const CustomError &CE) {
+ Sum += CE.getInfo();
+ });
+ EXPECT_EQ(Sum, 21) << "Failed to correctly prepend error to error list.";
+ }
+
+ // Test concatenating two error lists.
+ {
+ int Sum = 0;
+ handleAllErrors(
+ joinErrors(
+ joinErrors(
+ make_error<CustomError>(7),
+ make_error<CustomError>(7)),
+ joinErrors(
+ make_error<CustomError>(7),
+ make_error<CustomError>(7))),
+ [&](const CustomError &CE) {
+ Sum += CE.getInfo();
+ });
+ EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate error lists.";
+ }
+}
+
+// Test that we can consume success values.
+TEST(Error, ConsumeSuccess) {
+ Error E = Error::success();
+ consumeError(std::move(E));
+}
+
+TEST(Error, ConsumeError) {
+ Error E = make_error<CustomError>(7);
+ consumeError(std::move(E));
+}
+
+// Test that handleAllUnhandledErrors crashes if an error is not caught.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, FailureToHandle) {
+ auto FailToHandle = []() {
+ handleAllErrors(make_error<CustomError>(7), [&](const CustomSubError &SE) {
+ errs() << "This should never be called";
+ exit(1);
+ });
+ };
+
+ EXPECT_DEATH(FailToHandle(),
+ "Failure value returned from cantFail wrapped call")
+ << "Unhandled Error in handleAllErrors call did not cause an "
+ "abort()";
+}
+#endif
+
+// Test that handleAllUnhandledErrors crashes if an error is returned from a
+// handler.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, FailureFromHandler) {
+ auto ReturnErrorFromHandler = []() {
+ handleAllErrors(make_error<CustomError>(7),
+ [&](std::unique_ptr<CustomSubError> SE) {
+ return Error(std::move(SE));
+ });
+ };
+
+ EXPECT_DEATH(ReturnErrorFromHandler(),
+ "Failure value returned from cantFail wrapped call")
+ << " Error returned from handler in handleAllErrors call did not "
+ "cause abort()";
+}
+#endif
+
+// Test that we can return values from handleErrors.
+TEST(Error, CatchErrorFromHandler) {
+ int ErrorInfo = 0;
+
+ Error E = handleErrors(
+ make_error<CustomError>(7),
+ [&](std::unique_ptr<CustomError> CE) { return Error(std::move(CE)); });
+
+ handleAllErrors(std::move(E),
+ [&](const CustomError &CE) { ErrorInfo = CE.getInfo(); });
+
+ EXPECT_EQ(ErrorInfo, 7)
+ << "Failed to handle Error returned from handleErrors.";
+}
+
+TEST(Error, StringError) {
+ std::string Msg;
+ raw_string_ostream S(Msg);
+ logAllUnhandledErrors(
+ make_error<StringError>("foo" + Twine(42), inconvertibleErrorCode()), S);
+ EXPECT_EQ(S.str(), "foo42\n") << "Unexpected StringError log result";
+
+ auto EC =
+ errorToErrorCode(make_error<StringError>("", errc::invalid_argument));
+ EXPECT_EQ(EC, errc::invalid_argument)
+ << "Failed to convert StringError to error_code.";
+}
+
+TEST(Error, createStringError) {
+ static const char *Bar = "bar";
+ static const std::error_code EC = errc::invalid_argument;
+ std::string Msg;
+ raw_string_ostream S(Msg);
+ logAllUnhandledErrors(createStringError(EC, "foo%s%d0x%" PRIx8, Bar, 1, 0xff),
+ S);
+ EXPECT_EQ(S.str(), "foobar10xff\n")
+ << "Unexpected createStringError() log result";
+
+ S.flush();
+ Msg.clear();
+ logAllUnhandledErrors(createStringError(EC, Bar), S);
+ EXPECT_EQ(S.str(), "bar\n")
+ << "Unexpected createStringError() (overloaded) log result";
+
+ S.flush();
+ Msg.clear();
+ auto Res = errorToErrorCode(createStringError(EC, "foo%s", Bar));
+ EXPECT_EQ(Res, EC)
+ << "Failed to convert createStringError() result to error_code.";
+}
+
+// Test that the ExitOnError utility works as expected.
+TEST(Error, ExitOnError) {
+ ExitOnError ExitOnErr;
+ ExitOnErr.setBanner("Error in tool:");
+ ExitOnErr.setExitCodeMapper([](const Error &E) {
+ if (E.isA<CustomSubError>())
+ return 2;
+ return 1;
+ });
+
+ // Make sure we don't bail on success.
+ ExitOnErr(Error::success());
+ EXPECT_EQ(ExitOnErr(Expected<int>(7)), 7)
+ << "exitOnError returned an invalid value for Expected";
+
+ int A = 7;
+ int &B = ExitOnErr(Expected<int&>(A));
+ EXPECT_EQ(&A, &B) << "ExitOnError failed to propagate reference";
+
+ // Exit tests.
+ EXPECT_EXIT(ExitOnErr(make_error<CustomError>(7)),
+ ::testing::ExitedWithCode(1), "Error in tool:")
+ << "exitOnError returned an unexpected error result";
+
+ EXPECT_EXIT(ExitOnErr(Expected<int>(make_error<CustomSubError>(0, 0))),
+ ::testing::ExitedWithCode(2), "Error in tool:")
+ << "exitOnError returned an unexpected error result";
+}
+
+// Test that the ExitOnError utility works as expected.
+TEST(Error, CantFailSuccess) {
+ cantFail(Error::success());
+
+ int X = cantFail(Expected<int>(42));
+ EXPECT_EQ(X, 42) << "Expected value modified by cantFail";
+
+ int Dummy = 42;
+ int &Y = cantFail(Expected<int&>(Dummy));
+ EXPECT_EQ(&Dummy, &Y) << "Reference mangled by cantFail";
+}
+
+// Test that cantFail results in a crash if you pass it a failure value.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
+TEST(Error, CantFailDeath) {
+ EXPECT_DEATH(
+ cantFail(make_error<StringError>("foo", inconvertibleErrorCode()),
+ "Cantfail call failed"),
+ "Cantfail call failed")
+ << "cantFail(Error) did not cause an abort for failure value";
+
+ EXPECT_DEATH(
+ {
+ auto IEC = inconvertibleErrorCode();
+ int X = cantFail(Expected<int>(make_error<StringError>("foo", IEC)));
+ (void)X;
+ },
+ "Failure value returned from cantFail wrapped call")
+ << "cantFail(Expected<int>) did not cause an abort for failure value";
+}
+#endif
+
+
+// Test Checked Expected<T> in success mode.
+TEST(Error, CheckedExpectedInSuccessMode) {
+ Expected<int> A = 7;
+ EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'";
+ // Access is safe in second test, since we checked the error in the first.
+ EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value";
+}
+
+// Test Expected with reference type.
+TEST(Error, ExpectedWithReferenceType) {
+ int A = 7;
+ Expected<int&> B = A;
+ // 'Check' B.
+ (void)!!B;
+ int &C = *B;
+ EXPECT_EQ(&A, &C) << "Expected failed to propagate reference";
+}
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UncheckedExpectedInSuccessModeDestruction) {
+ EXPECT_DEATH({ Expected<int> A = 7; },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+#endif
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UncheckedExpectedInSuccessModeAccess) {
+ EXPECT_DEATH({ Expected<int> A = 7; *A; },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+#endif
+
+// Test Unchecked Expected<T> in success mode.
+// We expect this to blow up the same way Error would.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UncheckedExpectedInSuccessModeAssignment) {
+ EXPECT_DEATH({ Expected<int> A = 7; A = 7; },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecekd Expected<T> success value did not cause an abort().";
+}
+#endif
+
+// Test Expected<T> in failure mode.
+TEST(Error, ExpectedInFailureMode) {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_FALSE(!!A) << "Expected with error value doesn't convert to 'false'";
+ Error E = A.takeError();
+ EXPECT_TRUE(E.isA<CustomError>()) << "Incorrect Expected error value";
+ consumeError(std::move(E));
+}
+
+// Check that an Expected instance with an error value doesn't allow access to
+// operator*.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, AccessExpectedInFailureMode) {
+ Expected<int> A = make_error<CustomError>(42);
+ EXPECT_DEATH(*A, "Expected<T> must be checked before access or destruction.")
+ << "Incorrect Expected error value";
+ consumeError(A.takeError());
+}
+#endif
+
+// Check that an Expected instance with an error triggers an abort if
+// unhandled.
+// Test runs in debug mode only.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(Error, UnhandledExpectedInFailureMode) {
+ EXPECT_DEATH({ Expected<int> A = make_error<CustomError>(42); },
+ "Expected<T> must be checked before access or destruction.")
+ << "Unchecked Expected<T> failure value did not cause an abort()";
+}
+#endif
+
+// Test covariance of Expected.
+TEST(Error, ExpectedCovariance) {
+ class B {};
+ class D : public B {};
+
+ Expected<B *> A1(Expected<D *>(nullptr));
+ // Check A1 by converting to bool before assigning to it.
+ (void)!!A1;
+ A1 = Expected<D *>(nullptr);
+ // Check A1 again before destruction.
+ (void)!!A1;
+
+ Expected<std::unique_ptr<B>> A2(Expected<std::unique_ptr<D>>(nullptr));
+ // Check A2 by converting to bool before assigning to it.
+ (void)!!A2;
+ A2 = Expected<std::unique_ptr<D>>(nullptr);
+ // Check A2 again before destruction.
+ (void)!!A2;
+}
+
+// Test that handleExpected just returns success values.
+TEST(Error, HandleExpectedSuccess) {
+ auto ValOrErr =
+ handleExpected(Expected<int>(42),
+ []() { return Expected<int>(43); });
+ EXPECT_TRUE(!!ValOrErr)
+ << "handleExpected should have returned a success value here";
+ EXPECT_EQ(*ValOrErr, 42)
+ << "handleExpected should have returned the original success value here";
+}
+
+enum FooStrategy { Aggressive, Conservative };
+
+static Expected<int> foo(FooStrategy S) {
+ if (S == Aggressive)
+ return make_error<CustomError>(7);
+ return 42;
+}
+
+// Test that handleExpected invokes the error path if errors are not handled.
+TEST(Error, HandleExpectedUnhandledError) {
+ // foo(Aggressive) should return a CustomError which should pass through as
+ // there is no handler for CustomError.
+ auto ValOrErr =
+ handleExpected(
+ foo(Aggressive),
+ []() { return foo(Conservative); });
+
+ EXPECT_FALSE(!!ValOrErr)
+ << "handleExpected should have returned an error here";
+ auto Err = ValOrErr.takeError();
+ EXPECT_TRUE(Err.isA<CustomError>())
+ << "handleExpected should have returned the CustomError generated by "
+ "foo(Aggressive) here";
+ consumeError(std::move(Err));
+}
+
+// Test that handleExpected invokes the fallback path if errors are handled.
+TEST(Error, HandleExpectedHandledError) {
+ // foo(Aggressive) should return a CustomError which should handle triggering
+ // the fallback path.
+ auto ValOrErr =
+ handleExpected(
+ foo(Aggressive),
+ []() { return foo(Conservative); },
+ [](const CustomError&) { /* do nothing */ });
+
+ EXPECT_TRUE(!!ValOrErr)
+ << "handleExpected should have returned a success value here";
+ EXPECT_EQ(*ValOrErr, 42)
+ << "handleExpected returned the wrong success value";
+}
+
+TEST(Error, ErrorCodeConversions) {
+ // Round-trip a success value to check that it converts correctly.
+ EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())),
+ std::error_code())
+ << "std::error_code() should round-trip via Error conversions";
+
+ // Round-trip an error value to check that it converts correctly.
+ EXPECT_EQ(errorToErrorCode(errorCodeToError(errc::invalid_argument)),
+ errc::invalid_argument)
+ << "std::error_code error value should round-trip via Error "
+ "conversions";
+
+ // Round-trip a success value through ErrorOr/Expected to check that it
+ // converts correctly.
+ {
+ auto Orig = ErrorOr<int>(42);
+ auto RoundTripped =
+ expectedToErrorOr(errorOrToExpected(ErrorOr<int>(42)));
+ EXPECT_EQ(*Orig, *RoundTripped)
+ << "ErrorOr<T> success value should round-trip via Expected<T> "
+ "conversions.";
+ }
+
+ // Round-trip a failure value through ErrorOr/Expected to check that it
+ // converts correctly.
+ {
+ auto Orig = ErrorOr<int>(errc::invalid_argument);
+ auto RoundTripped =
+ expectedToErrorOr(
+ errorOrToExpected(ErrorOr<int>(errc::invalid_argument)));
+ EXPECT_EQ(Orig.getError(), RoundTripped.getError())
+ << "ErrorOr<T> failure value should round-trip via Expected<T> "
+ "conversions.";
+ }
+}
+
+// Test that error messages work.
+TEST(Error, ErrorMessage) {
+ EXPECT_EQ(toString(Error::success()).compare(""), 0);
+
+ Error E1 = make_error<CustomError>(0);
+ EXPECT_EQ(toString(std::move(E1)).compare("CustomError {0}"), 0);
+
+ Error E2 = make_error<CustomError>(0);
+ handleAllErrors(std::move(E2), [](const CustomError &CE) {
+ EXPECT_EQ(CE.message().compare("CustomError {0}"), 0);
+ });
+
+ Error E3 = joinErrors(make_error<CustomError>(0), make_error<CustomError>(1));
+ EXPECT_EQ(toString(std::move(E3))
+ .compare("CustomError {0}\n"
+ "CustomError {1}"),
+ 0);
+}
+
+TEST(Error, Stream) {
+ {
+ Error OK = Error::success();
+ std::string Buf;
+ llvm::raw_string_ostream S(Buf);
+ S << OK;
+ EXPECT_EQ("success", S.str());
+ consumeError(std::move(OK));
+ }
+ {
+ Error E1 = make_error<CustomError>(0);
+ std::string Buf;
+ llvm::raw_string_ostream S(Buf);
+ S << E1;
+ EXPECT_EQ("CustomError {0}", S.str());
+ consumeError(std::move(E1));
+ }
+}
+
+TEST(Error, ErrorMatchers) {
+ EXPECT_THAT_ERROR(Error::success(), Succeeded());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()),
+ "Expected: succeeded\n Actual: failed (CustomError {0})");
+
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed());
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()),
+ "Expected: failed\n Actual: succeeded");
+
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomError>());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(Error::success(), Failed<CustomError>()),
+ "Expected: failed with Error of given type\n Actual: succeeded");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<CustomSubError>()),
+ "Error was not of given type");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(
+ joinErrors(make_error<CustomError>(0), make_error<CustomError>(1)),
+ Failed<CustomError>()),
+ "multiple errors");
+
+ EXPECT_THAT_ERROR(
+ make_error<CustomError>(0),
+ Failed<CustomError>(testing::Property(&CustomError::getInfo, 0)));
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_ERROR(
+ make_error<CustomError>(0),
+ Failed<CustomError>(testing::Property(&CustomError::getInfo, 1))),
+ "Expected: failed with Error of given type and the error is an object "
+ "whose given property is equal to 1\n"
+ " Actual: failed (CustomError {0})");
+ EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed<ErrorInfoBase>());
+
+ EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
+ Succeeded()),
+ "Expected: succeeded\n Actual: failed (CustomError {0})");
+
+ EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()),
+ "Expected: failed\n Actual: succeeded with value 0");
+
+ EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0));
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
+ HasValue(0)),
+ "Expected: succeeded with value (is equal to 0)\n"
+ " Actual: failed (CustomError {0})");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)),
+ "Expected: succeeded with value (is equal to 0)\n"
+ " Actual: succeeded with value 1, (isn't equal to 0)");
+
+ EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed());
+ int a = 1;
+ EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded());
+ EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1)));
+
+ EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0)));
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))),
+ "Expected: succeeded with value (is > 1)\n"
+ " Actual: succeeded with value 0, (isn't > 1)");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)),
+ HasValue(testing::Gt(1))),
+ "Expected: succeeded with value (is > 1)\n"
+ " Actual: failed (CustomError {0})");
+}
+
+TEST(Error, C_API) {
+ EXPECT_THAT_ERROR(unwrap(wrap(Error::success())), Succeeded())
+ << "Failed to round-trip Error success value via C API";
+ EXPECT_THAT_ERROR(unwrap(wrap(make_error<CustomError>(0))),
+ Failed<CustomError>())
+ << "Failed to round-trip Error failure value via C API";
+
+ auto Err =
+ wrap(make_error<StringError>("test message", inconvertibleErrorCode()));
+ EXPECT_EQ(LLVMGetErrorTypeId(Err), LLVMGetStringErrorTypeId())
+ << "Failed to match error type ids via C API";
+ char *ErrMsg = LLVMGetErrorMessage(Err);
+ EXPECT_STREQ(ErrMsg, "test message")
+ << "Failed to roundtrip StringError error message via C API";
+ LLVMDisposeErrorMessage(ErrMsg);
+
+ bool GotCSE = false;
+ bool GotCE = false;
+ handleAllErrors(
+ unwrap(wrap(joinErrors(make_error<CustomSubError>(42, 7),
+ make_error<CustomError>(42)))),
+ [&](CustomSubError &CSE) {
+ GotCSE = true;
+ },
+ [&](CustomError &CE) {
+ GotCE = true;
+ });
+ EXPECT_TRUE(GotCSE) << "Failed to round-trip ErrorList via C API";
+ EXPECT_TRUE(GotCE) << "Failed to round-trip ErrorList via C API";
+}
+
+TEST(Error, FileErrorTest) {
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(
+ {
+ Error S = Error::success();
+ consumeError(createFileError("file.bin", std::move(S)));
+ },
+ "");
+#endif
+ // Not allowed, would fail at compile-time
+ //consumeError(createFileError("file.bin", ErrorSuccess()));
+
+ Error E1 = make_error<CustomError>(1);
+ Error FE1 = createFileError("file.bin", std::move(E1));
+ EXPECT_EQ(toString(std::move(FE1)).compare("'file.bin': CustomError {1}"), 0);
+
+ Error E2 = make_error<CustomError>(2);
+ Error FE2 = createFileError("file.bin", std::move(E2));
+ handleAllErrors(std::move(FE2), [](const FileError &F) {
+ EXPECT_EQ(F.message().compare("'file.bin': CustomError {2}"), 0);
+ });
+
+ Error E3 = make_error<CustomError>(3);
+ Error FE3 = createFileError("file.bin", std::move(E3));
+ auto E31 = handleErrors(std::move(FE3), [](std::unique_ptr<FileError> F) {
+ return F->takeError();
+ });
+ handleAllErrors(std::move(E31), [](const CustomError &C) {
+ EXPECT_EQ(C.message().compare("CustomError {3}"), 0);
+ });
+
+ Error FE4 =
+ joinErrors(createFileError("file.bin", make_error<CustomError>(41)),
+ createFileError("file2.bin", make_error<CustomError>(42)));
+ EXPECT_EQ(toString(std::move(FE4))
+ .compare("'file.bin': CustomError {41}\n"
+ "'file2.bin': CustomError {42}"),
+ 0);
+}
+
+enum class test_error_code {
+ unspecified = 1,
+ error_1,
+ error_2,
+};
+
+} // end anon namespace
+
+namespace std {
+ template <>
+ struct is_error_code_enum<test_error_code> : std::true_type {};
+} // namespace std
+
+namespace {
+
+const std::error_category &TErrorCategory();
+
+inline std::error_code make_error_code(test_error_code E) {
+ return std::error_code(static_cast<int>(E), TErrorCategory());
+}
+
+class TestDebugError : public ErrorInfo<TestDebugError, StringError> {
+public:
+ using ErrorInfo<TestDebugError, StringError >::ErrorInfo; // inherit constructors
+ TestDebugError(const Twine &S) : ErrorInfo(S, test_error_code::unspecified) {}
+ static char ID;
+};
+
+class TestErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "error"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<test_error_code>(Condition)) {
+ case test_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case test_error_code::error_1:
+ return "Error 1.";
+ case test_error_code::error_2:
+ return "Error 2.";
+ }
+ llvm_unreachable("Unrecognized test_error_code");
+ }
+};
+
+static llvm::ManagedStatic<TestErrorCategory> TestErrCategory;
+const std::error_category &TErrorCategory() { return *TestErrCategory; }
+
+char TestDebugError::ID;
+
+TEST(Error, SubtypeStringErrorTest) {
+ auto E1 = make_error<TestDebugError>(test_error_code::error_1);
+ EXPECT_EQ(toString(std::move(E1)).compare("Error 1."), 0);
+
+ auto E2 = make_error<TestDebugError>(test_error_code::error_1,
+ "Detailed information");
+ EXPECT_EQ(toString(std::move(E2)).compare("Error 1. Detailed information"),
+ 0);
+
+ auto E3 = make_error<TestDebugError>(test_error_code::error_2);
+ handleAllErrors(std::move(E3), [](const TestDebugError &F) {
+ EXPECT_EQ(F.message().compare("Error 2."), 0);
+ });
+
+ auto E4 = joinErrors(make_error<TestDebugError>(test_error_code::error_1,
+ "Detailed information"),
+ make_error<TestDebugError>(test_error_code::error_2));
+ EXPECT_EQ(toString(std::move(E4))
+ .compare("Error 1. Detailed information\n"
+ "Error 2."),
+ 0);
+}
+
+} // namespace
diff --git a/src/llvm-project/llvm/unittests/Support/FileOutputBufferTest.cpp b/src/llvm-project/llvm/unittests/Support/FileOutputBufferTest.cpp
new file mode 100644
index 0000000..5548595
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/FileOutputBufferTest.cpp
@@ -0,0 +1,174 @@
+//===- llvm/unittest/Support/FileOutputBuffer.cpp - unit tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
+namespace {
+TEST(FileOutputBuffer, Test) {
+ // Create unique temporary directory for these tests
+ SmallString<128> TestDirectory;
+ {
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("FileOutputBuffer-test", TestDirectory));
+ }
+
+ // TEST 1: Verify commit case.
+ SmallString<128> File1(TestDirectory);
+ File1.append("/file1");
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(File1, 8192);
+ ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr;
+ // Start buffer with special header.
+ memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
+ // Write to end of buffer to verify it is writable.
+ memcpy(Buffer->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20);
+ // Commit buffer.
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit()));
+ }
+
+ // Verify file is correct size.
+ uint64_t File1Size;
+ ASSERT_NO_ERROR(fs::file_size(Twine(File1), File1Size));
+ ASSERT_EQ(File1Size, 8192ULL);
+ ASSERT_NO_ERROR(fs::remove(File1.str()));
+
+ // TEST 2: Verify abort case.
+ SmallString<128> File2(TestDirectory);
+ File2.append("/file2");
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> Buffer2OrErr =
+ FileOutputBuffer::create(File2, 8192);
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer2OrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer2 = *Buffer2OrErr;
+ // Fill buffer with special header.
+ memcpy(Buffer2->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
+ // Do *not* commit buffer.
+ }
+ // Verify file does not exist (because buffer not committed).
+ ASSERT_EQ(fs::access(Twine(File2), fs::AccessMode::Exist),
+ errc::no_such_file_or_directory);
+ ASSERT_NO_ERROR(fs::remove(File2.str()));
+
+ // TEST 3: Verify sizing down case.
+ SmallString<128> File3(TestDirectory);
+ File3.append("/file3");
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(File3, 8192000);
+ ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr;
+ // Start buffer with special header.
+ memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
+ // Write to end of buffer to verify it is writable.
+ memcpy(Buffer->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20);
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit()));
+ }
+
+ // Verify file is correct size.
+ uint64_t File3Size;
+ ASSERT_NO_ERROR(fs::file_size(Twine(File3), File3Size));
+ ASSERT_EQ(File3Size, 8192000ULL);
+ ASSERT_NO_ERROR(fs::remove(File3.str()));
+
+ // TEST 4: Verify file can be made executable.
+ SmallString<128> File4(TestDirectory);
+ File4.append("/file4");
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(File4, 8192, FileOutputBuffer::F_executable);
+ ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr;
+ // Start buffer with special header.
+ memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20);
+ // Commit buffer.
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit()));
+ }
+ // Verify file exists and is executable.
+ fs::file_status Status;
+ ASSERT_NO_ERROR(fs::status(Twine(File4), Status));
+ bool IsExecutable = (Status.permissions() & fs::owner_exe);
+ EXPECT_TRUE(IsExecutable);
+ ASSERT_NO_ERROR(fs::remove(File4.str()));
+
+ // Clean up.
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+
+TEST(FileOutputBuffer, TestModify) {
+ // Create unique temporary directory for these tests
+ SmallString<128> TestDirectory;
+ {
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("FileOutputBuffer-modify", TestDirectory));
+ }
+
+ SmallString<128> File1(TestDirectory);
+ File1.append("/file");
+ // First write some data.
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(File1, 10);
+ ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr;
+ memcpy(Buffer->getBufferStart(), "AAAAAAAAAA", 10);
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit()));
+ }
+
+ // Then re-open the file for modify and change only some bytes.
+ {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(File1, size_t(-1), FileOutputBuffer::F_modify);
+ ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError()));
+ std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr;
+ ASSERT_EQ(10U, Buffer->getBufferSize());
+ uint8_t *Data = Buffer->getBufferStart();
+ Data[0] = 'X';
+ Data[9] = 'X';
+ ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit()));
+ }
+
+ // Finally, re-open the file for read and verify that it has the modified
+ // contents.
+ {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile(File1);
+ ASSERT_NO_ERROR(BufferOrErr.getError());
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrErr);
+ ASSERT_EQ(10U, Buffer->getBufferSize());
+ EXPECT_EQ(StringRef("XAAAAAAAAX"), Buffer->getBuffer());
+ }
+
+ // Clean up.
+ ASSERT_NO_ERROR(fs::remove(File1));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory));
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/FormatVariadicTest.cpp b/src/llvm-project/llvm/unittests/Support/FormatVariadicTest.cpp
new file mode 100644
index 0000000..91a44ba
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/FormatVariadicTest.cpp
@@ -0,0 +1,691 @@
+//===- FormatVariadicTest.cpp - Unit tests for string formatting ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Compile-time tests templates in the detail namespace.
+namespace {
+struct Format : public FormatAdapter<int> {
+ Format(int N) : FormatAdapter<int>(std::move(N)) {}
+ void format(raw_ostream &OS, StringRef Opt) override { OS << "Format"; }
+};
+
+using detail::uses_format_member;
+using detail::uses_missing_provider;
+
+static_assert(uses_format_member<Format>::value, "");
+static_assert(uses_format_member<Format &>::value, "");
+static_assert(uses_format_member<Format &&>::value, "");
+static_assert(uses_format_member<const Format>::value, "");
+static_assert(uses_format_member<const Format &>::value, "");
+static_assert(uses_format_member<const volatile Format>::value, "");
+static_assert(uses_format_member<const volatile Format &>::value, "");
+
+struct NoFormat {};
+static_assert(uses_missing_provider<NoFormat>::value, "");
+}
+
+TEST(FormatVariadicTest, EmptyFormatString) {
+ auto Replacements = formatv_object_base::parseFormatString("");
+ EXPECT_EQ(0U, Replacements.size());
+}
+
+TEST(FormatVariadicTest, NoReplacements) {
+ const StringRef kFormatString = "This is a test";
+ auto Replacements = formatv_object_base::parseFormatString(kFormatString);
+ ASSERT_EQ(1U, Replacements.size());
+ EXPECT_EQ(kFormatString, Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+}
+
+TEST(FormatVariadicTest, EscapedBrace) {
+ // {{ should be replaced with {
+ auto Replacements = formatv_object_base::parseFormatString("{{");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("{", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+
+ // An even number N of braces should be replaced with N/2 braces.
+ Replacements = formatv_object_base::parseFormatString("{{{{{{");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("{{{", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Literal, Replacements[0].Type);
+}
+
+TEST(FormatVariadicTest, ValidReplacementSequence) {
+ // 1. Simple replacement - parameter index only
+ auto Replacements = formatv_object_base::parseFormatString("{0}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ Replacements = formatv_object_base::parseFormatString("{1}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(1u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 2. Parameter index with right alignment
+ Replacements = formatv_object_base::parseFormatString("{0,3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 3. And left alignment
+ Replacements = formatv_object_base::parseFormatString("{0,-3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 4. And center alignment
+ Replacements = formatv_object_base::parseFormatString("{0,=3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Center, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 4. Parameter index with option string
+ Replacements = formatv_object_base::parseFormatString("{0:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 5. Parameter index with alignment before option string
+ Replacements = formatv_object_base::parseFormatString("{0,-3:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 7. Parameter indices, options, and alignment can all have whitespace.
+ Replacements = formatv_object_base::parseFormatString("{ 0, -3 : foo }");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // 8. Everything after the first option specifier is part of the style, even
+ // if it contains another option specifier.
+ Replacements = formatv_object_base::parseFormatString("{0:0:1}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0:0:1", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("0:1", Replacements[0].Options);
+
+ // 9. Custom padding character
+ Replacements = formatv_object_base::parseFormatString("{0,p+4:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0,p+4:foo", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(4u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ('p', Replacements[0].Pad);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ // Format string special characters are allowed as padding character
+ Replacements = formatv_object_base::parseFormatString("{0,-+4:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0,-+4:foo", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(4u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ('-', Replacements[0].Pad);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ Replacements = formatv_object_base::parseFormatString("{0,+-4:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0,+-4:foo", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(4u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[0].Where);
+ EXPECT_EQ('+', Replacements[0].Pad);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ Replacements = formatv_object_base::parseFormatString("{0,==4:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0,==4:foo", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(4u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Center, Replacements[0].Where);
+ EXPECT_EQ('=', Replacements[0].Pad);
+ EXPECT_EQ("foo", Replacements[0].Options);
+
+ Replacements = formatv_object_base::parseFormatString("{0,:=4:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ("0,:=4:foo", Replacements[0].Spec);
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(4u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Center, Replacements[0].Where);
+ EXPECT_EQ(':', Replacements[0].Pad);
+ EXPECT_EQ("foo", Replacements[0].Options);
+}
+
+TEST(FormatVariadicTest, DefaultReplacementValues) {
+ // 2. If options string is missing, it defaults to empty.
+ auto Replacements = formatv_object_base::parseFormatString("{0,3}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // Including if the colon is present but contains no text.
+ Replacements = formatv_object_base::parseFormatString("{0,3:}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(3u, Replacements[0].Align);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // 3. If alignment is missing, it defaults to 0, right, space
+ Replacements = formatv_object_base::parseFormatString("{0:foo}");
+ ASSERT_EQ(1u, Replacements.size());
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ(' ', Replacements[0].Pad);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ("foo", Replacements[0].Options);
+}
+
+TEST(FormatVariadicTest, MultipleReplacements) {
+ auto Replacements =
+ formatv_object_base::parseFormatString("{0} {1:foo}-{2,-3:bar}");
+ ASSERT_EQ(5u, Replacements.size());
+ // {0}
+ EXPECT_EQ(ReplacementType::Format, Replacements[0].Type);
+ EXPECT_EQ(0u, Replacements[0].Index);
+ EXPECT_EQ(0u, Replacements[0].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[0].Where);
+ EXPECT_EQ("", Replacements[0].Options);
+
+ // " "
+ EXPECT_EQ(ReplacementType::Literal, Replacements[1].Type);
+ EXPECT_EQ(" ", Replacements[1].Spec);
+
+ // {1:foo} - Options=foo
+ EXPECT_EQ(ReplacementType::Format, Replacements[2].Type);
+ EXPECT_EQ(1u, Replacements[2].Index);
+ EXPECT_EQ(0u, Replacements[2].Align);
+ EXPECT_EQ(AlignStyle::Right, Replacements[2].Where);
+ EXPECT_EQ("foo", Replacements[2].Options);
+
+ // "-"
+ EXPECT_EQ(ReplacementType::Literal, Replacements[3].Type);
+ EXPECT_EQ("-", Replacements[3].Spec);
+
+ // {2:bar,-3} - Options=bar, Align=-3
+ EXPECT_EQ(ReplacementType::Format, Replacements[4].Type);
+ EXPECT_EQ(2u, Replacements[4].Index);
+ EXPECT_EQ(3u, Replacements[4].Align);
+ EXPECT_EQ(AlignStyle::Left, Replacements[4].Where);
+ EXPECT_EQ("bar", Replacements[4].Options);
+}
+
+TEST(FormatVariadicTest, FormatNoReplacements) {
+ EXPECT_EQ("", formatv("").str());
+ EXPECT_EQ("Test", formatv("Test").str());
+}
+
+TEST(FormatVariadicTest, FormatBasicTypesOneReplacement) {
+ EXPECT_EQ("1", formatv("{0}", 1).str());
+ EXPECT_EQ("c", formatv("{0}", 'c').str());
+ EXPECT_EQ("-3", formatv("{0}", -3).str());
+ EXPECT_EQ("Test", formatv("{0}", "Test").str());
+ EXPECT_EQ("Test2", formatv("{0}", StringRef("Test2")).str());
+ EXPECT_EQ("Test3", formatv("{0}", std::string("Test3")).str());
+}
+
+TEST(FormatVariadicTest, IntegralHexFormatting) {
+ // 1. Trivial cases. Make sure hex is not the default.
+ EXPECT_EQ("0", formatv("{0}", 0).str());
+ EXPECT_EQ("2748", formatv("{0}", 0xABC).str());
+ EXPECT_EQ("-2748", formatv("{0}", -0xABC).str());
+
+ // 3. various hex prefixes.
+ EXPECT_EQ("0xFF", formatv("{0:X}", 255).str());
+ EXPECT_EQ("0xFF", formatv("{0:X+}", 255).str());
+ EXPECT_EQ("0xff", formatv("{0:x}", 255).str());
+ EXPECT_EQ("0xff", formatv("{0:x+}", 255).str());
+ EXPECT_EQ("FF", formatv("{0:X-}", 255).str());
+ EXPECT_EQ("ff", formatv("{0:x-}", 255).str());
+
+ // 5. Precision pads left of the most significant digit but right of the
+ // prefix (if one exists).
+ EXPECT_EQ("0xFF", formatv("{0:X2}", 255).str());
+ EXPECT_EQ("0xFF", formatv("{0:X+2}", 255).str());
+ EXPECT_EQ("0x0ff", formatv("{0:x3}", 255).str());
+ EXPECT_EQ("0x0ff", formatv("{0:x+3}", 255).str());
+ EXPECT_EQ("00FF", formatv("{0:X-4}", 255).str());
+ EXPECT_EQ("00ff", formatv("{0:x-4}", 255).str());
+
+ // 6. Try some larger types.
+ EXPECT_EQ("0xDEADBEEFDEADBEEF",
+ formatv("{0:X16}", -2401053088876216593LL).str());
+ EXPECT_EQ("0xFEEBDAEDFEEBDAED",
+ formatv("{0:X16}", 0xFEEBDAEDFEEBDAEDULL).str());
+ EXPECT_EQ("0x00000000DEADBEEF", formatv("{0:X16}", 0xDEADBEEF).str());
+
+ // 7. Padding should take into account the prefix
+ EXPECT_EQ("0xff", formatv("{0,4:x}", 255).str());
+ EXPECT_EQ(" 0xff", formatv("{0,5:x+}", 255).str());
+ EXPECT_EQ(" FF", formatv("{0,4:X-}", 255).str());
+ EXPECT_EQ(" ff", formatv("{0,5:x-}", 255).str());
+
+ // 8. Including when it's been zero-padded
+ EXPECT_EQ(" 0x0ff", formatv("{0,7:x3}", 255).str());
+ EXPECT_EQ(" 0x00ff", formatv("{0,7:x+4}", 255).str());
+ EXPECT_EQ(" 000FF", formatv("{0,7:X-5}", 255).str());
+ EXPECT_EQ(" 0000ff", formatv("{0,7:x-6}", 255).str());
+
+ // 9. Precision with default format specifier should work too
+ EXPECT_EQ(" 255", formatv("{0,7:3}", 255).str());
+ EXPECT_EQ(" 0255", formatv("{0,7:4}", 255).str());
+ EXPECT_EQ(" 00255", formatv("{0,7:5}", 255).str());
+ EXPECT_EQ(" 000255", formatv("{0,7:6}", 255).str());
+}
+
+TEST(FormatVariadicTest, PointerFormatting) {
+ // 1. Trivial cases. Hex is default. Default Precision is pointer width.
+ if (sizeof(void *) == 4) {
+ EXPECT_EQ("0x00000000", formatv("{0}", (void *)0).str());
+ EXPECT_EQ("0x00000ABC", formatv("{0}", (void *)0xABC).str());
+ } else {
+ EXPECT_EQ("0x0000000000000000", formatv("{0}", (void *)0).str());
+ EXPECT_EQ("0x0000000000000ABC", formatv("{0}", (void *)0xABC).str());
+ }
+
+ // 2. But we can reduce the precision explicitly.
+ EXPECT_EQ("0x0", formatv("{0:0}", (void *)0).str());
+ EXPECT_EQ("0xABC", formatv("{0:0}", (void *)0xABC).str());
+ EXPECT_EQ("0x0000", formatv("{0:4}", (void *)0).str());
+ EXPECT_EQ("0x0ABC", formatv("{0:4}", (void *)0xABC).str());
+
+ // 3. various hex prefixes.
+ EXPECT_EQ("0x0ABC", formatv("{0:X4}", (void *)0xABC).str());
+ EXPECT_EQ("0x0abc", formatv("{0:x4}", (void *)0xABC).str());
+ EXPECT_EQ("0ABC", formatv("{0:X-4}", (void *)0xABC).str());
+ EXPECT_EQ("0abc", formatv("{0:x-4}", (void *)0xABC).str());
+}
+
+TEST(FormatVariadicTest, IntegralNumberFormatting) {
+ // 1. Test comma grouping with default widths and precisions.
+ EXPECT_EQ("0", formatv("{0:N}", 0).str());
+ EXPECT_EQ("10", formatv("{0:N}", 10).str());
+ EXPECT_EQ("100", formatv("{0:N}", 100).str());
+ EXPECT_EQ("1,000", formatv("{0:N}", 1000).str());
+ EXPECT_EQ("1,234,567,890", formatv("{0:N}", 1234567890).str());
+ EXPECT_EQ("-10", formatv("{0:N}", -10).str());
+ EXPECT_EQ("-100", formatv("{0:N}", -100).str());
+ EXPECT_EQ("-1,000", formatv("{0:N}", -1000).str());
+ EXPECT_EQ("-1,234,567,890", formatv("{0:N}", -1234567890).str());
+
+ // 2. If there is no comma, width and precision pad to the same absolute
+ // size.
+ EXPECT_EQ(" 1", formatv("{0,2:N}", 1).str());
+
+ // 3. But if there is a comma or negative sign, width factors them in but
+ // precision doesn't.
+ EXPECT_EQ(" 1,000", formatv("{0,6:N}", 1000).str());
+ EXPECT_EQ(" -1,000", formatv("{0,7:N}", -1000).str());
+
+ // 4. Large widths all line up.
+ EXPECT_EQ(" 1,000", formatv("{0,11:N}", 1000).str());
+ EXPECT_EQ(" -1,000", formatv("{0,11:N}", -1000).str());
+ EXPECT_EQ(" -100,000", formatv("{0,11:N}", -100000).str());
+}
+
+TEST(FormatVariadicTest, StringFormatting) {
+ const char FooArray[] = "FooArray";
+ const char *FooPtr = "FooPtr";
+ llvm::StringRef FooRef("FooRef");
+ constexpr StringLiteral FooLiteral("FooLiteral");
+ std::string FooString("FooString");
+ // 1. Test that we can print various types of strings.
+ EXPECT_EQ(FooArray, formatv("{0}", FooArray).str());
+ EXPECT_EQ(FooPtr, formatv("{0}", FooPtr).str());
+ EXPECT_EQ(FooRef, formatv("{0}", FooRef).str());
+ EXPECT_EQ(FooLiteral, formatv("{0}", FooLiteral).str());
+ EXPECT_EQ(FooString, formatv("{0}", FooString).str());
+
+ // 2. Test that the precision specifier prints the correct number of
+ // characters.
+ EXPECT_EQ("FooA", formatv("{0:4}", FooArray).str());
+ EXPECT_EQ("FooP", formatv("{0:4}", FooPtr).str());
+ EXPECT_EQ("FooR", formatv("{0:4}", FooRef).str());
+ EXPECT_EQ("FooS", formatv("{0:4}", FooString).str());
+
+ // 3. And that padding works.
+ EXPECT_EQ(" FooA", formatv("{0,6:4}", FooArray).str());
+ EXPECT_EQ(" FooP", formatv("{0,6:4}", FooPtr).str());
+ EXPECT_EQ(" FooR", formatv("{0,6:4}", FooRef).str());
+ EXPECT_EQ(" FooS", formatv("{0,6:4}", FooString).str());
+}
+
+TEST(FormatVariadicTest, CharFormatting) {
+ // 1. Not much to see here. Just print a char with and without padding.
+ EXPECT_EQ("C", formatv("{0}", 'C').str());
+ EXPECT_EQ(" C", formatv("{0,3}", 'C').str());
+
+ // 2. char is really an integral type though, where the only difference is
+ // that the "default" is to print the ASCII. So if a non-default presentation
+ // specifier exists, it should print as an integer.
+ EXPECT_EQ("37", formatv("{0:D}", (char)37).str());
+ EXPECT_EQ(" 037", formatv("{0,5:D3}", (char)37).str());
+}
+
+TEST(FormatVariadicTest, BoolTest) {
+ // 1. Default style is lowercase text (same as 't')
+ EXPECT_EQ("true", formatv("{0}", true).str());
+ EXPECT_EQ("false", formatv("{0}", false).str());
+ EXPECT_EQ("true", formatv("{0:t}", true).str());
+ EXPECT_EQ("false", formatv("{0:t}", false).str());
+
+ // 2. T - uppercase text
+ EXPECT_EQ("TRUE", formatv("{0:T}", true).str());
+ EXPECT_EQ("FALSE", formatv("{0:T}", false).str());
+
+ // 3. D / d - integral
+ EXPECT_EQ("1", formatv("{0:D}", true).str());
+ EXPECT_EQ("0", formatv("{0:D}", false).str());
+ EXPECT_EQ("1", formatv("{0:d}", true).str());
+ EXPECT_EQ("0", formatv("{0:d}", false).str());
+
+ // 4. Y - uppercase yes/no
+ EXPECT_EQ("YES", formatv("{0:Y}", true).str());
+ EXPECT_EQ("NO", formatv("{0:Y}", false).str());
+
+ // 5. y - lowercase yes/no
+ EXPECT_EQ("yes", formatv("{0:y}", true).str());
+ EXPECT_EQ("no", formatv("{0:y}", false).str());
+}
+
+TEST(FormatVariadicTest, DoubleFormatting) {
+ // Test exponents, fixed point, and percent formatting.
+
+ // 1. Signed, unsigned, and zero exponent format.
+ EXPECT_EQ("0.000000E+00", formatv("{0:E}", 0.0).str());
+ EXPECT_EQ("-0.000000E+00", formatv("{0:E}", -0.0).str());
+ EXPECT_EQ("1.100000E+00", formatv("{0:E}", 1.1).str());
+ EXPECT_EQ("-1.100000E+00", formatv("{0:E}", -1.1).str());
+ EXPECT_EQ("1.234568E+03", formatv("{0:E}", 1234.5678).str());
+ EXPECT_EQ("-1.234568E+03", formatv("{0:E}", -1234.5678).str());
+ EXPECT_EQ("1.234568E-03", formatv("{0:E}", .0012345678).str());
+ EXPECT_EQ("-1.234568E-03", formatv("{0:E}", -.0012345678).str());
+
+ // 2. With padding and precision.
+ EXPECT_EQ(" 0.000E+00", formatv("{0,11:E3}", 0.0).str());
+ EXPECT_EQ(" -1.100E+00", formatv("{0,11:E3}", -1.1).str());
+ EXPECT_EQ(" 1.235E+03", formatv("{0,11:E3}", 1234.5678).str());
+ EXPECT_EQ(" -1.235E-03", formatv("{0,11:E3}", -.0012345678).str());
+
+ // 3. Signed, unsigned, and zero fixed point format.
+ EXPECT_EQ("0.00", formatv("{0:F}", 0.0).str());
+ EXPECT_EQ("-0.00", formatv("{0:F}", -0.0).str());
+ EXPECT_EQ("1.10", formatv("{0:F}", 1.1).str());
+ EXPECT_EQ("-1.10", formatv("{0:F}", -1.1).str());
+ EXPECT_EQ("1234.57", formatv("{0:F}", 1234.5678).str());
+ EXPECT_EQ("-1234.57", formatv("{0:F}", -1234.5678).str());
+ EXPECT_EQ("0.00", formatv("{0:F}", .0012345678).str());
+ EXPECT_EQ("-0.00", formatv("{0:F}", -.0012345678).str());
+
+ // 2. With padding and precision.
+ EXPECT_EQ(" 0.000", formatv("{0,8:F3}", 0.0).str());
+ EXPECT_EQ(" -1.100", formatv("{0,8:F3}", -1.1).str());
+ EXPECT_EQ("1234.568", formatv("{0,8:F3}", 1234.5678).str());
+ EXPECT_EQ(" -0.001", formatv("{0,8:F3}", -.0012345678).str());
+}
+
+TEST(FormatVariadicTest, CustomPaddingCharacter) {
+ // 1. Padding with custom character
+ EXPECT_EQ("==123", formatv("{0,=+5}", 123).str());
+ EXPECT_EQ("=123=", formatv("{0,==5}", 123).str());
+ EXPECT_EQ("123==", formatv("{0,=-5}", 123).str());
+
+ // 2. Combined with zero padding
+ EXPECT_EQ("=00123=", formatv("{0,==7:5}", 123).str());
+}
+
+struct format_tuple {
+ const char *Fmt;
+ explicit format_tuple(const char *Fmt) : Fmt(Fmt) {}
+
+ template <typename... Ts>
+ auto operator()(Ts &&... Values) const
+ -> decltype(formatv(Fmt, std::forward<Ts>(Values)...)) {
+ return formatv(Fmt, std::forward<Ts>(Values)...);
+ }
+};
+
+TEST(FormatVariadicTest, BigTest) {
+ using Tuple =
+ std::tuple<char, int, const char *, StringRef, std::string, double, float,
+ void *, int, double, int64_t, uint64_t, double, uint8_t>;
+ Tuple Ts[] = {
+ Tuple('a', 1, "Str", StringRef(), std::string(), 3.14159, -.17532f,
+ (void *)nullptr, 123456, 6.02E23, -908234908423, 908234908422234,
+ std::numeric_limits<double>::quiet_NaN(), 0xAB),
+ Tuple('x', 0xDDB5B, "LongerStr", "StringRef", "std::string", -2.7,
+ .08215f, (void *)nullptr, 0, 6.62E-34, -908234908423,
+ 908234908422234, std::numeric_limits<double>::infinity(), 0x0)};
+ // Test long string formatting with many edge cases combined.
+ const char *Intro =
+ "There are {{{0}} items in the tuple, and {{{1}} tuple(s) in the array.";
+ const char *Header =
+ "{0,6}|{1,8}|{2,=10}|{3,=10}|{4,=13}|{5,7}|{6,7}|{7,10}|{8,"
+ "-7}|{9,10}|{10,16}|{11,17}|{12,6}|{13,4}";
+ const char *Line =
+ "{0,6}|{1,8:X}|{2,=10}|{3,=10:5}|{4,=13}|{5,7:3}|{6,7:P2}|{7,"
+ "10:X8}|{8,-7:N}|{9,10:E4}|{10,16:N}|{11,17:D}|{12,6}|{13,"
+ "4:X}";
+
+ std::string S;
+ llvm::raw_string_ostream Stream(S);
+ Stream << formatv(Intro, std::tuple_size<Tuple>::value,
+ llvm::array_lengthof(Ts))
+ << "\n";
+ Stream << formatv(Header, "Char", "HexInt", "Str", "Ref", "std::str",
+ "double", "float", "pointer", "comma", "exp", "bigint",
+ "bigint2", "limit", "byte")
+ << "\n";
+ for (auto &Item : Ts) {
+ Stream << llvm::apply_tuple(format_tuple(Line), Item) << "\n";
+ }
+ Stream.flush();
+ const char *Expected =
+ R"foo(There are {14} items in the tuple, and {2} tuple(s) in the array.
+ Char| HexInt| Str | Ref | std::str | double| float| pointer|comma | exp| bigint| bigint2| limit|byte
+ a| 0x1| Str | | | 3.142|-17.53%|0x00000000|123,456|6.0200E+23|-908,234,908,423| 908234908422234| nan|0xAB
+ x| 0xDDB5B|LongerStr | Strin | std::string | -2.700| 8.21%|0x00000000|0 |6.6200E-34|-908,234,908,423| 908234908422234| INF| 0x0
+)foo";
+
+ EXPECT_EQ(Expected, S);
+}
+
+TEST(FormatVariadicTest, Range) {
+ std::vector<int> IntRange = {1, 1, 2, 3, 5, 8, 13};
+
+ // 1. Simple range with default separator and element style.
+ EXPECT_EQ("1, 1, 2, 3, 5, 8, 13",
+ formatv("{0}", make_range(IntRange.begin(), IntRange.end())).str());
+ EXPECT_EQ("1, 2, 3, 5, 8",
+ formatv("{0}", make_range(IntRange.begin() + 1, IntRange.end() - 1))
+ .str());
+
+ // 2. Non-default separator
+ EXPECT_EQ(
+ "1/1/2/3/5/8/13",
+ formatv("{0:$[/]}", make_range(IntRange.begin(), IntRange.end())).str());
+
+ // 3. Default separator, non-default element style.
+ EXPECT_EQ(
+ "0x1, 0x1, 0x2, 0x3, 0x5, 0x8, 0xd",
+ formatv("{0:@[x]}", make_range(IntRange.begin(), IntRange.end())).str());
+
+ // 4. Non-default separator and element style.
+ EXPECT_EQ(
+ "0x1 + 0x1 + 0x2 + 0x3 + 0x5 + 0x8 + 0xd",
+ formatv("{0:$[ + ]@[x]}", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+
+ // 5. Element style and/or separator using alternate delimeters to allow using
+ // delimeter characters as part of the separator.
+ EXPECT_EQ(
+ "<0x1><0x1><0x2><0x3><0x5><0x8><0xd>",
+ formatv("<{0:$[><]@(x)}>", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+ EXPECT_EQ(
+ "[0x1][0x1][0x2][0x3][0x5][0x8][0xd]",
+ formatv("[{0:$(][)@[x]}]", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+ EXPECT_EQ(
+ "(0x1)(0x1)(0x2)(0x3)(0x5)(0x8)(0xd)",
+ formatv("({0:$<)(>@<x>})", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+
+ // 5. Empty range.
+ EXPECT_EQ("", formatv("{0:$[+]@[x]}",
+ make_range(IntRange.begin(), IntRange.begin()))
+ .str());
+
+ // 6. Empty separator and style.
+ EXPECT_EQ("11235813",
+ formatv("{0:$[]@<>}", make_range(IntRange.begin(), IntRange.end()))
+ .str());
+}
+
+TEST(FormatVariadicTest, Adapter) {
+ class Negative : public FormatAdapter<int> {
+ public:
+ explicit Negative(int N) : FormatAdapter<int>(std::move(N)) {}
+ void format(raw_ostream &S, StringRef Options) override { S << -Item; }
+ };
+
+ EXPECT_EQ("-7", formatv("{0}", Negative(7)).str());
+
+ int N = 171;
+
+ EXPECT_EQ(" 171 ",
+ formatv("{0}", fmt_align(N, AlignStyle::Center, 7)).str());
+ EXPECT_EQ("--171--",
+ formatv("{0}", fmt_align(N, AlignStyle::Center, 7, '-')).str());
+ EXPECT_EQ(" 171 ", formatv("{0}", fmt_pad(N, 1, 3)).str());
+ EXPECT_EQ("171171171171171", formatv("{0}", fmt_repeat(N, 5)).str());
+
+ EXPECT_EQ(" ABABABABAB ",
+ formatv("{0:X-}", fmt_pad(fmt_repeat(N, 5), 1, 3)).str());
+ EXPECT_EQ(" AB AB AB AB AB ",
+ formatv("{0,=34:X-}", fmt_repeat(fmt_pad(N, 1, 3), 5)).str());
+}
+
+TEST(FormatVariadicTest, MoveConstructor) {
+ auto fmt = formatv("{0} {1}", 1, 2);
+ auto fmt2 = std::move(fmt);
+ std::string S = fmt2;
+ EXPECT_EQ("1 2", S);
+}
+TEST(FormatVariadicTest, ImplicitConversions) {
+ std::string S = formatv("{0} {1}", 1, 2);
+ EXPECT_EQ("1 2", S);
+
+ SmallString<4> S2 = formatv("{0} {1}", 1, 2);
+ EXPECT_EQ("1 2", S2);
+}
+
+TEST(FormatVariadicTest, FormatAdapter) {
+ EXPECT_EQ("Format", formatv("{0}", Format(1)).str());
+
+ Format var(1);
+ EXPECT_EQ("Format", formatv("{0}", var).str());
+ EXPECT_EQ("Format", formatv("{0}", std::move(var)).str());
+
+ // Not supposed to compile
+ // const Format cvar(1);
+ // EXPECT_EQ("Format", formatv("{0}", cvar).str());
+}
+
+TEST(FormatVariadicTest, FormatFormatvObject) {
+ EXPECT_EQ("Format", formatv("F{0}t", formatv("o{0}a", "rm")).str());
+ EXPECT_EQ("[ ! ]", formatv("[{0,+5}]", formatv("{0,-2}", "!")).str());
+}
+
+namespace {
+struct Recorder {
+ int Copied = 0, Moved = 0;
+ Recorder() = default;
+ Recorder(const Recorder &Copy) : Copied(1 + Copy.Copied), Moved(Copy.Moved) {}
+ Recorder(const Recorder &&Move)
+ : Copied(Move.Copied), Moved(1 + Move.Moved) {}
+};
+} // namespace
+namespace llvm {
+template <> struct format_provider<Recorder> {
+ static void format(const Recorder &R, raw_ostream &OS, StringRef style) {
+ OS << R.Copied << "C " << R.Moved << "M";
+ }
+};
+} // namespace
+
+TEST(FormatVariadicTest, CopiesAndMoves) {
+ Recorder R;
+ EXPECT_EQ("0C 0M", formatv("{0}", R).str());
+ EXPECT_EQ("0C 3M", formatv("{0}", std::move(R)).str());
+ EXPECT_EQ("0C 3M", formatv("{0}", Recorder()).str());
+ EXPECT_EQ(0, R.Copied);
+ EXPECT_EQ(0, R.Moved);
+}
+
+namespace adl {
+struct X {};
+raw_ostream &operator<<(raw_ostream &OS, const X &) { return OS << "X"; }
+} // namespace adl
+TEST(FormatVariadicTest, FormatStreamable) {
+ adl::X X;
+ EXPECT_EQ("X", formatv("{0}", X).str());
+}
+
+TEST(FormatVariadicTest, FormatError) {
+ auto E1 = make_error<StringError>("X", inconvertibleErrorCode());
+ EXPECT_EQ("X", formatv("{0}", E1).str());
+ EXPECT_TRUE(E1.isA<StringError>()); // not consumed
+ EXPECT_EQ("X", formatv("{0}", fmt_consume(std::move(E1))).str());
+ EXPECT_FALSE(E1.isA<StringError>()); // consumed
+}
diff --git a/src/llvm-project/llvm/unittests/Support/GlobPatternTest.cpp b/src/llvm-project/llvm/unittests/Support/GlobPatternTest.cpp
new file mode 100644
index 0000000..d7016ab
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/GlobPatternTest.cpp
@@ -0,0 +1,79 @@
+//===- llvm/unittest/Support/GlobPatternTest.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/GlobPattern.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+namespace {
+
+class GlobPatternTest : public ::testing::Test {};
+
+TEST_F(GlobPatternTest, Basics) {
+ Expected<GlobPattern> Pat1 = GlobPattern::create("");
+ EXPECT_TRUE((bool)Pat1);
+ EXPECT_TRUE(Pat1->match(""));
+ EXPECT_FALSE(Pat1->match("a"));
+
+ Expected<GlobPattern> Pat2 = GlobPattern::create("ab*c*def");
+ EXPECT_TRUE((bool)Pat2);
+ EXPECT_TRUE(Pat2->match("abcdef"));
+ EXPECT_TRUE(Pat2->match("abxcxdef"));
+ EXPECT_FALSE(Pat2->match(""));
+ EXPECT_FALSE(Pat2->match("xabcdef"));
+ EXPECT_FALSE(Pat2->match("abcdefx"));
+
+ Expected<GlobPattern> Pat3 = GlobPattern::create("a??c");
+ EXPECT_TRUE((bool)Pat3);
+ EXPECT_TRUE(Pat3->match("axxc"));
+ EXPECT_FALSE(Pat3->match("axxx"));
+ EXPECT_FALSE(Pat3->match(""));
+
+ Expected<GlobPattern> Pat4 = GlobPattern::create("[abc-fy-z]");
+ EXPECT_TRUE((bool)Pat4);
+ EXPECT_TRUE(Pat4->match("a"));
+ EXPECT_TRUE(Pat4->match("b"));
+ EXPECT_TRUE(Pat4->match("c"));
+ EXPECT_TRUE(Pat4->match("d"));
+ EXPECT_TRUE(Pat4->match("e"));
+ EXPECT_TRUE(Pat4->match("f"));
+ EXPECT_TRUE(Pat4->match("y"));
+ EXPECT_TRUE(Pat4->match("z"));
+ EXPECT_FALSE(Pat4->match("g"));
+ EXPECT_FALSE(Pat4->match(""));
+
+ Expected<GlobPattern> Pat5 = GlobPattern::create("[^abc-fy-z]");
+ EXPECT_TRUE((bool)Pat5);
+ EXPECT_TRUE(Pat5->match("g"));
+ EXPECT_FALSE(Pat5->match("a"));
+ EXPECT_FALSE(Pat5->match("b"));
+ EXPECT_FALSE(Pat5->match("c"));
+ EXPECT_FALSE(Pat5->match("d"));
+ EXPECT_FALSE(Pat5->match("e"));
+ EXPECT_FALSE(Pat5->match("f"));
+ EXPECT_FALSE(Pat5->match("y"));
+ EXPECT_FALSE(Pat5->match("z"));
+ EXPECT_FALSE(Pat5->match(""));
+}
+
+TEST_F(GlobPatternTest, Invalid) {
+ Expected<GlobPattern> Pat1 = GlobPattern::create("[");
+ EXPECT_FALSE((bool)Pat1);
+ handleAllErrors(Pat1.takeError(), [&](ErrorInfoBase &EIB) {});
+}
+
+TEST_F(GlobPatternTest, ExtSym) {
+ Expected<GlobPattern> Pat1 = GlobPattern::create("a*\xFF");
+ EXPECT_TRUE((bool)Pat1);
+ EXPECT_TRUE(Pat1->match("axxx\xFF"));
+ Expected<GlobPattern> Pat2 = GlobPattern::create("[\xFF-\xFF]");
+ EXPECT_TRUE((bool)Pat2);
+ EXPECT_TRUE(Pat2->match("\xFF"));
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/Host.cpp b/src/llvm-project/llvm/unittests/Support/Host.cpp
new file mode 100644
index 0000000..0d257a7
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/Host.cpp
@@ -0,0 +1,298 @@
+//========- unittests/Support/Host.cpp - Host.cpp tests --------------========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Host.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
+#include "gtest/gtest.h"
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
+using namespace llvm;
+
+class HostTest : public testing::Test {
+ Triple Host;
+
+protected:
+ bool isSupportedArchAndOS() {
+ // Initially this is only testing detection of the number of
+ // physical cores, which is currently only supported/tested for
+ // x86_64 Linux and Darwin.
+ return (Host.getArch() == Triple::x86_64 &&
+ (Host.isOSDarwin() || Host.getOS() == Triple::Linux));
+ }
+
+ HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {}
+};
+
+TEST_F(HostTest, NumPhysicalCores) {
+ int Num = sys::getHostNumPhysicalCores();
+
+ if (isSupportedArchAndOS())
+ ASSERT_GT(Num, 0);
+ else
+ ASSERT_EQ(Num, -1);
+}
+
+TEST(getLinuxHostCPUName, ARM) {
+ StringRef CortexA9ProcCpuinfo = R"(
+processor : 0
+model name : ARMv7 Processor rev 10 (v7l)
+BogoMIPS : 1393.66
+Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x2
+CPU part : 0xc09
+CPU revision : 10
+
+processor : 1
+model name : ARMv7 Processor rev 10 (v7l)
+BogoMIPS : 1393.66
+Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant : 0x2
+CPU part : 0xc09
+CPU revision : 10
+
+Hardware : Generic OMAP4 (Flattened Device Tree)
+Revision : 0000
+Serial : 0000000000000000
+)";
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(CortexA9ProcCpuinfo),
+ "cortex-a9");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
+ "CPU part : 0xc0f"),
+ "cortex-a15");
+ // Verify that both CPU implementer and CPU part are checked:
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
+ "CPU part : 0xc0f"),
+ "generic");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x06f"),
+ "krait");
+}
+
+TEST(getLinuxHostCPUName, AArch64) {
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
+ "CPU part : 0xd03"),
+ "cortex-a53");
+ // Verify that both CPU implementer and CPU part are checked:
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
+ "CPU part : 0xd03"),
+ "generic");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x201"),
+ "kryo");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x800"),
+ "cortex-a73");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0x801"),
+ "cortex-a73");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0xc00"),
+ "falkor");
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
+ "CPU part : 0xc01"),
+ "saphira");
+
+ // MSM8992/4 weirdness
+ StringRef MSM8992ProcCpuInfo = R"(
+Processor : AArch64 Processor rev 3 (aarch64)
+processor : 0
+processor : 1
+processor : 2
+processor : 3
+processor : 4
+processor : 5
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x41
+CPU architecture: 8
+CPU variant : 0x0
+CPU part : 0xd03
+CPU revision : 3
+
+Hardware : Qualcomm Technologies, Inc MSM8992
+)";
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo),
+ "cortex-a53");
+
+ // Exynos big.LITTLE weirdness
+ const std::string ExynosProcCpuInfo = R"(
+processor : 0
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x41
+CPU architecture: 8
+CPU variant : 0x0
+CPU part : 0xd03
+
+processor : 1
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x53
+CPU architecture: 8
+)";
+
+ // Verify default for Exynos.
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
+ "CPU variant : 0xc\n"
+ "CPU part : 0xafe"),
+ "exynos-m1");
+ // Verify Exynos M1.
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
+ "CPU variant : 0x1\n"
+ "CPU part : 0x001"),
+ "exynos-m1");
+ // Verify Exynos M2.
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
+ "CPU variant : 0x4\n"
+ "CPU part : 0x001"),
+ "exynos-m2");
+
+ const std::string ThunderX2T99ProcCpuInfo = R"(
+processor : 0
+BogoMIPS : 400.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
+CPU implementer : 0x43
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x0af
+)";
+
+ // Verify different versions of ThunderX2T99.
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x42\n"
+ "CPU part : 0x516"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x42\n"
+ "CPU part : 0x0516"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0x516"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0x0516"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x42\n"
+ "CPU part : 0xaf"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x42\n"
+ "CPU part : 0x0af"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0xaf"),
+ "thunderx2t99");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0x0af"),
+ "thunderx2t99");
+
+ // Verify ThunderXT88.
+ const std::string ThunderXT88ProcCpuInfo = R"(
+processor : 0
+BogoMIPS : 200.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x43
+CPU architecture: 8
+CPU variant : 0x1
+CPU part : 0x0a1
+)";
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0x0a1"),
+ "thunderxt88");
+
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
+ "CPU implementer : 0x43\n"
+ "CPU part : 0xa1"),
+ "thunderxt88");
+
+ // Verify HiSilicon processors.
+ EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x48\n"
+ "CPU part : 0xd01"),
+ "tsv110");
+}
+
+#if defined(__APPLE__)
+TEST_F(HostTest, getMacOSHostVersion) {
+ using namespace llvm::sys;
+ llvm::Triple HostTriple(getProcessTriple());
+ if (!HostTriple.isMacOSX())
+ return;
+
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(fs::createUniqueDirectory("host_test", TestDirectory));
+ SmallString<128> OutputFile(TestDirectory);
+ path::append(OutputFile, "out");
+
+ const char *SwVersPath = "/usr/bin/sw_vers";
+ StringRef argv[] = {SwVersPath, "-productVersion"};
+ StringRef OutputPath = OutputFile.str();
+ const Optional<StringRef> Redirects[] = {/*STDIN=*/None,
+ /*STDOUT=*/OutputPath,
+ /*STDERR=*/None};
+ int RetCode = ExecuteAndWait(SwVersPath, argv, /*env=*/llvm::None, Redirects);
+ ASSERT_EQ(0, RetCode);
+
+ int FD = 0;
+ ASSERT_NO_ERROR(fs::openFileForRead(OutputPath, FD));
+ off_t Size = ::lseek(FD, 0, SEEK_END);
+ ASSERT_NE(-1, Size);
+ ::lseek(FD, 0, SEEK_SET);
+ std::unique_ptr<char[]> Buffer = llvm::make_unique<char[]>(Size);
+ ASSERT_EQ(::read(FD, Buffer.get(), Size), Size);
+ ::close(FD);
+
+ // Ensure that the two versions match.
+ StringRef SystemVersion(Buffer.get(), Size);
+ unsigned SystemMajor, SystemMinor, SystemMicro;
+ ASSERT_EQ(llvm::Triple((Twine("x86_64-apple-macos") + SystemVersion))
+ .getMacOSXVersion(SystemMajor, SystemMinor, SystemMicro),
+ true);
+ unsigned HostMajor, HostMinor, HostMicro;
+ ASSERT_EQ(HostTriple.getMacOSXVersion(HostMajor, HostMinor, HostMicro), true);
+
+ // Don't compare the 'Micro' version, as it's always '0' for the 'Darwin'
+ // triples.
+ ASSERT_EQ(std::tie(SystemMajor, SystemMinor), std::tie(HostMajor, HostMinor));
+
+ ASSERT_NO_ERROR(fs::remove(OutputPath));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp b/src/llvm-project/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp
new file mode 100644
index 0000000..2fd6bd8
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ItaniumManglingCanonicalizerTest.cpp
@@ -0,0 +1,377 @@
+//===-------------- ItaniumManglingCanonicalizerTest.cpp ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ItaniumManglingCanonicalizer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+
+#include <cstdlib>
+#include <map>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError;
+using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind;
+
+struct Equivalence {
+ FragmentKind Kind;
+ llvm::StringRef First;
+ llvm::StringRef Second;
+};
+
+// A set of manglings that should all be considered equivalent.
+using EquivalenceClass = std::vector<llvm::StringRef>;
+
+struct Testcase {
+ // A set of equivalences to register.
+ std::vector<Equivalence> Equivalences;
+ // A set of distinct equivalence classes created by registering the
+ // equivalences.
+ std::vector<EquivalenceClass> Classes;
+};
+
+// A function that returns a set of test cases.
+static std::vector<Testcase> getTestcases() {
+ return {
+ // Three different manglings for std::string (old libstdc++, new libstdc++,
+ // libc++).
+ {
+ {
+ {FragmentKind::Type, "Ss",
+ "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"},
+ {FragmentKind::Type, "Ss",
+ "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ },
+ {
+ {"_Z1fv"},
+ {"_Z1fSs",
+ "_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",
+ "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ {"_ZNKSs4sizeEv",
+ "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv",
+ "_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv"},
+ }
+ },
+
+ // Check that substitutions are properly handled.
+ {
+ {
+ // ::X <-> ::N::X<int>
+ {FragmentKind::Type, "1X", "N1N1XIiEE"},
+ // ::T<T<int, int>, T<int, int>> <-> T<int>
+ {FragmentKind::Type, "1TIS_IiiES0_E", "1TIiE"},
+ // A::B::foo <-> AB::foo
+ {FragmentKind::Name, "N1A1B3fooE", "N2AB3fooE"},
+ },
+ {
+ {"_Z1f1XPS_RS_", "_Z1fN1N1XIiEEPS1_RS1_"},
+ {"_ZN1A1B3fooE1TIS1_IiiES2_EPS3_RS3_", "_ZN2AB3fooE1TIiEPS1_RS1_"},
+ }
+ },
+
+ // Check that nested equivalences are properly handled.
+ {
+ {
+ // std::__1::char_traits == std::__cxx11::char_traits
+ // (Note that this is unused and should make no difference,
+ // but it should not cause us to fail to match up the cases
+ // below.)
+ {FragmentKind::Name,
+ "NSt3__111char_traitsE",
+ "NSt7__cxx1111char_traitsE"},
+ // std::__1::allocator == std::allocator
+ {FragmentKind::Name,
+ "NSt3__19allocatorE",
+ "Sa"}, // "Sa" is not strictly a <name> but we accept it as one.
+ // std::__1::vector == std::vector
+ {FragmentKind::Name,
+ "St6vector",
+ "NSt3__16vectorE"},
+ // std::__1::basic_string<
+ // char
+ // std::__1::char_traits<char>,
+ // std::__1::allocator<char>> ==
+ // std::__cxx11::basic_string<
+ // char,
+ // std::char_traits<char>,
+ // std::allocator<char>>
+ {FragmentKind::Type,
+ "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",
+ "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ // X<A> <-> X<B>
+ {FragmentKind::Type, "1XI1AE", "1XI1BE"},
+ // X <-> Y
+ {FragmentKind::Name, "1X", "1Y"},
+ },
+ {
+ // f(std::string)
+ {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",
+ "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ // f(std::vector<int>)
+ {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},
+ // f(X<A>), f(X<B>), f(Y<A>), f(Y<B>)
+ {"_Z1f1XI1AE", "_Z1f1XI1BE", "_Z1f1YI1AE", "_Z1f1YI1BE"},
+ // f(X<C>), f(Y<C>)
+ {"_Z1f1XI1CE", "_Z1f1YI1CE"},
+ }
+ },
+
+ // Check namespace equivalences.
+ {
+ {
+ // std::__1 == std::__cxx11
+ {FragmentKind::Name, "St3__1", "St7__cxx11"},
+ // std::__1::allocator == std::allocator
+ {FragmentKind::Name, "NSt3__19allocatorE", "Sa"},
+ // std::vector == std::__1::vector
+ {FragmentKind::Name, "St6vector", "NSt3__16vectorE"},
+ // std::__cxx11::char_traits == std::char_traits
+ // (This indirectly means that std::__1::char_traits == std::char_traits,
+ // due to the std::__cxx11 == std::__1 equivalence, which is what we rely
+ // on below.)
+ {FragmentKind::Name, "NSt7__cxx1111char_traitsE", "St11char_traits"},
+ },
+ {
+ // f(std::foo)
+ {"_Z1fNSt7__cxx113fooE",
+ "_Z1fNSt3__13fooE"},
+ // f(std::string)
+ {"_Z1fNSt7__cxx1111char_traitsIcEE",
+ "_Z1fNSt3__111char_traitsIcEE",
+ "_Z1fSt11char_traitsIcE"},
+ // f(std::string)
+ {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",
+ "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ // f(std::vector<int>)
+ {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},
+ }
+ },
+
+ // Check namespace equivalences for namespace 'std'. We support using 'St'
+ // for this, despite it not technically being a <name>.
+ {
+ {
+ // std::__1 == std
+ {FragmentKind::Name, "St3__1", "St"},
+ // std::__1 == std::__cxx11
+ {FragmentKind::Name, "St3__1", "St7__cxx11"},
+ // FIXME: Should a 'std' equivalence also cover the predefined
+ // substitutions?
+ // std::__1::allocator == std::allocator
+ {FragmentKind::Name, "NSt3__19allocatorE", "Sa"},
+ },
+ {
+ {"_Z1fSt3foo", "_Z1fNSt3__13fooE", "_Z1fNSt7__cxx113fooE"},
+ {"_Z1fNSt3bar3bazE", "_Z1fNSt3__13bar3bazE"},
+ // f(std::string)
+ {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",
+ "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},
+ // f(std::vector<int>)
+ {"_Z1fSt6vectorIiSaIiEE", "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},
+ }
+ },
+
+ // Check mutually-recursive equivalences.
+ {
+ {
+ {FragmentKind::Type, "1A", "1B"},
+ {FragmentKind::Type, "1A", "1C"},
+ {FragmentKind::Type, "1D", "1B"},
+ {FragmentKind::Type, "1C", "1E"},
+ },
+ {
+ {"_Z1f1A", "_Z1f1B", "_Z1f1C", "_Z1f1D", "_Z1f1E"},
+ {"_Z1f1F"},
+ }
+ },
+
+ // Check <encoding>s.
+ {
+ {
+ {FragmentKind::Encoding, "1fv", "1gv"},
+ },
+ {
+ // f(void) -> g(void)
+ {"_Z1fv", "_Z1gv"},
+ // static local 'n' in f(void) -> static local 'n' in g(void)
+ {"_ZZ1fvE1n", "_ZZ1gvE1n"},
+ }
+ },
+
+ // Corner case: the substitution can appear within its own expansion.
+ {
+ {
+ // X <-> Y<X>
+ {FragmentKind::Type, "1X", "1YI1XE"},
+ // A<B> <-> B
+ {FragmentKind::Type, "1AI1BE", "1B"},
+ },
+ {
+ // f(X) == f(Y<X>) == f(Y<Y<X>>) == f(Y<Y<Y<X>>>)
+ {"_Z1f1X", "_Z1f1YI1XE", "_Z1f1YIS_I1XEE", "_Z1f1YIS_IS_I1XEEE"},
+ // f(B) == f(A<B>) == f(A<A<B>>) == f(A<A<A<B>>>)
+ {"_Z1f1B", "_Z1f1AI1BE", "_Z1f1AIS_I1BEE", "_Z1f1AIS_IS_I1BEEE"},
+ }
+ },
+
+ // Redundant equivalences are accepted (and have no effect).
+ {
+ {
+ {FragmentKind::Name, "3std", "St"},
+ {FragmentKind::Name, "1X", "1Y"},
+ {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"},
+ },
+ {}
+ },
+
+ // Check that ctor and dtor variants are considered distinct.
+ {
+ {},
+ {{"_ZN1XC1Ev"}, {"_ZN1XC2Ev"}, {"_ZN1XD1Ev"}, {"_ZN1XD2Ev"}}
+ },
+
+ // Ensure array types with and without bounds are handled properly.
+ {
+ {
+ {FragmentKind::Type, "A_i", "A1_f"},
+ },
+ {
+ {"_Z1fRA_i", "_Z1fRA_i", "_Z1fRA1_f"},
+ {"_Z1fRA1_i"}, {"_Z1fRA_f"},
+ }
+ },
+ };
+}
+
+// A function to get a set of test cases for forward template references.
+static std::vector<Testcase> getForwardTemplateReferenceTestcases() {
+ return {
+ // ForwardTemplateReference does not support canonicalization.
+ // FIXME: We should consider ways of fixing this, perhaps by eliminating
+ // the ForwardTemplateReference node with a tree transformation.
+ {
+ {
+ // X::operator T() <with T = A> == Y::operator T() <with T = A>
+ {FragmentKind::Encoding, "N1XcvT_I1AEEv", "N1YcvT_I1AEEv"},
+ // A == B
+ {FragmentKind::Name, "1A", "1B"},
+ },
+ {
+ // All combinations result in unique equivalence classes.
+ {"_ZN1XcvT_I1AEEv"},
+ {"_ZN1XcvT_I1BEEv"},
+ {"_ZN1YcvT_I1AEEv"},
+ {"_ZN1YcvT_I1BEEv"},
+ // Even giving the same string twice gives a new class.
+ {"_ZN1XcvT_I1AEEv"},
+ }
+ },
+ };
+}
+
+template<bool CanonicalizeFirst>
+static void testTestcases(ArrayRef<Testcase> Testcases) {
+ for (const auto &Testcase : Testcases) {
+ llvm::ItaniumManglingCanonicalizer Canonicalizer;
+ for (const auto &Equiv : Testcase.Equivalences) {
+ auto Result =
+ Canonicalizer.addEquivalence(Equiv.Kind, Equiv.First, Equiv.Second);
+ EXPECT_EQ(Result, EquivalenceError::Success)
+ << "couldn't add equivalence between " << Equiv.First << " and "
+ << Equiv.Second;
+ }
+
+ using CanonKey = llvm::ItaniumManglingCanonicalizer::Key;
+
+ std::map<const EquivalenceClass*, CanonKey> Keys;
+ if (CanonicalizeFirst)
+ for (const auto &Class : Testcase.Classes)
+ Keys.insert({&Class, Canonicalizer.canonicalize(*Class.begin())});
+
+ std::map<CanonKey, llvm::StringRef> Found;
+ for (const auto &Class : Testcase.Classes) {
+ CanonKey ClassKey = Keys[&Class];
+ for (llvm::StringRef Str : Class) {
+ // Force a copy to be made when calling lookup to test that it doesn't
+ // retain any part of the provided string.
+ CanonKey ThisKey = CanonicalizeFirst
+ ? Canonicalizer.lookup(std::string(Str))
+ : Canonicalizer.canonicalize(Str);
+ EXPECT_NE(ThisKey, CanonKey()) << "couldn't canonicalize " << Str;
+ if (ClassKey) {
+ EXPECT_EQ(ThisKey, ClassKey)
+ << Str << " not in the same class as " << *Class.begin();
+ } else {
+ ClassKey = ThisKey;
+ }
+ }
+ EXPECT_TRUE(Found.insert({ClassKey, *Class.begin()}).second)
+ << *Class.begin() << " is in the same class as " << Found[ClassKey];
+ }
+ }
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) {
+ testTestcases<false>(getTestcases());
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestLookup) {
+ testTestcases<true>(getTestcases());
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) {
+ // lookup(...) after canonicalization (intentionally) returns different
+ // values for this testcase.
+ testTestcases<false>(getForwardTemplateReferenceTestcases());
+}
+
+
+TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) {
+ llvm::ItaniumManglingCanonicalizer Canonicalizer;
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "", "1X"),
+ EquivalenceError::InvalidFirstMangling);
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1X", "1ab"),
+ EquivalenceError::InvalidSecondMangling);
+ EXPECT_EQ(Canonicalizer.canonicalize("_Z3fooE"),
+ llvm::ItaniumManglingCanonicalizer::Key());
+ EXPECT_EQ(Canonicalizer.canonicalize("foo"),
+ llvm::ItaniumManglingCanonicalizer::Key());
+
+ // A reference to a template parameter ('T_' etc) cannot appear in a <name>,
+ // because we don't have template arguments to bind to it. (The arguments in
+ // an 'I ... E' construct in the <name> aren't registered as
+ // backreferenceable arguments in this sense, because they're not part of
+ // the template argument list of an <encoding>.
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Name, "N1XcvT_I1AEE",
+ "1f"),
+ EquivalenceError::InvalidFirstMangling);
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestBadEquivalenceOrder) {
+ llvm::ItaniumManglingCanonicalizer Canonicalizer;
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1P1XE", "N1Q1XE"),
+ EquivalenceError::Success);
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1P", "1Q"),
+ EquivalenceError::ManglingAlreadyUsed);
+
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1C1XE", "N1A1YE"),
+ EquivalenceError::Success);
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1A", "1B"),
+ EquivalenceError::Success);
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1C", "1D"),
+ EquivalenceError::Success);
+ EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1B", "1D"),
+ EquivalenceError::ManglingAlreadyUsed);
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/JSONTest.cpp b/src/llvm-project/llvm/unittests/Support/JSONTest.cpp
new file mode 100644
index 0000000..9f2d47b
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/JSONTest.cpp
@@ -0,0 +1,389 @@
+//===-- JSONTest.cpp - JSON unit tests --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/JSON.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace json {
+
+namespace {
+
+std::string s(const Value &E) { return llvm::formatv("{0}", E).str(); }
+std::string sp(const Value &E) { return llvm::formatv("{0:2}", E).str(); }
+
+TEST(JSONTest, Types) {
+ EXPECT_EQ("true", s(true));
+ EXPECT_EQ("null", s(nullptr));
+ EXPECT_EQ("2.5", s(2.5));
+ EXPECT_EQ(R"("foo")", s("foo"));
+ EXPECT_EQ("[1,2,3]", s({1, 2, 3}));
+ EXPECT_EQ(R"({"x":10,"y":20})", s(Object{{"x", 10}, {"y", 20}}));
+
+#ifdef NDEBUG
+ EXPECT_EQ(R"("��")", s("\xC0\x80"));
+ EXPECT_EQ(R"({"��":0})", s(Object{{"\xC0\x80", 0}}));
+#else
+ EXPECT_DEATH(s("\xC0\x80"), "Invalid UTF-8");
+ EXPECT_DEATH(s(Object{{"\xC0\x80", 0}}), "Invalid UTF-8");
+#endif
+}
+
+TEST(JSONTest, Constructors) {
+ // Lots of edge cases around empty and singleton init lists.
+ EXPECT_EQ("[[[3]]]", s({{{3}}}));
+ EXPECT_EQ("[[[]]]", s({{{}}}));
+ EXPECT_EQ("[[{}]]", s({{Object{}}}));
+ EXPECT_EQ(R"({"A":{"B":{}}})", s(Object{{"A", Object{{"B", Object{}}}}}));
+ EXPECT_EQ(R"({"A":{"B":{"X":"Y"}}})",
+ s(Object{{"A", Object{{"B", Object{{"X", "Y"}}}}}}));
+ EXPECT_EQ("null", s(llvm::Optional<double>()));
+ EXPECT_EQ("2.5", s(llvm::Optional<double>(2.5)));
+ EXPECT_EQ("[[2.5,null]]", s(std::vector<std::vector<llvm::Optional<double>>>{
+ {2.5, llvm::None}}));
+}
+
+TEST(JSONTest, StringOwnership) {
+ char X[] = "Hello";
+ Value Alias = static_cast<const char *>(X);
+ X[1] = 'a';
+ EXPECT_EQ(R"("Hallo")", s(Alias));
+
+ std::string Y = "Hello";
+ Value Copy = Y;
+ Y[1] = 'a';
+ EXPECT_EQ(R"("Hello")", s(Copy));
+}
+
+TEST(JSONTest, CanonicalOutput) {
+ // Objects are sorted (but arrays aren't)!
+ EXPECT_EQ(R"({"a":1,"b":2,"c":3})", s(Object{{"a", 1}, {"c", 3}, {"b", 2}}));
+ EXPECT_EQ(R"(["a","c","b"])", s({"a", "c", "b"}));
+ EXPECT_EQ("3", s(3.0));
+}
+
+TEST(JSONTest, Escaping) {
+ std::string test = {
+ 0, // Strings may contain nulls.
+ '\b', '\f', // Have mnemonics, but we escape numerically.
+ '\r', '\n', '\t', // Escaped with mnemonics.
+ 'S', '\"', '\\', // Printable ASCII characters.
+ '\x7f', // Delete is not escaped.
+ '\xce', '\x94', // Non-ASCII UTF-8 is not escaped.
+ };
+
+ std::string teststring = R"("\u0000\u0008\u000c\r\n\tS\"\\)"
+ "\x7f\xCE\x94\"";
+
+ EXPECT_EQ(teststring, s(test));
+
+ EXPECT_EQ(R"({"object keys are\nescaped":true})",
+ s(Object{{"object keys are\nescaped", true}}));
+}
+
+TEST(JSONTest, PrettyPrinting) {
+ const char str[] = R"({
+ "empty_array": [],
+ "empty_object": {},
+ "full_array": [
+ 1,
+ null
+ ],
+ "full_object": {
+ "nested_array": [
+ {
+ "property": "value"
+ }
+ ]
+ }
+})";
+
+ EXPECT_EQ(str, sp(Object{
+ {"empty_object", Object{}},
+ {"empty_array", {}},
+ {"full_array", {1, nullptr}},
+ {"full_object",
+ Object{
+ {"nested_array",
+ {Object{
+ {"property", "value"},
+ }}},
+ }},
+ }));
+}
+
+TEST(JSONTest, Parse) {
+ auto Compare = [](llvm::StringRef S, Value Expected) {
+ if (auto E = parse(S)) {
+ // Compare both string forms and with operator==, in case we have bugs.
+ EXPECT_EQ(*E, Expected);
+ EXPECT_EQ(sp(*E), sp(Expected));
+ } else {
+ handleAllErrors(E.takeError(), [S](const llvm::ErrorInfoBase &E) {
+ FAIL() << "Failed to parse JSON >>> " << S << " <<<: " << E.message();
+ });
+ }
+ };
+
+ Compare(R"(true)", true);
+ Compare(R"(false)", false);
+ Compare(R"(null)", nullptr);
+
+ Compare(R"(42)", 42);
+ Compare(R"(2.5)", 2.5);
+ Compare(R"(2e50)", 2e50);
+ Compare(R"(1.2e3456789)", std::numeric_limits<double>::infinity());
+
+ Compare(R"("foo")", "foo");
+ Compare(R"("\"\\\b\f\n\r\t")", "\"\\\b\f\n\r\t");
+ Compare(R"("\u0000")", llvm::StringRef("\0", 1));
+ Compare("\"\x7f\"", "\x7f");
+ Compare(R"("\ud801\udc37")", u8"\U00010437"); // UTF16 surrogate pair escape.
+ Compare("\"\xE2\x82\xAC\xF0\x9D\x84\x9E\"", u8"\u20ac\U0001d11e"); // UTF8
+ Compare(
+ R"("LoneLeading=\ud801, LoneTrailing=\udc01, LeadingLeadingTrailing=\ud801\ud801\udc37")",
+ u8"LoneLeading=\ufffd, LoneTrailing=\ufffd, "
+ u8"LeadingLeadingTrailing=\ufffd\U00010437"); // Invalid unicode.
+
+ Compare(R"({"":0,"":0})", Object{{"", 0}});
+ Compare(R"({"obj":{},"arr":[]})", Object{{"obj", Object{}}, {"arr", {}}});
+ Compare(R"({"\n":{"\u0000":[[[[]]]]}})",
+ Object{{"\n", Object{
+ {llvm::StringRef("\0", 1), {{{{}}}}},
+ }}});
+ Compare("\r[\n\t] ", {});
+}
+
+TEST(JSONTest, ParseErrors) {
+ auto ExpectErr = [](llvm::StringRef Msg, llvm::StringRef S) {
+ if (auto E = parse(S)) {
+ // Compare both string forms and with operator==, in case we have bugs.
+ FAIL() << "Parsed JSON >>> " << S << " <<< but wanted error: " << Msg;
+ } else {
+ handleAllErrors(E.takeError(), [S, Msg](const llvm::ErrorInfoBase &E) {
+ EXPECT_THAT(E.message(), testing::HasSubstr(Msg)) << S;
+ });
+ }
+ };
+ ExpectErr("Unexpected EOF", "");
+ ExpectErr("Unexpected EOF", "[");
+ ExpectErr("Text after end of document", "[][]");
+ ExpectErr("Invalid JSON value (false?)", "fuzzy");
+ ExpectErr("Expected , or ]", "[2?]");
+ ExpectErr("Expected object key", "{a:2}");
+ ExpectErr("Expected : after object key", R"({"a",2})");
+ ExpectErr("Expected , or } after object property", R"({"a":2 "b":3})");
+ ExpectErr("Invalid JSON value", R"([&%!])");
+ ExpectErr("Invalid JSON value (number?)", "1e1.0");
+ ExpectErr("Unterminated string", R"("abc\"def)");
+ ExpectErr("Control character in string", "\"abc\ndef\"");
+ ExpectErr("Invalid escape sequence", R"("\030")");
+ ExpectErr("Invalid \\u escape sequence", R"("\usuck")");
+ ExpectErr("[3:3, byte=19]", R"({
+ "valid": 1,
+ invalid: 2
+})");
+ ExpectErr("Invalid UTF-8 sequence", "\"\xC0\x80\""); // WTF-8 null
+}
+
+// Direct tests of isUTF8 and fixUTF8. Internal uses are also tested elsewhere.
+TEST(JSONTest, UTF8) {
+ for (const char *Valid : {
+ "this is ASCII text",
+ "thïs tëxt häs BMP chäräctërs",
+ "𐌶𐌰L𐌾𐍈 C𐍈𐌼𐌴𐍃",
+ }) {
+ EXPECT_TRUE(isUTF8(Valid)) << Valid;
+ EXPECT_EQ(fixUTF8(Valid), Valid);
+ }
+ for (auto Invalid : std::vector<std::pair<const char *, const char *>>{
+ {"lone trailing \x81\x82 bytes", "lone trailing �� bytes"},
+ {"missing trailing \xD0 bytes", "missing trailing � bytes"},
+ {"truncated character \xD0", "truncated character �"},
+ {"not \xC1\x80 the \xE0\x9f\xBF shortest \xF0\x83\x83\x83 encoding",
+ "not �� the ��� shortest ���� encoding"},
+ {"too \xF9\x80\x80\x80\x80 long", "too ����� long"},
+ {"surrogate \xED\xA0\x80 invalid \xF4\x90\x80\x80",
+ "surrogate ��� invalid ����"}}) {
+ EXPECT_FALSE(isUTF8(Invalid.first)) << Invalid.first;
+ EXPECT_EQ(fixUTF8(Invalid.first), Invalid.second);
+ }
+}
+
+TEST(JSONTest, Inspection) {
+ llvm::Expected<Value> Doc = parse(R"(
+ {
+ "null": null,
+ "boolean": false,
+ "number": 2.78,
+ "string": "json",
+ "array": [null, true, 3.14, "hello", [1,2,3], {"time": "arrow"}],
+ "object": {"fruit": "banana"}
+ }
+ )");
+ EXPECT_TRUE(!!Doc);
+
+ Object *O = Doc->getAsObject();
+ ASSERT_TRUE(O);
+
+ EXPECT_FALSE(O->getNull("missing"));
+ EXPECT_FALSE(O->getNull("boolean"));
+ EXPECT_TRUE(O->getNull("null"));
+
+ EXPECT_EQ(O->getNumber("number"), llvm::Optional<double>(2.78));
+ EXPECT_FALSE(O->getInteger("number"));
+ EXPECT_EQ(O->getString("string"), llvm::Optional<llvm::StringRef>("json"));
+ ASSERT_FALSE(O->getObject("missing"));
+ ASSERT_FALSE(O->getObject("array"));
+ ASSERT_TRUE(O->getObject("object"));
+ EXPECT_EQ(*O->getObject("object"), (Object{{"fruit", "banana"}}));
+
+ Array *A = O->getArray("array");
+ ASSERT_TRUE(A);
+ EXPECT_EQ((*A)[1].getAsBoolean(), llvm::Optional<bool>(true));
+ ASSERT_TRUE((*A)[4].getAsArray());
+ EXPECT_EQ(*(*A)[4].getAsArray(), (Array{1, 2, 3}));
+ EXPECT_EQ((*(*A)[4].getAsArray())[1].getAsInteger(),
+ llvm::Optional<int64_t>(2));
+ int I = 0;
+ for (Value &E : *A) {
+ if (I++ == 5) {
+ ASSERT_TRUE(E.getAsObject());
+ EXPECT_EQ(E.getAsObject()->getString("time"),
+ llvm::Optional<llvm::StringRef>("arrow"));
+ } else
+ EXPECT_FALSE(E.getAsObject());
+ }
+}
+
+// Verify special integer handling - we try to preserve exact int64 values.
+TEST(JSONTest, Integers) {
+ struct {
+ const char *Desc;
+ Value Val;
+ const char *Str;
+ llvm::Optional<int64_t> AsInt;
+ llvm::Optional<double> AsNumber;
+ } TestCases[] = {
+ {
+ "Non-integer. Stored as double, not convertible.",
+ double{1.5},
+ "1.5",
+ llvm::None,
+ 1.5,
+ },
+
+ {
+ "Integer, not exact double. Stored as int64, convertible.",
+ int64_t{0x4000000000000001},
+ "4611686018427387905",
+ int64_t{0x4000000000000001},
+ double{0x4000000000000000},
+ },
+
+ {
+ "Negative integer, not exact double. Stored as int64, convertible.",
+ int64_t{-0x4000000000000001},
+ "-4611686018427387905",
+ int64_t{-0x4000000000000001},
+ double{-0x4000000000000000},
+ },
+
+ {
+ "Dynamically exact integer. Stored as double, convertible.",
+ double{0x6000000000000000},
+ "6.9175290276410819e+18",
+ int64_t{0x6000000000000000},
+ double{0x6000000000000000},
+ },
+
+ {
+ "Dynamically integer, >64 bits. Stored as double, not convertible.",
+ 1.5 * double{0x8000000000000000},
+ "1.3835058055282164e+19",
+ llvm::None,
+ 1.5 * double{0x8000000000000000},
+ },
+ };
+ for (const auto &T : TestCases) {
+ EXPECT_EQ(T.Str, s(T.Val)) << T.Desc;
+ llvm::Expected<Value> Doc = parse(T.Str);
+ EXPECT_TRUE(!!Doc) << T.Desc;
+ EXPECT_EQ(Doc->getAsInteger(), T.AsInt) << T.Desc;
+ EXPECT_EQ(Doc->getAsNumber(), T.AsNumber) << T.Desc;
+ EXPECT_EQ(T.Val, *Doc) << T.Desc;
+ EXPECT_EQ(T.Str, s(*Doc)) << T.Desc;
+ }
+}
+
+// Sample struct with typical JSON-mapping rules.
+struct CustomStruct {
+ CustomStruct() : B(false) {}
+ CustomStruct(std::string S, llvm::Optional<int> I, bool B)
+ : S(S), I(I), B(B) {}
+ std::string S;
+ llvm::Optional<int> I;
+ bool B;
+};
+inline bool operator==(const CustomStruct &L, const CustomStruct &R) {
+ return L.S == R.S && L.I == R.I && L.B == R.B;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const CustomStruct &S) {
+ return OS << "(" << S.S << ", " << (S.I ? std::to_string(*S.I) : "None")
+ << ", " << S.B << ")";
+}
+bool fromJSON(const Value &E, CustomStruct &R) {
+ ObjectMapper O(E);
+ if (!O || !O.map("str", R.S) || !O.map("int", R.I))
+ return false;
+ O.map("bool", R.B);
+ return true;
+}
+
+TEST(JSONTest, Deserialize) {
+ std::map<std::string, std::vector<CustomStruct>> R;
+ CustomStruct ExpectedStruct = {"foo", 42, true};
+ std::map<std::string, std::vector<CustomStruct>> Expected;
+ Value J = Object{
+ {"foo",
+ Array{
+ Object{
+ {"str", "foo"},
+ {"int", 42},
+ {"bool", true},
+ {"unknown", "ignored"},
+ },
+ Object{{"str", "bar"}},
+ Object{
+ {"str", "baz"}, {"bool", "string"}, // OK, deserialize ignores.
+ },
+ }}};
+ Expected["foo"] = {
+ CustomStruct("foo", 42, true),
+ CustomStruct("bar", llvm::None, false),
+ CustomStruct("baz", llvm::None, false),
+ };
+ ASSERT_TRUE(fromJSON(J, R));
+ EXPECT_EQ(R, Expected);
+
+ CustomStruct V;
+ EXPECT_FALSE(fromJSON(nullptr, V)) << "Not an object " << V;
+ EXPECT_FALSE(fromJSON(Object{}, V)) << "Missing required field " << V;
+ EXPECT_FALSE(fromJSON(Object{{"str", 1}}, V)) << "Wrong type " << V;
+ // Optional<T> must parse as the correct type if present.
+ EXPECT_FALSE(fromJSON(Object{{"str", 1}, {"int", "string"}}, V))
+ << "Wrong type for Optional<T> " << V;
+}
+
+} // namespace
+} // namespace json
+} // namespace llvm
diff --git a/src/llvm-project/llvm/unittests/Support/LEB128Test.cpp b/src/llvm-project/llvm/unittests/Support/LEB128Test.cpp
new file mode 100644
index 0000000..1c9b5db
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/LEB128Test.cpp
@@ -0,0 +1,368 @@
+//===- llvm/unittest/Support/LEB128Test.cpp - LEB128 function tests -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <string>
+using namespace llvm;
+
+namespace {
+
+TEST(LEB128Test, EncodeSLEB128) {
+#define EXPECT_SLEB128_EQ(EXPECTED, VALUE, PAD) \
+ do { \
+ std::string Expected(EXPECTED, sizeof(EXPECTED) - 1); \
+ \
+ /* encodeSLEB128(uint64_t, raw_ostream &, unsigned) */ \
+ std::string Actual1; \
+ raw_string_ostream Stream(Actual1); \
+ encodeSLEB128(VALUE, Stream, PAD); \
+ Stream.flush(); \
+ EXPECT_EQ(Expected, Actual1); \
+ \
+ /* encodeSLEB128(uint64_t, uint8_t *, unsigned) */ \
+ uint8_t Buffer[32]; \
+ unsigned Size = encodeSLEB128(VALUE, Buffer, PAD); \
+ std::string Actual2(reinterpret_cast<const char *>(Buffer), Size); \
+ EXPECT_EQ(Expected, Actual2); \
+ } while (0)
+
+ // Encode SLEB128
+ EXPECT_SLEB128_EQ("\x00", 0, 0);
+ EXPECT_SLEB128_EQ("\x01", 1, 0);
+ EXPECT_SLEB128_EQ("\x7f", -1, 0);
+ EXPECT_SLEB128_EQ("\x3f", 63, 0);
+ EXPECT_SLEB128_EQ("\x41", -63, 0);
+ EXPECT_SLEB128_EQ("\x40", -64, 0);
+ EXPECT_SLEB128_EQ("\xbf\x7f", -65, 0);
+ EXPECT_SLEB128_EQ("\xc0\x00", 64, 0);
+
+ // Encode SLEB128 with some extra padding bytes
+ EXPECT_SLEB128_EQ("\x80\x00", 0, 2);
+ EXPECT_SLEB128_EQ("\x80\x80\x00", 0, 3);
+ EXPECT_SLEB128_EQ("\xff\x80\x00", 0x7f, 3);
+ EXPECT_SLEB128_EQ("\xff\x80\x80\x00", 0x7f, 4);
+ EXPECT_SLEB128_EQ("\x80\x81\x00", 0x80, 3);
+ EXPECT_SLEB128_EQ("\x80\x81\x80\x00", 0x80, 4);
+ EXPECT_SLEB128_EQ("\xc0\x7f", -0x40, 2);
+
+ EXPECT_SLEB128_EQ("\xc0\xff\x7f", -0x40, 3);
+ EXPECT_SLEB128_EQ("\x80\xff\x7f", -0x80, 3);
+ EXPECT_SLEB128_EQ("\x80\xff\xff\x7f", -0x80, 4);
+
+#undef EXPECT_SLEB128_EQ
+}
+
+TEST(LEB128Test, EncodeULEB128) {
+#define EXPECT_ULEB128_EQ(EXPECTED, VALUE, PAD) \
+ do { \
+ std::string Expected(EXPECTED, sizeof(EXPECTED) - 1); \
+ \
+ /* encodeULEB128(uint64_t, raw_ostream &, unsigned) */ \
+ std::string Actual1; \
+ raw_string_ostream Stream(Actual1); \
+ encodeULEB128(VALUE, Stream, PAD); \
+ Stream.flush(); \
+ EXPECT_EQ(Expected, Actual1); \
+ \
+ /* encodeULEB128(uint64_t, uint8_t *, unsigned) */ \
+ uint8_t Buffer[32]; \
+ unsigned Size = encodeULEB128(VALUE, Buffer, PAD); \
+ std::string Actual2(reinterpret_cast<const char *>(Buffer), Size); \
+ EXPECT_EQ(Expected, Actual2); \
+ } while (0)
+
+ // Encode ULEB128
+ EXPECT_ULEB128_EQ("\x00", 0, 0);
+ EXPECT_ULEB128_EQ("\x01", 1, 0);
+ EXPECT_ULEB128_EQ("\x3f", 63, 0);
+ EXPECT_ULEB128_EQ("\x40", 64, 0);
+ EXPECT_ULEB128_EQ("\x7f", 0x7f, 0);
+ EXPECT_ULEB128_EQ("\x80\x01", 0x80, 0);
+ EXPECT_ULEB128_EQ("\x81\x01", 0x81, 0);
+ EXPECT_ULEB128_EQ("\x90\x01", 0x90, 0);
+ EXPECT_ULEB128_EQ("\xff\x01", 0xff, 0);
+ EXPECT_ULEB128_EQ("\x80\x02", 0x100, 0);
+ EXPECT_ULEB128_EQ("\x81\x02", 0x101, 0);
+
+ // Encode ULEB128 with some extra padding bytes
+ EXPECT_ULEB128_EQ("\x80\x00", 0, 2);
+ EXPECT_ULEB128_EQ("\x80\x80\x00", 0, 3);
+ EXPECT_ULEB128_EQ("\xff\x00", 0x7f, 2);
+ EXPECT_ULEB128_EQ("\xff\x80\x00", 0x7f, 3);
+ EXPECT_ULEB128_EQ("\x80\x81\x00", 0x80, 3);
+ EXPECT_ULEB128_EQ("\x80\x81\x80\x00", 0x80, 4);
+
+#undef EXPECT_ULEB128_EQ
+}
+
+TEST(LEB128Test, DecodeULEB128) {
+#define EXPECT_DECODE_ULEB128_EQ(EXPECTED, VALUE) \
+ do { \
+ unsigned ActualSize = 0; \
+ uint64_t Actual = decodeULEB128(reinterpret_cast<const uint8_t *>(VALUE), \
+ &ActualSize); \
+ EXPECT_EQ(sizeof(VALUE) - 1, ActualSize); \
+ EXPECT_EQ(EXPECTED, Actual); \
+ } while (0)
+
+ // Decode ULEB128
+ EXPECT_DECODE_ULEB128_EQ(0u, "\x00");
+ EXPECT_DECODE_ULEB128_EQ(1u, "\x01");
+ EXPECT_DECODE_ULEB128_EQ(63u, "\x3f");
+ EXPECT_DECODE_ULEB128_EQ(64u, "\x40");
+ EXPECT_DECODE_ULEB128_EQ(0x7fu, "\x7f");
+ EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x01");
+ EXPECT_DECODE_ULEB128_EQ(0x81u, "\x81\x01");
+ EXPECT_DECODE_ULEB128_EQ(0x90u, "\x90\x01");
+ EXPECT_DECODE_ULEB128_EQ(0xffu, "\xff\x01");
+ EXPECT_DECODE_ULEB128_EQ(0x100u, "\x80\x02");
+ EXPECT_DECODE_ULEB128_EQ(0x101u, "\x81\x02");
+ EXPECT_DECODE_ULEB128_EQ(4294975616ULL, "\x80\xc1\x80\x80\x10");
+
+ // Decode ULEB128 with extra padding bytes
+ EXPECT_DECODE_ULEB128_EQ(0u, "\x80\x00");
+ EXPECT_DECODE_ULEB128_EQ(0u, "\x80\x80\x00");
+ EXPECT_DECODE_ULEB128_EQ(0x7fu, "\xff\x00");
+ EXPECT_DECODE_ULEB128_EQ(0x7fu, "\xff\x80\x00");
+ EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x81\x00");
+ EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x81\x80\x00");
+
+#undef EXPECT_DECODE_ULEB128_EQ
+}
+
+TEST(LEB128Test, DecodeSLEB128) {
+#define EXPECT_DECODE_SLEB128_EQ(EXPECTED, VALUE) \
+ do { \
+ unsigned ActualSize = 0; \
+ int64_t Actual = decodeSLEB128(reinterpret_cast<const uint8_t *>(VALUE), \
+ &ActualSize); \
+ EXPECT_EQ(sizeof(VALUE) - 1, ActualSize); \
+ EXPECT_EQ(EXPECTED, Actual); \
+ } while (0)
+
+ // Decode SLEB128
+ EXPECT_DECODE_SLEB128_EQ(0L, "\x00");
+ EXPECT_DECODE_SLEB128_EQ(1L, "\x01");
+ EXPECT_DECODE_SLEB128_EQ(63L, "\x3f");
+ EXPECT_DECODE_SLEB128_EQ(-64L, "\x40");
+ EXPECT_DECODE_SLEB128_EQ(-63L, "\x41");
+ EXPECT_DECODE_SLEB128_EQ(-1L, "\x7f");
+ EXPECT_DECODE_SLEB128_EQ(128L, "\x80\x01");
+ EXPECT_DECODE_SLEB128_EQ(129L, "\x81\x01");
+ EXPECT_DECODE_SLEB128_EQ(-129L, "\xff\x7e");
+ EXPECT_DECODE_SLEB128_EQ(-128L, "\x80\x7f");
+ EXPECT_DECODE_SLEB128_EQ(-127L, "\x81\x7f");
+ EXPECT_DECODE_SLEB128_EQ(64L, "\xc0\x00");
+ EXPECT_DECODE_SLEB128_EQ(-12345L, "\xc7\x9f\x7f");
+
+ // Decode unnormalized SLEB128 with extra padding bytes.
+ EXPECT_DECODE_SLEB128_EQ(0L, "\x80\x00");
+ EXPECT_DECODE_SLEB128_EQ(0L, "\x80\x80\x00");
+ EXPECT_DECODE_SLEB128_EQ(0x7fL, "\xff\x00");
+ EXPECT_DECODE_SLEB128_EQ(0x7fL, "\xff\x80\x00");
+ EXPECT_DECODE_SLEB128_EQ(0x80L, "\x80\x81\x00");
+ EXPECT_DECODE_SLEB128_EQ(0x80L, "\x80\x81\x80\x00");
+
+#undef EXPECT_DECODE_SLEB128_EQ
+}
+
+TEST(LEB128Test, SLEB128Size) {
+ // Positive Value Testing Plan:
+ // (1) 128 ^ n - 1 ........ need (n+1) bytes
+ // (2) 128 ^ n ............ need (n+1) bytes
+ // (3) 128 ^ n * 63 ....... need (n+1) bytes
+ // (4) 128 ^ n * 64 - 1 ... need (n+1) bytes
+ // (5) 128 ^ n * 64 ....... need (n+2) bytes
+
+ EXPECT_EQ(1u, getSLEB128Size(0x0LL));
+ EXPECT_EQ(1u, getSLEB128Size(0x1LL));
+ EXPECT_EQ(1u, getSLEB128Size(0x3fLL));
+ EXPECT_EQ(1u, getSLEB128Size(0x3fLL));
+ EXPECT_EQ(2u, getSLEB128Size(0x40LL));
+
+ EXPECT_EQ(2u, getSLEB128Size(0x7fLL));
+ EXPECT_EQ(2u, getSLEB128Size(0x80LL));
+ EXPECT_EQ(2u, getSLEB128Size(0x1f80LL));
+ EXPECT_EQ(2u, getSLEB128Size(0x1fffLL));
+ EXPECT_EQ(3u, getSLEB128Size(0x2000LL));
+
+ EXPECT_EQ(3u, getSLEB128Size(0x3fffLL));
+ EXPECT_EQ(3u, getSLEB128Size(0x4000LL));
+ EXPECT_EQ(3u, getSLEB128Size(0xfc000LL));
+ EXPECT_EQ(3u, getSLEB128Size(0xfffffLL));
+ EXPECT_EQ(4u, getSLEB128Size(0x100000LL));
+
+ EXPECT_EQ(4u, getSLEB128Size(0x1fffffLL));
+ EXPECT_EQ(4u, getSLEB128Size(0x200000LL));
+ EXPECT_EQ(4u, getSLEB128Size(0x7e00000LL));
+ EXPECT_EQ(4u, getSLEB128Size(0x7ffffffLL));
+ EXPECT_EQ(5u, getSLEB128Size(0x8000000LL));
+
+ EXPECT_EQ(5u, getSLEB128Size(0xfffffffLL));
+ EXPECT_EQ(5u, getSLEB128Size(0x10000000LL));
+ EXPECT_EQ(5u, getSLEB128Size(0x3f0000000LL));
+ EXPECT_EQ(5u, getSLEB128Size(0x3ffffffffLL));
+ EXPECT_EQ(6u, getSLEB128Size(0x400000000LL));
+
+ EXPECT_EQ(6u, getSLEB128Size(0x7ffffffffLL));
+ EXPECT_EQ(6u, getSLEB128Size(0x800000000LL));
+ EXPECT_EQ(6u, getSLEB128Size(0x1f800000000LL));
+ EXPECT_EQ(6u, getSLEB128Size(0x1ffffffffffLL));
+ EXPECT_EQ(7u, getSLEB128Size(0x20000000000LL));
+
+ EXPECT_EQ(7u, getSLEB128Size(0x3ffffffffffLL));
+ EXPECT_EQ(7u, getSLEB128Size(0x40000000000LL));
+ EXPECT_EQ(7u, getSLEB128Size(0xfc0000000000LL));
+ EXPECT_EQ(7u, getSLEB128Size(0xffffffffffffLL));
+ EXPECT_EQ(8u, getSLEB128Size(0x1000000000000LL));
+
+ EXPECT_EQ(8u, getSLEB128Size(0x1ffffffffffffLL));
+ EXPECT_EQ(8u, getSLEB128Size(0x2000000000000LL));
+ EXPECT_EQ(8u, getSLEB128Size(0x7e000000000000LL));
+ EXPECT_EQ(8u, getSLEB128Size(0x7fffffffffffffLL));
+ EXPECT_EQ(9u, getSLEB128Size(0x80000000000000LL));
+
+ EXPECT_EQ(9u, getSLEB128Size(0xffffffffffffffLL));
+ EXPECT_EQ(9u, getSLEB128Size(0x100000000000000LL));
+ EXPECT_EQ(9u, getSLEB128Size(0x3f00000000000000LL));
+ EXPECT_EQ(9u, getSLEB128Size(0x3fffffffffffffffLL));
+ EXPECT_EQ(10u, getSLEB128Size(0x4000000000000000LL));
+
+ EXPECT_EQ(10u, getSLEB128Size(0x7fffffffffffffffLL));
+ EXPECT_EQ(10u, getSLEB128Size(INT64_MAX));
+
+ // Negative Value Testing Plan:
+ // (1) - 128 ^ n - 1 ........ need (n+1) bytes
+ // (2) - 128 ^ n ............ need (n+1) bytes
+ // (3) - 128 ^ n * 63 ....... need (n+1) bytes
+ // (4) - 128 ^ n * 64 ....... need (n+1) bytes (different from positive one)
+ // (5) - 128 ^ n * 65 - 1 ... need (n+2) bytes (if n > 0)
+ // (6) - 128 ^ n * 65 ....... need (n+2) bytes
+
+ EXPECT_EQ(1u, getSLEB128Size(0x0LL));
+ EXPECT_EQ(1u, getSLEB128Size(-0x1LL));
+ EXPECT_EQ(1u, getSLEB128Size(-0x3fLL));
+ EXPECT_EQ(1u, getSLEB128Size(-0x40LL));
+ EXPECT_EQ(1u, getSLEB128Size(-0x40LL)); // special case
+ EXPECT_EQ(2u, getSLEB128Size(-0x41LL));
+
+ EXPECT_EQ(2u, getSLEB128Size(-0x7fLL));
+ EXPECT_EQ(2u, getSLEB128Size(-0x80LL));
+ EXPECT_EQ(2u, getSLEB128Size(-0x1f80LL));
+ EXPECT_EQ(2u, getSLEB128Size(-0x2000LL));
+ EXPECT_EQ(3u, getSLEB128Size(-0x207fLL));
+ EXPECT_EQ(3u, getSLEB128Size(-0x2080LL));
+
+ EXPECT_EQ(3u, getSLEB128Size(-0x3fffLL));
+ EXPECT_EQ(3u, getSLEB128Size(-0x4000LL));
+ EXPECT_EQ(3u, getSLEB128Size(-0xfc000LL));
+ EXPECT_EQ(3u, getSLEB128Size(-0x100000LL));
+ EXPECT_EQ(4u, getSLEB128Size(-0x103fffLL));
+ EXPECT_EQ(4u, getSLEB128Size(-0x104000LL));
+
+ EXPECT_EQ(4u, getSLEB128Size(-0x1fffffLL));
+ EXPECT_EQ(4u, getSLEB128Size(-0x200000LL));
+ EXPECT_EQ(4u, getSLEB128Size(-0x7e00000LL));
+ EXPECT_EQ(4u, getSLEB128Size(-0x8000000LL));
+ EXPECT_EQ(5u, getSLEB128Size(-0x81fffffLL));
+ EXPECT_EQ(5u, getSLEB128Size(-0x8200000LL));
+
+ EXPECT_EQ(5u, getSLEB128Size(-0xfffffffLL));
+ EXPECT_EQ(5u, getSLEB128Size(-0x10000000LL));
+ EXPECT_EQ(5u, getSLEB128Size(-0x3f0000000LL));
+ EXPECT_EQ(5u, getSLEB128Size(-0x400000000LL));
+ EXPECT_EQ(6u, getSLEB128Size(-0x40fffffffLL));
+ EXPECT_EQ(6u, getSLEB128Size(-0x410000000LL));
+
+ EXPECT_EQ(6u, getSLEB128Size(-0x7ffffffffLL));
+ EXPECT_EQ(6u, getSLEB128Size(-0x800000000LL));
+ EXPECT_EQ(6u, getSLEB128Size(-0x1f800000000LL));
+ EXPECT_EQ(6u, getSLEB128Size(-0x20000000000LL));
+ EXPECT_EQ(7u, getSLEB128Size(-0x207ffffffffLL));
+ EXPECT_EQ(7u, getSLEB128Size(-0x20800000000LL));
+
+ EXPECT_EQ(7u, getSLEB128Size(-0x3ffffffffffLL));
+ EXPECT_EQ(7u, getSLEB128Size(-0x40000000000LL));
+ EXPECT_EQ(7u, getSLEB128Size(-0xfc0000000000LL));
+ EXPECT_EQ(7u, getSLEB128Size(-0x1000000000000LL));
+ EXPECT_EQ(8u, getSLEB128Size(-0x103ffffffffffLL));
+ EXPECT_EQ(8u, getSLEB128Size(-0x1040000000000LL));
+
+ EXPECT_EQ(8u, getSLEB128Size(-0x1ffffffffffffLL));
+ EXPECT_EQ(8u, getSLEB128Size(-0x2000000000000LL));
+ EXPECT_EQ(8u, getSLEB128Size(-0x7e000000000000LL));
+ EXPECT_EQ(8u, getSLEB128Size(-0x80000000000000LL));
+ EXPECT_EQ(9u, getSLEB128Size(-0x81ffffffffffffLL));
+ EXPECT_EQ(9u, getSLEB128Size(-0x82000000000000LL));
+
+ EXPECT_EQ(9u, getSLEB128Size(-0xffffffffffffffLL));
+ EXPECT_EQ(9u, getSLEB128Size(-0x100000000000000LL));
+ EXPECT_EQ(9u, getSLEB128Size(-0x3f00000000000000LL));
+ EXPECT_EQ(9u, getSLEB128Size(-0x4000000000000000LL));
+ EXPECT_EQ(10u, getSLEB128Size(-0x40ffffffffffffffLL));
+ EXPECT_EQ(10u, getSLEB128Size(-0x4100000000000000LL));
+
+ EXPECT_EQ(10u, getSLEB128Size(-0x7fffffffffffffffLL));
+ EXPECT_EQ(10u, getSLEB128Size(-0x8000000000000000LL));
+ EXPECT_EQ(10u, getSLEB128Size(INT64_MIN));
+}
+
+TEST(LEB128Test, ULEB128Size) {
+ // Testing Plan:
+ // (1) 128 ^ n ............ need (n+1) bytes
+ // (2) 128 ^ n * 64 ....... need (n+1) bytes
+ // (3) 128 ^ (n+1) - 1 .... need (n+1) bytes
+
+ EXPECT_EQ(1u, getULEB128Size(0)); // special case
+
+ EXPECT_EQ(1u, getULEB128Size(0x1ULL));
+ EXPECT_EQ(1u, getULEB128Size(0x40ULL));
+ EXPECT_EQ(1u, getULEB128Size(0x7fULL));
+
+ EXPECT_EQ(2u, getULEB128Size(0x80ULL));
+ EXPECT_EQ(2u, getULEB128Size(0x2000ULL));
+ EXPECT_EQ(2u, getULEB128Size(0x3fffULL));
+
+ EXPECT_EQ(3u, getULEB128Size(0x4000ULL));
+ EXPECT_EQ(3u, getULEB128Size(0x100000ULL));
+ EXPECT_EQ(3u, getULEB128Size(0x1fffffULL));
+
+ EXPECT_EQ(4u, getULEB128Size(0x200000ULL));
+ EXPECT_EQ(4u, getULEB128Size(0x8000000ULL));
+ EXPECT_EQ(4u, getULEB128Size(0xfffffffULL));
+
+ EXPECT_EQ(5u, getULEB128Size(0x10000000ULL));
+ EXPECT_EQ(5u, getULEB128Size(0x400000000ULL));
+ EXPECT_EQ(5u, getULEB128Size(0x7ffffffffULL));
+
+ EXPECT_EQ(6u, getULEB128Size(0x800000000ULL));
+ EXPECT_EQ(6u, getULEB128Size(0x20000000000ULL));
+ EXPECT_EQ(6u, getULEB128Size(0x3ffffffffffULL));
+
+ EXPECT_EQ(7u, getULEB128Size(0x40000000000ULL));
+ EXPECT_EQ(7u, getULEB128Size(0x1000000000000ULL));
+ EXPECT_EQ(7u, getULEB128Size(0x1ffffffffffffULL));
+
+ EXPECT_EQ(8u, getULEB128Size(0x2000000000000ULL));
+ EXPECT_EQ(8u, getULEB128Size(0x80000000000000ULL));
+ EXPECT_EQ(8u, getULEB128Size(0xffffffffffffffULL));
+
+ EXPECT_EQ(9u, getULEB128Size(0x100000000000000ULL));
+ EXPECT_EQ(9u, getULEB128Size(0x4000000000000000ULL));
+ EXPECT_EQ(9u, getULEB128Size(0x7fffffffffffffffULL));
+
+ EXPECT_EQ(10u, getULEB128Size(0x8000000000000000ULL));
+
+ EXPECT_EQ(10u, getULEB128Size(UINT64_MAX));
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/LineIteratorTest.cpp b/src/llvm-project/llvm/unittests/Support/LineIteratorTest.cpp
new file mode 100644
index 0000000..67f9d97
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/LineIteratorTest.cpp
@@ -0,0 +1,193 @@
+//===- LineIterator.cpp - Unit tests --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+namespace {
+
+TEST(LineIteratorTest, Basic) {
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer("line 1\n"
+ "line 2\n"
+ "line 3");
+
+ line_iterator I = line_iterator(*Buffer), E;
+
+ EXPECT_FALSE(I.is_at_eof());
+ EXPECT_NE(E, I);
+
+ EXPECT_EQ("line 1", *I);
+ EXPECT_EQ(1, I.line_number());
+ ++I;
+ EXPECT_EQ("line 2", *I);
+ EXPECT_EQ(2, I.line_number());
+ ++I;
+ EXPECT_EQ("line 3", *I);
+ EXPECT_EQ(3, I.line_number());
+ ++I;
+
+ EXPECT_TRUE(I.is_at_eof());
+ EXPECT_EQ(E, I);
+}
+
+TEST(LineIteratorTest, CommentAndBlankSkipping) {
+ std::unique_ptr<MemoryBuffer> Buffer(
+ MemoryBuffer::getMemBuffer("line 1\n"
+ "line 2\n"
+ "# Comment 1\n"
+ "\n"
+ "line 5\n"
+ "\n"
+ "# Comment 2"));
+
+ line_iterator I = line_iterator(*Buffer, true, '#'), E;
+
+ EXPECT_FALSE(I.is_at_eof());
+ EXPECT_NE(E, I);
+
+ EXPECT_EQ("line 1", *I);
+ EXPECT_EQ(1, I.line_number());
+ ++I;
+ EXPECT_EQ("line 2", *I);
+ EXPECT_EQ(2, I.line_number());
+ ++I;
+ EXPECT_EQ("line 5", *I);
+ EXPECT_EQ(5, I.line_number());
+ ++I;
+
+ EXPECT_TRUE(I.is_at_eof());
+ EXPECT_EQ(E, I);
+}
+
+TEST(LineIteratorTest, CommentSkippingKeepBlanks) {
+ std::unique_ptr<MemoryBuffer> Buffer(
+ MemoryBuffer::getMemBuffer("line 1\n"
+ "line 2\n"
+ "# Comment 1\n"
+ "# Comment 2\n"
+ "\n"
+ "line 6\n"
+ "\n"
+ "# Comment 3"));
+
+ line_iterator I = line_iterator(*Buffer, false, '#'), E;
+
+ EXPECT_FALSE(I.is_at_eof());
+ EXPECT_NE(E, I);
+
+ EXPECT_EQ("line 1", *I);
+ EXPECT_EQ(1, I.line_number());
+ ++I;
+ EXPECT_EQ("line 2", *I);
+ EXPECT_EQ(2, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(5, I.line_number());
+ ++I;
+ EXPECT_EQ("line 6", *I);
+ EXPECT_EQ(6, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(7, I.line_number());
+ ++I;
+
+ EXPECT_TRUE(I.is_at_eof());
+ EXPECT_EQ(E, I);
+}
+
+
+TEST(LineIteratorTest, BlankSkipping) {
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer("\n\n\n"
+ "line 1\n"
+ "\n\n\n"
+ "line 2\n"
+ "\n\n\n");
+
+ line_iterator I = line_iterator(*Buffer), E;
+
+ EXPECT_FALSE(I.is_at_eof());
+ EXPECT_NE(E, I);
+
+ EXPECT_EQ("line 1", *I);
+ EXPECT_EQ(4, I.line_number());
+ ++I;
+ EXPECT_EQ("line 2", *I);
+ EXPECT_EQ(8, I.line_number());
+ ++I;
+
+ EXPECT_TRUE(I.is_at_eof());
+ EXPECT_EQ(E, I);
+}
+
+TEST(LineIteratorTest, BlankKeeping) {
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer("\n\n"
+ "line 3\n"
+ "\n"
+ "line 5\n"
+ "\n\n");
+ line_iterator I = line_iterator(*Buffer, false), E;
+
+ EXPECT_FALSE(I.is_at_eof());
+ EXPECT_NE(E, I);
+
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(1, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(2, I.line_number());
+ ++I;
+ EXPECT_EQ("line 3", *I);
+ EXPECT_EQ(3, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(4, I.line_number());
+ ++I;
+ EXPECT_EQ("line 5", *I);
+ EXPECT_EQ(5, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(6, I.line_number());
+ ++I;
+ EXPECT_EQ("", *I);
+ EXPECT_EQ(7, I.line_number());
+ ++I;
+
+ EXPECT_TRUE(I.is_at_eof());
+ EXPECT_EQ(E, I);
+}
+
+TEST(LineIteratorTest, EmptyBuffers) {
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer("");
+ EXPECT_TRUE(line_iterator(*Buffer).is_at_eof());
+ EXPECT_EQ(line_iterator(), line_iterator(*Buffer));
+ EXPECT_TRUE(line_iterator(*Buffer, false).is_at_eof());
+ EXPECT_EQ(line_iterator(), line_iterator(*Buffer, false));
+
+ Buffer = MemoryBuffer::getMemBuffer("\n\n\n");
+ EXPECT_TRUE(line_iterator(*Buffer).is_at_eof());
+ EXPECT_EQ(line_iterator(), line_iterator(*Buffer));
+
+ Buffer = MemoryBuffer::getMemBuffer("# foo\n"
+ "\n"
+ "# bar");
+ EXPECT_TRUE(line_iterator(*Buffer, true, '#').is_at_eof());
+ EXPECT_EQ(line_iterator(), line_iterator(*Buffer, true, '#'));
+
+ Buffer = MemoryBuffer::getMemBuffer("\n"
+ "# baz\n"
+ "\n");
+ EXPECT_TRUE(line_iterator(*Buffer, true, '#').is_at_eof());
+ EXPECT_EQ(line_iterator(), line_iterator(*Buffer, true, '#'));
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/LockFileManagerTest.cpp b/src/llvm-project/llvm/unittests/Support/LockFileManagerTest.cpp
new file mode 100644
index 0000000..1775d05
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/LockFileManagerTest.cpp
@@ -0,0 +1,127 @@
+//===- unittests/LockFileManagerTest.cpp - LockFileManager tests ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+TEST(LockFileManagerTest, Basic) {
+ SmallString<64> TmpDir;
+ std::error_code EC;
+ EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
+ ASSERT_FALSE(EC);
+
+ SmallString<64> LockedFile(TmpDir);
+ sys::path::append(LockedFile, "file.lock");
+
+ {
+ // The lock file should not exist, so we should successfully acquire it.
+ LockFileManager Locked1(LockedFile);
+ EXPECT_EQ(LockFileManager::LFS_Owned, Locked1.getState());
+
+ // Attempting to reacquire the lock should fail. Waiting on it would cause
+ // deadlock, so don't try that.
+ LockFileManager Locked2(LockedFile);
+ EXPECT_NE(LockFileManager::LFS_Owned, Locked2.getState());
+ }
+
+ // Now that the lock is out of scope, the file should be gone.
+ EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));
+
+ EC = sys::fs::remove(StringRef(TmpDir));
+ ASSERT_FALSE(EC);
+}
+
+TEST(LockFileManagerTest, LinkLockExists) {
+ SmallString<64> TmpDir;
+ std::error_code EC;
+ EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
+ ASSERT_FALSE(EC);
+
+ SmallString<64> LockedFile(TmpDir);
+ sys::path::append(LockedFile, "file");
+
+ SmallString<64> FileLocK(TmpDir);
+ sys::path::append(FileLocK, "file.lock");
+
+ SmallString<64> TmpFileLock(TmpDir);
+ sys::path::append(TmpFileLock, "file.lock-000");
+
+ int FD;
+ EC = sys::fs::openFileForWrite(StringRef(TmpFileLock), FD);
+ ASSERT_FALSE(EC);
+
+ int Ret = close(FD);
+ ASSERT_EQ(Ret, 0);
+
+ EC = sys::fs::create_link(TmpFileLock.str(), FileLocK.str());
+ ASSERT_FALSE(EC);
+
+ EC = sys::fs::remove(StringRef(TmpFileLock));
+ ASSERT_FALSE(EC);
+
+ {
+ // The lock file doesn't point to a real file, so we should successfully
+ // acquire it.
+ LockFileManager Locked(LockedFile);
+ EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
+ }
+
+ // Now that the lock is out of scope, the file should be gone.
+ EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));
+
+ EC = sys::fs::remove(StringRef(TmpDir));
+ ASSERT_FALSE(EC);
+}
+
+
+TEST(LockFileManagerTest, RelativePath) {
+ SmallString<64> TmpDir;
+ std::error_code EC;
+ EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
+ ASSERT_FALSE(EC);
+
+ char PathBuf[1024];
+ const char *OrigPath = getcwd(PathBuf, 1024);
+ ASSERT_FALSE(chdir(TmpDir.c_str()));
+
+ sys::fs::create_directory("inner");
+ SmallString<64> LockedFile("inner");
+ sys::path::append(LockedFile, "file");
+
+ SmallString<64> FileLock(LockedFile);
+ FileLock += ".lock";
+
+ {
+ // The lock file should not exist, so we should successfully acquire it.
+ LockFileManager Locked(LockedFile);
+ EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
+ EXPECT_TRUE(sys::fs::exists(FileLock.str()));
+ }
+
+ // Now that the lock is out of scope, the file should be gone.
+ EXPECT_FALSE(sys::fs::exists(LockedFile.str()));
+ EXPECT_FALSE(sys::fs::exists(FileLock.str()));
+
+ EC = sys::fs::remove("inner");
+ ASSERT_FALSE(EC);
+
+ ASSERT_FALSE(chdir(OrigPath));
+
+ EC = sys::fs::remove(StringRef(TmpDir));
+ ASSERT_FALSE(EC);
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/MD5Test.cpp b/src/llvm-project/llvm/unittests/Support/MD5Test.cpp
new file mode 100644
index 0000000..bac1ec2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/MD5Test.cpp
@@ -0,0 +1,72 @@
+//===- llvm/unittest/Support/MD5Test.cpp - MD5 tests ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unit tests for the MD5 functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MD5.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+/// Tests an arbitrary set of bytes passed as \p Input.
+void TestMD5Sum(ArrayRef<uint8_t> Input, StringRef Final) {
+ MD5 Hash;
+ Hash.update(Input);
+ MD5::MD5Result MD5Res;
+ Hash.final(MD5Res);
+ SmallString<32> Res;
+ MD5::stringifyResult(MD5Res, Res);
+ EXPECT_EQ(Res, Final);
+}
+
+void TestMD5Sum(StringRef Input, StringRef Final) {
+ MD5 Hash;
+ Hash.update(Input);
+ MD5::MD5Result MD5Res;
+ Hash.final(MD5Res);
+ SmallString<32> Res;
+ MD5::stringifyResult(MD5Res, Res);
+ EXPECT_EQ(Res, Final);
+}
+
+TEST(MD5Test, MD5) {
+ TestMD5Sum(makeArrayRef((const uint8_t *)"", (size_t) 0),
+ "d41d8cd98f00b204e9800998ecf8427e");
+ TestMD5Sum(makeArrayRef((const uint8_t *)"a", (size_t) 1),
+ "0cc175b9c0f1b6a831c399e269772661");
+ TestMD5Sum(makeArrayRef((const uint8_t *)"abcdefghijklmnopqrstuvwxyz",
+ (size_t) 26),
+ "c3fcd3d76192e4007dfb496cca67e13b");
+ TestMD5Sum(makeArrayRef((const uint8_t *)"\0", (size_t) 1),
+ "93b885adfe0da089cdf634904fd59f71");
+ TestMD5Sum(makeArrayRef((const uint8_t *)"a\0", (size_t) 2),
+ "4144e195f46de78a3623da7364d04f11");
+ TestMD5Sum(makeArrayRef((const uint8_t *)"abcdefghijklmnopqrstuvwxyz\0",
+ (size_t) 27),
+ "81948d1f1554f58cd1a56ebb01f808cb");
+ TestMD5Sum("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
+}
+
+TEST(MD5HashTest, MD5) {
+ ArrayRef<uint8_t> Input((const uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26);
+ std::array<uint8_t, 16> Vec = MD5::hash(Input);
+ MD5::MD5Result MD5Res;
+ SmallString<32> Res;
+ memcpy(MD5Res.Bytes.data(), Vec.data(), Vec.size());
+ MD5::stringifyResult(MD5Res, Res);
+ EXPECT_EQ(Res, "c3fcd3d76192e4007dfb496cca67e13b");
+ EXPECT_EQ(0x3be167ca6c49fb7dULL, MD5Res.high());
+ EXPECT_EQ(0x00e49261d7d3fcc3ULL, MD5Res.low());
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ManagedStatic.cpp b/src/llvm-project/llvm/unittests/Support/ManagedStatic.cpp
new file mode 100644
index 0000000..d3cc80c
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ManagedStatic.cpp
@@ -0,0 +1,102 @@
+//===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Config/config.h"
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) && \
+ !__has_feature(memory_sanitizer)
+namespace test1 {
+ llvm::ManagedStatic<int> ms;
+ void *helper(void*) {
+ *ms;
+ return nullptr;
+ }
+
+ // Valgrind's leak checker complains glibc's stack allocation.
+ // To appease valgrind, we provide our own stack for each thread.
+ void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
+ void *stack = safe_malloc(n);
+ pthread_attr_init(&a);
+#if defined(__linux__)
+ pthread_attr_setstack(&a, stack, n);
+#endif
+ return stack;
+ }
+}
+
+TEST(Initialize, MultipleThreads) {
+ // Run this test under tsan: http://code.google.com/p/data-race-test/
+
+ pthread_attr_t a1, a2;
+ void *p1 = test1::allocate_stack(a1);
+ void *p2 = test1::allocate_stack(a2);
+
+ pthread_t t1, t2;
+ pthread_create(&t1, &a1, test1::helper, nullptr);
+ pthread_create(&t2, &a2, test1::helper, nullptr);
+ pthread_join(t1, nullptr);
+ pthread_join(t2, nullptr);
+ free(p1);
+ free(p2);
+}
+#endif
+
+namespace NestedStatics {
+static ManagedStatic<int> Ms1;
+struct Nest {
+ Nest() {
+ ++(*Ms1);
+ }
+
+ ~Nest() {
+ assert(Ms1.isConstructed());
+ ++(*Ms1);
+ }
+};
+static ManagedStatic<Nest> Ms2;
+
+TEST(ManagedStaticTest, NestedStatics) {
+ EXPECT_FALSE(Ms1.isConstructed());
+ EXPECT_FALSE(Ms2.isConstructed());
+
+ *Ms2;
+ EXPECT_TRUE(Ms1.isConstructed());
+ EXPECT_TRUE(Ms2.isConstructed());
+}
+} // namespace NestedStatics
+
+namespace CustomCreatorDeletor {
+struct CustomCreate {
+ static void *call() {
+ void *Mem = safe_malloc(sizeof(int));
+ *((int *)Mem) = 42;
+ return Mem;
+ }
+};
+struct CustomDelete {
+ static void call(void *P) { std::free(P); }
+};
+static ManagedStatic<int, CustomCreate, CustomDelete> Custom;
+TEST(ManagedStaticTest, CustomCreatorDeletor) {
+ EXPECT_EQ(42, *Custom);
+}
+} // namespace CustomCreatorDeletor
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/MathExtrasTest.cpp b/src/llvm-project/llvm/unittests/Support/MathExtrasTest.cpp
new file mode 100644
index 0000000..694a1f2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/MathExtrasTest.cpp
@@ -0,0 +1,472 @@
+//===- unittests/Support/MathExtrasTest.cpp - math utils tests ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MathExtras.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(MathExtras, countTrailingZeros) {
+ uint8_t Z8 = 0;
+ uint16_t Z16 = 0;
+ uint32_t Z32 = 0;
+ uint64_t Z64 = 0;
+ EXPECT_EQ(8u, countTrailingZeros(Z8));
+ EXPECT_EQ(16u, countTrailingZeros(Z16));
+ EXPECT_EQ(32u, countTrailingZeros(Z32));
+ EXPECT_EQ(64u, countTrailingZeros(Z64));
+
+ uint8_t NZ8 = 42;
+ uint16_t NZ16 = 42;
+ uint32_t NZ32 = 42;
+ uint64_t NZ64 = 42;
+ EXPECT_EQ(1u, countTrailingZeros(NZ8));
+ EXPECT_EQ(1u, countTrailingZeros(NZ16));
+ EXPECT_EQ(1u, countTrailingZeros(NZ32));
+ EXPECT_EQ(1u, countTrailingZeros(NZ64));
+}
+
+TEST(MathExtras, countLeadingZeros) {
+ uint8_t Z8 = 0;
+ uint16_t Z16 = 0;
+ uint32_t Z32 = 0;
+ uint64_t Z64 = 0;
+ EXPECT_EQ(8u, countLeadingZeros(Z8));
+ EXPECT_EQ(16u, countLeadingZeros(Z16));
+ EXPECT_EQ(32u, countLeadingZeros(Z32));
+ EXPECT_EQ(64u, countLeadingZeros(Z64));
+
+ uint8_t NZ8 = 42;
+ uint16_t NZ16 = 42;
+ uint32_t NZ32 = 42;
+ uint64_t NZ64 = 42;
+ EXPECT_EQ(2u, countLeadingZeros(NZ8));
+ EXPECT_EQ(10u, countLeadingZeros(NZ16));
+ EXPECT_EQ(26u, countLeadingZeros(NZ32));
+ EXPECT_EQ(58u, countLeadingZeros(NZ64));
+
+ EXPECT_EQ(8u, countLeadingZeros(0x00F000FFu));
+ EXPECT_EQ(8u, countLeadingZeros(0x00F12345u));
+ for (unsigned i = 0; i <= 30; ++i) {
+ EXPECT_EQ(31 - i, countLeadingZeros(1u << i));
+ }
+
+ EXPECT_EQ(8u, countLeadingZeros(0x00F1234500F12345ULL));
+ EXPECT_EQ(1u, countLeadingZeros(1ULL << 62));
+ for (unsigned i = 0; i <= 62; ++i) {
+ EXPECT_EQ(63 - i, countLeadingZeros(1ULL << i));
+ }
+}
+
+TEST(MathExtras, onesMask) {
+ EXPECT_EQ(0U, maskLeadingOnes<uint8_t>(0));
+ EXPECT_EQ(0U, maskTrailingOnes<uint8_t>(0));
+ EXPECT_EQ(0U, maskLeadingOnes<uint16_t>(0));
+ EXPECT_EQ(0U, maskTrailingOnes<uint16_t>(0));
+ EXPECT_EQ(0U, maskLeadingOnes<uint32_t>(0));
+ EXPECT_EQ(0U, maskTrailingOnes<uint32_t>(0));
+ EXPECT_EQ(0U, maskLeadingOnes<uint64_t>(0));
+ EXPECT_EQ(0U, maskTrailingOnes<uint64_t>(0));
+
+ EXPECT_EQ(0x00000003U, maskTrailingOnes<uint32_t>(2U));
+ EXPECT_EQ(0xC0000000U, maskLeadingOnes<uint32_t>(2U));
+
+ EXPECT_EQ(0x000007FFU, maskTrailingOnes<uint32_t>(11U));
+ EXPECT_EQ(0xFFE00000U, maskLeadingOnes<uint32_t>(11U));
+
+ EXPECT_EQ(0xFFFFFFFFU, maskTrailingOnes<uint32_t>(32U));
+ EXPECT_EQ(0xFFFFFFFFU, maskLeadingOnes<uint32_t>(32U));
+ EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, maskTrailingOnes<uint64_t>(64U));
+ EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, maskLeadingOnes<uint64_t>(64U));
+
+ EXPECT_EQ(0x0000FFFFFFFFFFFFULL, maskTrailingOnes<uint64_t>(48U));
+ EXPECT_EQ(0xFFFFFFFFFFFF0000ULL, maskLeadingOnes<uint64_t>(48U));
+}
+
+TEST(MathExtras, findFirstSet) {
+ uint8_t Z8 = 0;
+ uint16_t Z16 = 0;
+ uint32_t Z32 = 0;
+ uint64_t Z64 = 0;
+ EXPECT_EQ(0xFFULL, findFirstSet(Z8));
+ EXPECT_EQ(0xFFFFULL, findFirstSet(Z16));
+ EXPECT_EQ(0xFFFFFFFFULL, findFirstSet(Z32));
+ EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findFirstSet(Z64));
+
+ uint8_t NZ8 = 42;
+ uint16_t NZ16 = 42;
+ uint32_t NZ32 = 42;
+ uint64_t NZ64 = 42;
+ EXPECT_EQ(1u, findFirstSet(NZ8));
+ EXPECT_EQ(1u, findFirstSet(NZ16));
+ EXPECT_EQ(1u, findFirstSet(NZ32));
+ EXPECT_EQ(1u, findFirstSet(NZ64));
+}
+
+TEST(MathExtras, findLastSet) {
+ uint8_t Z8 = 0;
+ uint16_t Z16 = 0;
+ uint32_t Z32 = 0;
+ uint64_t Z64 = 0;
+ EXPECT_EQ(0xFFULL, findLastSet(Z8));
+ EXPECT_EQ(0xFFFFULL, findLastSet(Z16));
+ EXPECT_EQ(0xFFFFFFFFULL, findLastSet(Z32));
+ EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, findLastSet(Z64));
+
+ uint8_t NZ8 = 42;
+ uint16_t NZ16 = 42;
+ uint32_t NZ32 = 42;
+ uint64_t NZ64 = 42;
+ EXPECT_EQ(5u, findLastSet(NZ8));
+ EXPECT_EQ(5u, findLastSet(NZ16));
+ EXPECT_EQ(5u, findLastSet(NZ32));
+ EXPECT_EQ(5u, findLastSet(NZ64));
+}
+
+TEST(MathExtras, isIntN) {
+ EXPECT_TRUE(isIntN(16, 32767));
+ EXPECT_FALSE(isIntN(16, 32768));
+}
+
+TEST(MathExtras, isUIntN) {
+ EXPECT_TRUE(isUIntN(16, 65535));
+ EXPECT_FALSE(isUIntN(16, 65536));
+ EXPECT_TRUE(isUIntN(1, 0));
+ EXPECT_TRUE(isUIntN(6, 63));
+}
+
+TEST(MathExtras, maxIntN) {
+ EXPECT_EQ(32767, maxIntN(16));
+ EXPECT_EQ(2147483647, maxIntN(32));
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), maxIntN(32));
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), maxIntN(64));
+}
+
+TEST(MathExtras, minIntN) {
+ EXPECT_EQ(-32768LL, minIntN(16));
+ EXPECT_EQ(-64LL, minIntN(7));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), minIntN(32));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), minIntN(64));
+}
+
+TEST(MathExtras, maxUIntN) {
+ EXPECT_EQ(0xffffULL, maxUIntN(16));
+ EXPECT_EQ(0xffffffffULL, maxUIntN(32));
+ EXPECT_EQ(0xffffffffffffffffULL, maxUIntN(64));
+ EXPECT_EQ(1ULL, maxUIntN(1));
+ EXPECT_EQ(0x0fULL, maxUIntN(4));
+}
+
+TEST(MathExtras, reverseBits) {
+ uint8_t NZ8 = 42;
+ uint16_t NZ16 = 42;
+ uint32_t NZ32 = 42;
+ uint64_t NZ64 = 42;
+ EXPECT_EQ(0x54ULL, reverseBits(NZ8));
+ EXPECT_EQ(0x5400ULL, reverseBits(NZ16));
+ EXPECT_EQ(0x54000000ULL, reverseBits(NZ32));
+ EXPECT_EQ(0x5400000000000000ULL, reverseBits(NZ64));
+}
+
+TEST(MathExtras, isPowerOf2_32) {
+ EXPECT_FALSE(isPowerOf2_32(0));
+ EXPECT_TRUE(isPowerOf2_32(1 << 6));
+ EXPECT_TRUE(isPowerOf2_32(1 << 12));
+ EXPECT_FALSE(isPowerOf2_32((1 << 19) + 3));
+ EXPECT_FALSE(isPowerOf2_32(0xABCDEF0));
+}
+
+TEST(MathExtras, isPowerOf2_64) {
+ EXPECT_FALSE(isPowerOf2_64(0));
+ EXPECT_TRUE(isPowerOf2_64(1LL << 46));
+ EXPECT_TRUE(isPowerOf2_64(1LL << 12));
+ EXPECT_FALSE(isPowerOf2_64((1LL << 53) + 3));
+ EXPECT_FALSE(isPowerOf2_64(0xABCDEF0ABCDEF0LL));
+}
+
+TEST(MathExtras, PowerOf2Ceil) {
+ EXPECT_EQ(0U, PowerOf2Ceil(0U));
+ EXPECT_EQ(8U, PowerOf2Ceil(8U));
+ EXPECT_EQ(8U, PowerOf2Ceil(7U));
+}
+
+TEST(MathExtras, PowerOf2Floor) {
+ EXPECT_EQ(0U, PowerOf2Floor(0U));
+ EXPECT_EQ(8U, PowerOf2Floor(8U));
+ EXPECT_EQ(4U, PowerOf2Floor(7U));
+}
+
+TEST(MathExtras, ByteSwap_32) {
+ EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
+ EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
+}
+
+TEST(MathExtras, ByteSwap_64) {
+ EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL));
+ EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL));
+}
+
+TEST(MathExtras, countLeadingOnes) {
+ for (int i = 30; i >= 0; --i) {
+ // Start with all ones and unset some bit.
+ EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
+ }
+ for (int i = 62; i >= 0; --i) {
+ // Start with all ones and unset some bit.
+ EXPECT_EQ(63u - i, countLeadingOnes(0xFFFFFFFFFFFFFFFFULL ^ (1LL << i)));
+ }
+ for (int i = 30; i >= 0; --i) {
+ // Start with all ones and unset some bit.
+ EXPECT_EQ(31u - i, countLeadingOnes(0xFFFFFFFF ^ (1 << i)));
+ }
+}
+
+TEST(MathExtras, FloatBits) {
+ static const float kValue = 5632.34f;
+ EXPECT_FLOAT_EQ(kValue, BitsToFloat(FloatToBits(kValue)));
+}
+
+TEST(MathExtras, DoubleBits) {
+ static const double kValue = 87987234.983498;
+ EXPECT_DOUBLE_EQ(kValue, BitsToDouble(DoubleToBits(kValue)));
+}
+
+TEST(MathExtras, MinAlign) {
+ EXPECT_EQ(1u, MinAlign(2, 3));
+ EXPECT_EQ(2u, MinAlign(2, 4));
+ EXPECT_EQ(1u, MinAlign(17, 64));
+ EXPECT_EQ(256u, MinAlign(256, 512));
+}
+
+TEST(MathExtras, NextPowerOf2) {
+ EXPECT_EQ(4u, NextPowerOf2(3));
+ EXPECT_EQ(16u, NextPowerOf2(15));
+ EXPECT_EQ(256u, NextPowerOf2(128));
+}
+
+TEST(MathExtras, alignTo) {
+ EXPECT_EQ(8u, alignTo(5, 8));
+ EXPECT_EQ(24u, alignTo(17, 8));
+ EXPECT_EQ(0u, alignTo(~0LL, 8));
+
+ EXPECT_EQ(7u, alignTo(5, 8, 7));
+ EXPECT_EQ(17u, alignTo(17, 8, 1));
+ EXPECT_EQ(3u, alignTo(~0LL, 8, 3));
+ EXPECT_EQ(552u, alignTo(321, 255, 42));
+}
+
+template<typename T>
+void SaturatingAddTestHelper()
+{
+ const T Max = std::numeric_limits<T>::max();
+ bool ResultOverflowed;
+
+ EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2)));
+ EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingAdd(Max, T(1)));
+ EXPECT_EQ(Max, SaturatingAdd(Max, T(1), &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1)));
+ EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingAdd(T(1), Max));
+ EXPECT_EQ(Max, SaturatingAdd(T(1), Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingAdd(Max, Max));
+ EXPECT_EQ(Max, SaturatingAdd(Max, Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+}
+
+TEST(MathExtras, SaturatingAdd) {
+ SaturatingAddTestHelper<uint8_t>();
+ SaturatingAddTestHelper<uint16_t>();
+ SaturatingAddTestHelper<uint32_t>();
+ SaturatingAddTestHelper<uint64_t>();
+}
+
+template<typename T>
+void SaturatingMultiplyTestHelper()
+{
+ const T Max = std::numeric_limits<T>::max();
+ bool ResultOverflowed;
+
+ // Test basic multiplication.
+ EXPECT_EQ(T(6), SaturatingMultiply(T(2), T(3)));
+ EXPECT_EQ(T(6), SaturatingMultiply(T(2), T(3), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(6), SaturatingMultiply(T(3), T(2)));
+ EXPECT_EQ(T(6), SaturatingMultiply(T(3), T(2), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ // Test multiplication by zero.
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(0)));
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(0), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(0), SaturatingMultiply(T(1), T(0)));
+ EXPECT_EQ(T(0), SaturatingMultiply(T(1), T(0), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(1)));
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), T(1), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(0), SaturatingMultiply(Max, T(0)));
+ EXPECT_EQ(T(0), SaturatingMultiply(Max, T(0), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), Max));
+ EXPECT_EQ(T(0), SaturatingMultiply(T(0), Max, &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ // Test multiplication by maximum value.
+ EXPECT_EQ(Max, SaturatingMultiply(Max, T(2)));
+ EXPECT_EQ(Max, SaturatingMultiply(Max, T(2), &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingMultiply(T(2), Max));
+ EXPECT_EQ(Max, SaturatingMultiply(T(2), Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingMultiply(Max, Max));
+ EXPECT_EQ(Max, SaturatingMultiply(Max, Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ // Test interesting boundary conditions for algorithm -
+ // ((1 << A) - 1) * ((1 << B) + K) for K in [-1, 0, 1]
+ // and A + B == std::numeric_limits<T>::digits.
+ // We expect overflow iff A > B and K = 1.
+ const int Digits = std::numeric_limits<T>::digits;
+ for (int A = 1, B = Digits - 1; B >= 1; ++A, --B) {
+ for (int K = -1; K <= 1; ++K) {
+ T X = (T(1) << A) - T(1);
+ T Y = (T(1) << B) + K;
+ bool OverflowExpected = A > B && K == 1;
+
+ if(OverflowExpected) {
+ EXPECT_EQ(Max, SaturatingMultiply(X, Y));
+ EXPECT_EQ(Max, SaturatingMultiply(X, Y, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+ } else {
+ EXPECT_EQ(X * Y, SaturatingMultiply(X, Y));
+ EXPECT_EQ(X * Y, SaturatingMultiply(X, Y, &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+ }
+ }
+ }
+}
+
+TEST(MathExtras, SaturatingMultiply) {
+ SaturatingMultiplyTestHelper<uint8_t>();
+ SaturatingMultiplyTestHelper<uint16_t>();
+ SaturatingMultiplyTestHelper<uint32_t>();
+ SaturatingMultiplyTestHelper<uint64_t>();
+}
+
+template<typename T>
+void SaturatingMultiplyAddTestHelper()
+{
+ const T Max = std::numeric_limits<T>::max();
+ bool ResultOverflowed;
+
+ // Test basic multiply-add.
+ EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10)));
+ EXPECT_EQ(T(16), SaturatingMultiplyAdd(T(2), T(3), T(10), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ // Test multiply overflows, add doesn't overflow
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(0), &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ // Test multiply doesn't overflow, add overflows
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ // Test multiply-add with Max as operand
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), T(1), Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(T(1), Max, T(1), &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, T(1), &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ EXPECT_EQ(Max, SaturatingMultiplyAdd(Max, Max, Max, &ResultOverflowed));
+ EXPECT_TRUE(ResultOverflowed);
+
+ // Test multiply-add with 0 as operand
+ EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(1), T(0), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(1), T(0), T(1), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(1), SaturatingMultiplyAdd(T(0), T(0), T(1), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+ EXPECT_EQ(T(0), SaturatingMultiplyAdd(T(0), T(0), T(0), &ResultOverflowed));
+ EXPECT_FALSE(ResultOverflowed);
+
+}
+
+TEST(MathExtras, SaturatingMultiplyAdd) {
+ SaturatingMultiplyAddTestHelper<uint8_t>();
+ SaturatingMultiplyAddTestHelper<uint16_t>();
+ SaturatingMultiplyAddTestHelper<uint32_t>();
+ SaturatingMultiplyAddTestHelper<uint64_t>();
+}
+
+TEST(MathExtras, IsShiftedUInt) {
+ EXPECT_TRUE((isShiftedUInt<1, 0>(0)));
+ EXPECT_TRUE((isShiftedUInt<1, 0>(1)));
+ EXPECT_FALSE((isShiftedUInt<1, 0>(2)));
+ EXPECT_FALSE((isShiftedUInt<1, 0>(3)));
+ EXPECT_FALSE((isShiftedUInt<1, 0>(0x8000000000000000)));
+ EXPECT_TRUE((isShiftedUInt<1, 63>(0x8000000000000000)));
+ EXPECT_TRUE((isShiftedUInt<2, 62>(0xC000000000000000)));
+ EXPECT_FALSE((isShiftedUInt<2, 62>(0xE000000000000000)));
+
+ // 0x201 is ten bits long and has a 1 in the MSB and LSB.
+ EXPECT_TRUE((isShiftedUInt<10, 5>(uint64_t(0x201) << 5)));
+ EXPECT_FALSE((isShiftedUInt<10, 5>(uint64_t(0x201) << 4)));
+ EXPECT_FALSE((isShiftedUInt<10, 5>(uint64_t(0x201) << 6)));
+}
+
+TEST(MathExtras, IsShiftedInt) {
+ EXPECT_TRUE((isShiftedInt<1, 0>(0)));
+ EXPECT_TRUE((isShiftedInt<1, 0>(-1)));
+ EXPECT_FALSE((isShiftedInt<1, 0>(2)));
+ EXPECT_FALSE((isShiftedInt<1, 0>(3)));
+ EXPECT_FALSE((isShiftedInt<1, 0>(0x8000000000000000)));
+ EXPECT_TRUE((isShiftedInt<1, 63>(0x8000000000000000)));
+ EXPECT_TRUE((isShiftedInt<2, 62>(0xC000000000000000)));
+ EXPECT_FALSE((isShiftedInt<2, 62>(0xE000000000000000)));
+
+ // 0x201 is ten bits long and has a 1 in the MSB and LSB.
+ EXPECT_TRUE((isShiftedInt<11, 5>(int64_t(0x201) << 5)));
+ EXPECT_FALSE((isShiftedInt<11, 5>(int64_t(0x201) << 3)));
+ EXPECT_FALSE((isShiftedInt<11, 5>(int64_t(0x201) << 6)));
+ EXPECT_TRUE((isShiftedInt<11, 5>(-(int64_t(0x201) << 5))));
+ EXPECT_FALSE((isShiftedInt<11, 5>(-(int64_t(0x201) << 3))));
+ EXPECT_FALSE((isShiftedInt<11, 5>(-(int64_t(0x201) << 6))));
+
+ EXPECT_TRUE((isShiftedInt<6, 10>(-(int64_t(1) << 15))));
+ EXPECT_FALSE((isShiftedInt<6, 10>(int64_t(1) << 15)));
+}
+
+} // namespace
diff --git a/src/llvm-project/llvm/unittests/Support/MemoryBufferTest.cpp b/src/llvm-project/llvm/unittests/Support/MemoryBufferTest.cpp
new file mode 100644
index 0000000..034b2ea
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/MemoryBufferTest.cpp
@@ -0,0 +1,292 @@
+//===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements unit tests for the MemoryBuffer support class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class MemoryBufferTest : public testing::Test {
+protected:
+ MemoryBufferTest()
+ : data("this is some data")
+ { }
+
+ void SetUp() override {}
+
+ /// Common testing for different modes of getOpenFileSlice.
+ /// Creates a temporary file with known contents, and uses
+ /// MemoryBuffer::getOpenFileSlice to map it.
+ /// If \p Reopen is true, the file is closed after creating and reopened
+ /// anew before using MemoryBuffer.
+ void testGetOpenFileSlice(bool Reopen);
+
+ typedef std::unique_ptr<MemoryBuffer> OwningBuffer;
+
+ std::string data;
+};
+
+TEST_F(MemoryBufferTest, get) {
+ // Default name and null-terminator flag
+ OwningBuffer MB1(MemoryBuffer::getMemBuffer(data));
+ EXPECT_TRUE(nullptr != MB1.get());
+
+ // RequiresNullTerminator = false
+ OwningBuffer MB2(MemoryBuffer::getMemBuffer(data, "one", false));
+ EXPECT_TRUE(nullptr != MB2.get());
+
+ // RequiresNullTerminator = true
+ OwningBuffer MB3(MemoryBuffer::getMemBuffer(data, "two", true));
+ EXPECT_TRUE(nullptr != MB3.get());
+
+ // verify all 3 buffers point to the same address
+ EXPECT_EQ(MB1->getBufferStart(), MB2->getBufferStart());
+ EXPECT_EQ(MB2->getBufferStart(), MB3->getBufferStart());
+
+ // verify the original data is unmodified after deleting the buffers
+ MB1.reset();
+ MB2.reset();
+ MB3.reset();
+ EXPECT_EQ("this is some data", data);
+}
+
+TEST_F(MemoryBufferTest, NullTerminator4K) {
+ // Test that a file with size that is a multiple of the page size can be null
+ // terminated correctly by MemoryBuffer.
+ int TestFD;
+ SmallString<64> TestPath;
+ sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",
+ TestFD, TestPath);
+ FileRemover Cleanup(TestPath);
+ raw_fd_ostream OF(TestFD, true, /*unbuffered=*/true);
+ for (unsigned i = 0; i < 4096 / 16; ++i) {
+ OF << "0123456789abcdef";
+ }
+ OF.close();
+
+ ErrorOr<OwningBuffer> MB = MemoryBuffer::getFile(TestPath.c_str());
+ std::error_code EC = MB.getError();
+ ASSERT_FALSE(EC);
+
+ const char *BufData = MB.get()->getBufferStart();
+ EXPECT_EQ('f', BufData[4095]);
+ EXPECT_EQ('\0', BufData[4096]);
+}
+
+TEST_F(MemoryBufferTest, copy) {
+ // copy with no name
+ OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data));
+ EXPECT_TRUE(nullptr != MBC1.get());
+
+ // copy with a name
+ OwningBuffer MBC2(MemoryBuffer::getMemBufferCopy(data, "copy"));
+ EXPECT_TRUE(nullptr != MBC2.get());
+
+ // verify the two copies do not point to the same place
+ EXPECT_NE(MBC1->getBufferStart(), MBC2->getBufferStart());
+}
+
+TEST_F(MemoryBufferTest, make_new) {
+ // 0-sized buffer
+ OwningBuffer Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0));
+ EXPECT_TRUE(nullptr != Zero.get());
+
+ // uninitialized buffer with no name
+ OwningBuffer One(WritableMemoryBuffer::getNewUninitMemBuffer(321));
+ EXPECT_TRUE(nullptr != One.get());
+
+ // uninitialized buffer with name
+ OwningBuffer Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla"));
+ EXPECT_TRUE(nullptr != Two.get());
+
+ // 0-initialized buffer with no name
+ OwningBuffer Three(WritableMemoryBuffer::getNewMemBuffer(321, data));
+ EXPECT_TRUE(nullptr != Three.get());
+ for (size_t i = 0; i < 321; ++i)
+ EXPECT_EQ(0, Three->getBufferStart()[0]);
+
+ // 0-initialized buffer with name
+ OwningBuffer Four(WritableMemoryBuffer::getNewMemBuffer(123, "zeros"));
+ EXPECT_TRUE(nullptr != Four.get());
+ for (size_t i = 0; i < 123; ++i)
+ EXPECT_EQ(0, Four->getBufferStart()[0]);
+}
+
+void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) {
+ // Test that MemoryBuffer::getOpenFile works properly when no null
+ // terminator is requested and the size is large enough to trigger
+ // the usage of memory mapping.
+ int TestFD;
+ SmallString<64> TestPath;
+ // Create a temporary file and write data into it.
+ sys::fs::createTemporaryFile("prefix", "temp", TestFD, TestPath);
+ FileRemover Cleanup(TestPath);
+ // OF is responsible for closing the file; If the file is not
+ // reopened, it will be unbuffered so that the results are
+ // immediately visible through the fd.
+ raw_fd_ostream OF(TestFD, true, !Reopen);
+ for (int i = 0; i < 60000; ++i) {
+ OF << "0123456789";
+ }
+
+ if (Reopen) {
+ OF.close();
+ EXPECT_FALSE(sys::fs::openFileForRead(TestPath.c_str(), TestFD));
+ }
+
+ ErrorOr<OwningBuffer> Buf =
+ MemoryBuffer::getOpenFileSlice(TestFD, TestPath.c_str(),
+ 40000, // Size
+ 80000 // Offset
+ );
+
+ std::error_code EC = Buf.getError();
+ EXPECT_FALSE(EC);
+
+ StringRef BufData = Buf.get()->getBuffer();
+ EXPECT_EQ(BufData.size(), 40000U);
+ EXPECT_EQ(BufData[0], '0');
+ EXPECT_EQ(BufData[9], '9');
+}
+
+TEST_F(MemoryBufferTest, getOpenFileNoReopen) {
+ testGetOpenFileSlice(false);
+}
+
+TEST_F(MemoryBufferTest, getOpenFileReopened) {
+ testGetOpenFileSlice(true);
+}
+
+TEST_F(MemoryBufferTest, reference) {
+ OwningBuffer MB(MemoryBuffer::getMemBuffer(data));
+ MemoryBufferRef MBR(*MB);
+
+ EXPECT_EQ(MB->getBufferStart(), MBR.getBufferStart());
+ EXPECT_EQ(MB->getBufferIdentifier(), MBR.getBufferIdentifier());
+}
+
+TEST_F(MemoryBufferTest, slice) {
+ // Create a file that is six pages long with different data on each page.
+ int FD;
+ SmallString<64> TestPath;
+ sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD, TestPath);
+ FileRemover Cleanup(TestPath);
+ raw_fd_ostream OF(FD, true, /*unbuffered=*/true);
+ for (unsigned i = 0; i < 0x2000 / 8; ++i) {
+ OF << "12345678";
+ }
+ for (unsigned i = 0; i < 0x2000 / 8; ++i) {
+ OF << "abcdefgh";
+ }
+ for (unsigned i = 0; i < 0x2000 / 8; ++i) {
+ OF << "ABCDEFGH";
+ }
+ OF.close();
+
+ // Try offset of one page.
+ ErrorOr<OwningBuffer> MB = MemoryBuffer::getFileSlice(TestPath.str(),
+ 0x4000, 0x1000);
+ std::error_code EC = MB.getError();
+ ASSERT_FALSE(EC);
+ EXPECT_EQ(0x4000UL, MB.get()->getBufferSize());
+
+ StringRef BufData = MB.get()->getBuffer();
+ EXPECT_TRUE(BufData.substr(0x0000,8).equals("12345678"));
+ EXPECT_TRUE(BufData.substr(0x0FF8,8).equals("12345678"));
+ EXPECT_TRUE(BufData.substr(0x1000,8).equals("abcdefgh"));
+ EXPECT_TRUE(BufData.substr(0x2FF8,8).equals("abcdefgh"));
+ EXPECT_TRUE(BufData.substr(0x3000,8).equals("ABCDEFGH"));
+ EXPECT_TRUE(BufData.substr(0x3FF8,8).equals("ABCDEFGH"));
+
+ // Try non-page aligned.
+ ErrorOr<OwningBuffer> MB2 = MemoryBuffer::getFileSlice(TestPath.str(),
+ 0x3000, 0x0800);
+ EC = MB2.getError();
+ ASSERT_FALSE(EC);
+ EXPECT_EQ(0x3000UL, MB2.get()->getBufferSize());
+
+ StringRef BufData2 = MB2.get()->getBuffer();
+ EXPECT_TRUE(BufData2.substr(0x0000,8).equals("12345678"));
+ EXPECT_TRUE(BufData2.substr(0x17F8,8).equals("12345678"));
+ EXPECT_TRUE(BufData2.substr(0x1800,8).equals("abcdefgh"));
+ EXPECT_TRUE(BufData2.substr(0x2FF8,8).equals("abcdefgh"));
+}
+
+TEST_F(MemoryBufferTest, writableSlice) {
+ // Create a file initialized with some data
+ int FD;
+ SmallString<64> TestPath;
+ sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD,
+ TestPath);
+ FileRemover Cleanup(TestPath);
+ raw_fd_ostream OF(FD, true);
+ for (unsigned i = 0; i < 0x1000; ++i)
+ OF << "0123456789abcdef";
+ OF.close();
+
+ {
+ auto MBOrError =
+ WritableMemoryBuffer::getFileSlice(TestPath.str(), 0x6000, 0x2000);
+ ASSERT_FALSE(MBOrError.getError());
+ // Write some data. It should be mapped private, so that upon completion
+ // the original file contents are not modified.
+ WritableMemoryBuffer &MB = **MBOrError;
+ ASSERT_EQ(0x6000u, MB.getBufferSize());
+ char *Start = MB.getBufferStart();
+ ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());
+ ::memset(Start, 'x', MB.getBufferSize());
+ }
+
+ auto MBOrError = MemoryBuffer::getFile(TestPath);
+ ASSERT_FALSE(MBOrError.getError());
+ auto &MB = **MBOrError;
+ ASSERT_EQ(0x10000u, MB.getBufferSize());
+ for (size_t i = 0; i < MB.getBufferSize(); i += 0x10)
+ EXPECT_EQ("0123456789abcdef", MB.getBuffer().substr(i, 0x10)) << "i: " << i;
+}
+
+TEST_F(MemoryBufferTest, writeThroughFile) {
+ // Create a file initialized with some data
+ int FD;
+ SmallString<64> TestPath;
+ sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD,
+ TestPath);
+ FileRemover Cleanup(TestPath);
+ raw_fd_ostream OF(FD, true);
+ OF << "0123456789abcdef";
+ OF.close();
+ {
+ auto MBOrError = WriteThroughMemoryBuffer::getFile(TestPath);
+ ASSERT_FALSE(MBOrError.getError());
+ // Write some data. It should be mapped readwrite, so that upon completion
+ // the original file contents are modified.
+ WriteThroughMemoryBuffer &MB = **MBOrError;
+ ASSERT_EQ(16u, MB.getBufferSize());
+ char *Start = MB.getBufferStart();
+ ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());
+ ::memset(Start, 'x', MB.getBufferSize());
+ }
+
+ auto MBOrError = MemoryBuffer::getFile(TestPath);
+ ASSERT_FALSE(MBOrError.getError());
+ auto &MB = **MBOrError;
+ ASSERT_EQ(16u, MB.getBufferSize());
+ EXPECT_EQ("xxxxxxxxxxxxxxxx", MB.getBuffer());
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/MemoryTest.cpp b/src/llvm-project/llvm/unittests/Support/MemoryTest.cpp
new file mode 100644
index 0000000..bc2fba0
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/MemoryTest.cpp
@@ -0,0 +1,418 @@
+//===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/Process.h"
+#include "gtest/gtest.h"
+#include <cassert>
+#include <cstdlib>
+
+#if defined(__NetBSD__)
+// clang-format off
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <unistd.h>
+// clang-format on
+#endif
+
+using namespace llvm;
+using namespace sys;
+
+namespace {
+
+bool IsMPROTECT() {
+#if defined(__NetBSD__)
+ int mib[3];
+ int paxflags;
+ size_t len = sizeof(paxflags);
+
+ mib[0] = CTL_PROC;
+ mib[1] = getpid();
+ mib[2] = PROC_PID_PAXFLAGS;
+
+ if (sysctl(mib, 3, &paxflags, &len, NULL, 0) != 0)
+ err(EXIT_FAILURE, "sysctl");
+
+ return !!(paxflags & CTL_PROC_PAXFLAGS_MPROTECT);
+#else
+ return false;
+#endif
+}
+
+class MappedMemoryTest : public ::testing::TestWithParam<unsigned> {
+public:
+ MappedMemoryTest() {
+ Flags = GetParam();
+ PageSize = sys::Process::getPageSize();
+ }
+
+protected:
+ // Adds RW flags to permit testing of the resulting memory
+ unsigned getTestableEquivalent(unsigned RequestedFlags) {
+ switch (RequestedFlags) {
+ case Memory::MF_READ:
+ case Memory::MF_WRITE:
+ case Memory::MF_READ|Memory::MF_WRITE:
+ return Memory::MF_READ|Memory::MF_WRITE;
+ case Memory::MF_READ|Memory::MF_EXEC:
+ case Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC:
+ case Memory::MF_EXEC:
+ return Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC;
+ }
+ // Default in case values are added to the enum, as required by some compilers
+ return Memory::MF_READ|Memory::MF_WRITE;
+ }
+
+ // Returns true if the memory blocks overlap
+ bool doesOverlap(MemoryBlock M1, MemoryBlock M2) {
+ if (M1.base() == M2.base())
+ return true;
+
+ if (M1.base() > M2.base())
+ return (unsigned char *)M2.base() + M2.size() > M1.base();
+
+ return (unsigned char *)M1.base() + M1.size() > M2.base();
+ }
+
+ unsigned Flags;
+ size_t PageSize;
+};
+
+// MPROTECT prevents W+X mmaps
+#define CHECK_UNSUPPORTED() \
+ do { \
+ if ((Flags & Memory::MF_WRITE) && (Flags & Memory::MF_EXEC) && \
+ IsMPROTECT()) \
+ return; \
+ } while (0)
+
+TEST_P(MappedMemoryTest, AllocAndRelease) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+TEST_P(MappedMemoryTest, MultipleAllocAndRelease) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ MemoryBlock M4 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ EXPECT_NE((void*)nullptr, M4.base());
+ EXPECT_LE(16U, M4.size());
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, BasicWrite) {
+ // This test applies only to readable and writeable combinations
+ if (Flags &&
+ !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE)))
+ return;
+ CHECK_UNSUPPORTED();
+
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ int *a = (int*)M1.base();
+ *a = 1;
+ EXPECT_EQ(1, *a);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+TEST_P(MappedMemoryTest, MultipleWrite) {
+ // This test applies only to readable and writeable combinations
+ if (Flags &&
+ !((Flags & Memory::MF_READ) && (Flags & Memory::MF_WRITE)))
+ return;
+ CHECK_UNSUPPORTED();
+
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(1U * sizeof(int), M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(8U * sizeof(int), M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(4U * sizeof(int), M3.size());
+
+ int *x = (int*)M1.base();
+ *x = 1;
+
+ int *y = (int*)M2.base();
+ for (int i = 0; i < 8; i++) {
+ y[i] = i;
+ }
+
+ int *z = (int*)M3.base();
+ *z = 42;
+
+ EXPECT_EQ(1, *x);
+ EXPECT_EQ(7, y[7]);
+ EXPECT_EQ(42, *z);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+
+ MemoryBlock M4 = Memory::allocateMappedMemory(64 * sizeof(int), nullptr,
+ Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ EXPECT_NE((void*)nullptr, M4.base());
+ EXPECT_LE(64U * sizeof(int), M4.size());
+ x = (int*)M4.base();
+ *x = 4;
+ EXPECT_EQ(4, *x);
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+
+ // Verify that M2 remains unaffected by other activity
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(i, y[i]);
+ }
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, EnabledWrite) {
+ // MPROTECT prevents W+X, and since this test always adds W we need
+ // to block any variant with X.
+ if ((Flags & Memory::MF_EXEC) && IsMPROTECT())
+ return;
+
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(2 * sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), nullptr, Flags,
+ EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(2U * sizeof(int), M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(8U * sizeof(int), M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(4U * sizeof(int), M3.size());
+
+ EXPECT_FALSE(Memory::protectMappedMemory(M1, getTestableEquivalent(Flags)));
+ EXPECT_FALSE(Memory::protectMappedMemory(M2, getTestableEquivalent(Flags)));
+ EXPECT_FALSE(Memory::protectMappedMemory(M3, getTestableEquivalent(Flags)));
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ int *x = (int*)M1.base();
+ *x = 1;
+ int *y = (int*)M2.base();
+ for (unsigned int i = 0; i < 8; i++) {
+ y[i] = i;
+ }
+ int *z = (int*)M3.base();
+ *z = 42;
+
+ EXPECT_EQ(1, *x);
+ EXPECT_EQ(7, y[7]);
+ EXPECT_EQ(42, *z);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_EQ(6, y[6]);
+
+ MemoryBlock M4 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ EXPECT_NE((void*)nullptr, M4.base());
+ EXPECT_LE(16U, M4.size());
+ EXPECT_EQ(std::error_code(),
+ Memory::protectMappedMemory(M4, getTestableEquivalent(Flags)));
+ x = (int*)M4.base();
+ *x = 4;
+ EXPECT_EQ(4, *x);
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, SuccessiveNear) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, nullptr, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &M1, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &M2, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, DuplicateNear) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock Near((void*)(3*PageSize), 16);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, ZeroNear) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock Near(nullptr, 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, ZeroSizeNear) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock Near((void*)(4*PageSize), 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)nullptr, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)nullptr, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, UnalignedNear) {
+ CHECK_UNSUPPORTED();
+ std::error_code EC;
+ MemoryBlock Near((void*)(2*PageSize+5), 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(15, &Near, Flags, EC);
+ EXPECT_EQ(std::error_code(), EC);
+
+ EXPECT_NE((void*)nullptr, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+// Note that Memory::MF_WRITE is not supported exclusively across
+// operating systems and architectures and can imply MF_READ|MF_WRITE
+unsigned MemoryFlags[] = {
+ Memory::MF_READ,
+ Memory::MF_WRITE,
+ Memory::MF_READ|Memory::MF_WRITE,
+ Memory::MF_EXEC,
+ Memory::MF_READ|Memory::MF_EXEC,
+ Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC
+ };
+
+INSTANTIATE_TEST_CASE_P(AllocationTests,
+ MappedMemoryTest,
+ ::testing::ValuesIn(MemoryFlags),);
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/NativeFormatTests.cpp b/src/llvm-project/llvm/unittests/Support/NativeFormatTests.cpp
new file mode 100644
index 0000000..52acb6a
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/NativeFormatTests.cpp
@@ -0,0 +1,176 @@
+//===- llvm/unittest/Support/NativeFormatTests.cpp - formatting tests -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/NativeFormatting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <type_traits>
+
+using namespace llvm;
+
+namespace {
+
+template <typename T> std::string format_number(T N, IntegerStyle Style) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_integer(Str, N, 0, Style);
+ Str.flush();
+ return S;
+}
+
+std::string format_number(uint64_t N, HexPrintStyle Style,
+ Optional<size_t> Width = None) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_hex(Str, N, Style, Width);
+ Str.flush();
+ return S;
+}
+
+std::string format_number(double D, FloatStyle Style,
+ Optional<size_t> Precision = None) {
+ std::string S;
+ llvm::raw_string_ostream Str(S);
+ write_double(Str, D, Style, Precision);
+ Str.flush();
+ return S;
+}
+
+// Test basic number formatting with various styles and default width and
+// precision.
+TEST(NativeFormatTest, BasicIntegerTests) {
+ // Simple integers with no decimal.
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Integer));
+ EXPECT_EQ("2425", format_number(2425, IntegerStyle::Integer));
+ EXPECT_EQ("-2425", format_number(-2425, IntegerStyle::Integer));
+
+ EXPECT_EQ("0", format_number(0LL, IntegerStyle::Integer));
+ EXPECT_EQ("257257257235709",
+ format_number(257257257235709LL, IntegerStyle::Integer));
+ EXPECT_EQ("-257257257235709",
+ format_number(-257257257235709LL, IntegerStyle::Integer));
+
+ // Number formatting.
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+ EXPECT_EQ("2,425", format_number(2425, IntegerStyle::Number));
+ EXPECT_EQ("-2,425", format_number(-2425, IntegerStyle::Number));
+ EXPECT_EQ("257,257,257,235,709",
+ format_number(257257257235709LL, IntegerStyle::Number));
+ EXPECT_EQ("-257,257,257,235,709",
+ format_number(-257257257235709LL, IntegerStyle::Number));
+
+ // Hex formatting.
+ // lower case, prefix.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixLower));
+ EXPECT_EQ("0xbeef", format_number(0xbeefLL, HexPrintStyle::PrefixLower));
+ EXPECT_EQ("0xdeadbeef",
+ format_number(0xdeadbeefLL, HexPrintStyle::PrefixLower));
+
+ // upper-case, prefix.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixUpper));
+ EXPECT_EQ("0xBEEF", format_number(0xbeefLL, HexPrintStyle::PrefixUpper));
+ EXPECT_EQ("0xDEADBEEF",
+ format_number(0xdeadbeefLL, HexPrintStyle::PrefixUpper));
+
+ // lower-case, no prefix
+ EXPECT_EQ("0", format_number(0, HexPrintStyle::Lower));
+ EXPECT_EQ("beef", format_number(0xbeefLL, HexPrintStyle::Lower));
+ EXPECT_EQ("deadbeef", format_number(0xdeadbeefLL, HexPrintStyle::Lower));
+
+ // upper-case, no prefix.
+ EXPECT_EQ("0", format_number(0, HexPrintStyle::Upper));
+ EXPECT_EQ("BEEF", format_number(0xbeef, HexPrintStyle::Upper));
+ EXPECT_EQ("DEADBEEF", format_number(0xdeadbeef, HexPrintStyle::Upper));
+}
+
+// Test basic floating point formatting with various styles and default width
+// and precision.
+TEST(NativeFormatTest, BasicFloatingPointTests) {
+ // Double
+ EXPECT_EQ("0.000000e+00", format_number(0.0, FloatStyle::Exponent));
+ EXPECT_EQ("-0.000000e+00", format_number(-0.0, FloatStyle::Exponent));
+ EXPECT_EQ("1.100000e+00", format_number(1.1, FloatStyle::Exponent));
+ EXPECT_EQ("1.100000E+00", format_number(1.1, FloatStyle::ExponentUpper));
+
+ // Default precision is 2 for floating points.
+ EXPECT_EQ("1.10", format_number(1.1, FloatStyle::Fixed));
+ EXPECT_EQ("1.34", format_number(1.34, FloatStyle::Fixed));
+ EXPECT_EQ("1.34", format_number(1.344, FloatStyle::Fixed));
+ EXPECT_EQ("1.35", format_number(1.346, FloatStyle::Fixed));
+}
+
+// Test common boundary cases and min/max conditions.
+TEST(NativeFormatTest, BoundaryTests) {
+ // Min and max.
+ EXPECT_EQ("18446744073709551615",
+ format_number(UINT64_MAX, IntegerStyle::Integer));
+
+ EXPECT_EQ("9223372036854775807",
+ format_number(INT64_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("-9223372036854775808",
+ format_number(INT64_MIN, IntegerStyle::Integer));
+
+ EXPECT_EQ("4294967295", format_number(UINT32_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("2147483647", format_number(INT32_MAX, IntegerStyle::Integer));
+ EXPECT_EQ("-2147483648", format_number(INT32_MIN, IntegerStyle::Integer));
+
+ EXPECT_EQ("nan", format_number(std::numeric_limits<double>::quiet_NaN(),
+ FloatStyle::Fixed));
+ EXPECT_EQ("INF", format_number(std::numeric_limits<double>::infinity(),
+ FloatStyle::Fixed));
+}
+
+TEST(NativeFormatTest, HexTests) {
+ // Test hex formatting with different widths and precisions.
+
+ // Width less than the value should print the full value anyway.
+ EXPECT_EQ("0x0", format_number(0, HexPrintStyle::PrefixLower, 0));
+ EXPECT_EQ("0xabcde", format_number(0xABCDE, HexPrintStyle::PrefixLower, 3));
+
+ // Precision greater than the value should pad with 0s.
+ // TODO: The prefix should not be counted in the precision. But unfortunately
+ // it is and we have to live with it unless we fix all existing users of
+ // prefixed hex formatting.
+ EXPECT_EQ("0x000", format_number(0, HexPrintStyle::PrefixLower, 5));
+ EXPECT_EQ("0x0abcde", format_number(0xABCDE, HexPrintStyle::PrefixLower, 8));
+
+ EXPECT_EQ("00000", format_number(0, HexPrintStyle::Lower, 5));
+ EXPECT_EQ("000abcde", format_number(0xABCDE, HexPrintStyle::Lower, 8));
+
+ // Try printing more digits than can fit in a uint64.
+ EXPECT_EQ("0x00000000000000abcde",
+ format_number(0xABCDE, HexPrintStyle::PrefixLower, 21));
+}
+
+TEST(NativeFormatTest, IntegerTests) {
+ EXPECT_EQ("-10", format_number(-10, IntegerStyle::Integer));
+ EXPECT_EQ("-100", format_number(-100, IntegerStyle::Integer));
+ EXPECT_EQ("-1000", format_number(-1000, IntegerStyle::Integer));
+ EXPECT_EQ("-1234567890", format_number(-1234567890, IntegerStyle::Integer));
+ EXPECT_EQ("10", format_number(10, IntegerStyle::Integer));
+ EXPECT_EQ("100", format_number(100, IntegerStyle::Integer));
+ EXPECT_EQ("1000", format_number(1000, IntegerStyle::Integer));
+ EXPECT_EQ("1234567890", format_number(1234567890, IntegerStyle::Integer));
+}
+
+TEST(NativeFormatTest, CommaTests) {
+ EXPECT_EQ("0", format_number(0, IntegerStyle::Number));
+ EXPECT_EQ("10", format_number(10, IntegerStyle::Number));
+ EXPECT_EQ("100", format_number(100, IntegerStyle::Number));
+ EXPECT_EQ("1,000", format_number(1000, IntegerStyle::Number));
+ EXPECT_EQ("1,234,567,890", format_number(1234567890, IntegerStyle::Number));
+
+ EXPECT_EQ("-10", format_number(-10, IntegerStyle::Number));
+ EXPECT_EQ("-100", format_number(-100, IntegerStyle::Number));
+ EXPECT_EQ("-1,000", format_number(-1000, IntegerStyle::Number));
+ EXPECT_EQ("-1,234,567,890", format_number(-1234567890, IntegerStyle::Number));
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ParallelTest.cpp b/src/llvm-project/llvm/unittests/Support/ParallelTest.cpp
new file mode 100644
index 0000000..8779a61
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ParallelTest.cpp
@@ -0,0 +1,53 @@
+//===- llvm/unittest/Support/ParallelTest.cpp -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Parallel.h unit tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Parallel.h"
+#include "gtest/gtest.h"
+#include <array>
+#include <random>
+
+uint32_t array[1024 * 1024];
+
+using namespace llvm;
+
+// Tests below are hanging up on mingw. Investigating.
+#if !defined(__MINGW32__)
+
+TEST(Parallel, sort) {
+ std::mt19937 randEngine;
+ std::uniform_int_distribution<uint32_t> dist;
+
+ for (auto &i : array)
+ i = dist(randEngine);
+
+ sort(parallel::par, std::begin(array), std::end(array));
+ ASSERT_TRUE(std::is_sorted(std::begin(array), std::end(array)));
+}
+
+TEST(Parallel, parallel_for) {
+ // We need to test the case with a TaskSize > 1. We are white-box testing
+ // here. The TaskSize is calculated as (End - Begin) / 1024 at the time of
+ // writing.
+ uint32_t range[2050];
+ std::fill(range, range + 2050, 1);
+ for_each_n(parallel::par, 0, 2049, [&range](size_t I) { ++range[I]; });
+
+ uint32_t expected[2049];
+ std::fill(expected, expected + 2049, 2);
+ ASSERT_TRUE(std::equal(range, range + 2049, expected));
+ // Check that we don't write past the end of the requested range.
+ ASSERT_EQ(range[2049], 1u);
+}
+
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/Path.cpp b/src/llvm-project/llvm/unittests/Support/Path.cpp
new file mode 100644
index 0000000..97b77e2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/Path.cpp
@@ -0,0 +1,1698 @@
+//===- llvm/unittest/Support/Path.cpp - Path tests ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Path.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#ifdef _WIN32
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Chrono.h"
+#include <windows.h>
+#include <winerror.h>
+#endif
+
+#ifdef LLVM_ON_UNIX
+#include <pwd.h>
+#include <sys/stat.h>
+#endif
+
+using namespace llvm;
+using namespace llvm::sys;
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
+#define ASSERT_ERROR(x) \
+ if (!x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return a failure error code.\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ }
+
+namespace {
+
+struct FileDescriptorCloser {
+ explicit FileDescriptorCloser(int FD) : FD(FD) {}
+ ~FileDescriptorCloser() { ::close(FD); }
+ int FD;
+};
+
+TEST(is_separator, Works) {
+ EXPECT_TRUE(path::is_separator('/'));
+ EXPECT_FALSE(path::is_separator('\0'));
+ EXPECT_FALSE(path::is_separator('-'));
+ EXPECT_FALSE(path::is_separator(' '));
+
+ EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
+ EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
+
+#ifdef _WIN32
+ EXPECT_TRUE(path::is_separator('\\'));
+#else
+ EXPECT_FALSE(path::is_separator('\\'));
+#endif
+}
+
+TEST(Support, Path) {
+ SmallVector<StringRef, 40> paths;
+ paths.push_back("");
+ paths.push_back(".");
+ paths.push_back("..");
+ paths.push_back("foo");
+ paths.push_back("/");
+ paths.push_back("/foo");
+ paths.push_back("foo/");
+ paths.push_back("/foo/");
+ paths.push_back("foo/bar");
+ paths.push_back("/foo/bar");
+ paths.push_back("//net");
+ paths.push_back("//net/");
+ paths.push_back("//net/foo");
+ paths.push_back("///foo///");
+ paths.push_back("///foo///bar");
+ paths.push_back("/.");
+ paths.push_back("./");
+ paths.push_back("/..");
+ paths.push_back("../");
+ paths.push_back("foo/.");
+ paths.push_back("foo/..");
+ paths.push_back("foo/./");
+ paths.push_back("foo/./bar");
+ paths.push_back("foo/..");
+ paths.push_back("foo/../");
+ paths.push_back("foo/../bar");
+ paths.push_back("c:");
+ paths.push_back("c:/");
+ paths.push_back("c:foo");
+ paths.push_back("c:/foo");
+ paths.push_back("c:foo/");
+ paths.push_back("c:/foo/");
+ paths.push_back("c:/foo/bar");
+ paths.push_back("prn:");
+ paths.push_back("c:\\");
+ paths.push_back("c:foo");
+ paths.push_back("c:\\foo");
+ paths.push_back("c:foo\\");
+ paths.push_back("c:\\foo\\");
+ paths.push_back("c:\\foo/");
+ paths.push_back("c:/foo\\bar");
+
+ for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(),
+ e = paths.end();
+ i != e;
+ ++i) {
+ SCOPED_TRACE(*i);
+ SmallVector<StringRef, 5> ComponentStack;
+ for (sys::path::const_iterator ci = sys::path::begin(*i),
+ ce = sys::path::end(*i);
+ ci != ce;
+ ++ci) {
+ EXPECT_FALSE(ci->empty());
+ ComponentStack.push_back(*ci);
+ }
+
+ SmallVector<StringRef, 5> ReverseComponentStack;
+ for (sys::path::reverse_iterator ci = sys::path::rbegin(*i),
+ ce = sys::path::rend(*i);
+ ci != ce;
+ ++ci) {
+ EXPECT_FALSE(ci->empty());
+ ReverseComponentStack.push_back(*ci);
+ }
+ std::reverse(ReverseComponentStack.begin(), ReverseComponentStack.end());
+ EXPECT_THAT(ComponentStack, testing::ContainerEq(ReverseComponentStack));
+
+ // Crash test most of the API - since we're iterating over all of our paths
+ // here there isn't really anything reasonable to assert on in the results.
+ (void)path::has_root_path(*i);
+ (void)path::root_path(*i);
+ (void)path::has_root_name(*i);
+ (void)path::root_name(*i);
+ (void)path::has_root_directory(*i);
+ (void)path::root_directory(*i);
+ (void)path::has_parent_path(*i);
+ (void)path::parent_path(*i);
+ (void)path::has_filename(*i);
+ (void)path::filename(*i);
+ (void)path::has_stem(*i);
+ (void)path::stem(*i);
+ (void)path::has_extension(*i);
+ (void)path::extension(*i);
+ (void)path::is_absolute(*i);
+ (void)path::is_relative(*i);
+
+ SmallString<128> temp_store;
+ temp_store = *i;
+ ASSERT_NO_ERROR(fs::make_absolute(temp_store));
+ temp_store = *i;
+ path::remove_filename(temp_store);
+
+ temp_store = *i;
+ path::replace_extension(temp_store, "ext");
+ StringRef filename(temp_store.begin(), temp_store.size()), stem, ext;
+ stem = path::stem(filename);
+ ext = path::extension(filename);
+ EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str());
+
+ path::native(*i, temp_store);
+ }
+
+ SmallString<32> Relative("foo.cpp");
+ sys::fs::make_absolute("/root", Relative);
+ Relative[5] = '/'; // Fix up windows paths.
+ ASSERT_EQ("/root/foo.cpp", Relative);
+}
+
+TEST(Support, FilenameParent) {
+ EXPECT_EQ("/", path::filename("/"));
+ EXPECT_EQ("", path::parent_path("/"));
+
+ EXPECT_EQ("\\", path::filename("c:\\", path::Style::windows));
+ EXPECT_EQ("c:", path::parent_path("c:\\", path::Style::windows));
+
+ EXPECT_EQ("/", path::filename("///"));
+ EXPECT_EQ("", path::parent_path("///"));
+
+ EXPECT_EQ("\\", path::filename("c:\\\\", path::Style::windows));
+ EXPECT_EQ("c:", path::parent_path("c:\\\\", path::Style::windows));
+
+ EXPECT_EQ("bar", path::filename("/foo/bar"));
+ EXPECT_EQ("/foo", path::parent_path("/foo/bar"));
+
+ EXPECT_EQ("foo", path::filename("/foo"));
+ EXPECT_EQ("/", path::parent_path("/foo"));
+
+ EXPECT_EQ("foo", path::filename("foo"));
+ EXPECT_EQ("", path::parent_path("foo"));
+
+ EXPECT_EQ(".", path::filename("foo/"));
+ EXPECT_EQ("foo", path::parent_path("foo/"));
+
+ EXPECT_EQ("//net", path::filename("//net"));
+ EXPECT_EQ("", path::parent_path("//net"));
+
+ EXPECT_EQ("/", path::filename("//net/"));
+ EXPECT_EQ("//net", path::parent_path("//net/"));
+
+ EXPECT_EQ("foo", path::filename("//net/foo"));
+ EXPECT_EQ("//net/", path::parent_path("//net/foo"));
+
+ // These checks are just to make sure we do something reasonable with the
+ // paths below. They are not meant to prescribe the one true interpretation of
+ // these paths. Other decompositions (e.g. "//" -> "" + "//") are also
+ // possible.
+ EXPECT_EQ("/", path::filename("//"));
+ EXPECT_EQ("", path::parent_path("//"));
+
+ EXPECT_EQ("\\", path::filename("\\\\", path::Style::windows));
+ EXPECT_EQ("", path::parent_path("\\\\", path::Style::windows));
+
+ EXPECT_EQ("\\", path::filename("\\\\\\", path::Style::windows));
+ EXPECT_EQ("", path::parent_path("\\\\\\", path::Style::windows));
+}
+
+static std::vector<StringRef>
+GetComponents(StringRef Path, path::Style S = path::Style::native) {
+ return {path::begin(Path, S), path::end(Path)};
+}
+
+TEST(Support, PathIterator) {
+ EXPECT_THAT(GetComponents("/foo"), testing::ElementsAre("/", "foo"));
+ EXPECT_THAT(GetComponents("/"), testing::ElementsAre("/"));
+ EXPECT_THAT(GetComponents("//"), testing::ElementsAre("/"));
+ EXPECT_THAT(GetComponents("///"), testing::ElementsAre("/"));
+ EXPECT_THAT(GetComponents("c/d/e/foo.txt"),
+ testing::ElementsAre("c", "d", "e", "foo.txt"));
+ EXPECT_THAT(GetComponents(".c/.d/../."),
+ testing::ElementsAre(".c", ".d", "..", "."));
+ EXPECT_THAT(GetComponents("/c/d/e/foo.txt"),
+ testing::ElementsAre("/", "c", "d", "e", "foo.txt"));
+ EXPECT_THAT(GetComponents("/.c/.d/../."),
+ testing::ElementsAre("/", ".c", ".d", "..", "."));
+ EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows),
+ testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));
+ EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/"));
+ EXPECT_THAT(GetComponents("//net/c/foo.txt"),
+ testing::ElementsAre("//net", "/", "c", "foo.txt"));
+}
+
+TEST(Support, AbsolutePathIteratorEnd) {
+ // Trailing slashes are converted to '.' unless they are part of the root path.
+ SmallVector<std::pair<StringRef, path::Style>, 4> Paths;
+ Paths.emplace_back("/foo/", path::Style::native);
+ Paths.emplace_back("/foo//", path::Style::native);
+ Paths.emplace_back("//net/foo/", path::Style::native);
+ Paths.emplace_back("c:\\foo\\", path::Style::windows);
+
+ for (auto &Path : Paths) {
+ SCOPED_TRACE(Path.first);
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
+ EXPECT_EQ(".", LastComponent);
+ }
+
+ SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths;
+ RootPaths.emplace_back("/", path::Style::native);
+ RootPaths.emplace_back("//net/", path::Style::native);
+ RootPaths.emplace_back("c:\\", path::Style::windows);
+ RootPaths.emplace_back("//net//", path::Style::native);
+ RootPaths.emplace_back("c:\\\\", path::Style::windows);
+
+ for (auto &Path : RootPaths) {
+ SCOPED_TRACE(Path.first);
+ StringRef LastComponent = *path::rbegin(Path.first, Path.second);
+ EXPECT_EQ(1u, LastComponent.size());
+ EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));
+ }
+}
+
+TEST(Support, HomeDirectory) {
+ std::string expected;
+#ifdef _WIN32
+ if (wchar_t const *path = ::_wgetenv(L"USERPROFILE")) {
+ auto pathLen = ::wcslen(path);
+ ArrayRef<char> ref{reinterpret_cast<char const *>(path),
+ pathLen * sizeof(wchar_t)};
+ convertUTF16ToUTF8String(ref, expected);
+ }
+#else
+ if (char const *path = ::getenv("HOME"))
+ expected = path;
+#endif
+ // Do not try to test it if we don't know what to expect.
+ // On Windows we use something better than env vars.
+ if (!expected.empty()) {
+ SmallString<128> HomeDir;
+ auto status = path::home_directory(HomeDir);
+ EXPECT_TRUE(status);
+ EXPECT_EQ(expected, HomeDir);
+ }
+}
+
+#ifdef LLVM_ON_UNIX
+TEST(Support, HomeDirectoryWithNoEnv) {
+ std::string OriginalStorage;
+ char const *OriginalEnv = ::getenv("HOME");
+ if (OriginalEnv) {
+ // We're going to unset it, so make a copy and save a pointer to the copy
+ // so that we can reset it at the end of the test.
+ OriginalStorage = OriginalEnv;
+ OriginalEnv = OriginalStorage.c_str();
+ }
+
+ // Don't run the test if we have nothing to compare against.
+ struct passwd *pw = getpwuid(getuid());
+ if (!pw || !pw->pw_dir) return;
+
+ ::unsetenv("HOME");
+ EXPECT_EQ(nullptr, ::getenv("HOME"));
+ std::string PwDir = pw->pw_dir;
+
+ SmallString<128> HomeDir;
+ auto status = path::home_directory(HomeDir);
+ EXPECT_TRUE(status);
+ EXPECT_EQ(PwDir, HomeDir);
+
+ // Now put the environment back to its original state (meaning that if it was
+ // unset before, we don't reset it).
+ if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1);
+}
+#endif
+
+TEST(Support, TempDirectory) {
+ SmallString<32> TempDir;
+ path::system_temp_directory(false, TempDir);
+ EXPECT_TRUE(!TempDir.empty());
+ TempDir.clear();
+ path::system_temp_directory(true, TempDir);
+ EXPECT_TRUE(!TempDir.empty());
+}
+
+#ifdef _WIN32
+static std::string path2regex(std::string Path) {
+ size_t Pos = 0;
+ while ((Pos = Path.find('\\', Pos)) != std::string::npos) {
+ Path.replace(Pos, 1, "\\\\");
+ Pos += 2;
+ }
+ return Path;
+}
+
+/// Helper for running temp dir test in separated process. See below.
+#define EXPECT_TEMP_DIR(prepare, expected) \
+ EXPECT_EXIT( \
+ { \
+ prepare; \
+ SmallString<300> TempDir; \
+ path::system_temp_directory(true, TempDir); \
+ raw_os_ostream(std::cerr) << TempDir; \
+ std::exit(0); \
+ }, \
+ ::testing::ExitedWithCode(0), path2regex(expected))
+
+TEST(SupportDeathTest, TempDirectoryOnWindows) {
+ // In this test we want to check how system_temp_directory responds to
+ // different values of specific env vars. To prevent corrupting env vars of
+ // the current process all checks are done in separated processes.
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:\\OtherFolder"), "C:\\OtherFolder");
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:/Unix/Path/Seperators"),
+ "C:\\Unix\\Path\\Seperators");
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"Local Path"), ".+\\Local Path$");
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"F:\\TrailingSep\\"), "F:\\TrailingSep");
+ EXPECT_TEMP_DIR(
+ _wputenv_s(L"TMP", L"C:\\2\x03C0r-\x00B5\x00B3\\\x2135\x2080"),
+ "C:\\2\xCF\x80r-\xC2\xB5\xC2\xB3\\\xE2\x84\xB5\xE2\x82\x80");
+
+ // Test $TMP empty, $TEMP set.
+ EXPECT_TEMP_DIR(
+ {
+ _wputenv_s(L"TMP", L"");
+ _wputenv_s(L"TEMP", L"C:\\Valid\\Path");
+ },
+ "C:\\Valid\\Path");
+
+ // All related env vars empty
+ EXPECT_TEMP_DIR(
+ {
+ _wputenv_s(L"TMP", L"");
+ _wputenv_s(L"TEMP", L"");
+ _wputenv_s(L"USERPROFILE", L"");
+ },
+ "C:\\Temp");
+
+ // Test evn var / path with 260 chars.
+ SmallString<270> Expected{"C:\\Temp\\AB\\123456789"};
+ while (Expected.size() < 260)
+ Expected.append("\\DirNameWith19Charss");
+ ASSERT_EQ(260U, Expected.size());
+ EXPECT_TEMP_DIR(_putenv_s("TMP", Expected.c_str()), Expected.c_str());
+}
+#endif
+
+class FileSystemTest : public testing::Test {
+protected:
+ /// Unique temporary directory in which all created filesystem entities must
+ /// be placed. It is removed at the end of each test (must be empty).
+ SmallString<128> TestDirectory;
+ SmallString<128> NonExistantFile;
+
+ void SetUp() override {
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("file-system-test", TestDirectory));
+ // We don't care about this specific file.
+ errs() << "Test Directory: " << TestDirectory << '\n';
+ errs().flush();
+ NonExistantFile = TestDirectory;
+
+ // Even though this value is hardcoded, is a 128-bit GUID, so we should be
+ // guaranteed that this file will never exist.
+ sys::path::append(NonExistantFile, "1B28B495C16344CB9822E588CD4C3EF0");
+ }
+
+ void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); }
+};
+
+TEST_F(FileSystemTest, Unique) {
+ // Create a temp file.
+ int FileDescriptor;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(
+ fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+
+ // The same file should return an identical unique id.
+ fs::UniqueID F1, F2;
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F1));
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F2));
+ ASSERT_EQ(F1, F2);
+
+ // Different files should return different unique ids.
+ int FileDescriptor2;
+ SmallString<64> TempPath2;
+ ASSERT_NO_ERROR(
+ fs::createTemporaryFile("prefix", "temp", FileDescriptor2, TempPath2));
+
+ fs::UniqueID D;
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D));
+ ASSERT_NE(D, F1);
+ ::close(FileDescriptor2);
+
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
+
+ // Two paths representing the same file on disk should still provide the
+ // same unique id. We can test this by making a hard link.
+ ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));
+ fs::UniqueID D2;
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D2));
+ ASSERT_EQ(D2, F1);
+
+ ::close(FileDescriptor);
+
+ SmallString<128> Dir1;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("dir1", Dir1));
+ ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F1));
+ ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F2));
+ ASSERT_EQ(F1, F2);
+
+ SmallString<128> Dir2;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("dir2", Dir2));
+ ASSERT_NO_ERROR(fs::getUniqueID(Dir2.c_str(), F2));
+ ASSERT_NE(F1, F2);
+ ASSERT_NO_ERROR(fs::remove(Dir1));
+ ASSERT_NO_ERROR(fs::remove(Dir2));
+ ASSERT_NO_ERROR(fs::remove(TempPath2));
+ ASSERT_NO_ERROR(fs::remove(TempPath));
+}
+
+TEST_F(FileSystemTest, RealPath) {
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/test1/test2/test3"));
+ ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/test1/test2/test3"));
+
+ SmallString<64> RealBase;
+ SmallString<64> Expected;
+ SmallString<64> Actual;
+
+ // TestDirectory itself might be under a symlink or have been specified with
+ // a different case than the existing temp directory. In such cases real_path
+ // on the concatenated path will differ in the TestDirectory portion from
+ // how we specified it. Make sure to compare against the real_path of the
+ // TestDirectory, and not just the value of TestDirectory.
+ ASSERT_NO_ERROR(fs::real_path(TestDirectory, RealBase));
+ path::native(Twine(RealBase) + "/test1/test2", Expected);
+
+ ASSERT_NO_ERROR(fs::real_path(
+ Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual));
+
+ EXPECT_EQ(Expected, Actual);
+
+ SmallString<64> HomeDir;
+
+ // This can fail if $HOME is not set and getpwuid fails.
+ bool Result = llvm::sys::path::home_directory(HomeDir);
+ if (Result) {
+ ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected));
+ ASSERT_NO_ERROR(fs::real_path("~", Actual, true));
+ EXPECT_EQ(Expected, Actual);
+ ASSERT_NO_ERROR(fs::real_path("~/", Actual, true));
+ EXPECT_EQ(Expected, Actual);
+ }
+
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1"));
+}
+
+TEST_F(FileSystemTest, ExpandTilde) {
+ SmallString<64> Expected;
+ SmallString<64> Actual;
+ SmallString<64> HomeDir;
+
+ // This can fail if $HOME is not set and getpwuid fails.
+ bool Result = llvm::sys::path::home_directory(HomeDir);
+ if (Result) {
+ fs::expand_tilde(HomeDir, Expected);
+
+ fs::expand_tilde("~", Actual);
+ EXPECT_EQ(Expected, Actual);
+
+#ifdef _WIN32
+ Expected += "\\foo";
+ fs::expand_tilde("~\\foo", Actual);
+#else
+ Expected += "/foo";
+ fs::expand_tilde("~/foo", Actual);
+#endif
+
+ EXPECT_EQ(Expected, Actual);
+ }
+}
+
+#ifdef LLVM_ON_UNIX
+TEST_F(FileSystemTest, RealPathNoReadPerm) {
+ SmallString<64> Expanded;
+
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/noreadperm"));
+ ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/noreadperm"));
+
+ fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::no_perms);
+ fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::all_exe);
+
+ ASSERT_NO_ERROR(fs::real_path(Twine(TestDirectory) + "/noreadperm", Expanded,
+ false));
+
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/noreadperm"));
+}
+#endif
+
+
+TEST_F(FileSystemTest, TempFileKeepDiscard) {
+ // We can keep then discard.
+ auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");
+ ASSERT_TRUE((bool)TempFileOrError);
+ fs::TempFile File = std::move(*TempFileOrError);
+ ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep"));
+ ASSERT_FALSE((bool)File.discard());
+ ASSERT_TRUE(fs::exists(TestDirectory + "/keep"));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep"));
+}
+
+TEST_F(FileSystemTest, TempFileDiscardDiscard) {
+ // We can discard twice.
+ auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");
+ ASSERT_TRUE((bool)TempFileOrError);
+ fs::TempFile File = std::move(*TempFileOrError);
+ ASSERT_FALSE((bool)File.discard());
+ ASSERT_FALSE((bool)File.discard());
+ ASSERT_FALSE(fs::exists(TestDirectory + "/keep"));
+}
+
+TEST_F(FileSystemTest, TempFiles) {
+ // Create a temp file.
+ int FileDescriptor;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(
+ fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+
+ // Make sure it exists.
+ ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
+
+ // Create another temp tile.
+ int FD2;
+ SmallString<64> TempPath2;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD2, TempPath2));
+ ASSERT_TRUE(TempPath2.endswith(".temp"));
+ ASSERT_NE(TempPath.str(), TempPath2.str());
+
+ fs::file_status A, B;
+ ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
+ ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
+ EXPECT_FALSE(fs::equivalent(A, B));
+
+ ::close(FD2);
+
+ // Remove Temp2.
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
+ ASSERT_EQ(fs::remove(Twine(TempPath2), false),
+ errc::no_such_file_or_directory);
+
+ std::error_code EC = fs::status(TempPath2.c_str(), B);
+ EXPECT_EQ(EC, errc::no_such_file_or_directory);
+ EXPECT_EQ(B.type(), fs::file_type::file_not_found);
+
+ // Make sure Temp2 doesn't exist.
+ ASSERT_EQ(fs::access(Twine(TempPath2), sys::fs::AccessMode::Exist),
+ errc::no_such_file_or_directory);
+
+ SmallString<64> TempPath3;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3));
+ ASSERT_FALSE(TempPath3.endswith("."));
+ FileRemover Cleanup3(TempPath3);
+
+ // Create a hard link to Temp1.
+ ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));
+ bool equal;
+ ASSERT_NO_ERROR(fs::equivalent(Twine(TempPath), Twine(TempPath2), equal));
+ EXPECT_TRUE(equal);
+ ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
+ ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
+ EXPECT_TRUE(fs::equivalent(A, B));
+
+ // Remove Temp1.
+ ::close(FileDescriptor);
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));
+
+ // Remove the hard link.
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
+
+ // Make sure Temp1 doesn't exist.
+ ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist),
+ errc::no_such_file_or_directory);
+
+#ifdef _WIN32
+ // Path name > 260 chars should get an error.
+ const char *Path270 =
+ "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8"
+ "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"
+ "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"
+ "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"
+ "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";
+ EXPECT_EQ(fs::createUniqueFile(Path270, FileDescriptor, TempPath),
+ errc::invalid_argument);
+ // Relative path < 247 chars, no problem.
+ const char *Path216 =
+ "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"
+ "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"
+ "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"
+ "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";
+ ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath));
+ ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));
+#endif
+}
+
+TEST_F(FileSystemTest, TempFileCollisions) {
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("CreateUniqueFileTest", TestDirectory));
+ FileRemover Cleanup(TestDirectory);
+ SmallString<128> Model = TestDirectory;
+ path::append(Model, "%.tmp");
+ SmallString<128> Path;
+ std::vector<fs::TempFile> TempFiles;
+
+ auto TryCreateTempFile = [&]() {
+ Expected<fs::TempFile> T = fs::TempFile::create(Model);
+ if (T) {
+ TempFiles.push_back(std::move(*T));
+ return true;
+ } else {
+ logAllUnhandledErrors(T.takeError(), errs(),
+ "Failed to create temporary file: ");
+ return false;
+ }
+ };
+
+ // We should be able to create exactly 16 temporary files.
+ for (int i = 0; i < 16; ++i)
+ EXPECT_TRUE(TryCreateTempFile());
+ EXPECT_FALSE(TryCreateTempFile());
+
+ for (fs::TempFile &T : TempFiles)
+ cantFail(T.discard());
+}
+
+TEST_F(FileSystemTest, CreateDir) {
+ ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
+ ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
+ ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false),
+ errc::file_exists);
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "foo"));
+
+#ifdef LLVM_ON_UNIX
+ // Set a 0000 umask so that we can test our directory permissions.
+ mode_t OldUmask = ::umask(0000);
+
+ fs::file_status Status;
+ ASSERT_NO_ERROR(
+ fs::create_directory(Twine(TestDirectory) + "baz500", false,
+ fs::perms::owner_read | fs::perms::owner_exe));
+ ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz500", Status));
+ ASSERT_EQ(Status.permissions() & fs::perms::all_all,
+ fs::perms::owner_read | fs::perms::owner_exe);
+ ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "baz777", false,
+ fs::perms::all_all));
+ ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz777", Status));
+ ASSERT_EQ(Status.permissions() & fs::perms::all_all, fs::perms::all_all);
+
+ // Restore umask to be safe.
+ ::umask(OldUmask);
+#endif
+
+#ifdef _WIN32
+ // Prove that create_directories() can handle a pathname > 248 characters,
+ // which is the documented limit for CreateDirectory().
+ // (248 is MAX_PATH subtracting room for an 8.3 filename.)
+ // Generate a directory path guaranteed to fall into that range.
+ size_t TmpLen = TestDirectory.size();
+ const char *OneDir = "\\123456789";
+ size_t OneDirLen = strlen(OneDir);
+ ASSERT_LT(OneDirLen, 12U);
+ size_t NLevels = ((248 - TmpLen) / OneDirLen) + 1;
+ SmallString<260> LongDir(TestDirectory);
+ for (size_t I = 0; I < NLevels; ++I)
+ LongDir.append(OneDir);
+ ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));
+ ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));
+ ASSERT_EQ(fs::create_directories(Twine(LongDir), false),
+ errc::file_exists);
+ // Tidy up, "recursively" removing the directories.
+ StringRef ThisDir(LongDir);
+ for (size_t J = 0; J < NLevels; ++J) {
+ ASSERT_NO_ERROR(fs::remove(ThisDir));
+ ThisDir = path::parent_path(ThisDir);
+ }
+
+ // Also verify that paths with Unix separators are handled correctly.
+ std::string LongPathWithUnixSeparators(TestDirectory.str());
+ // Add at least one subdirectory to TestDirectory, and replace slashes with
+ // backslashes
+ do {
+ LongPathWithUnixSeparators.append("/DirNameWith19Charss");
+ } while (LongPathWithUnixSeparators.size() < 260);
+ std::replace(LongPathWithUnixSeparators.begin(),
+ LongPathWithUnixSeparators.end(),
+ '\\', '/');
+ ASSERT_NO_ERROR(fs::create_directories(Twine(LongPathWithUnixSeparators)));
+ // cleanup
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) +
+ "/DirNameWith19Charss"));
+
+ // Similarly for a relative pathname. Need to set the current directory to
+ // TestDirectory so that the one we create ends up in the right place.
+ char PreviousDir[260];
+ size_t PreviousDirLen = ::GetCurrentDirectoryA(260, PreviousDir);
+ ASSERT_GT(PreviousDirLen, 0U);
+ ASSERT_LT(PreviousDirLen, 260U);
+ ASSERT_NE(::SetCurrentDirectoryA(TestDirectory.c_str()), 0);
+ LongDir.clear();
+ // Generate a relative directory name with absolute length > 248.
+ size_t LongDirLen = 249 - TestDirectory.size();
+ LongDir.assign(LongDirLen, 'a');
+ ASSERT_NO_ERROR(fs::create_directory(Twine(LongDir)));
+ // While we're here, prove that .. and . handling works in these long paths.
+ const char *DotDotDirs = "\\..\\.\\b";
+ LongDir.append(DotDotDirs);
+ ASSERT_NO_ERROR(fs::create_directory("b"));
+ ASSERT_EQ(fs::create_directory(Twine(LongDir), false), errc::file_exists);
+ // And clean up.
+ ASSERT_NO_ERROR(fs::remove("b"));
+ ASSERT_NO_ERROR(fs::remove(
+ Twine(LongDir.substr(0, LongDir.size() - strlen(DotDotDirs)))));
+ ASSERT_NE(::SetCurrentDirectoryA(PreviousDir), 0);
+#endif
+}
+
+TEST_F(FileSystemTest, DirectoryIteration) {
+ std::error_code ec;
+ for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec))
+ ASSERT_NO_ERROR(ec);
+
+ // Create a known hierarchy to recurse over.
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/recursive/a0/aa1"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/recursive/a0/ab1"));
+ ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) +
+ "/recursive/dontlookhere/da1"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/recursive/z0/za1"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/recursive/pop/p1"));
+ typedef std::vector<std::string> v_t;
+ v_t visited;
+ for (fs::recursive_directory_iterator i(Twine(TestDirectory)
+ + "/recursive", ec), e; i != e; i.increment(ec)){
+ ASSERT_NO_ERROR(ec);
+ if (path::filename(i->path()) == "p1") {
+ i.pop();
+ // FIXME: recursive_directory_iterator should be more robust.
+ if (i == e) break;
+ }
+ if (path::filename(i->path()) == "dontlookhere")
+ i.no_push();
+ visited.push_back(path::filename(i->path()));
+ }
+ v_t::const_iterator a0 = find(visited, "a0");
+ v_t::const_iterator aa1 = find(visited, "aa1");
+ v_t::const_iterator ab1 = find(visited, "ab1");
+ v_t::const_iterator dontlookhere = find(visited, "dontlookhere");
+ v_t::const_iterator da1 = find(visited, "da1");
+ v_t::const_iterator z0 = find(visited, "z0");
+ v_t::const_iterator za1 = find(visited, "za1");
+ v_t::const_iterator pop = find(visited, "pop");
+ v_t::const_iterator p1 = find(visited, "p1");
+
+ // Make sure that each path was visited correctly.
+ ASSERT_NE(a0, visited.end());
+ ASSERT_NE(aa1, visited.end());
+ ASSERT_NE(ab1, visited.end());
+ ASSERT_NE(dontlookhere, visited.end());
+ ASSERT_EQ(da1, visited.end()); // Not visited.
+ ASSERT_NE(z0, visited.end());
+ ASSERT_NE(za1, visited.end());
+ ASSERT_NE(pop, visited.end());
+ ASSERT_EQ(p1, visited.end()); // Not visited.
+
+ // Make sure that parents were visited before children. No other ordering
+ // guarantees can be made across siblings.
+ ASSERT_LT(a0, aa1);
+ ASSERT_LT(a0, ab1);
+ ASSERT_LT(z0, za1);
+
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/aa1"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/ab1"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0"));
+ ASSERT_NO_ERROR(
+ fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere/da1"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop/p1"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0/za1"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive"));
+
+ // Test recursive_directory_iterator level()
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/reclevel/a/b/c"));
+ fs::recursive_directory_iterator I(Twine(TestDirectory) + "/reclevel", ec), E;
+ for (int l = 0; I != E; I.increment(ec), ++l) {
+ ASSERT_NO_ERROR(ec);
+ EXPECT_EQ(I.level(), l);
+ }
+ EXPECT_EQ(I, E);
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b/c"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a"));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel"));
+}
+
+#ifdef LLVM_ON_UNIX
+TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) {
+ // Create a known hierarchy to recurse over.
+ ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + "/symlink"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/a"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/symlink/b/bb"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/ba"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/bc"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/c"));
+ ASSERT_NO_ERROR(
+ fs::create_directories(Twine(TestDirectory) + "/symlink/d/dd/ddd"));
+ ASSERT_NO_ERROR(fs::create_link(Twine(TestDirectory) + "/symlink/d/dd",
+ Twine(TestDirectory) + "/symlink/d/da"));
+ ASSERT_NO_ERROR(
+ fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e"));
+
+ typedef std::vector<std::string> v_t;
+ v_t VisitedNonBrokenSymlinks;
+ v_t VisitedBrokenSymlinks;
+ std::error_code ec;
+ using testing::UnorderedElementsAre;
+ using testing::UnorderedElementsAreArray;
+
+ // Broken symbol links are expected to throw an error.
+ for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e;
+ i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+ if (i->status().getError() ==
+ std::make_error_code(std::errc::no_such_file_or_directory)) {
+ VisitedBrokenSymlinks.push_back(path::filename(i->path()));
+ continue;
+ }
+ VisitedNonBrokenSymlinks.push_back(path::filename(i->path()));
+ }
+ EXPECT_THAT(VisitedNonBrokenSymlinks, UnorderedElementsAre("b", "d"));
+ VisitedNonBrokenSymlinks.clear();
+
+ EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre("a", "c", "e"));
+ VisitedBrokenSymlinks.clear();
+
+ // Broken symbol links are expected to throw an error.
+ for (fs::recursive_directory_iterator i(
+ Twine(TestDirectory) + "/symlink", ec), e; i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+ if (i->status().getError() ==
+ std::make_error_code(std::errc::no_such_file_or_directory)) {
+ VisitedBrokenSymlinks.push_back(path::filename(i->path()));
+ continue;
+ }
+ VisitedNonBrokenSymlinks.push_back(path::filename(i->path()));
+ }
+ EXPECT_THAT(VisitedNonBrokenSymlinks,
+ UnorderedElementsAre("b", "bb", "d", "da", "dd", "ddd", "ddd"));
+ VisitedNonBrokenSymlinks.clear();
+
+ EXPECT_THAT(VisitedBrokenSymlinks,
+ UnorderedElementsAre("a", "ba", "bc", "c", "e"));
+ VisitedBrokenSymlinks.clear();
+
+ for (fs::recursive_directory_iterator i(
+ Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), e;
+ i != e; i.increment(ec)) {
+ ASSERT_NO_ERROR(ec);
+ if (i->status().getError() ==
+ std::make_error_code(std::errc::no_such_file_or_directory)) {
+ VisitedBrokenSymlinks.push_back(path::filename(i->path()));
+ continue;
+ }
+ VisitedNonBrokenSymlinks.push_back(path::filename(i->path()));
+ }
+ EXPECT_THAT(VisitedNonBrokenSymlinks,
+ UnorderedElementsAreArray({"a", "b", "ba", "bb", "bc", "c", "d",
+ "da", "dd", "ddd", "e"}));
+ VisitedNonBrokenSymlinks.clear();
+
+ EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre());
+ VisitedBrokenSymlinks.clear();
+
+ ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink"));
+}
+#endif
+
+TEST_F(FileSystemTest, Remove) {
+ SmallString<64> BaseDir;
+ SmallString<64> Paths[4];
+ int fds[4];
+ ASSERT_NO_ERROR(fs::createUniqueDirectory("fs_remove", BaseDir));
+
+ ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/baz"));
+ ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/buzz"));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[0], Paths[0]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[1], Paths[1]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[2], Paths[2]));
+ ASSERT_NO_ERROR(fs::createUniqueFile(
+ Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[3], Paths[3]));
+
+ for (int fd : fds)
+ ::close(fd);
+
+ EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/baz"));
+ EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/buzz"));
+ EXPECT_TRUE(fs::exists(Paths[0]));
+ EXPECT_TRUE(fs::exists(Paths[1]));
+ EXPECT_TRUE(fs::exists(Paths[2]));
+ EXPECT_TRUE(fs::exists(Paths[3]));
+
+ ASSERT_NO_ERROR(fs::remove_directories("D:/footest"));
+
+ ASSERT_NO_ERROR(fs::remove_directories(BaseDir));
+ ASSERT_FALSE(fs::exists(BaseDir));
+}
+
+#ifdef _WIN32
+TEST_F(FileSystemTest, CarriageReturn) {
+ SmallString<128> FilePathname(TestDirectory);
+ std::error_code EC;
+ path::append(FilePathname, "test");
+
+ {
+ raw_fd_ostream File(FilePathname, EC, sys::fs::F_Text);
+ ASSERT_NO_ERROR(EC);
+ File << '\n';
+ }
+ {
+ auto Buf = MemoryBuffer::getFile(FilePathname.str());
+ EXPECT_TRUE((bool)Buf);
+ EXPECT_EQ(Buf.get()->getBuffer(), "\r\n");
+ }
+
+ {
+ raw_fd_ostream File(FilePathname, EC, sys::fs::F_None);
+ ASSERT_NO_ERROR(EC);
+ File << '\n';
+ }
+ {
+ auto Buf = MemoryBuffer::getFile(FilePathname.str());
+ EXPECT_TRUE((bool)Buf);
+ EXPECT_EQ(Buf.get()->getBuffer(), "\n");
+ }
+ ASSERT_NO_ERROR(fs::remove(Twine(FilePathname)));
+}
+#endif
+
+TEST_F(FileSystemTest, Resize) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ ASSERT_NO_ERROR(fs::resize_file(FD, 123));
+ fs::file_status Status;
+ ASSERT_NO_ERROR(fs::status(FD, Status));
+ ASSERT_EQ(Status.getSize(), 123U);
+ ::close(FD);
+ ASSERT_NO_ERROR(fs::remove(TempPath));
+}
+
+TEST_F(FileSystemTest, MD5) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ StringRef Data("abcdefghijklmnopqrstuvwxyz");
+ ASSERT_EQ(write(FD, Data.data(), Data.size()), static_cast<ssize_t>(Data.size()));
+ lseek(FD, 0, SEEK_SET);
+ auto Hash = fs::md5_contents(FD);
+ ::close(FD);
+ ASSERT_NO_ERROR(Hash.getError());
+
+ EXPECT_STREQ("c3fcd3d76192e4007dfb496cca67e13b", Hash->digest().c_str());
+}
+
+TEST_F(FileSystemTest, FileMapping) {
+ // Create a temp file.
+ int FileDescriptor;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(
+ fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+ unsigned Size = 4096;
+ ASSERT_NO_ERROR(fs::resize_file(FileDescriptor, Size));
+
+ // Map in temp file and add some content
+ std::error_code EC;
+ StringRef Val("hello there");
+ {
+ fs::mapped_file_region mfr(FileDescriptor,
+ fs::mapped_file_region::readwrite, Size, 0, EC);
+ ASSERT_NO_ERROR(EC);
+ std::copy(Val.begin(), Val.end(), mfr.data());
+ // Explicitly add a 0.
+ mfr.data()[Val.size()] = 0;
+ // Unmap temp file
+ }
+ ASSERT_EQ(close(FileDescriptor), 0);
+
+ // Map it back in read-only
+ {
+ int FD;
+ EC = fs::openFileForRead(Twine(TempPath), FD);
+ ASSERT_NO_ERROR(EC);
+ fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC);
+ ASSERT_NO_ERROR(EC);
+
+ // Verify content
+ EXPECT_EQ(StringRef(mfr.const_data()), Val);
+
+ // Unmap temp file
+ fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC);
+ ASSERT_NO_ERROR(EC);
+ ASSERT_EQ(close(FD), 0);
+ }
+ ASSERT_NO_ERROR(fs::remove(TempPath));
+}
+
+TEST(Support, NormalizePath) {
+ using TestTuple = std::tuple<const char *, const char *, const char *>;
+ std::vector<TestTuple> Tests;
+ Tests.emplace_back("a", "a", "a");
+ Tests.emplace_back("a/b", "a\\b", "a/b");
+ Tests.emplace_back("a\\b", "a\\b", "a/b");
+ Tests.emplace_back("a\\\\b", "a\\\\b", "a\\\\b");
+ Tests.emplace_back("\\a", "\\a", "/a");
+ Tests.emplace_back("a\\", "a\\", "a/");
+
+ for (auto &T : Tests) {
+ SmallString<64> Win(std::get<0>(T));
+ SmallString<64> Posix(Win);
+ path::native(Win, path::Style::windows);
+ path::native(Posix, path::Style::posix);
+ EXPECT_EQ(std::get<1>(T), Win);
+ EXPECT_EQ(std::get<2>(T), Posix);
+ }
+
+#if defined(_WIN32)
+ SmallString<64> PathHome;
+ path::home_directory(PathHome);
+
+ const char *Path7a = "~/aaa";
+ SmallString<64> Path7(Path7a);
+ path::native(Path7);
+ EXPECT_TRUE(Path7.endswith("\\aaa"));
+ EXPECT_TRUE(Path7.startswith(PathHome));
+ EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));
+
+ const char *Path8a = "~";
+ SmallString<64> Path8(Path8a);
+ path::native(Path8);
+ EXPECT_EQ(Path8, PathHome);
+
+ const char *Path9a = "~aaa";
+ SmallString<64> Path9(Path9a);
+ path::native(Path9);
+ EXPECT_EQ(Path9, "~aaa");
+
+ const char *Path10a = "aaa/~/b";
+ SmallString<64> Path10(Path10a);
+ path::native(Path10);
+ EXPECT_EQ(Path10, "aaa\\~\\b");
+#endif
+}
+
+TEST(Support, RemoveLeadingDotSlash) {
+ StringRef Path1("././/foolz/wat");
+ StringRef Path2("./////");
+
+ Path1 = path::remove_leading_dotslash(Path1);
+ EXPECT_EQ(Path1, "foolz/wat");
+ Path2 = path::remove_leading_dotslash(Path2);
+ EXPECT_EQ(Path2, "");
+}
+
+static std::string remove_dots(StringRef path, bool remove_dot_dot,
+ path::Style style) {
+ SmallString<256> buffer(path);
+ path::remove_dots(buffer, remove_dot_dot, style);
+ return buffer.str();
+}
+
+TEST(Support, RemoveDots) {
+ EXPECT_EQ("foolz\\wat",
+ remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));
+ EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));
+
+ EXPECT_EQ("a\\..\\b\\c",
+ remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));
+ EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));
+ EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\a\\c",
+ remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));
+ EXPECT_EQ("..\\..\\a\\c",
+ remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));
+
+ SmallString<64> Path1(".\\.\\c");
+ EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));
+ EXPECT_EQ("c", Path1);
+
+ EXPECT_EQ("foolz/wat",
+ remove_dots("././/foolz/wat", false, path::Style::posix));
+ EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));
+
+ EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));
+ EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));
+ EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));
+ EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("../../a/c",
+ remove_dots("../../a/b/../c", true, path::Style::posix));
+ EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));
+ EXPECT_EQ("/a/c",
+ remove_dots("/../a/b//../././/c", true, path::Style::posix));
+
+ SmallString<64> Path2("././c");
+ EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));
+ EXPECT_EQ("c", Path2);
+}
+
+TEST(Support, ReplacePathPrefix) {
+ SmallString<64> Path1("/foo");
+ SmallString<64> Path2("/old/foo");
+ SmallString<64> OldPrefix("/old");
+ SmallString<64> NewPrefix("/new");
+ SmallString<64> NewPrefix2("/longernew");
+ SmallString<64> EmptyPrefix("");
+
+ SmallString<64> Path = Path1;
+ path::replace_path_prefix(Path, OldPrefix, NewPrefix);
+ EXPECT_EQ(Path, "/foo");
+ Path = Path2;
+ path::replace_path_prefix(Path, OldPrefix, NewPrefix);
+ EXPECT_EQ(Path, "/new/foo");
+ Path = Path2;
+ path::replace_path_prefix(Path, OldPrefix, NewPrefix2);
+ EXPECT_EQ(Path, "/longernew/foo");
+ Path = Path1;
+ path::replace_path_prefix(Path, EmptyPrefix, NewPrefix);
+ EXPECT_EQ(Path, "/new/foo");
+ Path = Path2;
+ path::replace_path_prefix(Path, OldPrefix, EmptyPrefix);
+ EXPECT_EQ(Path, "/foo");
+}
+
+TEST_F(FileSystemTest, OpenFileForRead) {
+ // Create a temp file.
+ int FileDescriptor;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(
+ fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
+ FileRemover Cleanup(TempPath);
+
+ // Make sure it exists.
+ ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
+
+ // Open the file for read
+ int FileDescriptor2;
+ SmallString<64> ResultPath;
+ ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor2,
+ fs::OF_None, &ResultPath))
+
+ // If we succeeded, check that the paths are the same (modulo case):
+ if (!ResultPath.empty()) {
+ // The paths returned by createTemporaryFile and getPathFromOpenFD
+ // should reference the same file on disk.
+ fs::UniqueID D1, D2;
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1));
+ ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2));
+ ASSERT_EQ(D1, D2);
+ }
+ ::close(FileDescriptor);
+ ::close(FileDescriptor2);
+
+#ifdef _WIN32
+ // Since Windows Vista, file access time is not updated by default.
+ // This is instead updated manually by openFileForRead.
+ // https://blogs.technet.microsoft.com/filecab/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance/
+ // This part of the unit test is Windows specific as the updating of
+ // access times can be disabled on Linux using /etc/fstab.
+
+ // Set access time to UNIX epoch.
+ ASSERT_NO_ERROR(sys::fs::openFileForWrite(Twine(TempPath), FileDescriptor,
+ fs::CD_OpenExisting));
+ TimePoint<> Epoch(std::chrono::milliseconds(0));
+ ASSERT_NO_ERROR(fs::setLastAccessAndModificationTime(FileDescriptor, Epoch));
+ ::close(FileDescriptor);
+
+ // Open the file and ensure access time is updated, when forced.
+ ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor,
+ fs::OF_UpdateAtime, &ResultPath));
+
+ sys::fs::file_status Status;
+ ASSERT_NO_ERROR(sys::fs::status(FileDescriptor, Status));
+ auto FileAccessTime = Status.getLastAccessedTime();
+
+ ASSERT_NE(Epoch, FileAccessTime);
+ ::close(FileDescriptor);
+
+ // Ideally this test would include a case when ATime is not forced to update,
+ // however the expected behaviour will differ depending on the configuration
+ // of the Windows file system.
+#endif
+}
+
+static void createFileWithData(const Twine &Path, bool ShouldExistBefore,
+ fs::CreationDisposition Disp, StringRef Data) {
+ int FD;
+ ASSERT_EQ(ShouldExistBefore, fs::exists(Path));
+ ASSERT_NO_ERROR(fs::openFileForWrite(Path, FD, Disp));
+ FileDescriptorCloser Closer(FD);
+ ASSERT_TRUE(fs::exists(Path));
+
+ ASSERT_EQ(Data.size(), (size_t)write(FD, Data.data(), Data.size()));
+}
+
+static void verifyFileContents(const Twine &Path, StringRef Contents) {
+ auto Buffer = MemoryBuffer::getFile(Path);
+ ASSERT_TRUE((bool)Buffer);
+ StringRef Data = Buffer.get()->getBuffer();
+ ASSERT_EQ(Data, Contents);
+}
+
+TEST_F(FileSystemTest, CreateNew) {
+ int FD;
+ Optional<FileDescriptorCloser> Closer;
+
+ // Succeeds if the file does not exist.
+ ASSERT_FALSE(fs::exists(NonExistantFile));
+ ASSERT_NO_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));
+ ASSERT_TRUE(fs::exists(NonExistantFile));
+
+ FileRemover Cleanup(NonExistantFile);
+ Closer.emplace(FD);
+
+ // And creates a file of size 0.
+ sys::fs::file_status Status;
+ ASSERT_NO_ERROR(sys::fs::status(FD, Status));
+ EXPECT_EQ(0ULL, Status.getSize());
+
+ // Close this first, before trying to re-open the file.
+ Closer.reset();
+
+ // But fails if the file does exist.
+ ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));
+}
+
+TEST_F(FileSystemTest, CreateAlways) {
+ int FD;
+ Optional<FileDescriptorCloser> Closer;
+
+ // Succeeds if the file does not exist.
+ ASSERT_FALSE(fs::exists(NonExistantFile));
+ ASSERT_NO_ERROR(
+ fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));
+
+ Closer.emplace(FD);
+
+ ASSERT_TRUE(fs::exists(NonExistantFile));
+
+ FileRemover Cleanup(NonExistantFile);
+
+ // And creates a file of size 0.
+ uint64_t FileSize;
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(0ULL, FileSize);
+
+ // If we write some data to it re-create it with CreateAlways, it succeeds and
+ // truncates to 0 bytes.
+ ASSERT_EQ(4, write(FD, "Test", 4));
+
+ Closer.reset();
+
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(4ULL, FileSize);
+
+ ASSERT_NO_ERROR(
+ fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));
+ Closer.emplace(FD);
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(0ULL, FileSize);
+}
+
+TEST_F(FileSystemTest, OpenExisting) {
+ int FD;
+
+ // Fails if the file does not exist.
+ ASSERT_FALSE(fs::exists(NonExistantFile));
+ ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));
+ ASSERT_FALSE(fs::exists(NonExistantFile));
+
+ // Make a dummy file now so that we can try again when the file does exist.
+ createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
+ FileRemover Cleanup(NonExistantFile);
+ uint64_t FileSize;
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(4ULL, FileSize);
+
+ // If we re-create it with different data, it overwrites rather than
+ // appending.
+ createFileWithData(NonExistantFile, true, fs::CD_OpenExisting, "Buzz");
+ verifyFileContents(NonExistantFile, "Buzz");
+}
+
+TEST_F(FileSystemTest, OpenAlways) {
+ // Succeeds if the file does not exist.
+ createFileWithData(NonExistantFile, false, fs::CD_OpenAlways, "Fizz");
+ FileRemover Cleanup(NonExistantFile);
+ uint64_t FileSize;
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(4ULL, FileSize);
+
+ // Now re-open it and write again, verifying the contents get over-written.
+ createFileWithData(NonExistantFile, true, fs::CD_OpenAlways, "Bu");
+ verifyFileContents(NonExistantFile, "Buzz");
+}
+
+TEST_F(FileSystemTest, AppendSetsCorrectFileOffset) {
+ fs::CreationDisposition Disps[] = {fs::CD_CreateAlways, fs::CD_OpenAlways,
+ fs::CD_OpenExisting};
+
+ // Write some data and re-open it with every possible disposition (this is a
+ // hack that shouldn't work, but is left for compatibility. F_Append
+ // overrides
+ // the specified disposition.
+ for (fs::CreationDisposition Disp : Disps) {
+ int FD;
+ Optional<FileDescriptorCloser> Closer;
+
+ createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
+
+ FileRemover Cleanup(NonExistantFile);
+
+ uint64_t FileSize;
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(4ULL, FileSize);
+ ASSERT_NO_ERROR(
+ fs::openFileForWrite(NonExistantFile, FD, Disp, fs::OF_Append));
+ Closer.emplace(FD);
+ ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
+ ASSERT_EQ(4ULL, FileSize);
+
+ ASSERT_EQ(4, write(FD, "Buzz", 4));
+ Closer.reset();
+
+ verifyFileContents(NonExistantFile, "FizzBuzz");
+ }
+}
+
+static void verifyRead(int FD, StringRef Data, bool ShouldSucceed) {
+ std::vector<char> Buffer;
+ Buffer.resize(Data.size());
+ int Result = ::read(FD, Buffer.data(), Buffer.size());
+ if (ShouldSucceed) {
+ ASSERT_EQ((size_t)Result, Data.size());
+ ASSERT_EQ(Data, StringRef(Buffer.data(), Buffer.size()));
+ } else {
+ ASSERT_EQ(-1, Result);
+ ASSERT_EQ(EBADF, errno);
+ }
+}
+
+static void verifyWrite(int FD, StringRef Data, bool ShouldSucceed) {
+ int Result = ::write(FD, Data.data(), Data.size());
+ if (ShouldSucceed)
+ ASSERT_EQ((size_t)Result, Data.size());
+ else {
+ ASSERT_EQ(-1, Result);
+ ASSERT_EQ(EBADF, errno);
+ }
+}
+
+TEST_F(FileSystemTest, ReadOnlyFileCantWrite) {
+ createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
+ FileRemover Cleanup(NonExistantFile);
+
+ int FD;
+ ASSERT_NO_ERROR(fs::openFileForRead(NonExistantFile, FD));
+ FileDescriptorCloser Closer(FD);
+
+ verifyWrite(FD, "Buzz", false);
+ verifyRead(FD, "Fizz", true);
+}
+
+TEST_F(FileSystemTest, WriteOnlyFileCantRead) {
+ createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
+ FileRemover Cleanup(NonExistantFile);
+
+ int FD;
+ ASSERT_NO_ERROR(
+ fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));
+ FileDescriptorCloser Closer(FD);
+ verifyRead(FD, "Fizz", false);
+ verifyWrite(FD, "Buzz", true);
+}
+
+TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) {
+ createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
+ FileRemover Cleanup(NonExistantFile);
+
+ int FD;
+ ASSERT_NO_ERROR(fs::openFileForReadWrite(NonExistantFile, FD,
+ fs::CD_OpenExisting, fs::OF_None));
+ FileDescriptorCloser Closer(FD);
+ verifyRead(FD, "Fizz", true);
+ verifyWrite(FD, "Buzz", true);
+}
+
+TEST_F(FileSystemTest, set_current_path) {
+ SmallString<128> path;
+
+ ASSERT_NO_ERROR(fs::current_path(path));
+ ASSERT_NE(TestDirectory, path);
+
+ struct RestorePath {
+ SmallString<128> path;
+ RestorePath(const SmallString<128> &path) : path(path) {}
+ ~RestorePath() { fs::set_current_path(path); }
+ } restore_path(path);
+
+ ASSERT_NO_ERROR(fs::set_current_path(TestDirectory));
+
+ ASSERT_NO_ERROR(fs::current_path(path));
+
+ fs::UniqueID D1, D2;
+ ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1));
+ ASSERT_NO_ERROR(fs::getUniqueID(path, D2));
+ ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;
+}
+
+TEST_F(FileSystemTest, permissions) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ FileRemover Cleanup(TempPath);
+
+ // Make sure it exists.
+ ASSERT_TRUE(fs::exists(Twine(TempPath)));
+
+ auto CheckPermissions = [&](fs::perms Expected) {
+ ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath);
+ return Actual && *Actual == Expected;
+ };
+
+ std::error_code NoError;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));
+
+#if defined(_WIN32)
+ fs::perms ReadOnly = fs::all_read | fs::all_exe;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+#else
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::no_perms));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));
+
+ // Modern BSDs require root to set the sticky bit on files.
+ // AIX without root will mask off (i.e., lose) the sticky bit on files.
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \
+ !defined(_AIX)
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |
+ fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe | fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_perms));
+#endif // !FreeBSD && !NetBSD && !OpenBSD && !AIX
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms & ~fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_perms & ~fs::sticky_bit));
+#endif
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ProcessTest.cpp b/src/llvm-project/llvm/unittests/Support/ProcessTest.cpp
new file mode 100644
index 0000000..85b1839
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ProcessTest.cpp
@@ -0,0 +1,65 @@
+//===- unittest/Support/ProcessTest.cpp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Process.h"
+#include "gtest/gtest.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace {
+
+using namespace llvm;
+using namespace sys;
+
+TEST(ProcessTest, GetRandomNumberTest) {
+ const unsigned r1 = Process::GetRandomNumber();
+ const unsigned r2 = Process::GetRandomNumber();
+ // It should be extremely unlikely that both r1 and r2 are 0.
+ EXPECT_NE((r1 | r2), 0u);
+}
+
+#ifdef _MSC_VER
+#define setenv(name, var, ignore) _putenv_s(name, var)
+#endif
+
+#if HAVE_SETENV || _MSC_VER
+TEST(ProcessTest, Basic) {
+ setenv("__LLVM_TEST_ENVIRON_VAR__", "abc", true);
+ Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));
+ EXPECT_TRUE(val.hasValue());
+ EXPECT_STREQ("abc", val->c_str());
+}
+
+TEST(ProcessTest, None) {
+ Optional<std::string> val(
+ Process::GetEnv("__LLVM_TEST_ENVIRON_NO_SUCH_VAR__"));
+ EXPECT_FALSE(val.hasValue());
+}
+#endif
+
+#ifdef _WIN32
+
+TEST(ProcessTest, EmptyVal) {
+ SetEnvironmentVariableA("__LLVM_TEST_ENVIRON_VAR__", "");
+ Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));
+ EXPECT_TRUE(val.hasValue());
+ EXPECT_STREQ("", val->c_str());
+}
+
+TEST(ProcessTest, Wchar) {
+ SetEnvironmentVariableW(L"__LLVM_TEST_ENVIRON_VAR__", L"abcdefghijklmnopqrs");
+ Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__"));
+ EXPECT_TRUE(val.hasValue());
+ EXPECT_STREQ("abcdefghijklmnopqrs", val->c_str());
+}
+#endif
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ProgramTest.cpp b/src/llvm-project/llvm/unittests/Support/ProgramTest.cpp
new file mode 100644
index 0000000..ec1c85a
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ProgramTest.cpp
@@ -0,0 +1,340 @@
+//===- unittest/Support/ProgramTest.cpp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Program.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+#include <stdlib.h>
+#if defined(__APPLE__)
+# include <crt_externs.h>
+#elif !defined(_MSC_VER)
+// Forward declare environ in case it's not provided by stdlib.h.
+extern char **environ;
+#endif
+
+#if defined(LLVM_ON_UNIX)
+#include <unistd.h>
+void sleep_for(unsigned int seconds) {
+ sleep(seconds);
+}
+#elif defined(_WIN32)
+#include <windows.h>
+void sleep_for(unsigned int seconds) {
+ Sleep(seconds * 1000);
+}
+#else
+#error sleep_for is not implemented on your platform.
+#endif
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+// From TestMain.cpp.
+extern const char *TestMainArgv0;
+
+namespace {
+
+using namespace llvm;
+using namespace sys;
+
+static cl::opt<std::string>
+ProgramTestStringArg1("program-test-string-arg1");
+static cl::opt<std::string>
+ProgramTestStringArg2("program-test-string-arg2");
+
+class ProgramEnvTest : public testing::Test {
+ std::vector<StringRef> EnvTable;
+ std::vector<std::string> EnvStorage;
+
+protected:
+ void SetUp() override {
+ auto EnvP = [] {
+#if defined(_WIN32)
+ _wgetenv(L"TMP"); // Populate _wenviron, initially is null
+ return _wenviron;
+#elif defined(__APPLE__)
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+ }();
+ ASSERT_TRUE(EnvP);
+
+ auto prepareEnvVar = [this](decltype(*EnvP) Var) -> StringRef {
+#if defined(_WIN32)
+ // On Windows convert UTF16 encoded variable to UTF8
+ auto Len = wcslen(Var);
+ ArrayRef<char> Ref{reinterpret_cast<char const *>(Var),
+ Len * sizeof(*Var)};
+ EnvStorage.emplace_back();
+ auto convStatus = convertUTF16ToUTF8String(Ref, EnvStorage.back());
+ EXPECT_TRUE(convStatus);
+ return EnvStorage.back();
+#else
+ (void)this;
+ return StringRef(Var);
+#endif
+ };
+
+ while (*EnvP != nullptr) {
+ EnvTable.emplace_back(prepareEnvVar(*EnvP));
+ ++EnvP;
+ }
+ }
+
+ void TearDown() override {
+ EnvTable.clear();
+ EnvStorage.clear();
+ }
+
+ void addEnvVar(StringRef Var) { EnvTable.emplace_back(Var); }
+
+ ArrayRef<StringRef> getEnviron() const { return EnvTable; }
+};
+
+#ifdef _WIN32
+TEST_F(ProgramEnvTest, CreateProcessLongPath) {
+ if (getenv("LLVM_PROGRAM_TEST_LONG_PATH"))
+ exit(0);
+
+ // getMainExecutable returns an absolute path; prepend the long-path prefix.
+ std::string MyAbsExe =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ std::string MyExe;
+ if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
+ MyExe.append("\\\\?\\");
+ MyExe.append(MyAbsExe);
+
+ StringRef ArgV[] = {MyExe,
+ "--gtest_filter=ProgramEnvTest.CreateProcessLongPath"};
+
+ // Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child.
+ addEnvVar("LLVM_PROGRAM_TEST_LONG_PATH=1");
+
+ // Redirect stdout to a long path.
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("program-redirect-test", TestDirectory));
+ SmallString<256> LongPath(TestDirectory);
+ LongPath.push_back('\\');
+ // MAX_PATH = 260
+ LongPath.append(260 - TestDirectory.size(), 'a');
+
+ std::string Error;
+ bool ExecutionFailed;
+ Optional<StringRef> Redirects[] = {None, LongPath.str(), None};
+ int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects,
+ /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
+ &ExecutionFailed);
+ EXPECT_FALSE(ExecutionFailed) << Error;
+ EXPECT_EQ(0, RC);
+
+ // Remove the long stdout.
+ ASSERT_NO_ERROR(fs::remove(Twine(LongPath)));
+ ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory)));
+}
+#endif
+
+TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) {
+ if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
+ if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&
+ ProgramTestStringArg2 == "has\\\\ trailing\\") {
+ exit(0); // Success! The arguments were passed and parsed.
+ }
+ exit(1);
+ }
+
+ std::string my_exe =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ StringRef argv[] = {
+ my_exe,
+ "--gtest_filter=ProgramEnvTest.CreateProcessTrailingSlash",
+ "-program-test-string-arg1",
+ "has\\\\ trailing\\",
+ "-program-test-string-arg2",
+ "has\\\\ trailing\\"};
+
+ // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child.
+ addEnvVar("LLVM_PROGRAM_TEST_CHILD=1");
+
+ std::string error;
+ bool ExecutionFailed;
+ // Redirect stdout and stdin to NUL, but let stderr through.
+#ifdef _WIN32
+ StringRef nul("NUL");
+#else
+ StringRef nul("/dev/null");
+#endif
+ Optional<StringRef> redirects[] = { nul, nul, None };
+ int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects,
+ /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error,
+ &ExecutionFailed);
+ EXPECT_FALSE(ExecutionFailed) << error;
+ EXPECT_EQ(0, rc);
+}
+
+TEST_F(ProgramEnvTest, TestExecuteNoWait) {
+ using namespace llvm::sys;
+
+ if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) {
+ sleep_for(/*seconds*/ 1);
+ exit(0);
+ }
+
+ std::string Executable =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ StringRef argv[] = {Executable,
+ "--gtest_filter=ProgramEnvTest.TestExecuteNoWait"};
+
+ // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child.
+ addEnvVar("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1");
+
+ std::string Error;
+ bool ExecutionFailed;
+ ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
+ &ExecutionFailed);
+ ASSERT_FALSE(ExecutionFailed) << Error;
+ ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
+
+ unsigned LoopCount = 0;
+
+ // Test that Wait() with WaitUntilTerminates=true works. In this case,
+ // LoopCount should only be incremented once.
+ while (true) {
+ ++LoopCount;
+ ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error);
+ ASSERT_TRUE(Error.empty());
+ if (WaitResult.Pid == PI1.Pid)
+ break;
+ }
+
+ EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1";
+
+ ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error,
+ &ExecutionFailed);
+ ASSERT_FALSE(ExecutionFailed) << Error;
+ ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
+
+ // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this
+ // cse, LoopCount should be greater than 1 (more than one increment occurs).
+ while (true) {
+ ++LoopCount;
+ ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error);
+ ASSERT_TRUE(Error.empty());
+ if (WaitResult.Pid == PI2.Pid)
+ break;
+ }
+
+ ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
+}
+
+TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) {
+ using namespace llvm::sys;
+
+ if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) {
+ sleep_for(/*seconds*/ 10);
+ exit(0);
+ }
+
+ std::string Executable =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ StringRef argv[] = {
+ Executable, "--gtest_filter=ProgramEnvTest.TestExecuteAndWaitTimeout"};
+
+ // Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child.
+ addEnvVar("LLVM_PROGRAM_TEST_TIMEOUT=1");
+
+ std::string Error;
+ bool ExecutionFailed;
+ int RetCode =
+ ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0,
+ &Error, &ExecutionFailed);
+ ASSERT_EQ(-2, RetCode);
+}
+
+TEST(ProgramTest, TestExecuteNegative) {
+ std::string Executable = "i_dont_exist";
+ StringRef argv[] = {Executable};
+
+ {
+ std::string Error;
+ bool ExecutionFailed;
+ int RetCode = ExecuteAndWait(Executable, argv, llvm::None, {}, 0, 0, &Error,
+ &ExecutionFailed);
+ ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or "
+ "positive value indicating the result code";
+ ASSERT_TRUE(ExecutionFailed);
+ ASSERT_FALSE(Error.empty());
+ }
+
+ {
+ std::string Error;
+ bool ExecutionFailed;
+ ProcessInfo PI = ExecuteNoWait(Executable, argv, llvm::None, {}, 0, &Error,
+ &ExecutionFailed);
+ ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid)
+ << "On error ExecuteNoWait should return an invalid ProcessInfo";
+ ASSERT_TRUE(ExecutionFailed);
+ ASSERT_FALSE(Error.empty());
+ }
+
+}
+
+#ifdef _WIN32
+const char utf16le_text[] =
+ "\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61\x00";
+const char utf16be_text[] =
+ "\x00\x6c\x00\x69\x00\x6e\x00\x67\x00\xfc\x00\x69\x00\xe7\x00\x61";
+#endif
+const char utf8_text[] = "\x6c\x69\x6e\x67\xc3\xbc\x69\xc3\xa7\x61";
+
+TEST(ProgramTest, TestWriteWithSystemEncoding) {
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(fs::createUniqueDirectory("program-test", TestDirectory));
+ errs() << "Test Directory: " << TestDirectory << '\n';
+ errs().flush();
+ SmallString<128> file_pathname(TestDirectory);
+ path::append(file_pathname, "international-file.txt");
+ // Only on Windows we should encode in UTF16. For other systems, use UTF8
+ ASSERT_NO_ERROR(sys::writeFileWithEncoding(file_pathname.c_str(), utf8_text,
+ sys::WEM_UTF16));
+ int fd = 0;
+ ASSERT_NO_ERROR(fs::openFileForRead(file_pathname.c_str(), fd));
+#if defined(_WIN32)
+ char buf[18];
+ ASSERT_EQ(::read(fd, buf, 18), 18);
+ if (strncmp(buf, "\xfe\xff", 2) == 0) { // UTF16-BE
+ ASSERT_EQ(strncmp(&buf[2], utf16be_text, 16), 0);
+ } else if (strncmp(buf, "\xff\xfe", 2) == 0) { // UTF16-LE
+ ASSERT_EQ(strncmp(&buf[2], utf16le_text, 16), 0);
+ } else {
+ FAIL() << "Invalid BOM in UTF-16 file";
+ }
+#else
+ char buf[10];
+ ASSERT_EQ(::read(fd, buf, 10), 10);
+ ASSERT_EQ(strncmp(buf, utf8_text, 10), 0);
+#endif
+ ::close(fd);
+ ASSERT_NO_ERROR(fs::remove(file_pathname.str()));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/RegexTest.cpp b/src/llvm-project/llvm/unittests/Support/RegexTest.cpp
new file mode 100644
index 0000000..7e44a3c
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/RegexTest.cpp
@@ -0,0 +1,182 @@
+//===- llvm/unittest/Support/RegexTest.cpp - Regex tests --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Regex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "gtest/gtest.h"
+#include <cstring>
+
+using namespace llvm;
+namespace {
+
+class RegexTest : public ::testing::Test {
+};
+
+TEST_F(RegexTest, Basics) {
+ Regex r1("^[0-9]+$");
+ EXPECT_TRUE(r1.match("916"));
+ EXPECT_TRUE(r1.match("9"));
+ EXPECT_FALSE(r1.match("9a"));
+
+ SmallVector<StringRef, 1> Matches;
+ Regex r2("[0-9]+");
+ EXPECT_TRUE(r2.match("aa216b", &Matches));
+ EXPECT_EQ(1u, Matches.size());
+ EXPECT_EQ("216", Matches[0].str());
+
+ Regex r3("[0-9]+([a-f])?:([0-9]+)");
+ EXPECT_TRUE(r3.match("9a:513b", &Matches));
+ EXPECT_EQ(3u, Matches.size());
+ EXPECT_EQ("9a:513", Matches[0].str());
+ EXPECT_EQ("a", Matches[1].str());
+ EXPECT_EQ("513", Matches[2].str());
+
+ EXPECT_TRUE(r3.match("9:513b", &Matches));
+ EXPECT_EQ(3u, Matches.size());
+ EXPECT_EQ("9:513", Matches[0].str());
+ EXPECT_EQ("", Matches[1].str());
+ EXPECT_EQ("513", Matches[2].str());
+
+ Regex r4("a[^b]+b");
+ std::string String="axxb";
+ String[2] = '\0';
+ EXPECT_FALSE(r4.match("abb"));
+ EXPECT_TRUE(r4.match(String, &Matches));
+ EXPECT_EQ(1u, Matches.size());
+ EXPECT_EQ(String, Matches[0].str());
+
+ std::string NulPattern="X[0-9]+X([a-f])?:([0-9]+)";
+ String="YX99a:513b";
+ NulPattern[7] = '\0';
+ Regex r5(NulPattern);
+ EXPECT_FALSE(r5.match(String));
+ EXPECT_FALSE(r5.match("X9"));
+ String[3]='\0';
+ EXPECT_TRUE(r5.match(String));
+}
+
+TEST_F(RegexTest, Backreferences) {
+ Regex r1("([a-z]+)_\\1");
+ SmallVector<StringRef, 4> Matches;
+ EXPECT_TRUE(r1.match("abc_abc", &Matches));
+ EXPECT_EQ(2u, Matches.size());
+ EXPECT_FALSE(r1.match("abc_ab", &Matches));
+
+ Regex r2("a([0-9])b\\1c\\1");
+ EXPECT_TRUE(r2.match("a4b4c4", &Matches));
+ EXPECT_EQ(2u, Matches.size());
+ EXPECT_EQ("4", Matches[1].str());
+ EXPECT_FALSE(r2.match("a2b2c3"));
+
+ Regex r3("a([0-9])([a-z])b\\1\\2");
+ EXPECT_TRUE(r3.match("a6zb6z", &Matches));
+ EXPECT_EQ(3u, Matches.size());
+ EXPECT_EQ("6", Matches[1].str());
+ EXPECT_EQ("z", Matches[2].str());
+ EXPECT_FALSE(r3.match("a6zb6y"));
+ EXPECT_FALSE(r3.match("a6zb7z"));
+}
+
+TEST_F(RegexTest, Substitution) {
+ std::string Error;
+
+ EXPECT_EQ("aNUMber", Regex("[0-9]+").sub("NUM", "a1234ber"));
+
+ // Standard Escapes
+ EXPECT_EQ("a\\ber", Regex("[0-9]+").sub("\\\\", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+ EXPECT_EQ("a\nber", Regex("[0-9]+").sub("\\n", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+ EXPECT_EQ("a\tber", Regex("[0-9]+").sub("\\t", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+ EXPECT_EQ("ajber", Regex("[0-9]+").sub("\\j", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+
+ EXPECT_EQ("aber", Regex("[0-9]+").sub("\\", "a1234ber", &Error));
+ EXPECT_EQ(Error, "replacement string contained trailing backslash");
+
+ // Backreferences
+ EXPECT_EQ("aa1234bber", Regex("a[0-9]+b").sub("a\\0b", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+
+ EXPECT_EQ("a1234ber", Regex("a([0-9]+)b").sub("a\\1b", "a1234ber", &Error));
+ EXPECT_EQ("", Error);
+
+ EXPECT_EQ("aber", Regex("a[0-9]+b").sub("a\\100b", "a1234ber", &Error));
+ EXPECT_EQ(Error, "invalid backreference string '100'");
+}
+
+TEST_F(RegexTest, IsLiteralERE) {
+ EXPECT_TRUE(Regex::isLiteralERE("abc"));
+ EXPECT_FALSE(Regex::isLiteralERE("a(bc)"));
+ EXPECT_FALSE(Regex::isLiteralERE("^abc"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc$"));
+ EXPECT_FALSE(Regex::isLiteralERE("a|bc"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc*"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc+"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc?"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc."));
+ EXPECT_FALSE(Regex::isLiteralERE("a[bc]"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc\\1"));
+ EXPECT_FALSE(Regex::isLiteralERE("abc{1,2}"));
+}
+
+TEST_F(RegexTest, Escape) {
+ EXPECT_EQ("a\\[bc\\]", Regex::escape("a[bc]"));
+ EXPECT_EQ("abc\\{1\\\\,2\\}", Regex::escape("abc{1\\,2}"));
+}
+
+TEST_F(RegexTest, IsValid) {
+ std::string Error;
+ EXPECT_FALSE(Regex("(foo").isValid(Error));
+ EXPECT_EQ("parentheses not balanced", Error);
+ EXPECT_FALSE(Regex("a[b-").isValid(Error));
+ EXPECT_EQ("invalid character range", Error);
+}
+
+TEST_F(RegexTest, MoveConstruct) {
+ Regex r1("^[0-9]+$");
+ Regex r2(std::move(r1));
+ EXPECT_TRUE(r2.match("916"));
+}
+
+TEST_F(RegexTest, MoveAssign) {
+ Regex r1("^[0-9]+$");
+ Regex r2("abc");
+ r2 = std::move(r1);
+ EXPECT_TRUE(r2.match("916"));
+ std::string Error;
+ EXPECT_FALSE(r1.isValid(Error));
+}
+
+TEST_F(RegexTest, NoArgConstructor) {
+ std::string Error;
+ Regex r1;
+ EXPECT_FALSE(r1.isValid(Error));
+ EXPECT_EQ("invalid regular expression", Error);
+ r1 = Regex("abc");
+ EXPECT_TRUE(r1.isValid(Error));
+}
+
+TEST_F(RegexTest, MatchInvalid) {
+ Regex r1;
+ std::string Error;
+ EXPECT_FALSE(r1.isValid(Error));
+ EXPECT_FALSE(r1.match("X"));
+}
+
+// https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3727
+TEST_F(RegexTest, OssFuzz3727Regression) {
+ // Wrap in a StringRef so the NUL byte doesn't terminate the string
+ Regex r(StringRef("[[[=GS\x00[=][", 10));
+ std::string Error;
+ EXPECT_FALSE(r.isValid(Error));
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ReplaceFileTest.cpp b/src/llvm-project/llvm/unittests/Support/ReplaceFileTest.cpp
new file mode 100644
index 0000000..15143be
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ReplaceFileTest.cpp
@@ -0,0 +1,173 @@
+//===- llvm/unittest/Support/ReplaceFileTest.cpp - unit tests -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+
+#define ASSERT_NO_ERROR(x) \
+ do { \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ errs() << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ } \
+ } while (false)
+
+namespace {
+std::error_code CreateFileWithContent(const SmallString<128> &FilePath,
+ const StringRef &content) {
+ int FD = 0;
+ if (std::error_code ec = fs::openFileForWrite(FilePath, FD))
+ return ec;
+
+ const bool ShouldClose = true;
+ raw_fd_ostream OS(FD, ShouldClose);
+ OS << content;
+
+ return std::error_code();
+}
+
+class ScopedFD {
+ int FD;
+
+ ScopedFD(const ScopedFD &) = delete;
+ ScopedFD &operator=(const ScopedFD &) = delete;
+
+ public:
+ explicit ScopedFD(int Descriptor) : FD(Descriptor) {}
+ ~ScopedFD() { Process::SafelyCloseFileDescriptor(FD); }
+};
+
+bool FDHasContent(int FD, StringRef Content) {
+ auto Buffer = MemoryBuffer::getOpenFile(FD, "", -1);
+ assert(Buffer);
+ return Buffer.get()->getBuffer() == Content;
+}
+
+bool FileHasContent(StringRef File, StringRef Content) {
+ int FD = 0;
+ auto EC = fs::openFileForRead(File, FD);
+ (void)EC;
+ assert(!EC);
+ ScopedFD EventuallyCloseIt(FD);
+ return FDHasContent(FD, Content);
+}
+
+TEST(rename, FileOpenedForReadingCanBeReplaced) {
+ // Create unique temporary directory for this test.
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(fs::createUniqueDirectory(
+ "FileOpenedForReadingCanBeReplaced-test", TestDirectory));
+
+ // Add a couple of files to the test directory.
+ SmallString<128> SourceFileName(TestDirectory);
+ path::append(SourceFileName, "source");
+
+ SmallString<128> TargetFileName(TestDirectory);
+ path::append(TargetFileName, "target");
+
+ ASSERT_NO_ERROR(CreateFileWithContent(SourceFileName, "!!source!!"));
+ ASSERT_NO_ERROR(CreateFileWithContent(TargetFileName, "!!target!!"));
+
+ {
+ // Open the target file for reading.
+ int ReadFD = 0;
+ ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, ReadFD));
+ ScopedFD EventuallyCloseIt(ReadFD);
+
+ // Confirm we can replace the file while it is open.
+ EXPECT_TRUE(!fs::rename(SourceFileName, TargetFileName));
+
+ // We should still be able to read the old data through the existing
+ // descriptor.
+ EXPECT_TRUE(FDHasContent(ReadFD, "!!target!!"));
+
+ // The source file should no longer exist
+ EXPECT_FALSE(fs::exists(SourceFileName));
+ }
+
+ // If we obtain a new descriptor for the target file, we should find that it
+ // contains the content that was in the source file.
+ EXPECT_TRUE(FileHasContent(TargetFileName, "!!source!!"));
+
+ // Rename the target file back to the source file name to confirm that rename
+ // still works if the destination does not already exist.
+ EXPECT_TRUE(!fs::rename(TargetFileName, SourceFileName));
+ EXPECT_FALSE(fs::exists(TargetFileName));
+ ASSERT_TRUE(fs::exists(SourceFileName));
+
+ // Clean up.
+ ASSERT_NO_ERROR(fs::remove(SourceFileName));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+
+TEST(rename, ExistingTemp) {
+ // Test that existing .tmpN files don't get deleted by the Windows
+ // sys::fs::rename implementation.
+ SmallString<128> TestDirectory;
+ ASSERT_NO_ERROR(
+ fs::createUniqueDirectory("ExistingTemp-test", TestDirectory));
+
+ SmallString<128> SourceFileName(TestDirectory);
+ path::append(SourceFileName, "source");
+
+ SmallString<128> TargetFileName(TestDirectory);
+ path::append(TargetFileName, "target");
+
+ SmallString<128> TargetTmp0FileName(TestDirectory);
+ path::append(TargetTmp0FileName, "target.tmp0");
+
+ SmallString<128> TargetTmp1FileName(TestDirectory);
+ path::append(TargetTmp1FileName, "target.tmp1");
+
+ ASSERT_NO_ERROR(CreateFileWithContent(SourceFileName, "!!source!!"));
+ ASSERT_NO_ERROR(CreateFileWithContent(TargetFileName, "!!target!!"));
+ ASSERT_NO_ERROR(CreateFileWithContent(TargetTmp0FileName, "!!target.tmp0!!"));
+
+ {
+ // Use mapped_file_region to make sure that the destination file is mmap'ed.
+ // This will cause SetInformationByHandle to fail when renaming to the
+ // destination, and we will follow the code path that tries to give target
+ // a temporary name.
+ int TargetFD;
+ std::error_code EC;
+ ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, TargetFD));
+ ScopedFD X(TargetFD);
+ sys::fs::mapped_file_region MFR(
+ TargetFD, sys::fs::mapped_file_region::readonly, 10, 0, EC);
+ ASSERT_FALSE(EC);
+
+ ASSERT_NO_ERROR(fs::rename(SourceFileName, TargetFileName));
+
+#ifdef _WIN32
+ // Make sure that target was temporarily renamed to target.tmp1 on Windows.
+ // This is signified by a permission denied error as opposed to no such file
+ // or directory when trying to open it.
+ int Tmp1FD;
+ EXPECT_EQ(errc::permission_denied,
+ fs::openFileForRead(TargetTmp1FileName, Tmp1FD));
+#endif
+ }
+
+ EXPECT_TRUE(FileHasContent(TargetTmp0FileName, "!!target.tmp0!!"));
+
+ ASSERT_NO_ERROR(fs::remove(TargetFileName));
+ ASSERT_NO_ERROR(fs::remove(TargetTmp0FileName));
+ ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/ReverseIterationTest.cpp b/src/llvm-project/llvm/unittests/Support/ReverseIterationTest.cpp
new file mode 100644
index 0000000..930bd43
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ReverseIterationTest.cpp
@@ -0,0 +1,110 @@
+//===- llvm/unittest/Support/ReverseIterationTest.cpp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Reverse Iteration unit tests.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/ReverseIteration.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(ReverseIterationTest, DenseMapTest1) {
+ static_assert(detail::IsPointerLike<int *>::value,
+ "int * is pointer-like");
+ static_assert(detail::IsPointerLike<uintptr_t>::value,
+ "uintptr_t is pointer-like");
+ static_assert(!detail::IsPointerLike<int>::value,
+ "int is not pointer-like");
+ static_assert(detail::IsPointerLike<void *>::value,
+ "void * is pointer-like");
+ struct IncompleteType;
+ static_assert(detail::IsPointerLike<IncompleteType *>::value,
+ "incomplete * is pointer-like");
+
+ // For a DenseMap with non-pointer-like keys, forward iteration equals
+ // reverse iteration.
+ DenseMap<int, int> Map;
+ int Keys[] = { 1, 2, 3, 4 };
+
+ // Insert keys into the DenseMap.
+ for (auto Key: Keys)
+ Map[Key] = 0;
+
+ // Note: This is the observed order of keys in the DenseMap.
+ // If there is any change in the behavior of the DenseMap, this order
+ // would need to be adjusted accordingly.
+ int IterKeys[] = { 2, 4, 1, 3 };
+
+ // Check that the DenseMap is iterated in the expected order.
+ for (const auto &Tuple : zip(Map, IterKeys))
+ ASSERT_EQ(std::get<0>(Tuple).first, std::get<1>(Tuple));
+
+ // Check operator++ (post-increment).
+ int i = 0;
+ for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i)
+ ASSERT_EQ(iter->first, IterKeys[i]);
+}
+
+// Define a pointer-like int.
+struct PtrLikeInt { int value; };
+
+namespace llvm {
+
+template<> struct DenseMapInfo<PtrLikeInt *> {
+ static PtrLikeInt *getEmptyKey() {
+ static PtrLikeInt EmptyKey;
+ return &EmptyKey;
+ }
+
+ static PtrLikeInt *getTombstoneKey() {
+ static PtrLikeInt TombstoneKey;
+ return &TombstoneKey;
+ }
+
+ static int getHashValue(const PtrLikeInt *P) {
+ return P->value;
+ }
+
+ static bool isEqual(const PtrLikeInt *LHS, const PtrLikeInt *RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // end namespace llvm
+
+TEST(ReverseIterationTest, DenseMapTest2) {
+ static_assert(detail::IsPointerLike<PtrLikeInt *>::value,
+ "PtrLikeInt * is pointer-like");
+
+ PtrLikeInt a = {4}, b = {8}, c = {12}, d = {16};
+ PtrLikeInt *Keys[] = { &a, &b, &c, &d };
+
+ // Insert keys into the DenseMap.
+ DenseMap<PtrLikeInt *, int> Map;
+ for (auto *Key : Keys)
+ Map[Key] = Key->value;
+
+ // Note: If there is any change in the behavior of the DenseMap,
+ // the observed order of keys would need to be adjusted accordingly.
+ if (shouldReverseIterate<PtrLikeInt *>())
+ std::reverse(&Keys[0], &Keys[4]);
+
+ // Check that the DenseMap is iterated in the expected order.
+ for (const auto &Tuple : zip(Map, Keys))
+ ASSERT_EQ(std::get<0>(Tuple).second, std::get<1>(Tuple)->value);
+
+ // Check operator++ (post-increment).
+ int i = 0;
+ for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i)
+ ASSERT_EQ(iter->second, Keys[i]->value);
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ScaledNumberTest.cpp b/src/llvm-project/llvm/unittests/Support/ScaledNumberTest.cpp
new file mode 100644
index 0000000..9e3f6de
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ScaledNumberTest.cpp
@@ -0,0 +1,566 @@
+//===- llvm/unittest/Support/ScaledNumberTest.cpp - ScaledPair tests -----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ScaledNumber.h"
+#include "llvm/Support/DataTypes.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::ScaledNumbers;
+
+namespace {
+
+template <class UIntT> struct ScaledPair {
+ UIntT D;
+ int S;
+ ScaledPair(const std::pair<UIntT, int16_t> &F) : D(F.first), S(F.second) {}
+ ScaledPair(UIntT D, int S) : D(D), S(S) {}
+
+ bool operator==(const ScaledPair<UIntT> &X) const {
+ return D == X.D && S == X.S;
+ }
+};
+template <class UIntT>
+bool operator==(const std::pair<UIntT, int16_t> &L,
+ const ScaledPair<UIntT> &R) {
+ return ScaledPair<UIntT>(L) == R;
+}
+template <class UIntT>
+void PrintTo(const ScaledPair<UIntT> &F, ::std::ostream *os) {
+ *os << F.D << "*2^" << F.S;
+}
+
+typedef ScaledPair<uint32_t> SP32;
+typedef ScaledPair<uint64_t> SP64;
+
+TEST(ScaledNumberHelpersTest, getRounded) {
+ EXPECT_EQ(getRounded32(0, 0, false), SP32(0, 0));
+ EXPECT_EQ(getRounded32(0, 0, true), SP32(1, 0));
+ EXPECT_EQ(getRounded32(20, 21, true), SP32(21, 21));
+ EXPECT_EQ(getRounded32(UINT32_MAX, 0, false), SP32(UINT32_MAX, 0));
+ EXPECT_EQ(getRounded32(UINT32_MAX, 0, true), SP32(1 << 31, 1));
+
+ EXPECT_EQ(getRounded64(0, 0, false), SP64(0, 0));
+ EXPECT_EQ(getRounded64(0, 0, true), SP64(1, 0));
+ EXPECT_EQ(getRounded64(20, 21, true), SP64(21, 21));
+ EXPECT_EQ(getRounded64(UINT32_MAX, 0, false), SP64(UINT32_MAX, 0));
+ EXPECT_EQ(getRounded64(UINT32_MAX, 0, true), SP64(UINT64_C(1) << 32, 0));
+ EXPECT_EQ(getRounded64(UINT64_MAX, 0, false), SP64(UINT64_MAX, 0));
+ EXPECT_EQ(getRounded64(UINT64_MAX, 0, true), SP64(UINT64_C(1) << 63, 1));
+}
+
+TEST(ScaledNumberHelpersTest, getAdjusted) {
+ const uint64_t Max32In64 = UINT32_MAX;
+ EXPECT_EQ(getAdjusted32(0), SP32(0, 0));
+ EXPECT_EQ(getAdjusted32(0, 5), SP32(0, 5));
+ EXPECT_EQ(getAdjusted32(UINT32_MAX), SP32(UINT32_MAX, 0));
+ EXPECT_EQ(getAdjusted32(Max32In64 << 1), SP32(UINT32_MAX, 1));
+ EXPECT_EQ(getAdjusted32(Max32In64 << 1, 1), SP32(UINT32_MAX, 2));
+ EXPECT_EQ(getAdjusted32(Max32In64 << 31), SP32(UINT32_MAX, 31));
+ EXPECT_EQ(getAdjusted32(Max32In64 << 32), SP32(UINT32_MAX, 32));
+ EXPECT_EQ(getAdjusted32(Max32In64 + 1), SP32(1u << 31, 1));
+ EXPECT_EQ(getAdjusted32(UINT64_MAX), SP32(1u << 31, 33));
+
+ EXPECT_EQ(getAdjusted64(0), SP64(0, 0));
+ EXPECT_EQ(getAdjusted64(0, 5), SP64(0, 5));
+ EXPECT_EQ(getAdjusted64(UINT32_MAX), SP64(UINT32_MAX, 0));
+ EXPECT_EQ(getAdjusted64(Max32In64 << 1), SP64(Max32In64 << 1, 0));
+ EXPECT_EQ(getAdjusted64(Max32In64 << 1, 1), SP64(Max32In64 << 1, 1));
+ EXPECT_EQ(getAdjusted64(Max32In64 << 31), SP64(Max32In64 << 31, 0));
+ EXPECT_EQ(getAdjusted64(Max32In64 << 32), SP64(Max32In64 << 32, 0));
+ EXPECT_EQ(getAdjusted64(Max32In64 + 1), SP64(Max32In64 + 1, 0));
+ EXPECT_EQ(getAdjusted64(UINT64_MAX), SP64(UINT64_MAX, 0));
+}
+
+TEST(ScaledNumberHelpersTest, getProduct) {
+ // Zero.
+ EXPECT_EQ(SP32(0, 0), getProduct32(0, 0));
+ EXPECT_EQ(SP32(0, 0), getProduct32(0, 1));
+ EXPECT_EQ(SP32(0, 0), getProduct32(0, 33));
+
+ // Basic.
+ EXPECT_EQ(SP32(6, 0), getProduct32(2, 3));
+ EXPECT_EQ(SP32(UINT16_MAX / 3 * UINT16_MAX / 5 * 2, 0),
+ getProduct32(UINT16_MAX / 3, UINT16_MAX / 5 * 2));
+
+ // Overflow, no loss of precision.
+ // ==> 0xf00010 * 0x1001
+ // ==> 0xf00f00000 + 0x10010
+ // ==> 0xf00f10010
+ // ==> 0xf00f1001 * 2^4
+ EXPECT_EQ(SP32(0xf00f1001, 4), getProduct32(0xf00010, 0x1001));
+
+ // Overflow, loss of precision, rounds down.
+ // ==> 0xf000070 * 0x1001
+ // ==> 0xf00f000000 + 0x70070
+ // ==> 0xf00f070070
+ // ==> 0xf00f0700 * 2^8
+ EXPECT_EQ(SP32(0xf00f0700, 8), getProduct32(0xf000070, 0x1001));
+
+ // Overflow, loss of precision, rounds up.
+ // ==> 0xf000080 * 0x1001
+ // ==> 0xf00f000000 + 0x80080
+ // ==> 0xf00f080080
+ // ==> 0xf00f0801 * 2^8
+ EXPECT_EQ(SP32(0xf00f0801, 8), getProduct32(0xf000080, 0x1001));
+
+ // Reverse operand order.
+ EXPECT_EQ(SP32(0, 0), getProduct32(1, 0));
+ EXPECT_EQ(SP32(0, 0), getProduct32(33, 0));
+ EXPECT_EQ(SP32(6, 0), getProduct32(3, 2));
+ EXPECT_EQ(SP32(UINT16_MAX / 3 * UINT16_MAX / 5 * 2, 0),
+ getProduct32(UINT16_MAX / 5 * 2, UINT16_MAX / 3));
+ EXPECT_EQ(SP32(0xf00f1001, 4), getProduct32(0x1001, 0xf00010));
+ EXPECT_EQ(SP32(0xf00f0700, 8), getProduct32(0x1001, 0xf000070));
+ EXPECT_EQ(SP32(0xf00f0801, 8), getProduct32(0x1001, 0xf000080));
+
+ // Round to overflow.
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, 64),
+ getProduct64(UINT64_C(10376293541461622786),
+ UINT64_C(16397105843297379211)));
+
+ // Big number with rounding.
+ EXPECT_EQ(SP64(UINT64_C(9223372036854775810), 64),
+ getProduct64(UINT64_C(18446744073709551556),
+ UINT64_C(9223372036854775840)));
+}
+
+TEST(ScaledNumberHelpersTest, getQuotient) {
+ // Zero.
+ EXPECT_EQ(SP32(0, 0), getQuotient32(0, 0));
+ EXPECT_EQ(SP32(0, 0), getQuotient32(0, 1));
+ EXPECT_EQ(SP32(0, 0), getQuotient32(0, 73));
+ EXPECT_EQ(SP32(UINT32_MAX, MaxScale), getQuotient32(1, 0));
+ EXPECT_EQ(SP32(UINT32_MAX, MaxScale), getQuotient32(6, 0));
+
+ // Powers of two.
+ EXPECT_EQ(SP32(1u << 31, -31), getQuotient32(1, 1));
+ EXPECT_EQ(SP32(1u << 31, -30), getQuotient32(2, 1));
+ EXPECT_EQ(SP32(1u << 31, -33), getQuotient32(4, 16));
+ EXPECT_EQ(SP32(7u << 29, -29), getQuotient32(7, 1));
+ EXPECT_EQ(SP32(7u << 29, -30), getQuotient32(7, 2));
+ EXPECT_EQ(SP32(7u << 29, -33), getQuotient32(7, 16));
+
+ // Divide evenly.
+ EXPECT_EQ(SP32(3u << 30, -30), getQuotient32(9, 3));
+ EXPECT_EQ(SP32(9u << 28, -28), getQuotient32(63, 7));
+
+ // Divide unevenly.
+ EXPECT_EQ(SP32(0xaaaaaaab, -33), getQuotient32(1, 3));
+ EXPECT_EQ(SP32(0xd5555555, -31), getQuotient32(5, 3));
+
+ // 64-bit division is hard to test, since divide64 doesn't canonicalize its
+ // output. However, this is the algorithm the implementation uses:
+ //
+ // - Shift divisor right.
+ // - If we have 1 (power of 2), return early -- not canonicalized.
+ // - Shift dividend left.
+ // - 64-bit integer divide.
+ // - If there's a remainder, continue with long division.
+ //
+ // TODO: require less knowledge about the implementation in the test.
+
+ // Zero.
+ EXPECT_EQ(SP64(0, 0), getQuotient64(0, 0));
+ EXPECT_EQ(SP64(0, 0), getQuotient64(0, 1));
+ EXPECT_EQ(SP64(0, 0), getQuotient64(0, 73));
+ EXPECT_EQ(SP64(UINT64_MAX, MaxScale), getQuotient64(1, 0));
+ EXPECT_EQ(SP64(UINT64_MAX, MaxScale), getQuotient64(6, 0));
+
+ // Powers of two.
+ EXPECT_EQ(SP64(1, 0), getQuotient64(1, 1));
+ EXPECT_EQ(SP64(2, 0), getQuotient64(2, 1));
+ EXPECT_EQ(SP64(4, -4), getQuotient64(4, 16));
+ EXPECT_EQ(SP64(7, 0), getQuotient64(7, 1));
+ EXPECT_EQ(SP64(7, -1), getQuotient64(7, 2));
+ EXPECT_EQ(SP64(7, -4), getQuotient64(7, 16));
+
+ // Divide evenly.
+ EXPECT_EQ(SP64(UINT64_C(3) << 60, -60), getQuotient64(9, 3));
+ EXPECT_EQ(SP64(UINT64_C(9) << 58, -58), getQuotient64(63, 7));
+
+ // Divide unevenly.
+ EXPECT_EQ(SP64(0xaaaaaaaaaaaaaaab, -65), getQuotient64(1, 3));
+ EXPECT_EQ(SP64(0xd555555555555555, -63), getQuotient64(5, 3));
+}
+
+TEST(ScaledNumberHelpersTest, getLg) {
+ EXPECT_EQ(0, getLg(UINT32_C(1), 0));
+ EXPECT_EQ(1, getLg(UINT32_C(1), 1));
+ EXPECT_EQ(1, getLg(UINT32_C(2), 0));
+ EXPECT_EQ(3, getLg(UINT32_C(1), 3));
+ EXPECT_EQ(3, getLg(UINT32_C(7), 0));
+ EXPECT_EQ(3, getLg(UINT32_C(8), 0));
+ EXPECT_EQ(3, getLg(UINT32_C(9), 0));
+ EXPECT_EQ(3, getLg(UINT32_C(64), -3));
+ EXPECT_EQ(31, getLg((UINT32_MAX >> 1) + 2, 0));
+ EXPECT_EQ(32, getLg(UINT32_MAX, 0));
+ EXPECT_EQ(-1, getLg(UINT32_C(1), -1));
+ EXPECT_EQ(-1, getLg(UINT32_C(2), -2));
+ EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), 1));
+
+ EXPECT_EQ(0, getLg(UINT64_C(1), 0));
+ EXPECT_EQ(1, getLg(UINT64_C(1), 1));
+ EXPECT_EQ(1, getLg(UINT64_C(2), 0));
+ EXPECT_EQ(3, getLg(UINT64_C(1), 3));
+ EXPECT_EQ(3, getLg(UINT64_C(7), 0));
+ EXPECT_EQ(3, getLg(UINT64_C(8), 0));
+ EXPECT_EQ(3, getLg(UINT64_C(9), 0));
+ EXPECT_EQ(3, getLg(UINT64_C(64), -3));
+ EXPECT_EQ(63, getLg((UINT64_MAX >> 1) + 2, 0));
+ EXPECT_EQ(64, getLg(UINT64_MAX, 0));
+ EXPECT_EQ(-1, getLg(UINT64_C(1), -1));
+ EXPECT_EQ(-1, getLg(UINT64_C(2), -2));
+ EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), 1));
+}
+
+TEST(ScaledNumberHelpersTest, getLgFloor) {
+ EXPECT_EQ(0, getLgFloor(UINT32_C(1), 0));
+ EXPECT_EQ(1, getLgFloor(UINT32_C(1), 1));
+ EXPECT_EQ(1, getLgFloor(UINT32_C(2), 0));
+ EXPECT_EQ(2, getLgFloor(UINT32_C(7), 0));
+ EXPECT_EQ(3, getLgFloor(UINT32_C(1), 3));
+ EXPECT_EQ(3, getLgFloor(UINT32_C(8), 0));
+ EXPECT_EQ(3, getLgFloor(UINT32_C(9), 0));
+ EXPECT_EQ(3, getLgFloor(UINT32_C(64), -3));
+ EXPECT_EQ(31, getLgFloor((UINT32_MAX >> 1) + 2, 0));
+ EXPECT_EQ(31, getLgFloor(UINT32_MAX, 0));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), 1));
+
+ EXPECT_EQ(0, getLgFloor(UINT64_C(1), 0));
+ EXPECT_EQ(1, getLgFloor(UINT64_C(1), 1));
+ EXPECT_EQ(1, getLgFloor(UINT64_C(2), 0));
+ EXPECT_EQ(2, getLgFloor(UINT64_C(7), 0));
+ EXPECT_EQ(3, getLgFloor(UINT64_C(1), 3));
+ EXPECT_EQ(3, getLgFloor(UINT64_C(8), 0));
+ EXPECT_EQ(3, getLgFloor(UINT64_C(9), 0));
+ EXPECT_EQ(3, getLgFloor(UINT64_C(64), -3));
+ EXPECT_EQ(63, getLgFloor((UINT64_MAX >> 1) + 2, 0));
+ EXPECT_EQ(63, getLgFloor(UINT64_MAX, 0));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), 1));
+}
+
+TEST(ScaledNumberHelpersTest, getLgCeiling) {
+ EXPECT_EQ(0, getLgCeiling(UINT32_C(1), 0));
+ EXPECT_EQ(1, getLgCeiling(UINT32_C(1), 1));
+ EXPECT_EQ(1, getLgCeiling(UINT32_C(2), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT32_C(1), 3));
+ EXPECT_EQ(3, getLgCeiling(UINT32_C(7), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT32_C(8), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT32_C(64), -3));
+ EXPECT_EQ(4, getLgCeiling(UINT32_C(9), 0));
+ EXPECT_EQ(32, getLgCeiling(UINT32_MAX, 0));
+ EXPECT_EQ(32, getLgCeiling((UINT32_MAX >> 1) + 2, 0));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), 1));
+
+ EXPECT_EQ(0, getLgCeiling(UINT64_C(1), 0));
+ EXPECT_EQ(1, getLgCeiling(UINT64_C(1), 1));
+ EXPECT_EQ(1, getLgCeiling(UINT64_C(2), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT64_C(1), 3));
+ EXPECT_EQ(3, getLgCeiling(UINT64_C(7), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT64_C(8), 0));
+ EXPECT_EQ(3, getLgCeiling(UINT64_C(64), -3));
+ EXPECT_EQ(4, getLgCeiling(UINT64_C(9), 0));
+ EXPECT_EQ(64, getLgCeiling((UINT64_MAX >> 1) + 2, 0));
+ EXPECT_EQ(64, getLgCeiling(UINT64_MAX, 0));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), -1));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), 0));
+ EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), 1));
+}
+
+TEST(ScaledNumberHelpersTest, compare) {
+ EXPECT_EQ(0, compare(UINT32_C(0), 0, UINT32_C(0), 1));
+ EXPECT_EQ(0, compare(UINT32_C(0), 0, UINT32_C(0), -10));
+ EXPECT_EQ(0, compare(UINT32_C(0), 0, UINT32_C(0), 20));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(64), -3));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(32), -2));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(16), -1));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(8), 0));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(4), 1));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(2), 2));
+ EXPECT_EQ(0, compare(UINT32_C(8), 0, UINT32_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT32_C(0), 0, UINT32_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT32_C(7), 0, UINT32_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT32_C(7), 0, UINT32_C(64), -3));
+ EXPECT_EQ(1, compare(UINT32_C(9), 0, UINT32_C(1), 3));
+ EXPECT_EQ(1, compare(UINT32_C(9), 0, UINT32_C(64), -3));
+ EXPECT_EQ(1, compare(UINT32_C(9), 0, UINT32_C(0), 0));
+
+ EXPECT_EQ(0, compare(UINT64_C(0), 0, UINT64_C(0), 1));
+ EXPECT_EQ(0, compare(UINT64_C(0), 0, UINT64_C(0), -10));
+ EXPECT_EQ(0, compare(UINT64_C(0), 0, UINT64_C(0), 20));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(64), -3));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(32), -2));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(16), -1));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(8), 0));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(4), 1));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(2), 2));
+ EXPECT_EQ(0, compare(UINT64_C(8), 0, UINT64_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT64_C(0), 0, UINT64_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT64_C(7), 0, UINT64_C(1), 3));
+ EXPECT_EQ(-1, compare(UINT64_C(7), 0, UINT64_C(64), -3));
+ EXPECT_EQ(1, compare(UINT64_C(9), 0, UINT64_C(1), 3));
+ EXPECT_EQ(1, compare(UINT64_C(9), 0, UINT64_C(64), -3));
+ EXPECT_EQ(1, compare(UINT64_C(9), 0, UINT64_C(0), 0));
+ EXPECT_EQ(-1, compare(UINT64_MAX, 0, UINT64_C(1), 64));
+}
+
+TEST(ScaledNumberHelpersTest, matchScales) {
+#define MATCH_SCALES(T, LDIn, LSIn, RDIn, RSIn, LDOut, RDOut, SOut) \
+ do { \
+ T LDx = LDIn; \
+ T RDx = RDIn; \
+ T LDy = LDOut; \
+ T RDy = RDOut; \
+ int16_t LSx = LSIn; \
+ int16_t RSx = RSIn; \
+ int16_t Sy = SOut; \
+ \
+ EXPECT_EQ(SOut, matchScales(LDx, LSx, RDx, RSx)); \
+ EXPECT_EQ(LDy, LDx); \
+ EXPECT_EQ(RDy, RDx); \
+ if (LDy) { \
+ EXPECT_EQ(Sy, LSx); \
+ } \
+ if (RDy) { \
+ EXPECT_EQ(Sy, RSx); \
+ } \
+ } while (false)
+
+ MATCH_SCALES(uint32_t, 0, 0, 0, 0, 0, 0, 0);
+ MATCH_SCALES(uint32_t, 0, 50, 7, 1, 0, 7, 1);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 31, 1, 9, 0, UINT32_C(1) << 31, 4, 1);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 31, 2, 9, 0, UINT32_C(1) << 31, 2, 2);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 31, 3, 9, 0, UINT32_C(1) << 31, 1, 3);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 31, 4, 9, 0, UINT32_C(1) << 31, 0, 4);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 30, 4, 9, 0, UINT32_C(1) << 31, 1, 3);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 29, 4, 9, 0, UINT32_C(1) << 31, 2, 2);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 28, 4, 9, 0, UINT32_C(1) << 31, 4, 1);
+ MATCH_SCALES(uint32_t, UINT32_C(1) << 27, 4, 9, 0, UINT32_C(1) << 31, 9, 0);
+ MATCH_SCALES(uint32_t, 7, 1, 0, 50, 7, 0, 1);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 31, 1, 4, UINT32_C(1) << 31, 1);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 31, 2, 2, UINT32_C(1) << 31, 2);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 31, 3, 1, UINT32_C(1) << 31, 3);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 31, 4, 0, UINT32_C(1) << 31, 4);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 30, 4, 1, UINT32_C(1) << 31, 3);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 29, 4, 2, UINT32_C(1) << 31, 2);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 28, 4, 4, UINT32_C(1) << 31, 1);
+ MATCH_SCALES(uint32_t, 9, 0, UINT32_C(1) << 27, 4, 9, UINT32_C(1) << 31, 0);
+
+ MATCH_SCALES(uint64_t, 0, 0, 0, 0, 0, 0, 0);
+ MATCH_SCALES(uint64_t, 0, 100, 7, 1, 0, 7, 1);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 63, 1, 9, 0, UINT64_C(1) << 63, 4, 1);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 63, 2, 9, 0, UINT64_C(1) << 63, 2, 2);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 63, 3, 9, 0, UINT64_C(1) << 63, 1, 3);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 63, 4, 9, 0, UINT64_C(1) << 63, 0, 4);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 62, 4, 9, 0, UINT64_C(1) << 63, 1, 3);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 61, 4, 9, 0, UINT64_C(1) << 63, 2, 2);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 60, 4, 9, 0, UINT64_C(1) << 63, 4, 1);
+ MATCH_SCALES(uint64_t, UINT64_C(1) << 59, 4, 9, 0, UINT64_C(1) << 63, 9, 0);
+ MATCH_SCALES(uint64_t, 7, 1, 0, 100, 7, 0, 1);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 63, 1, 4, UINT64_C(1) << 63, 1);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 63, 2, 2, UINT64_C(1) << 63, 2);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 63, 3, 1, UINT64_C(1) << 63, 3);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 63, 4, 0, UINT64_C(1) << 63, 4);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 62, 4, 1, UINT64_C(1) << 63, 3);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 61, 4, 2, UINT64_C(1) << 63, 2);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 60, 4, 4, UINT64_C(1) << 63, 1);
+ MATCH_SCALES(uint64_t, 9, 0, UINT64_C(1) << 59, 4, 9, UINT64_C(1) << 63, 0);
+}
+
+TEST(ScaledNumberHelpersTest, getSum) {
+ // Zero.
+ EXPECT_EQ(SP32(1, 0), getSum32(0, 0, 1, 0));
+ EXPECT_EQ(SP32(8, -3), getSum32(0, 0, 8, -3));
+ EXPECT_EQ(SP32(UINT32_MAX, 0), getSum32(0, 0, UINT32_MAX, 0));
+
+ // Basic.
+ EXPECT_EQ(SP32(2, 0), getSum32(1, 0, 1, 0));
+ EXPECT_EQ(SP32(3, 0), getSum32(1, 0, 2, 0));
+ EXPECT_EQ(SP32(67, 0), getSum32(7, 0, 60, 0));
+
+ // Different scales.
+ EXPECT_EQ(SP32(3, 0), getSum32(1, 0, 1, 1));
+ EXPECT_EQ(SP32(4, 0), getSum32(2, 0, 1, 1));
+
+ // Loss of precision.
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, 1), getSum32(1, 32, 1, 0));
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, -31), getSum32(1, -32, 1, 0));
+
+ // Not quite loss of precision.
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, 1), getSum32(1, 32, 1, 1));
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, -32), getSum32(1, -32, 1, -1));
+
+ // Overflow.
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, 1), getSum32(1, 0, UINT32_MAX, 0));
+
+ // Reverse operand order.
+ EXPECT_EQ(SP32(1, 0), getSum32(1, 0, 0, 0));
+ EXPECT_EQ(SP32(8, -3), getSum32(8, -3, 0, 0));
+ EXPECT_EQ(SP32(UINT32_MAX, 0), getSum32(UINT32_MAX, 0, 0, 0));
+ EXPECT_EQ(SP32(3, 0), getSum32(2, 0, 1, 0));
+ EXPECT_EQ(SP32(67, 0), getSum32(60, 0, 7, 0));
+ EXPECT_EQ(SP32(3, 0), getSum32(1, 1, 1, 0));
+ EXPECT_EQ(SP32(4, 0), getSum32(1, 1, 2, 0));
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, 1), getSum32(1, 0, 1, 32));
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, -31), getSum32(1, 0, 1, -32));
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, 1), getSum32(1, 1, 1, 32));
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, -32), getSum32(1, -1, 1, -32));
+ EXPECT_EQ(SP32(UINT32_C(1) << 31, 1), getSum32(UINT32_MAX, 0, 1, 0));
+
+ // Zero.
+ EXPECT_EQ(SP64(1, 0), getSum64(0, 0, 1, 0));
+ EXPECT_EQ(SP64(8, -3), getSum64(0, 0, 8, -3));
+ EXPECT_EQ(SP64(UINT64_MAX, 0), getSum64(0, 0, UINT64_MAX, 0));
+
+ // Basic.
+ EXPECT_EQ(SP64(2, 0), getSum64(1, 0, 1, 0));
+ EXPECT_EQ(SP64(3, 0), getSum64(1, 0, 2, 0));
+ EXPECT_EQ(SP64(67, 0), getSum64(7, 0, 60, 0));
+
+ // Different scales.
+ EXPECT_EQ(SP64(3, 0), getSum64(1, 0, 1, 1));
+ EXPECT_EQ(SP64(4, 0), getSum64(2, 0, 1, 1));
+
+ // Loss of precision.
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, 1), getSum64(1, 64, 1, 0));
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, -63), getSum64(1, -64, 1, 0));
+
+ // Not quite loss of precision.
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, 1), getSum64(1, 64, 1, 1));
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, -64), getSum64(1, -64, 1, -1));
+
+ // Overflow.
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, 1), getSum64(1, 0, UINT64_MAX, 0));
+
+ // Reverse operand order.
+ EXPECT_EQ(SP64(1, 0), getSum64(1, 0, 0, 0));
+ EXPECT_EQ(SP64(8, -3), getSum64(8, -3, 0, 0));
+ EXPECT_EQ(SP64(UINT64_MAX, 0), getSum64(UINT64_MAX, 0, 0, 0));
+ EXPECT_EQ(SP64(3, 0), getSum64(2, 0, 1, 0));
+ EXPECT_EQ(SP64(67, 0), getSum64(60, 0, 7, 0));
+ EXPECT_EQ(SP64(3, 0), getSum64(1, 1, 1, 0));
+ EXPECT_EQ(SP64(4, 0), getSum64(1, 1, 2, 0));
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, 1), getSum64(1, 0, 1, 64));
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, -63), getSum64(1, 0, 1, -64));
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, 1), getSum64(1, 1, 1, 64));
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, -64), getSum64(1, -1, 1, -64));
+ EXPECT_EQ(SP64(UINT64_C(1) << 63, 1), getSum64(UINT64_MAX, 0, 1, 0));
+}
+
+TEST(ScaledNumberHelpersTest, getDifference) {
+ // Basic.
+ EXPECT_EQ(SP32(0, 0), getDifference32(1, 0, 1, 0));
+ EXPECT_EQ(SP32(1, 0), getDifference32(2, 0, 1, 0));
+ EXPECT_EQ(SP32(53, 0), getDifference32(60, 0, 7, 0));
+
+ // Equals "0", different scales.
+ EXPECT_EQ(SP32(0, 0), getDifference32(2, 0, 1, 1));
+
+ // Subtract "0".
+ EXPECT_EQ(SP32(1, 0), getDifference32(1, 0, 0, 0));
+ EXPECT_EQ(SP32(8, -3), getDifference32(8, -3, 0, 0));
+ EXPECT_EQ(SP32(UINT32_MAX, 0), getDifference32(UINT32_MAX, 0, 0, 0));
+
+ // Loss of precision.
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, 1),
+ getDifference32((UINT32_C(1) << 31) + 1, 1, 1, 0));
+ EXPECT_EQ(SP32((UINT32_C(1) << 31) + 1, -31),
+ getDifference32((UINT32_C(1) << 31) + 1, -31, 1, -32));
+
+ // Not quite loss of precision.
+ EXPECT_EQ(SP32(UINT32_MAX, 0), getDifference32(1, 32, 1, 0));
+ EXPECT_EQ(SP32(UINT32_MAX, -32), getDifference32(1, 0, 1, -32));
+
+ // Saturate to "0".
+ EXPECT_EQ(SP32(0, 0), getDifference32(0, 0, 1, 0));
+ EXPECT_EQ(SP32(0, 0), getDifference32(0, 0, 8, -3));
+ EXPECT_EQ(SP32(0, 0), getDifference32(0, 0, UINT32_MAX, 0));
+ EXPECT_EQ(SP32(0, 0), getDifference32(7, 0, 60, 0));
+ EXPECT_EQ(SP32(0, 0), getDifference32(1, 0, 1, 1));
+ EXPECT_EQ(SP32(0, 0), getDifference32(1, -32, 1, 0));
+ EXPECT_EQ(SP32(0, 0), getDifference32(1, -32, 1, -1));
+
+ // Regression tests for cases that failed during bringup.
+ EXPECT_EQ(SP32(UINT32_C(1) << 26, -31),
+ getDifference32(1, 0, UINT32_C(31) << 27, -32));
+
+ // Basic.
+ EXPECT_EQ(SP64(0, 0), getDifference64(1, 0, 1, 0));
+ EXPECT_EQ(SP64(1, 0), getDifference64(2, 0, 1, 0));
+ EXPECT_EQ(SP64(53, 0), getDifference64(60, 0, 7, 0));
+
+ // Equals "0", different scales.
+ EXPECT_EQ(SP64(0, 0), getDifference64(2, 0, 1, 1));
+
+ // Subtract "0".
+ EXPECT_EQ(SP64(1, 0), getDifference64(1, 0, 0, 0));
+ EXPECT_EQ(SP64(8, -3), getDifference64(8, -3, 0, 0));
+ EXPECT_EQ(SP64(UINT64_MAX, 0), getDifference64(UINT64_MAX, 0, 0, 0));
+
+ // Loss of precision.
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, 1),
+ getDifference64((UINT64_C(1) << 63) + 1, 1, 1, 0));
+ EXPECT_EQ(SP64((UINT64_C(1) << 63) + 1, -63),
+ getDifference64((UINT64_C(1) << 63) + 1, -63, 1, -64));
+
+ // Not quite loss of precision.
+ EXPECT_EQ(SP64(UINT64_MAX, 0), getDifference64(1, 64, 1, 0));
+ EXPECT_EQ(SP64(UINT64_MAX, -64), getDifference64(1, 0, 1, -64));
+
+ // Saturate to "0".
+ EXPECT_EQ(SP64(0, 0), getDifference64(0, 0, 1, 0));
+ EXPECT_EQ(SP64(0, 0), getDifference64(0, 0, 8, -3));
+ EXPECT_EQ(SP64(0, 0), getDifference64(0, 0, UINT64_MAX, 0));
+ EXPECT_EQ(SP64(0, 0), getDifference64(7, 0, 60, 0));
+ EXPECT_EQ(SP64(0, 0), getDifference64(1, 0, 1, 1));
+ EXPECT_EQ(SP64(0, 0), getDifference64(1, -64, 1, 0));
+ EXPECT_EQ(SP64(0, 0), getDifference64(1, -64, 1, -1));
+}
+
+TEST(ScaledNumberHelpersTest, arithmeticOperators) {
+ EXPECT_EQ(ScaledNumber<uint32_t>(10, 0),
+ ScaledNumber<uint32_t>(1, 3) + ScaledNumber<uint32_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint32_t>(6, 0),
+ ScaledNumber<uint32_t>(1, 3) - ScaledNumber<uint32_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint32_t>(2, 3),
+ ScaledNumber<uint32_t>(1, 3) * ScaledNumber<uint32_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint32_t>(1, 2),
+ ScaledNumber<uint32_t>(1, 3) / ScaledNumber<uint32_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint32_t>(1, 2), ScaledNumber<uint32_t>(1, 3) >> 1);
+ EXPECT_EQ(ScaledNumber<uint32_t>(1, 4), ScaledNumber<uint32_t>(1, 3) << 1);
+
+ EXPECT_EQ(ScaledNumber<uint64_t>(10, 0),
+ ScaledNumber<uint64_t>(1, 3) + ScaledNumber<uint64_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint64_t>(6, 0),
+ ScaledNumber<uint64_t>(1, 3) - ScaledNumber<uint64_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint64_t>(2, 3),
+ ScaledNumber<uint64_t>(1, 3) * ScaledNumber<uint64_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint64_t>(1, 2),
+ ScaledNumber<uint64_t>(1, 3) / ScaledNumber<uint64_t>(1, 1));
+ EXPECT_EQ(ScaledNumber<uint64_t>(1, 2), ScaledNumber<uint64_t>(1, 3) >> 1);
+ EXPECT_EQ(ScaledNumber<uint64_t>(1, 4), ScaledNumber<uint64_t>(1, 3) << 1);
+}
+
+TEST(ScaledNumberHelpersTest, toIntBug) {
+ ScaledNumber<uint32_t> n(1, 0);
+ EXPECT_EQ(1u, (n * n).toInt<uint32_t>());
+}
+
+} // end namespace
diff --git a/src/llvm-project/llvm/unittests/Support/SourceMgrTest.cpp b/src/llvm-project/llvm/unittests/Support/SourceMgrTest.cpp
new file mode 100644
index 0000000..7bb76f5
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/SourceMgrTest.cpp
@@ -0,0 +1,499 @@
+//===- unittests/Support/SourceMgrTest.cpp - SourceMgr tests --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class SourceMgrTest : public testing::Test {
+public:
+ SourceMgr SM;
+ unsigned MainBufferID;
+ std::string Output;
+
+ void setMainBuffer(StringRef Text, StringRef BufferName) {
+ std::unique_ptr<MemoryBuffer> MainBuffer =
+ MemoryBuffer::getMemBuffer(Text, BufferName);
+ MainBufferID = SM.AddNewSourceBuffer(std::move(MainBuffer), llvm::SMLoc());
+ }
+
+ SMLoc getLoc(unsigned Offset) {
+ return SMLoc::getFromPointer(
+ SM.getMemoryBuffer(MainBufferID)->getBufferStart() + Offset);
+ }
+
+ SMRange getRange(unsigned Offset, unsigned Length) {
+ return SMRange(getLoc(Offset), getLoc(Offset + Length));
+ }
+
+ void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+ const Twine &Msg, ArrayRef<SMRange> Ranges,
+ ArrayRef<SMFixIt> FixIts) {
+ raw_string_ostream OS(Output);
+ SM.PrintMessage(OS, Loc, Kind, Msg, Ranges, FixIts);
+ }
+};
+
+} // unnamed namespace
+
+TEST_F(SourceMgrTest, BasicError) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, BasicWarning) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Warning, "message", None, None);
+
+ EXPECT_EQ("file.in:1:5: warning: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, BasicRemark) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Remark, "message", None, None);
+
+ EXPECT_EQ("file.in:1:5: remark: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, BasicNote) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Note, "message", None, None);
+
+ EXPECT_EQ("file.in:1:5: note: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOfLine) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(6), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:7: error: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtNewline) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(7), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:8: error: message\n"
+ "aaa bbb\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEmptyBuffer) {
+ setMainBuffer("", "file.in");
+ printMessage(getLoc(0), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationJustOnSoleNewline) {
+ setMainBuffer("\n", "file.in");
+ printMessage(getLoc(0), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationJustAfterSoleNewline) {
+ setMainBuffer("\n", "file.in");
+ printMessage(getLoc(1), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:2:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationJustAfterNonNewline) {
+ setMainBuffer("123", "file.in");
+ printMessage(getLoc(3), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:4: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationOnFirstLineOfMultiline) {
+ setMainBuffer("1234\n6789\n", "file.in");
+ printMessage(getLoc(3), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:4: error: message\n"
+ "1234\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationOnEOLOfFirstLineOfMultiline) {
+ setMainBuffer("1234\n6789\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "1234\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationOnSecondLineOfMultiline) {
+ setMainBuffer("1234\n6789\n", "file.in");
+ printMessage(getLoc(5), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:2:1: error: message\n"
+ "6789\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationOnSecondLineOfMultilineNoSecondEOL) {
+ setMainBuffer("1234\n6789", "file.in");
+ printMessage(getLoc(5), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:2:1: error: message\n"
+ "6789\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationOnEOLOfSecondSecondLineOfMultiline) {
+ setMainBuffer("1234\n6789\n", "file.in");
+ printMessage(getLoc(9), SourceMgr::DK_Error, "message", None, None);
+
+ EXPECT_EQ("file.in:2:5: error: message\n"
+ "6789\n"
+ " ^\n",
+ Output);
+}
+
+#define STRING_LITERAL_253_BYTES \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n1234567890\n" \
+ "1234567890\n"
+
+//===----------------------------------------------------------------------===//
+// 255-byte buffer tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf255ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(253), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:1: error: message\n"
+ "12\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf255ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:2: error: message\n"
+ "12\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf255ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:3: error: message\n"
+ "12\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf255ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1\n" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(253), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:1: error: message\n"
+ "1\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf255ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1\n" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:2: error: message\n"
+ "1\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf255ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1\n" // + 2 = 255 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:25:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+//===----------------------------------------------------------------------===//
+// 256-byte buffer tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf256ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:2: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf256ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:3: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf256ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:4: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf256ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12\n" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(254), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:2: error: message\n"
+ "12\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf256ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12\n" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:3: error: message\n"
+ "12\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf256ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "12\n" // + 3 = 256 bytes
+ , "file.in");
+ printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:25:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+//===----------------------------------------------------------------------===//
+// 257-byte buffer tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf257ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1234" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:3: error: message\n"
+ "1234\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf257ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1234" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:4: error: message\n"
+ "1234\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf257ByteBuffer) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "1234" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(257), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:5: error: message\n"
+ "1234\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationBeforeEndOf257ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123\n" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(255), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:3: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationAtEndOf257ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123\n" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(256), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:24:4: error: message\n"
+ "123\n"
+ " ^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, LocationPastEndOf257ByteBufferEndingInNewline) {
+ setMainBuffer(STRING_LITERAL_253_BYTES // first 253 bytes
+ "123\n" // + 4 = 257 bytes
+ , "file.in");
+ printMessage(getLoc(257), SourceMgr::DK_Error, "message", None, None);
+ EXPECT_EQ("file.in:25:1: error: message\n"
+ "\n"
+ "^\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, BasicRange) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 3), None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ " ^~~\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, RangeWithTab) {
+ setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(3, 3), None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ " ~~~~~^~\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, MultiLineRange) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 7), None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ " ^~~\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, MultipleRanges) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ SMRange Ranges[] = { getRange(0, 3), getRange(4, 3) };
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ "~~~ ^~~\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, OverlappingRanges) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ SMRange Ranges[] = { getRange(0, 3), getRange(2, 4) };
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None);
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ "~~~~^~\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, BasicFixit) {
+ setMainBuffer("aaa bbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(4), SourceMgr::DK_Error, "message", None,
+ makeArrayRef(SMFixIt(getRange(4, 3), "zzz")));
+
+ EXPECT_EQ("file.in:1:5: error: message\n"
+ "aaa bbb\n"
+ " ^~~\n"
+ " zzz\n",
+ Output);
+}
+
+TEST_F(SourceMgrTest, FixitForTab) {
+ setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in");
+ printMessage(getLoc(3), SourceMgr::DK_Error, "message", None,
+ makeArrayRef(SMFixIt(getRange(3, 1), "zzz")));
+
+ EXPECT_EQ("file.in:1:4: error: message\n"
+ "aaa bbb\n"
+ " ^^^^^\n"
+ " zzz\n",
+ Output);
+}
+
diff --git a/src/llvm-project/llvm/unittests/Support/SpecialCaseListTest.cpp b/src/llvm-project/llvm/unittests/Support/SpecialCaseListTest.cpp
new file mode 100644
index 0000000..060703e
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/SpecialCaseListTest.cpp
@@ -0,0 +1,247 @@
+//===- SpecialCaseListTest.cpp - Unit tests for SpecialCaseList -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class SpecialCaseListTest : public ::testing::Test {
+protected:
+ std::unique_ptr<SpecialCaseList> makeSpecialCaseList(StringRef List,
+ std::string &Error) {
+ std::unique_ptr<MemoryBuffer> MB = MemoryBuffer::getMemBuffer(List);
+ return SpecialCaseList::create(MB.get(), Error);
+ }
+
+ std::unique_ptr<SpecialCaseList> makeSpecialCaseList(StringRef List) {
+ std::string Error;
+ auto SCL = makeSpecialCaseList(List, Error);
+ assert(SCL);
+ assert(Error == "");
+ return SCL;
+ }
+
+ std::string makeSpecialCaseListFile(StringRef Contents) {
+ int FD;
+ SmallString<64> Path;
+ sys::fs::createTemporaryFile("SpecialCaseListTest", "temp", FD, Path);
+ raw_fd_ostream OF(FD, true, true);
+ OF << Contents;
+ OF.close();
+ return Path.str();
+ }
+};
+
+TEST_F(SpecialCaseListTest, Basic) {
+ std::unique_ptr<SpecialCaseList> SCL =
+ makeSpecialCaseList("# This is a comment.\n"
+ "\n"
+ "src:hello\n"
+ "src:bye\n"
+ "src:hi=category\n"
+ "src:z*=category\n");
+ EXPECT_TRUE(SCL->inSection("", "src", "hello"));
+ EXPECT_TRUE(SCL->inSection("", "src", "bye"));
+ EXPECT_TRUE(SCL->inSection("", "src", "hi", "category"));
+ EXPECT_TRUE(SCL->inSection("", "src", "zzzz", "category"));
+ EXPECT_FALSE(SCL->inSection("", "src", "hi"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "hello"));
+ EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));
+
+ EXPECT_EQ(3u, SCL->inSectionBlame("", "src", "hello"));
+ EXPECT_EQ(4u, SCL->inSectionBlame("", "src", "bye"));
+ EXPECT_EQ(5u, SCL->inSectionBlame("", "src", "hi", "category"));
+ EXPECT_EQ(6u, SCL->inSectionBlame("", "src", "zzzz", "category"));
+ EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hi"));
+ EXPECT_EQ(0u, SCL->inSectionBlame("", "fun", "hello"));
+ EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hello", "category"));
+}
+
+TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) {
+ std::string Error;
+ EXPECT_EQ(nullptr, makeSpecialCaseList("# This is a comment.\n"
+ "\n"
+ "[not valid\n",
+ Error));
+ EXPECT_TRUE(
+ ((StringRef)Error).startswith("malformed section header on line 3:"));
+
+ EXPECT_EQ(nullptr, makeSpecialCaseList("\n\n\n"
+ "[not valid\n",
+ Error));
+ EXPECT_TRUE(
+ ((StringRef)Error).startswith("malformed section header on line 4:"));
+}
+
+TEST_F(SpecialCaseListTest, SectionRegexErrorHandling) {
+ std::string Error;
+ EXPECT_EQ(makeSpecialCaseList("[address", Error), nullptr);
+ EXPECT_TRUE(((StringRef)Error).startswith("malformed section header "));
+
+ EXPECT_EQ(makeSpecialCaseList("[[]", Error), nullptr);
+ EXPECT_TRUE(((StringRef)Error).startswith("malformed regex for section [: "));
+
+ EXPECT_EQ(makeSpecialCaseList("src:=", Error), nullptr);
+ EXPECT_TRUE(((StringRef)Error).endswith("Supplied regexp was blank"));
+}
+
+TEST_F(SpecialCaseListTest, Section) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:global\n"
+ "[sect1|sect2]\n"
+ "src:test1\n"
+ "[sect3*]\n"
+ "src:test2\n");
+ EXPECT_TRUE(SCL->inSection("arbitrary", "src", "global"));
+ EXPECT_TRUE(SCL->inSection("", "src", "global"));
+ EXPECT_TRUE(SCL->inSection("sect1", "src", "test1"));
+ EXPECT_FALSE(SCL->inSection("sect1-arbitrary", "src", "test1"));
+ EXPECT_FALSE(SCL->inSection("sect", "src", "test1"));
+ EXPECT_FALSE(SCL->inSection("sect1", "src", "test2"));
+ EXPECT_TRUE(SCL->inSection("sect2", "src", "test1"));
+ EXPECT_TRUE(SCL->inSection("sect3", "src", "test2"));
+ EXPECT_TRUE(SCL->inSection("sect3-arbitrary", "src", "test2"));
+ EXPECT_FALSE(SCL->inSection("", "src", "test1"));
+ EXPECT_FALSE(SCL->inSection("", "src", "test2"));
+}
+
+TEST_F(SpecialCaseListTest, GlobalInit) {
+ std::unique_ptr<SpecialCaseList> SCL =
+ makeSpecialCaseList("global:foo=init\n");
+ EXPECT_FALSE(SCL->inSection("", "global", "foo"));
+ EXPECT_FALSE(SCL->inSection("", "global", "bar"));
+ EXPECT_TRUE(SCL->inSection("", "global", "foo", "init"));
+ EXPECT_FALSE(SCL->inSection("", "global", "bar", "init"));
+
+ SCL = makeSpecialCaseList("type:t2=init\n");
+ EXPECT_FALSE(SCL->inSection("", "type", "t1"));
+ EXPECT_FALSE(SCL->inSection("", "type", "t2"));
+ EXPECT_FALSE(SCL->inSection("", "type", "t1", "init"));
+ EXPECT_TRUE(SCL->inSection("", "type", "t2", "init"));
+
+ SCL = makeSpecialCaseList("src:hello=init\n");
+ EXPECT_FALSE(SCL->inSection("", "src", "hello"));
+ EXPECT_FALSE(SCL->inSection("", "src", "bye"));
+ EXPECT_TRUE(SCL->inSection("", "src", "hello", "init"));
+ EXPECT_FALSE(SCL->inSection("", "src", "bye", "init"));
+}
+
+TEST_F(SpecialCaseListTest, Substring) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:hello\n"
+ "fun:foo\n"
+ "global:bar\n");
+ EXPECT_FALSE(SCL->inSection("", "src", "othello"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "tomfoolery"));
+ EXPECT_FALSE(SCL->inSection("", "global", "bartender"));
+
+ SCL = makeSpecialCaseList("fun:*foo*\n");
+ EXPECT_TRUE(SCL->inSection("", "fun", "tomfoolery"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "foobar"));
+}
+
+TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) {
+ std::string Error;
+ EXPECT_EQ(nullptr, makeSpecialCaseList("badline", Error));
+ EXPECT_EQ("malformed line 1: 'badline'", Error);
+ EXPECT_EQ(nullptr, makeSpecialCaseList("src:bad[a-", Error));
+ EXPECT_EQ("malformed regex in line 1: 'bad[a-': invalid character range",
+ Error);
+ EXPECT_EQ(nullptr, makeSpecialCaseList("src:a.c\n"
+ "fun:fun(a\n",
+ Error));
+ EXPECT_EQ("malformed regex in line 2: 'fun(a': parentheses not balanced",
+ Error);
+ std::vector<std::string> Files(1, "unexisting");
+ EXPECT_EQ(nullptr, SpecialCaseList::create(Files, Error));
+ EXPECT_EQ(0U, Error.find("can't open file 'unexisting':"));
+}
+
+TEST_F(SpecialCaseListTest, EmptySpecialCaseList) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("");
+ EXPECT_FALSE(SCL->inSection("", "foo", "bar"));
+}
+
+TEST_F(SpecialCaseListTest, MultipleBlacklists) {
+ std::vector<std::string> Files;
+ Files.push_back(makeSpecialCaseListFile("src:bar\n"
+ "src:*foo*\n"
+ "src:ban=init\n"));
+ Files.push_back(makeSpecialCaseListFile("src:baz\n"
+ "src:*fog*\n"));
+ auto SCL = SpecialCaseList::createOrDie(Files);
+ EXPECT_TRUE(SCL->inSection("", "src", "bar"));
+ EXPECT_TRUE(SCL->inSection("", "src", "baz"));
+ EXPECT_FALSE(SCL->inSection("", "src", "ban"));
+ EXPECT_TRUE(SCL->inSection("", "src", "ban", "init"));
+ EXPECT_TRUE(SCL->inSection("", "src", "tomfoolery"));
+ EXPECT_TRUE(SCL->inSection("", "src", "tomfoglery"));
+ for (auto &Path : Files)
+ sys::fs::remove(Path);
+}
+
+TEST_F(SpecialCaseListTest, NoTrigramsInRules) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b.r\n"
+ "fun:za*az\n");
+ EXPECT_TRUE(SCL->inSection("", "fun", "bar"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "baz"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
+}
+
+TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n"
+ "fun:za*az\n");
+ EXPECT_TRUE(SCL->inSection("", "fun", "abara"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "bor"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "zakaz"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "zaraza"));
+}
+
+TEST_F(SpecialCaseListTest, RepetitiveRule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
+ "fun:bar*\n");
+ EXPECT_TRUE(SCL->inSection("", "fun", "bara"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "abara"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "abarbarbarbar"));
+ EXPECT_FALSE(SCL->inSection("", "fun", "abarbarbar"));
+}
+
+TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
+ EXPECT_TRUE(SCL->inSection("", "src", "c++abi"));
+ EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
+}
+
+TEST_F(SpecialCaseListTest, PopularTrigram) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*aaaaaa*\n"
+ "fun:*aaaaa*\n"
+ "fun:*aaaa*\n"
+ "fun:*aaa*\n");
+ EXPECT_TRUE(SCL->inSection("", "fun", "aaa"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "aaaa"));
+ EXPECT_TRUE(SCL->inSection("", "fun", "aaaabbbaaa"));
+}
+
+TEST_F(SpecialCaseListTest, EscapedSymbols) {
+ std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
+ "src:*hello\\\\world*\n");
+ EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi"));
+ EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi"));
+ EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
+ EXPECT_TRUE(SCL->inSection("", "src", "C:\\hello\\world"));
+ EXPECT_TRUE(SCL->inSection("", "src", "hello\\world"));
+ EXPECT_FALSE(SCL->inSection("", "src", "hello\\\\world"));
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/StringPool.cpp b/src/llvm-project/llvm/unittests/Support/StringPool.cpp
new file mode 100644
index 0000000..ac39fec
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/StringPool.cpp
@@ -0,0 +1,31 @@
+//===- llvm/unittest/Support/StringPoiil.cpp - StringPool tests -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/StringPool.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(PooledStringPtrTest, OperatorEquals) {
+ StringPool pool;
+ const PooledStringPtr a = pool.intern("a");
+ const PooledStringPtr b = pool.intern("b");
+ EXPECT_FALSE(a == b);
+}
+
+TEST(PooledStringPtrTest, OperatorNotEquals) {
+ StringPool pool;
+ const PooledStringPtr a = pool.intern("a");
+ const PooledStringPtr b = pool.intern("b");
+ EXPECT_TRUE(a != b);
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/SwapByteOrderTest.cpp b/src/llvm-project/llvm/unittests/Support/SwapByteOrderTest.cpp
new file mode 100644
index 0000000..474eac6
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/SwapByteOrderTest.cpp
@@ -0,0 +1,201 @@
+//===- unittests/Support/SwapByteOrderTest.cpp - swap byte order test -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SwapByteOrder.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <ctime>
+using namespace llvm;
+
+#undef max
+
+namespace {
+
+// In these first two tests all of the original_uintx values are truncated
+// except for 64. We could avoid this, but there's really no point.
+
+TEST(getSwappedBytes, UnsignedRoundTrip) {
+ // The point of the bit twiddling of magic is to test with and without bits
+ // in every byte.
+ uint64_t value = 1;
+ for (std::size_t i = 0; i <= sizeof(value); ++i) {
+ uint8_t original_uint8 = static_cast<uint8_t>(value);
+ EXPECT_EQ(original_uint8,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_uint8)));
+
+ uint16_t original_uint16 = static_cast<uint16_t>(value);
+ EXPECT_EQ(original_uint16,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_uint16)));
+
+ uint32_t original_uint32 = static_cast<uint32_t>(value);
+ EXPECT_EQ(original_uint32,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_uint32)));
+
+ uint64_t original_uint64 = static_cast<uint64_t>(value);
+ EXPECT_EQ(original_uint64,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_uint64)));
+
+ value = (value << 8) | 0x55; // binary 0101 0101.
+ }
+}
+
+TEST(getSwappedBytes, SignedRoundTrip) {
+ // The point of the bit twiddling of magic is to test with and without bits
+ // in every byte.
+ uint64_t value = 1;
+ for (std::size_t i = 0; i <= sizeof(value); ++i) {
+ int8_t original_int8 = static_cast<int8_t>(value);
+ EXPECT_EQ(original_int8,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int8)));
+
+ int16_t original_int16 = static_cast<int16_t>(value);
+ EXPECT_EQ(original_int16,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int16)));
+
+ int32_t original_int32 = static_cast<int32_t>(value);
+ EXPECT_EQ(original_int32,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int32)));
+
+ int64_t original_int64 = static_cast<int64_t>(value);
+ EXPECT_EQ(original_int64,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int64)));
+
+ // Test other sign.
+ value *= -1;
+
+ original_int8 = static_cast<int8_t>(value);
+ EXPECT_EQ(original_int8,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int8)));
+
+ original_int16 = static_cast<int16_t>(value);
+ EXPECT_EQ(original_int16,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int16)));
+
+ original_int32 = static_cast<int32_t>(value);
+ EXPECT_EQ(original_int32,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int32)));
+
+ original_int64 = static_cast<int64_t>(value);
+ EXPECT_EQ(original_int64,
+ sys::getSwappedBytes(sys::getSwappedBytes(original_int64)));
+
+ // Return to normal sign and twiddle.
+ value *= -1;
+ value = (value << 8) | 0x55; // binary 0101 0101.
+ }
+}
+
+TEST(getSwappedBytes, uint8_t) {
+ EXPECT_EQ(uint8_t(0x11), sys::getSwappedBytes(uint8_t(0x11)));
+}
+
+TEST(getSwappedBytes, uint16_t) {
+ EXPECT_EQ(uint16_t(0x1122), sys::getSwappedBytes(uint16_t(0x2211)));
+}
+
+TEST(getSwappedBytes, uint32_t) {
+ EXPECT_EQ(uint32_t(0x11223344), sys::getSwappedBytes(uint32_t(0x44332211)));
+}
+
+TEST(getSwappedBytes, uint64_t) {
+ EXPECT_EQ(uint64_t(0x1122334455667788ULL),
+ sys::getSwappedBytes(uint64_t(0x8877665544332211ULL)));
+}
+
+TEST(getSwappedBytes, int8_t) {
+ EXPECT_EQ(int8_t(0x11), sys::getSwappedBytes(int8_t(0x11)));
+}
+
+TEST(getSwappedBytes, int16_t) {
+ EXPECT_EQ(int16_t(0x1122), sys::getSwappedBytes(int16_t(0x2211)));
+}
+
+TEST(getSwappedBytes, int32_t) {
+ EXPECT_EQ(int32_t(0x11223344), sys::getSwappedBytes(int32_t(0x44332211)));
+}
+
+TEST(getSwappedBytes, int64_t) {
+ EXPECT_EQ(int64_t(0x1122334455667788LL),
+ sys::getSwappedBytes(int64_t(0x8877665544332211LL)));
+}
+
+TEST(getSwappedBytes, float) {
+ EXPECT_EQ(1.79366203433576585078237386661e-43f, sys::getSwappedBytes(-0.0f));
+ // 0x11223344
+ EXPECT_EQ(7.1653228759765625e2f, sys::getSwappedBytes(1.2795344e-28f));
+}
+
+TEST(getSwappedBytes, double) {
+ EXPECT_EQ(6.32404026676795576546008054871e-322, sys::getSwappedBytes(-0.0));
+ // 0x1122334455667788
+ EXPECT_EQ(-7.08687663657301358331704585496e-268,
+ sys::getSwappedBytes(3.84141202447173065923064450234e-226));
+}
+
+TEST(swapByteOrder, uint8_t) {
+ uint8_t value = 0x11;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(uint8_t(0x11), value);
+}
+
+TEST(swapByteOrder, uint16_t) {
+ uint16_t value = 0x2211;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(uint16_t(0x1122), value);
+}
+
+TEST(swapByteOrder, uint32_t) {
+ uint32_t value = 0x44332211;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(uint32_t(0x11223344), value);
+}
+
+TEST(swapByteOrder, uint64_t) {
+ uint64_t value = 0x8877665544332211ULL;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(uint64_t(0x1122334455667788ULL), value);
+}
+
+TEST(swapByteOrder, int8_t) {
+ int8_t value = 0x11;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(int8_t(0x11), value);
+}
+
+TEST(swapByteOrder, int16_t) {
+ int16_t value = 0x2211;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(int16_t(0x1122), value);
+}
+
+TEST(swapByteOrder, int32_t) {
+ int32_t value = 0x44332211;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(int32_t(0x11223344), value);
+}
+
+TEST(swapByteOrder, int64_t) {
+ int64_t value = 0x8877665544332211LL;
+ sys::swapByteOrder(value);
+ EXPECT_EQ(int64_t(0x1122334455667788LL), value);
+}
+
+TEST(swapByteOrder, float) {
+ float value = 7.1653228759765625e2f; // 0x44332211
+ sys::swapByteOrder(value);
+ EXPECT_EQ(1.2795344e-28f, value);
+}
+
+TEST(swapByteOrder, double) {
+ double value = -7.08687663657301358331704585496e-268; // 0x8877665544332211
+ sys::swapByteOrder(value);
+ EXPECT_EQ(3.84141202447173065923064450234e-226, value);
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/SymbolRemappingReaderTest.cpp b/src/llvm-project/llvm/unittests/Support/SymbolRemappingReaderTest.cpp
new file mode 100644
index 0000000..717df62
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/SymbolRemappingReaderTest.cpp
@@ -0,0 +1,96 @@
+//===- unittests/Support/SymbolRemappingReaderTest.cpp --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SymbolRemappingReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+class SymbolRemappingReaderTest : public testing::Test {
+public:
+ std::unique_ptr<MemoryBuffer> Buffer;
+ SymbolRemappingReader Reader;
+
+ std::string readWithErrors(StringRef Text, StringRef BufferName) {
+ Buffer = MemoryBuffer::getMemBuffer(Text, BufferName);
+ Error E = Reader.read(*Buffer);
+ EXPECT_TRUE((bool)E);
+ return toString(std::move(E));
+ }
+
+ void read(StringRef Text, StringRef BufferName) {
+ Buffer = MemoryBuffer::getMemBuffer(Text, BufferName);
+ Error E = Reader.read(*Buffer);
+ EXPECT_FALSE((bool)E);
+ }
+};
+} // unnamed namespace
+
+TEST_F(SymbolRemappingReaderTest, ParseErrors) {
+ EXPECT_EQ(readWithErrors("error", "foo.map"),
+ "foo.map:1: Expected 'kind mangled_name mangled_name', "
+ "found 'error'");
+
+ EXPECT_EQ(readWithErrors("error m1 m2", "foo.map"),
+ "foo.map:1: Invalid kind, expected 'name', 'type', or 'encoding', "
+ "found 'error'");
+}
+
+TEST_F(SymbolRemappingReaderTest, DemanglingErrors) {
+ EXPECT_EQ(readWithErrors("type i banana", "foo.map"),
+ "foo.map:1: Could not demangle 'banana' as a <type>; "
+ "invalid mangling?");
+ EXPECT_EQ(readWithErrors("name i 1X", "foo.map"),
+ "foo.map:1: Could not demangle 'i' as a <name>; "
+ "invalid mangling?");
+ EXPECT_EQ(readWithErrors("name 1X 1fv", "foo.map"),
+ "foo.map:1: Could not demangle '1fv' as a <name>; "
+ "invalid mangling?");
+ EXPECT_EQ(readWithErrors("encoding 1fv 1f1gE", "foo.map"),
+ "foo.map:1: Could not demangle '1f1gE' as a <encoding>; "
+ "invalid mangling?");
+}
+
+TEST_F(SymbolRemappingReaderTest, BadMappingOrder) {
+ StringRef Map = R"(
+ # N::foo == M::bar
+ name N1N3fooE N1M3barE
+
+ # N:: == M::
+ name 1N 1M
+ )";
+ EXPECT_EQ(readWithErrors(Map, "foo.map"),
+ "foo.map:6: Manglings '1N' and '1M' have both been used in prior "
+ "remappings. Move this remapping earlier in the file.");
+}
+
+TEST_F(SymbolRemappingReaderTest, RemappingsAdded) {
+ StringRef Map = R"(
+ # A::foo == B::bar
+ name N1A3fooE N1B3barE
+
+ # int == long
+ type i l
+
+ # void f<int>() = void g<int>()
+ encoding 1fIiEvv 1gIiEvv
+ )";
+
+ read(Map, "foo.map");
+ auto Key = Reader.insert("_ZN1B3bar3bazIiEEvv");
+ EXPECT_NE(Key, SymbolRemappingReader::Key());
+ EXPECT_EQ(Key, Reader.lookup("_ZN1A3foo3bazIlEEvv"));
+ EXPECT_NE(Key, Reader.lookup("_ZN1C3foo3bazIlEEvv"));
+
+ Key = Reader.insert("_Z1fIiEvv");
+ EXPECT_NE(Key, SymbolRemappingReader::Key());
+ EXPECT_EQ(Key, Reader.lookup("_Z1gIlEvv"));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/TarWriterTest.cpp b/src/llvm-project/llvm/unittests/Support/TarWriterTest.cpp
new file mode 100644
index 0000000..901dd90
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TarWriterTest.cpp
@@ -0,0 +1,179 @@
+//===- llvm/unittest/Support/TarWriterTest.cpp ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include <vector>
+
+using namespace llvm;
+namespace {
+
+struct UstarHeader {
+ char Name[100];
+ char Mode[8];
+ char Uid[8];
+ char Gid[8];
+ char Size[12];
+ char Mtime[12];
+ char Checksum[8];
+ char TypeFlag;
+ char Linkname[100];
+ char Magic[6];
+ char Version[2];
+ char Uname[32];
+ char Gname[32];
+ char DevMajor[8];
+ char DevMinor[8];
+ char Prefix[155];
+ char Pad[12];
+};
+
+class TarWriterTest : public ::testing::Test {};
+
+static std::vector<uint8_t> createTar(StringRef Base, StringRef Filename) {
+ // Create a temporary file.
+ SmallString<128> Path;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("TarWriterTest", "tar", Path);
+ EXPECT_FALSE((bool)EC);
+
+ // Create a tar file.
+ Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, Base);
+ EXPECT_TRUE((bool)TarOrErr);
+ std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr);
+ Tar->append(Filename, "contents");
+ Tar.reset();
+
+ // Read the tar file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(Path);
+ EXPECT_TRUE((bool)MBOrErr);
+ std::unique_ptr<MemoryBuffer> MB = std::move(*MBOrErr);
+ std::vector<uint8_t> Buf((const uint8_t *)MB->getBufferStart(),
+ (const uint8_t *)MB->getBufferEnd());
+
+ // Windows does not allow us to remove a mmap'ed files, so
+ // unmap first and then remove the temporary file.
+ MB = nullptr;
+ sys::fs::remove(Path);
+
+ return Buf;
+}
+
+static UstarHeader createUstar(StringRef Base, StringRef Filename) {
+ std::vector<uint8_t> Buf = createTar(Base, Filename);
+ EXPECT_TRUE(Buf.size() >= sizeof(UstarHeader));
+ return *reinterpret_cast<const UstarHeader *>(Buf.data());
+}
+
+TEST_F(TarWriterTest, Basics) {
+ UstarHeader Hdr = createUstar("base", "file");
+ EXPECT_EQ("ustar", StringRef(Hdr.Magic));
+ EXPECT_EQ("00", StringRef(Hdr.Version, 2));
+ EXPECT_EQ("base/file", StringRef(Hdr.Name));
+ EXPECT_EQ("00000000010", StringRef(Hdr.Size));
+}
+
+TEST_F(TarWriterTest, LongFilename) {
+ std::string x154(154, 'x');
+ std::string x155(155, 'x');
+ std::string y99(99, 'y');
+ std::string y100(100, 'y');
+
+ UstarHeader Hdr1 = createUstar("", x154 + "/" + y99);
+ EXPECT_EQ("/" + x154, StringRef(Hdr1.Prefix));
+ EXPECT_EQ(y99, StringRef(Hdr1.Name));
+
+ UstarHeader Hdr2 = createUstar("", x155 + "/" + y99);
+ EXPECT_EQ("", StringRef(Hdr2.Prefix));
+ EXPECT_EQ("", StringRef(Hdr2.Name));
+
+ UstarHeader Hdr3 = createUstar("", x154 + "/" + y100);
+ EXPECT_EQ("", StringRef(Hdr3.Prefix));
+ EXPECT_EQ("", StringRef(Hdr3.Name));
+
+ UstarHeader Hdr4 = createUstar("", x155 + "/" + y100);
+ EXPECT_EQ("", StringRef(Hdr4.Prefix));
+ EXPECT_EQ("", StringRef(Hdr4.Name));
+
+ std::string yz = "yyyyyyyyyyyyyyyyyyyy/zzzzzzzzzzzzzzzzzzzz";
+ UstarHeader Hdr5 = createUstar("", x154 + "/" + yz);
+ EXPECT_EQ("/" + x154, StringRef(Hdr5.Prefix));
+ EXPECT_EQ(yz, StringRef(Hdr5.Name));
+}
+
+TEST_F(TarWriterTest, Pax) {
+ std::vector<uint8_t> Buf = createTar("", std::string(200, 'x'));
+ EXPECT_TRUE(Buf.size() >= 1024);
+
+ auto *Hdr = reinterpret_cast<const UstarHeader *>(Buf.data());
+ EXPECT_EQ("", StringRef(Hdr->Prefix));
+ EXPECT_EQ("", StringRef(Hdr->Name));
+
+ StringRef Pax = StringRef((char *)(Buf.data() + 512), 512);
+ EXPECT_TRUE(Pax.startswith("211 path=/" + std::string(200, 'x')));
+}
+
+TEST_F(TarWriterTest, SingleFile) {
+ SmallString<128> Path;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("TarWriterTest", "tar", Path);
+ EXPECT_FALSE((bool)EC);
+
+ Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, "");
+ EXPECT_TRUE((bool)TarOrErr);
+ std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr);
+ Tar->append("FooPath", "foo");
+ Tar.reset();
+
+ uint64_t TarSize;
+ EC = sys::fs::file_size(Path, TarSize);
+ EXPECT_FALSE((bool)EC);
+ EXPECT_EQ(TarSize, 2048ULL);
+}
+
+TEST_F(TarWriterTest, NoDuplicate) {
+ SmallString<128> Path;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("TarWriterTest", "tar", Path);
+ EXPECT_FALSE((bool)EC);
+
+ Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, "");
+ EXPECT_TRUE((bool)TarOrErr);
+ std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr);
+ Tar->append("FooPath", "foo");
+ Tar->append("BarPath", "bar");
+ Tar.reset();
+
+ uint64_t TarSize;
+ EC = sys::fs::file_size(Path, TarSize);
+ EXPECT_FALSE((bool)EC);
+ EXPECT_EQ(TarSize, 3072ULL);
+}
+
+TEST_F(TarWriterTest, Duplicate) {
+ SmallString<128> Path;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("TarWriterTest", "tar", Path);
+ EXPECT_FALSE((bool)EC);
+
+ Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, "");
+ EXPECT_TRUE((bool)TarOrErr);
+ std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr);
+ Tar->append("FooPath", "foo");
+ Tar->append("FooPath", "bar");
+ Tar.reset();
+
+ uint64_t TarSize;
+ EC = sys::fs::file_size(Path, TarSize);
+ EXPECT_FALSE((bool)EC);
+ EXPECT_EQ(TarSize, 2048ULL);
+}
+} // namespace
diff --git a/src/llvm-project/llvm/unittests/Support/TargetParserTest.cpp b/src/llvm-project/llvm/unittests/Support/TargetParserTest.cpp
new file mode 100644
index 0000000..18bbb6a
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TargetParserTest.cpp
@@ -0,0 +1,1015 @@
+//===----------- TargetParser.cpp - Target Parser -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TargetParser.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+namespace {
+const char *ARMArch[] = {
+ "armv2", "armv2a", "armv3", "armv3m", "armv4",
+ "armv4t", "armv5", "armv5t", "armv5e", "armv5te",
+ "armv5tej", "armv6", "armv6j", "armv6k", "armv6hl",
+ "armv6t2", "armv6kz", "armv6z", "armv6zk", "armv6-m",
+ "armv6m", "armv6sm", "armv6s-m", "armv7-a", "armv7",
+ "armv7a", "armv7ve", "armv7hl", "armv7l", "armv7-r",
+ "armv7r", "armv7-m", "armv7m", "armv7k", "armv7s",
+ "armv7e-m", "armv7em", "armv8-a", "armv8", "armv8a",
+ "armv8l", "armv8.1-a", "armv8.1a", "armv8.2-a", "armv8.2a",
+ "armv8.3-a", "armv8.3a", "armv8.4-a", "armv8.4a", "armv8.5-a",
+ "armv8.5a", "armv8-r", "armv8r", "armv8-m.base", "armv8m.base",
+ "armv8-m.main", "armv8m.main", "iwmmxt", "iwmmxt2", "xscale"
+};
+
+bool testARMCPU(StringRef CPUName, StringRef ExpectedArch,
+ StringRef ExpectedFPU, unsigned ExpectedFlags,
+ StringRef CPUAttr) {
+ ARM::ArchKind AK = ARM::parseCPUArch(CPUName);
+ bool pass = ARM::getArchName(AK).equals(ExpectedArch);
+ unsigned FPUKind = ARM::getDefaultFPU(CPUName, AK);
+ pass &= ARM::getFPUName(FPUKind).equals(ExpectedFPU);
+
+ unsigned ExtKind = ARM::getDefaultExtensions(CPUName, AK);
+ if (ExtKind > 1 && (ExtKind & ARM::AEK_NONE))
+ pass &= ((ExtKind ^ ARM::AEK_NONE) == ExpectedFlags);
+ else
+ pass &= (ExtKind == ExpectedFlags);
+
+ pass &= ARM::getCPUAttr(AK).equals(CPUAttr);
+
+ return pass;
+}
+
+TEST(TargetParserTest, testARMCPU) {
+ EXPECT_TRUE(testARMCPU("invalid", "invalid", "invalid",
+ ARM::AEK_NONE, ""));
+ EXPECT_TRUE(testARMCPU("generic", "invalid", "none",
+ ARM::AEK_NONE, ""));
+
+ EXPECT_TRUE(testARMCPU("arm2", "armv2", "none",
+ ARM::AEK_NONE, "2"));
+ EXPECT_TRUE(testARMCPU("arm3", "armv2a", "none",
+ ARM::AEK_NONE, "2A"));
+ EXPECT_TRUE(testARMCPU("arm6", "armv3", "none",
+ ARM::AEK_NONE, "3"));
+ EXPECT_TRUE(testARMCPU("arm7m", "armv3m", "none",
+ ARM::AEK_NONE, "3M"));
+ EXPECT_TRUE(testARMCPU("arm8", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("arm810", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm110", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm1100", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("strongarm1110", "armv4", "none",
+ ARM::AEK_NONE, "4"));
+ EXPECT_TRUE(testARMCPU("arm7tdmi", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm7tdmi-s", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm710t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm720t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9tdmi", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm920", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm920t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm922t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm9312", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm940t", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("ep9312", "armv4t", "none",
+ ARM::AEK_NONE, "4T"));
+ EXPECT_TRUE(testARMCPU("arm10tdmi", "armv5t", "none",
+ ARM::AEK_NONE, "5T"));
+ EXPECT_TRUE(testARMCPU("arm1020t", "armv5t", "none",
+ ARM::AEK_NONE, "5T"));
+ EXPECT_TRUE(testARMCPU("arm9e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm946e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm966e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm968e-s", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm10e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm1020e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm1022e", "armv5te", "none",
+ ARM::AEK_DSP, "5TE"));
+ EXPECT_TRUE(testARMCPU("arm926ej-s", "armv5tej", "none",
+ ARM::AEK_DSP, "5TEJ"));
+ EXPECT_TRUE(testARMCPU("arm1136j-s", "armv6", "none",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1136jf-s", "armv6", "vfpv2",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1136jz-s", "armv6", "none",
+ ARM::AEK_DSP, "6"));
+ EXPECT_TRUE(testARMCPU("arm1176jz-s", "armv6kz", "none",
+ ARM::AEK_SEC | ARM::AEK_DSP, "6KZ"));
+ EXPECT_TRUE(testARMCPU("mpcore", "armv6k", "vfpv2",
+ ARM::AEK_DSP, "6K"));
+ EXPECT_TRUE(testARMCPU("mpcorenovfp", "armv6k", "none",
+ ARM::AEK_DSP, "6K"));
+ EXPECT_TRUE(testARMCPU("arm1176jzf-s", "armv6kz", "vfpv2",
+ ARM::AEK_SEC | ARM::AEK_DSP, "6KZ"));
+ EXPECT_TRUE(testARMCPU("arm1156t2-s", "armv6t2", "none",
+ ARM::AEK_DSP, "6T2"));
+ EXPECT_TRUE(testARMCPU("arm1156t2f-s", "armv6t2", "vfpv2",
+ ARM::AEK_DSP, "6T2"));
+ EXPECT_TRUE(testARMCPU("cortex-m0", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m0plus", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m1", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("sc000", "armv6-m", "none",
+ ARM::AEK_NONE, "6-M"));
+ EXPECT_TRUE(testARMCPU("cortex-a5", "armv7-a", "neon-vfpv4",
+ ARM::AEK_MP | ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a7", "armv7-a", "neon-vfpv4",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_HWDIVARM | ARM::AEK_MP |
+ ARM::AEK_SEC | ARM::AEK_VIRT | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a8", "armv7-a", "neon",
+ ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a9", "armv7-a", "neon-fp16",
+ ARM::AEK_MP | ARM::AEK_SEC | ARM::AEK_DSP, "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a12", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a15", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a17", "armv7-a", "neon-vfpv4",
+ ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("krait", "armv7-a", "neon-vfpv4",
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "7-A"));
+ EXPECT_TRUE(testARMCPU("cortex-r4", "armv7-r", "none",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r4f", "armv7-r", "vfpv3-d16",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r5", "armv7-r", "vfpv3-d16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r7", "armv7-r", "vfpv3-d16-fp16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r8", "armv7-r", "vfpv3-d16-fp16",
+ ARM::AEK_MP | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "7-R"));
+ EXPECT_TRUE(testARMCPU("cortex-r52", "armv8-r", "neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_MP | ARM::AEK_VIRT |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
+ ARM::AEK_DSP,
+ "8-R"));
+ EXPECT_TRUE(
+ testARMCPU("sc300", "armv7-m", "none", ARM::AEK_HWDIVTHUMB, "7-M"));
+ EXPECT_TRUE(
+ testARMCPU("cortex-m3", "armv7-m", "none", ARM::AEK_HWDIVTHUMB, "7-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m4", "armv7e-m", "fpv4-sp-d16",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "7E-M"));
+ EXPECT_TRUE(testARMCPU("cortex-m7", "armv7e-m", "fpv5-d16",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "7E-M"));
+ EXPECT_TRUE(testARMCPU("cortex-a32", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a35", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a53", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a55", "armv8.2-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_FP16 |
+ ARM::AEK_RAS | ARM::AEK_DOTPROD,
+ "8.2-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a72", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a73", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("cortex-a75", "armv8.2-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_FP16 |
+ ARM::AEK_RAS | ARM::AEK_DOTPROD,
+ "8.2-A"));
+ EXPECT_TRUE(testARMCPU("cyclone", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m1", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m2", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m3", "armv8-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "8-A"));
+ EXPECT_TRUE(testARMCPU("exynos-m4", "armv8.2-a", "crypto-neon-fp-armv8",
+ ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP |
+ ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_DOTPROD |
+ ARM::AEK_FP16 | ARM::AEK_RAS,
+ "8.2-A"));
+ EXPECT_TRUE(testARMCPU("cortex-m23", "armv8-m.base", "none",
+ ARM::AEK_HWDIVTHUMB, "8-M.Baseline"));
+ EXPECT_TRUE(testARMCPU("cortex-m33", "armv8-m.main", "fpv5-sp-d16",
+ ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "8-M.Mainline"));
+ EXPECT_TRUE(testARMCPU("iwmmxt", "iwmmxt", "none",
+ ARM::AEK_NONE, "iwmmxt"));
+ EXPECT_TRUE(testARMCPU("xscale", "xscale", "none",
+ ARM::AEK_NONE, "xscale"));
+ EXPECT_TRUE(testARMCPU("swift", "armv7s", "neon-vfpv4",
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP,
+ "7-S"));
+}
+
+static constexpr unsigned NumARMCPUArchs = 82;
+
+TEST(TargetParserTest, testARMCPUArchList) {
+ SmallVector<StringRef, NumARMCPUArchs> List;
+ ARM::fillValidCPUArchList(List);
+
+ // No list exists for these in this test suite, so ensure all are
+ // valid, and match the expected 'magic' count.
+ EXPECT_EQ(List.size(), NumARMCPUArchs);
+ for(StringRef CPU : List) {
+ EXPECT_NE(ARM::parseCPUArch(CPU), ARM::ArchKind::INVALID);
+ }
+}
+
+TEST(TargetParserTest, testInvalidARMArch) {
+ auto InvalidArchStrings = {"armv", "armv99", "noarm"};
+ for (const char* InvalidArch : InvalidArchStrings)
+ EXPECT_EQ(ARM::parseArch(InvalidArch), ARM::ArchKind::INVALID);
+}
+
+bool testARMArch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch,
+ unsigned ArchAttr) {
+ ARM::ArchKind AK = ARM::parseArch(Arch);
+ return (AK!= ARM::ArchKind::INVALID) &
+ ARM::getDefaultCPU(Arch).equals(DefaultCPU) &
+ ARM::getSubArch(AK).equals(SubArch) &
+ (ARM::getArchAttr(AK) == ArchAttr);
+}
+
+TEST(TargetParserTest, testARMArch) {
+ EXPECT_TRUE(
+ testARMArch("armv2", "arm2", "v2",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv2a", "arm3", "v2a",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv3", "arm6", "v3",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv3m", "arm7m", "v3m",
+ ARMBuildAttrs::CPUArch::Pre_v4));
+ EXPECT_TRUE(
+ testARMArch("armv4", "strongarm", "v4",
+ ARMBuildAttrs::CPUArch::v4));
+ EXPECT_TRUE(
+ testARMArch("armv4t", "arm7tdmi", "v4t",
+ ARMBuildAttrs::CPUArch::v4T));
+ EXPECT_TRUE(
+ testARMArch("armv5t", "arm10tdmi", "v5",
+ ARMBuildAttrs::CPUArch::v5T));
+ EXPECT_TRUE(
+ testARMArch("armv5te", "arm1022e", "v5e",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("armv5tej", "arm926ej-s", "v5e",
+ ARMBuildAttrs::CPUArch::v5TEJ));
+ EXPECT_TRUE(
+ testARMArch("armv6", "arm1136jf-s", "v6",
+ ARMBuildAttrs::CPUArch::v6));
+ EXPECT_TRUE(
+ testARMArch("armv6k", "mpcore", "v6k",
+ ARMBuildAttrs::CPUArch::v6K));
+ EXPECT_TRUE(
+ testARMArch("armv6t2", "arm1156t2-s", "v6t2",
+ ARMBuildAttrs::CPUArch::v6T2));
+ EXPECT_TRUE(
+ testARMArch("armv6kz", "arm1176jzf-s", "v6kz",
+ ARMBuildAttrs::CPUArch::v6KZ));
+ EXPECT_TRUE(
+ testARMArch("armv6-m", "cortex-m0", "v6m",
+ ARMBuildAttrs::CPUArch::v6_M));
+ EXPECT_TRUE(
+ testARMArch("armv7-a", "generic", "v7",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7ve", "generic", "v7ve",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7-r", "cortex-r4", "v7r",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7-m", "cortex-m3", "v7m",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7e-m", "cortex-m4", "v7em",
+ ARMBuildAttrs::CPUArch::v7E_M));
+ EXPECT_TRUE(
+ testARMArch("armv8-a", "generic", "v8",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.1-a", "generic", "v8.1a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.2-a", "generic", "v8.2a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.3-a", "generic", "v8.3a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.4-a", "generic", "v8.4a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8.5-a", "generic", "v8.5a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(
+ testARMArch("armv8-r", "cortex-r52", "v8r",
+ ARMBuildAttrs::CPUArch::v8_R));
+ EXPECT_TRUE(
+ testARMArch("armv8-m.base", "generic", "v8m.base",
+ ARMBuildAttrs::CPUArch::v8_M_Base));
+ EXPECT_TRUE(
+ testARMArch("armv8-m.main", "generic", "v8m.main",
+ ARMBuildAttrs::CPUArch::v8_M_Main));
+ EXPECT_TRUE(
+ testARMArch("iwmmxt", "iwmmxt", "",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("iwmmxt2", "generic", "",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("xscale", "xscale", "v5e",
+ ARMBuildAttrs::CPUArch::v5TE));
+ EXPECT_TRUE(
+ testARMArch("armv7s", "swift", "v7s",
+ ARMBuildAttrs::CPUArch::v7));
+ EXPECT_TRUE(
+ testARMArch("armv7k", "generic", "v7k",
+ ARMBuildAttrs::CPUArch::v7));
+}
+
+bool testARMExtension(StringRef CPUName,ARM::ArchKind ArchKind, StringRef ArchExt) {
+ return ARM::getDefaultExtensions(CPUName, ArchKind) &
+ ARM::parseArchExt(ArchExt);
+}
+
+TEST(TargetParserTest, testARMExtension) {
+ EXPECT_FALSE(testARMExtension("arm2", ARM::ArchKind::INVALID, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm3", ARM::ArchKind::INVALID, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm6", ARM::ArchKind::INVALID, "thumb"));
+ EXPECT_FALSE(testARMExtension("arm7m", ARM::ArchKind::INVALID, "thumb"));
+ EXPECT_FALSE(testARMExtension("strongarm", ARM::ArchKind::INVALID, "dsp"));
+ EXPECT_FALSE(testARMExtension("arm7tdmi", ARM::ArchKind::INVALID, "dsp"));
+ EXPECT_FALSE(testARMExtension("arm10tdmi",
+ ARM::ArchKind::INVALID, "simd"));
+ EXPECT_FALSE(testARMExtension("arm1022e", ARM::ArchKind::INVALID, "simd"));
+ EXPECT_FALSE(testARMExtension("arm926ej-s",
+ ARM::ArchKind::INVALID, "simd"));
+ EXPECT_FALSE(testARMExtension("arm1136jf-s",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1176j-s",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1156t2-s",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("arm1176jzf-s",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-m0",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-a8",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-r4",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-m3",
+ ARM::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testARMExtension("cortex-a53",
+ ARM::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testARMExtension("cortex-a53",
+ ARM::ArchKind::INVALID, "fp16"));
+ EXPECT_TRUE(testARMExtension("cortex-a55",
+ ARM::ArchKind::INVALID, "fp16"));
+ EXPECT_FALSE(testARMExtension("cortex-a55",
+ ARM::ArchKind::INVALID, "fp16fml"));
+ EXPECT_TRUE(testARMExtension("cortex-a75",
+ ARM::ArchKind::INVALID, "fp16"));
+ EXPECT_FALSE(testARMExtension("cortex-a75",
+ ARM::ArchKind::INVALID, "fp16fml"));
+ EXPECT_FALSE(testARMExtension("cortex-r52",
+ ARM::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testARMExtension("iwmmxt", ARM::ArchKind::INVALID, "crc"));
+ EXPECT_FALSE(testARMExtension("xscale", ARM::ArchKind::INVALID, "crc"));
+ EXPECT_FALSE(testARMExtension("swift", ARM::ArchKind::INVALID, "crc"));
+
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV2, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV2A, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV3, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV3M, "thumb"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV4, "dsp"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV4T, "dsp"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5T, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5TE, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5TEJ, "simd"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6K, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic",
+ ARM::ArchKind::ARMV6T2, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic",
+ ARM::ArchKind::ARMV6KZ, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6M, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7A, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7R, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7M, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic",
+ ARM::ArchKind::ARMV7EM, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8A, "ras"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_1A, "ras"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_2A, "profile"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_2A, "fp16"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_2A, "fp16fml"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_3A, "fp16"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_3A, "fp16fml"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_4A, "fp16"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_4A, "fp16fml"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8R, "ras"));
+ EXPECT_FALSE(testARMExtension("generic",
+ ARM::ArchKind::ARMV8MBaseline, "crc"));
+ EXPECT_FALSE(testARMExtension("generic",
+ ARM::ArchKind::ARMV8MMainline, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::IWMMXT, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::IWMMXT2, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::XSCALE, "crc"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7S, "crypto"));
+ EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7K, "crypto"));
+}
+
+TEST(TargetParserTest, ARMFPUVersion) {
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ if (FK == ARM::FK_LAST || ARM::getFPUName(FK) == "invalid" ||
+ ARM::getFPUName(FK) == "none" || ARM::getFPUName(FK) == "softvfp")
+ EXPECT_EQ(ARM::FPUVersion::NONE, ARM::getFPUVersion(FK));
+ else
+ EXPECT_NE(ARM::FPUVersion::NONE, ARM::getFPUVersion(FK));
+}
+
+TEST(TargetParserTest, ARMFPUNeonSupportLevel) {
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ if (FK == ARM::FK_LAST ||
+ ARM::getFPUName(FK).find("neon") == std::string::npos)
+ EXPECT_EQ(ARM::NeonSupportLevel::None,
+ ARM::getFPUNeonSupportLevel(FK));
+ else
+ EXPECT_NE(ARM::NeonSupportLevel::None,
+ ARM::getFPUNeonSupportLevel(FK));
+}
+
+TEST(TargetParserTest, ARMFPURestriction) {
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1)) {
+ if (FK == ARM::FK_LAST ||
+ (ARM::getFPUName(FK).find("d16") == std::string::npos &&
+ ARM::getFPUName(FK).find("vfpv3xd") == std::string::npos))
+ EXPECT_EQ(ARM::FPURestriction::None, ARM::getFPURestriction(FK));
+ else
+ EXPECT_NE(ARM::FPURestriction::None, ARM::getFPURestriction(FK));
+ }
+}
+
+TEST(TargetParserTest, ARMExtensionFeatures) {
+ std::vector<StringRef> Features;
+ unsigned Extensions = ARM::AEK_CRC | ARM::AEK_CRYPTO | ARM::AEK_DSP |
+ ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_MP |
+ ARM::AEK_SEC | ARM::AEK_VIRT | ARM::AEK_RAS | ARM::AEK_FP16 |
+ ARM::AEK_FP16FML;
+
+ for (unsigned i = 0; i <= Extensions; i++)
+ EXPECT_TRUE(i == 0 ? !ARM::getExtensionFeatures(i, Features)
+ : ARM::getExtensionFeatures(i, Features));
+}
+
+TEST(TargetParserTest, ARMFPUFeatures) {
+ std::vector<StringRef> Features;
+ for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0);
+ FK <= ARM::FPUKind::FK_LAST;
+ FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1))
+ EXPECT_TRUE((FK == ARM::FK_INVALID || FK >= ARM::FK_LAST)
+ ? !ARM::getFPUFeatures(FK, Features)
+ : ARM::getFPUFeatures(FK, Features));
+}
+
+TEST(TargetParserTest, ARMArchExtFeature) {
+ const char *ArchExt[][4] = {{"crc", "nocrc", "+crc", "-crc"},
+ {"crypto", "nocrypto", "+crypto", "-crypto"},
+ {"dsp", "nodsp", "+dsp", "-dsp"},
+ {"fp", "nofp", nullptr, nullptr},
+ {"idiv", "noidiv", nullptr, nullptr},
+ {"mp", "nomp", nullptr, nullptr},
+ {"simd", "nosimd", nullptr, nullptr},
+ {"sec", "nosec", nullptr, nullptr},
+ {"virt", "novirt", nullptr, nullptr},
+ {"fp16", "nofp16", "+fullfp16", "-fullfp16"},
+ {"fp16fml", "nofp16fml", "+fp16fml", "-fp16fml"},
+ {"ras", "noras", "+ras", "-ras"},
+ {"dotprod", "nodotprod", "+dotprod", "-dotprod"},
+ {"os", "noos", nullptr, nullptr},
+ {"iwmmxt", "noiwmmxt", nullptr, nullptr},
+ {"iwmmxt2", "noiwmmxt2", nullptr, nullptr},
+ {"maverick", "maverick", nullptr, nullptr},
+ {"xscale", "noxscale", nullptr, nullptr},
+ {"sb", "nosb", "+sb", "-sb"}};
+
+ for (unsigned i = 0; i < array_lengthof(ArchExt); i++) {
+ EXPECT_EQ(StringRef(ArchExt[i][2]), ARM::getArchExtFeature(ArchExt[i][0]));
+ EXPECT_EQ(StringRef(ArchExt[i][3]), ARM::getArchExtFeature(ArchExt[i][1]));
+ }
+}
+
+TEST(TargetParserTest, ARMparseHWDiv) {
+ const char *hwdiv[] = {"thumb", "arm", "arm,thumb", "thumb,arm"};
+
+ for (unsigned i = 0; i < array_lengthof(hwdiv); i++)
+ EXPECT_NE(ARM::AEK_INVALID, ARM::parseHWDiv((StringRef)hwdiv[i]));
+}
+
+TEST(TargetParserTest, ARMparseArchEndianAndISA) {
+ const char *Arch[] = {
+ "v2", "v2a", "v3", "v3m", "v4", "v4t", "v5", "v5t",
+ "v5e", "v5te", "v5tej", "v6", "v6j", "v6k", "v6hl", "v6t2",
+ "v6kz", "v6z", "v6zk", "v6-m", "v6m", "v6sm", "v6s-m", "v7-a",
+ "v7", "v7a", "v7ve", "v7hl", "v7l", "v7-r", "v7r", "v7-m",
+ "v7m", "v7k", "v7s", "v7e-m", "v7em", "v8-a", "v8", "v8a",
+ "v8l", "v8.1-a", "v8.1a", "v8.2-a", "v8.2a", "v8.3-a", "v8.3a", "v8.4-a",
+ "v8.4a", "v8.5-a","v8.5a", "v8-r"
+ };
+
+ for (unsigned i = 0; i < array_lengthof(Arch); i++) {
+ std::string arm_1 = "armeb" + (std::string)(Arch[i]);
+ std::string arm_2 = "arm" + (std::string)(Arch[i]) + "eb";
+ std::string arm_3 = "arm" + (std::string)(Arch[i]);
+ std::string thumb_1 = "thumbeb" + (std::string)(Arch[i]);
+ std::string thumb_2 = "thumb" + (std::string)(Arch[i]) + "eb";
+ std::string thumb_3 = "thumb" + (std::string)(Arch[i]);
+
+ EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(arm_1));
+ EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(arm_2));
+ EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian(arm_3));
+
+ EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_1));
+ EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_2));
+ EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_3));
+ if (i >= 4) {
+ EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(thumb_1));
+ EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(thumb_2));
+ EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian(thumb_3));
+
+ EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_1));
+ EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_2));
+ EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_3));
+ }
+ }
+
+ EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian("aarch64"));
+ EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian("aarch64_be"));
+
+ EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("aarch64"));
+ EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("aarch64_be"));
+ EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("arm64"));
+ EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("arm64_be"));
+}
+
+TEST(TargetParserTest, ARMparseArchProfile) {
+ for (unsigned i = 0; i < array_lengthof(ARMArch); i++) {
+ switch (ARM::parseArch(ARMArch[i])) {
+ case ARM::ArchKind::ARMV6M:
+ case ARM::ArchKind::ARMV7M:
+ case ARM::ArchKind::ARMV7EM:
+ case ARM::ArchKind::ARMV8MMainline:
+ case ARM::ArchKind::ARMV8MBaseline:
+ EXPECT_EQ(ARM::ProfileKind::M, ARM::parseArchProfile(ARMArch[i]));
+ break;
+ case ARM::ArchKind::ARMV7R:
+ case ARM::ArchKind::ARMV8R:
+ EXPECT_EQ(ARM::ProfileKind::R, ARM::parseArchProfile(ARMArch[i]));
+ break;
+ case ARM::ArchKind::ARMV7A:
+ case ARM::ArchKind::ARMV7VE:
+ case ARM::ArchKind::ARMV7K:
+ case ARM::ArchKind::ARMV8A:
+ case ARM::ArchKind::ARMV8_1A:
+ case ARM::ArchKind::ARMV8_2A:
+ case ARM::ArchKind::ARMV8_3A:
+ case ARM::ArchKind::ARMV8_4A:
+ case ARM::ArchKind::ARMV8_5A:
+ EXPECT_EQ(ARM::ProfileKind::A, ARM::parseArchProfile(ARMArch[i]));
+ break;
+ default:
+ EXPECT_EQ(ARM::ProfileKind::INVALID, ARM::parseArchProfile(ARMArch[i]));
+ break;
+ }
+ }
+}
+
+TEST(TargetParserTest, ARMparseArchVersion) {
+ for (unsigned i = 0; i < array_lengthof(ARMArch); i++)
+ if (((std::string)ARMArch[i]).substr(0, 4) == "armv")
+ EXPECT_EQ((ARMArch[i][4] - 48u), ARM::parseArchVersion(ARMArch[i]));
+ else
+ EXPECT_EQ(5u, ARM::parseArchVersion(ARMArch[i]));
+}
+
+bool testAArch64CPU(StringRef CPUName, StringRef ExpectedArch,
+ StringRef ExpectedFPU, unsigned ExpectedFlags,
+ StringRef CPUAttr) {
+ AArch64::ArchKind AK = AArch64::parseCPUArch(CPUName);
+ bool pass = AArch64::getArchName(AK).equals(ExpectedArch);
+
+ unsigned ExtKind = AArch64::getDefaultExtensions(CPUName, AK);
+ if (ExtKind > 1 && (ExtKind & AArch64::AEK_NONE))
+ pass &= ((ExtKind ^ AArch64::AEK_NONE) == ExpectedFlags);
+ else
+ pass &= (ExtKind == ExpectedFlags);
+
+ pass &= AArch64::getCPUAttr(AK).equals(CPUAttr);
+
+ return pass;
+}
+
+TEST(TargetParserTest, testAArch64CPU) {
+ EXPECT_TRUE(testAArch64CPU(
+ "invalid", "invalid", "invalid",
+ AArch64::AEK_NONE, ""));
+ EXPECT_TRUE(testAArch64CPU(
+ "generic", "invalid", "none",
+ AArch64::AEK_NONE, ""));
+
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a35", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a53", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a55", "armv8.2-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_FP16 | AArch64::AEK_DOTPROD |
+ AArch64::AEK_RCPC, "8.2-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a72", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a73", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cortex-a75", "armv8.2-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_FP16 | AArch64::AEK_DOTPROD |
+ AArch64::AEK_RCPC, "8.2-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "cyclone", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m1", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m2", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m3", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "exynos-m4", "armv8.2-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO |
+ AArch64::AEK_DOTPROD | AArch64::AEK_FP | AArch64::AEK_FP16 |
+ AArch64::AEK_LSE | AArch64::AEK_RAS | AArch64::AEK_RDM |
+ AArch64::AEK_SIMD, "8.2-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "falkor", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RDM, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "kryo", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD, "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_FP | AArch64::AEK_SIMD, "8.1-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderx", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt81", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt83", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "thunderxt88", "armv8-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD |
+ AArch64::AEK_FP | AArch64::AEK_PROFILE,
+ "8-A"));
+ EXPECT_TRUE(testAArch64CPU(
+ "tsv110", "armv8.2-a", "crypto-neon-fp-armv8",
+ AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP |
+ AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_PROFILE | AArch64::AEK_FP16 |
+ AArch64::AEK_FP16FML | AArch64::AEK_DOTPROD,
+ "8.2-A"));
+}
+
+static constexpr unsigned NumAArch64CPUArchs = 21;
+
+TEST(TargetParserTest, testAArch64CPUArchList) {
+ SmallVector<StringRef, NumAArch64CPUArchs> List;
+ AArch64::fillValidCPUArchList(List);
+
+ // No list exists for these in this test suite, so ensure all are
+ // valid, and match the expected 'magic' count.
+ EXPECT_EQ(List.size(), NumAArch64CPUArchs);
+ for(StringRef CPU : List) {
+ EXPECT_NE(AArch64::parseCPUArch(CPU), AArch64::ArchKind::INVALID);
+ }
+}
+
+bool testAArch64Arch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch,
+ unsigned ArchAttr) {
+ AArch64::ArchKind AK = AArch64::parseArch(Arch);
+ return (AK != AArch64::ArchKind::INVALID) &
+ AArch64::getDefaultCPU(Arch).equals(DefaultCPU) &
+ AArch64::getSubArch(AK).equals(SubArch) &
+ (AArch64::getArchAttr(AK) == ArchAttr);
+}
+
+TEST(TargetParserTest, testAArch64Arch) {
+ EXPECT_TRUE(testAArch64Arch("armv8-a", "cortex-a53", "v8",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.1-a", "generic", "v8.1a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.2-a", "generic", "v8.2a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.3-a", "generic", "v8.3a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.4-a", "generic", "v8.4a",
+ ARMBuildAttrs::CPUArch::v8_A));
+ EXPECT_TRUE(testAArch64Arch("armv8.5-a", "generic", "v8.5a",
+ ARMBuildAttrs::CPUArch::v8_A));
+}
+
+bool testAArch64Extension(StringRef CPUName, AArch64::ArchKind AK,
+ StringRef ArchExt) {
+ return AArch64::getDefaultExtensions(CPUName, AK) &
+ AArch64::parseArchExt(ArchExt);
+}
+
+TEST(TargetParserTest, testAArch64Extension) {
+ EXPECT_FALSE(testAArch64Extension("cortex-a35",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a53",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a55",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a57",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a72",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a73",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a75",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("cyclone",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("exynos-m1",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("exynos-m2",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("exynos-m3",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("exynos-m4",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_TRUE(testAArch64Extension("exynos-m4",
+ AArch64::ArchKind::INVALID, "rdm"));
+ EXPECT_TRUE(testAArch64Extension("exynos-m4",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("exynos-m4",
+ AArch64::ArchKind::INVALID, "fullfp16"));
+ EXPECT_TRUE(testAArch64Extension("exynos-m4",
+ AArch64::ArchKind::INVALID, "dotprod"));
+ EXPECT_TRUE(testAArch64Extension("falkor",
+ AArch64::ArchKind::INVALID, "rdm"));
+ EXPECT_FALSE(testAArch64Extension("kryo",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "crc"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "rdm"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "rcpc"));
+ EXPECT_TRUE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "profile"));
+ EXPECT_FALSE(testAArch64Extension("saphira",
+ AArch64::ArchKind::INVALID, "fp16"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a55",
+ AArch64::ArchKind::INVALID, "fp16"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a55",
+ AArch64::ArchKind::INVALID, "fp16fml"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a55",
+ AArch64::ArchKind::INVALID, "dotprod"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a75",
+ AArch64::ArchKind::INVALID, "fp16"));
+ EXPECT_FALSE(testAArch64Extension("cortex-a75",
+ AArch64::ArchKind::INVALID, "fp16fml"));
+ EXPECT_TRUE(testAArch64Extension("cortex-a75",
+ AArch64::ArchKind::INVALID, "dotprod"));
+ EXPECT_FALSE(testAArch64Extension("thunderx2t99",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_FALSE(testAArch64Extension("thunderx",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt81",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt83",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_FALSE(testAArch64Extension("thunderxt88",
+ AArch64::ArchKind::INVALID, "lse"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "crypto"));
+ EXPECT_FALSE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "sha3"));
+ EXPECT_FALSE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "sm4"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "ras"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "profile"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "fp16"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "fp16fml"));
+ EXPECT_TRUE(testAArch64Extension("tsv110",
+ AArch64::ArchKind::INVALID, "dotprod"));
+
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8A, "ras"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_1A, "ras"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_2A, "profile"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_2A, "fp16"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_2A, "fp16fml"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_3A, "fp16"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_3A, "fp16fml"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_4A, "fp16"));
+ EXPECT_FALSE(testAArch64Extension(
+ "generic", AArch64::ArchKind::ARMV8_4A, "fp16fml"));
+}
+
+TEST(TargetParserTest, AArch64ExtensionFeatures) {
+ std::vector<StringRef> Features;
+ unsigned Extensions = AArch64::AEK_CRC | AArch64::AEK_CRYPTO |
+ AArch64::AEK_FP | AArch64::AEK_SIMD |
+ AArch64::AEK_FP16 | AArch64::AEK_PROFILE |
+ AArch64::AEK_RAS | AArch64::AEK_LSE |
+ AArch64::AEK_RDM | AArch64::AEK_SVE |
+ AArch64::AEK_DOTPROD | AArch64::AEK_RCPC |
+ AArch64::AEK_FP16FML;
+
+ for (unsigned i = 0; i <= Extensions; i++)
+ EXPECT_TRUE(i == 0 ? !AArch64::getExtensionFeatures(i, Features)
+ : AArch64::getExtensionFeatures(i, Features));
+}
+
+TEST(TargetParserTest, AArch64ArchFeatures) {
+ std::vector<StringRef> Features;
+
+ for (auto AK : AArch64::ArchKinds)
+ EXPECT_TRUE((AK == AArch64::ArchKind::INVALID)
+ ? !AArch64::getArchFeatures(AK, Features)
+ : AArch64::getArchFeatures(AK, Features));
+}
+
+TEST(TargetParserTest, AArch64ArchExtFeature) {
+ const char *ArchExt[][4] = {{"crc", "nocrc", "+crc", "-crc"},
+ {"crypto", "nocrypto", "+crypto", "-crypto"},
+ {"fp", "nofp", "+fp-armv8", "-fp-armv8"},
+ {"simd", "nosimd", "+neon", "-neon"},
+ {"fp16", "nofp16", "+fullfp16", "-fullfp16"},
+ {"fp16fml", "nofp16fml", "+fp16fml", "-fp16fml"},
+ {"profile", "noprofile", "+spe", "-spe"},
+ {"ras", "noras", "+ras", "-ras"},
+ {"lse", "nolse", "+lse", "-lse"},
+ {"rdm", "nordm", "+rdm", "-rdm"},
+ {"sve", "nosve", "+sve", "-sve"},
+ {"dotprod", "nodotprod", "+dotprod", "-dotprod"},
+ {"rcpc", "norcpc", "+rcpc", "-rcpc" },
+ {"rng", "norng", "+rand", "-rand"},
+ {"memtag", "nomemtag", "+mte", "-mte"},
+ {"ssbs", "nossbs", "+ssbs", "-ssbs"},
+ {"sb", "nosb", "+sb", "-sb"},
+ {"predres", "nopredres", "+predres", "-predres"}
+};
+
+ for (unsigned i = 0; i < array_lengthof(ArchExt); i++) {
+ EXPECT_EQ(StringRef(ArchExt[i][2]),
+ AArch64::getArchExtFeature(ArchExt[i][0]));
+ EXPECT_EQ(StringRef(ArchExt[i][3]),
+ AArch64::getArchExtFeature(ArchExt[i][1]));
+ }
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/TaskQueueTest.cpp b/src/llvm-project/llvm/unittests/Support/TaskQueueTest.cpp
new file mode 100644
index 0000000..14ca9c0
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TaskQueueTest.cpp
@@ -0,0 +1,108 @@
+//========- unittests/Support/TaskQueue.cpp - TaskQueue.h tests ------========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Config/llvm-config.h"
+
+#if LLVM_ENABLE_THREADS
+
+#include "llvm/Support/TaskQueue.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class TaskQueueTest : public testing::Test {
+protected:
+ TaskQueueTest() {}
+};
+
+TEST_F(TaskQueueTest, OrderedFutures) {
+ ThreadPool TP(1);
+ TaskQueue TQ(TP);
+ std::atomic<int> X{ 0 };
+ std::atomic<int> Y{ 0 };
+ std::atomic<int> Z{ 0 };
+
+ std::mutex M1, M2, M3;
+ std::unique_lock<std::mutex> L1(M1);
+ std::unique_lock<std::mutex> L2(M2);
+ std::unique_lock<std::mutex> L3(M3);
+
+ std::future<void> F1 = TQ.async([&] {
+ std::unique_lock<std::mutex> Lock(M1);
+ ++X;
+ });
+ std::future<void> F2 = TQ.async([&] {
+ std::unique_lock<std::mutex> Lock(M2);
+ ++Y;
+ });
+ std::future<void> F3 = TQ.async([&] {
+ std::unique_lock<std::mutex> Lock(M3);
+ ++Z;
+ });
+
+ L1.unlock();
+ F1.wait();
+ ASSERT_EQ(1, X);
+ ASSERT_EQ(0, Y);
+ ASSERT_EQ(0, Z);
+
+ L2.unlock();
+ F2.wait();
+ ASSERT_EQ(1, X);
+ ASSERT_EQ(1, Y);
+ ASSERT_EQ(0, Z);
+
+ L3.unlock();
+ F3.wait();
+ ASSERT_EQ(1, X);
+ ASSERT_EQ(1, Y);
+ ASSERT_EQ(1, Z);
+}
+
+TEST_F(TaskQueueTest, UnOrderedFutures) {
+ ThreadPool TP(1);
+ TaskQueue TQ(TP);
+ std::atomic<int> X{ 0 };
+ std::atomic<int> Y{ 0 };
+ std::atomic<int> Z{ 0 };
+ std::mutex M;
+
+ std::unique_lock<std::mutex> Lock(M);
+
+ std::future<void> F1 = TQ.async([&] { ++X; });
+ std::future<void> F2 = TQ.async([&] { ++Y; });
+ std::future<void> F3 = TQ.async([&M, &Z] {
+ std::unique_lock<std::mutex> Lock(M);
+ ++Z;
+ });
+
+ F2.wait();
+ ASSERT_EQ(1, X);
+ ASSERT_EQ(1, Y);
+ ASSERT_EQ(0, Z);
+
+ Lock.unlock();
+
+ F3.wait();
+ ASSERT_EQ(1, X);
+ ASSERT_EQ(1, Y);
+ ASSERT_EQ(1, Z);
+}
+
+TEST_F(TaskQueueTest, FutureWithReturnValue) {
+ ThreadPool TP(1);
+ TaskQueue TQ(TP);
+ std::future<std::string> F1 = TQ.async([&] { return std::string("Hello"); });
+ std::future<int> F2 = TQ.async([&] { return 42; });
+
+ ASSERT_EQ(42, F2.get());
+ ASSERT_EQ("Hello", F1.get());
+}
+#endif
diff --git a/src/llvm-project/llvm/unittests/Support/ThreadLocalTest.cpp b/src/llvm-project/llvm/unittests/Support/ThreadLocalTest.cpp
new file mode 100644
index 0000000..e71c7db
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ThreadLocalTest.cpp
@@ -0,0 +1,57 @@
+//===- llvm/unittest/Support/ThreadLocalTest.cpp - ThreadLocal tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ThreadLocal.h"
+#include "gtest/gtest.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace sys;
+
+namespace {
+
+class ThreadLocalTest : public ::testing::Test {
+};
+
+struct S {
+ int i;
+};
+
+TEST_F(ThreadLocalTest, Basics) {
+ ThreadLocal<const S> x;
+
+ static_assert(
+ std::is_const<std::remove_pointer<decltype(x.get())>::type>::value,
+ "ThreadLocal::get didn't return a pointer to const object");
+
+ EXPECT_EQ(nullptr, x.get());
+
+ S s;
+ x.set(&s);
+ EXPECT_EQ(&s, x.get());
+
+ x.erase();
+ EXPECT_EQ(nullptr, x.get());
+
+ ThreadLocal<S> y;
+
+ static_assert(
+ !std::is_const<std::remove_pointer<decltype(y.get())>::type>::value,
+ "ThreadLocal::get returned a pointer to const object");
+
+ EXPECT_EQ(nullptr, y.get());
+
+ y.set(&s);
+ EXPECT_EQ(&s, y.get());
+
+ y.erase();
+ EXPECT_EQ(nullptr, y.get());
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/ThreadPool.cpp b/src/llvm-project/llvm/unittests/Support/ThreadPool.cpp
new file mode 100644
index 0000000..0da33ad
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/ThreadPool.cpp
@@ -0,0 +1,166 @@
+//========- unittests/Support/ThreadPools.cpp - ThreadPools.h tests --========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ThreadPool.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// Fixture for the unittests, allowing to *temporarily* disable the unittests
+// on a particular platform
+class ThreadPoolTest : public testing::Test {
+ Triple Host;
+ SmallVector<Triple::ArchType, 4> UnsupportedArchs;
+ SmallVector<Triple::OSType, 4> UnsupportedOSs;
+ SmallVector<Triple::EnvironmentType, 1> UnsupportedEnvironments;
+protected:
+ // This is intended for platform as a temporary "XFAIL"
+ bool isUnsupportedOSOrEnvironment() {
+ Triple Host(Triple::normalize(sys::getProcessTriple()));
+
+ if (find(UnsupportedEnvironments, Host.getEnvironment()) !=
+ UnsupportedEnvironments.end())
+ return true;
+
+ if (is_contained(UnsupportedOSs, Host.getOS()))
+ return true;
+
+ if (is_contained(UnsupportedArchs, Host.getArch()))
+ return true;
+
+ return false;
+ }
+
+ ThreadPoolTest() {
+ // Add unsupported configuration here, example:
+ // UnsupportedArchs.push_back(Triple::x86_64);
+
+ // See https://llvm.org/bugs/show_bug.cgi?id=25829
+ UnsupportedArchs.push_back(Triple::ppc64le);
+ UnsupportedArchs.push_back(Triple::ppc64);
+ }
+
+ /// Make sure this thread not progress faster than the main thread.
+ void waitForMainThread() {
+ std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex);
+ WaitMainThread.wait(LockGuard, [&] { return MainThreadReady; });
+ }
+
+ /// Set the readiness of the main thread.
+ void setMainThreadReady() {
+ {
+ std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex);
+ MainThreadReady = true;
+ }
+ WaitMainThread.notify_all();
+ }
+
+ void SetUp() override { MainThreadReady = false; }
+
+ std::condition_variable WaitMainThread;
+ std::mutex WaitMainThreadMutex;
+ bool MainThreadReady;
+
+};
+
+#define CHECK_UNSUPPORTED() \
+ do { \
+ if (isUnsupportedOSOrEnvironment()) \
+ return; \
+ } while (0); \
+
+TEST_F(ThreadPoolTest, AsyncBarrier) {
+ CHECK_UNSUPPORTED();
+ // test that async & barrier work together properly.
+
+ std::atomic_int checked_in{0};
+
+ ThreadPool Pool;
+ for (size_t i = 0; i < 5; ++i) {
+ Pool.async([this, &checked_in] {
+ waitForMainThread();
+ ++checked_in;
+ });
+ }
+ ASSERT_EQ(0, checked_in);
+ setMainThreadReady();
+ Pool.wait();
+ ASSERT_EQ(5, checked_in);
+}
+
+static void TestFunc(std::atomic_int &checked_in, int i) { checked_in += i; }
+
+TEST_F(ThreadPoolTest, AsyncBarrierArgs) {
+ CHECK_UNSUPPORTED();
+ // Test that async works with a function requiring multiple parameters.
+ std::atomic_int checked_in{0};
+
+ ThreadPool Pool;
+ for (size_t i = 0; i < 5; ++i) {
+ Pool.async(TestFunc, std::ref(checked_in), i);
+ }
+ Pool.wait();
+ ASSERT_EQ(10, checked_in);
+}
+
+TEST_F(ThreadPoolTest, Async) {
+ CHECK_UNSUPPORTED();
+ ThreadPool Pool;
+ std::atomic_int i{0};
+ Pool.async([this, &i] {
+ waitForMainThread();
+ ++i;
+ });
+ Pool.async([&i] { ++i; });
+ ASSERT_NE(2, i.load());
+ setMainThreadReady();
+ Pool.wait();
+ ASSERT_EQ(2, i.load());
+}
+
+TEST_F(ThreadPoolTest, GetFuture) {
+ CHECK_UNSUPPORTED();
+ ThreadPool Pool{2};
+ std::atomic_int i{0};
+ Pool.async([this, &i] {
+ waitForMainThread();
+ ++i;
+ });
+ // Force the future using get()
+ Pool.async([&i] { ++i; }).get();
+ ASSERT_NE(2, i.load());
+ setMainThreadReady();
+ Pool.wait();
+ ASSERT_EQ(2, i.load());
+}
+
+TEST_F(ThreadPoolTest, PoolDestruction) {
+ CHECK_UNSUPPORTED();
+ // Test that we are waiting on destruction
+ std::atomic_int checked_in{0};
+ {
+ ThreadPool Pool;
+ for (size_t i = 0; i < 5; ++i) {
+ Pool.async([this, &checked_in] {
+ waitForMainThread();
+ ++checked_in;
+ });
+ }
+ ASSERT_EQ(0, checked_in);
+ setMainThreadReady();
+ }
+ ASSERT_EQ(5, checked_in);
+}
diff --git a/src/llvm-project/llvm/unittests/Support/Threading.cpp b/src/llvm-project/llvm/unittests/Support/Threading.cpp
new file mode 100644
index 0000000..be53026
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/Threading.cpp
@@ -0,0 +1,25 @@
+//===- unittests/Threading.cpp - Thread tests -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/thread.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(Threading, PhysicalConcurrency) {
+ auto Num = heavyweight_hardware_concurrency();
+ // Since Num is unsigned this will also catch us trying to
+ // return -1.
+ ASSERT_LE(Num, thread::hardware_concurrency());
+}
+
+} // end anon namespace
diff --git a/src/llvm-project/llvm/unittests/Support/TimerTest.cpp b/src/llvm-project/llvm/unittests/Support/TimerTest.cpp
new file mode 100644
index 0000000..a92ecf1
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TimerTest.cpp
@@ -0,0 +1,65 @@
+//===- unittests/TimerTest.cpp - Timer tests ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Timer.h"
+#include "gtest/gtest.h"
+
+#if _WIN32
+#include <windows.h>
+#else
+#include <time.h>
+#endif
+
+using namespace llvm;
+
+namespace {
+
+// FIXME: Put this somewhere in Support, it's also used in LockFileManager.
+void SleepMS() {
+#if _WIN32
+ Sleep(1);
+#else
+ struct timespec Interval;
+ Interval.tv_sec = 0;
+ Interval.tv_nsec = 1000000;
+ nanosleep(&Interval, nullptr);
+#endif
+}
+
+TEST(Timer, Additivity) {
+ Timer T1("T1", "T1");
+
+ EXPECT_TRUE(T1.isInitialized());
+
+ T1.startTimer();
+ T1.stopTimer();
+ auto TR1 = T1.getTotalTime();
+
+ T1.startTimer();
+ SleepMS();
+ T1.stopTimer();
+ auto TR2 = T1.getTotalTime();
+
+ EXPECT_TRUE(TR1 < TR2);
+}
+
+TEST(Timer, CheckIfTriggered) {
+ Timer T1("T1", "T1");
+
+ EXPECT_FALSE(T1.hasTriggered());
+ T1.startTimer();
+ EXPECT_TRUE(T1.hasTriggered());
+ T1.stopTimer();
+ EXPECT_TRUE(T1.hasTriggered());
+
+ T1.clear();
+ EXPECT_FALSE(T1.hasTriggered());
+}
+
+} // end anon namespace
diff --git a/src/llvm-project/llvm/unittests/Support/TrailingObjectsTest.cpp b/src/llvm-project/llvm/unittests/Support/TrailingObjectsTest.cpp
new file mode 100644
index 0000000..23acc54
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TrailingObjectsTest.cpp
@@ -0,0 +1,259 @@
+//=== - llvm/unittest/Support/TrailingObjectsTest.cpp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TrailingObjects.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+// This class, beyond being used by the test case, a nice
+// demonstration of the intended usage of TrailingObjects, with a
+// single trailing array.
+class Class1 final : protected TrailingObjects<Class1, short> {
+ friend TrailingObjects;
+
+ unsigned NumShorts;
+
+protected:
+ size_t numTrailingObjects(OverloadToken<short>) const { return NumShorts; }
+
+ Class1(int *ShortArray, unsigned NumShorts) : NumShorts(NumShorts) {
+ std::uninitialized_copy(ShortArray, ShortArray + NumShorts,
+ getTrailingObjects<short>());
+ }
+
+public:
+ static Class1 *create(int *ShortArray, unsigned NumShorts) {
+ void *Mem = ::operator new(totalSizeToAlloc<short>(NumShorts));
+ return new (Mem) Class1(ShortArray, NumShorts);
+ }
+ void operator delete(void *p) { ::operator delete(p); }
+
+ short get(unsigned Num) const { return getTrailingObjects<short>()[Num]; }
+
+ unsigned numShorts() const { return NumShorts; }
+
+ // Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
+ using TrailingObjects::totalSizeToAlloc;
+ using TrailingObjects::additionalSizeToAlloc;
+ using TrailingObjects::getTrailingObjects;
+};
+
+// Here, there are two singular optional object types appended. Note
+// that the alignment of Class2 is automatically increased to account
+// for the alignment requirements of the trailing objects.
+class Class2 final : protected TrailingObjects<Class2, double, short> {
+ friend TrailingObjects;
+
+ bool HasShort, HasDouble;
+
+protected:
+ size_t numTrailingObjects(OverloadToken<short>) const {
+ return HasShort ? 1 : 0;
+ }
+ size_t numTrailingObjects(OverloadToken<double>) const {
+ return HasDouble ? 1 : 0;
+ }
+
+ Class2(bool HasShort, bool HasDouble)
+ : HasShort(HasShort), HasDouble(HasDouble) {}
+
+public:
+ static Class2 *create(short S = 0, double D = 0.0) {
+ bool HasShort = S != 0;
+ bool HasDouble = D != 0.0;
+
+ void *Mem =
+ ::operator new(totalSizeToAlloc<double, short>(HasDouble, HasShort));
+ Class2 *C = new (Mem) Class2(HasShort, HasDouble);
+ if (HasShort)
+ *C->getTrailingObjects<short>() = S;
+ if (HasDouble)
+ *C->getTrailingObjects<double>() = D;
+ return C;
+ }
+ void operator delete(void *p) { ::operator delete(p); }
+
+ short getShort() const {
+ if (!HasShort)
+ return 0;
+ return *getTrailingObjects<short>();
+ }
+
+ double getDouble() const {
+ if (!HasDouble)
+ return 0.0;
+ return *getTrailingObjects<double>();
+ }
+
+ // Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
+ using TrailingObjects::totalSizeToAlloc;
+ using TrailingObjects::additionalSizeToAlloc;
+ using TrailingObjects::getTrailingObjects;
+};
+
+TEST(TrailingObjects, OneArg) {
+ int arr[] = {1, 2, 3};
+ Class1 *C = Class1::create(arr, 3);
+ EXPECT_EQ(sizeof(Class1), sizeof(unsigned));
+ EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short));
+ EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3);
+
+ EXPECT_EQ(alignof(Class1),
+ alignof(Class1::FixedSizeStorage<short>::with_counts<1>::type));
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<1>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(1), alignof(Class1)));
+ EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short));
+
+ EXPECT_EQ(alignof(Class1),
+ alignof(Class1::FixedSizeStorage<short>::with_counts<3>::type));
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<3>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(3), alignof(Class1)));
+ EXPECT_EQ(Class1::totalSizeToAlloc<short>(3),
+ sizeof(Class1) + sizeof(short) * 3);
+
+ EXPECT_EQ(C->getTrailingObjects<short>(), reinterpret_cast<short *>(C + 1));
+ EXPECT_EQ(C->get(0), 1);
+ EXPECT_EQ(C->get(2), 3);
+ delete C;
+}
+
+TEST(TrailingObjects, TwoArg) {
+ Class2 *C1 = Class2::create(4);
+ Class2 *C2 = Class2::create(0, 4.2);
+
+ EXPECT_EQ(sizeof(Class2), llvm::alignTo(sizeof(bool) * 2, alignof(double)));
+ EXPECT_EQ(alignof(Class2), alignof(double));
+
+ EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)),
+ sizeof(double));
+ EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(0, 1)),
+ sizeof(short));
+ EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)),
+ sizeof(double) * 3 + sizeof(short));
+
+ EXPECT_EQ(
+ alignof(Class2),
+ (alignof(
+ Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type)));
+ EXPECT_EQ(
+ sizeof(Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type),
+ llvm::alignTo(Class2::totalSizeToAlloc<double, short>(1, 1),
+ alignof(Class2)));
+ EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)),
+ sizeof(Class2) + sizeof(double) + sizeof(short));
+
+ EXPECT_EQ(C1->getDouble(), 0);
+ EXPECT_EQ(C1->getShort(), 4);
+ EXPECT_EQ(C1->getTrailingObjects<double>(),
+ reinterpret_cast<double *>(C1 + 1));
+ EXPECT_EQ(C1->getTrailingObjects<short>(), reinterpret_cast<short *>(C1 + 1));
+
+ EXPECT_EQ(C2->getDouble(), 4.2);
+ EXPECT_EQ(C2->getShort(), 0);
+ EXPECT_EQ(C2->getTrailingObjects<double>(),
+ reinterpret_cast<double *>(C2 + 1));
+ EXPECT_EQ(C2->getTrailingObjects<short>(),
+ reinterpret_cast<short *>(reinterpret_cast<double *>(C2 + 1) + 1));
+ delete C1;
+ delete C2;
+}
+
+// This test class is not trying to be a usage demo, just asserting
+// that three args does actually work too (it's the same code as
+// handles the second arg, so it's basically covered by the above, but
+// just in case..)
+class Class3 final : public TrailingObjects<Class3, double, short, bool> {
+ friend TrailingObjects;
+
+ size_t numTrailingObjects(OverloadToken<double>) const { return 1; }
+ size_t numTrailingObjects(OverloadToken<short>) const { return 1; }
+};
+
+TEST(TrailingObjects, ThreeArg) {
+ EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)),
+ sizeof(double) + sizeof(short) + 3 * sizeof(bool));
+ EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, alignof(double)));
+
+ EXPECT_EQ(
+ alignof(Class3),
+ (alignof(Class3::FixedSizeStorage<double, short,
+ bool>::with_counts<1, 1, 3>::type)));
+ EXPECT_EQ(
+ sizeof(Class3::FixedSizeStorage<double, short,
+ bool>::with_counts<1, 1, 3>::type),
+ llvm::alignTo(Class3::totalSizeToAlloc<double, short, bool>(1, 1, 3),
+ alignof(Class3)));
+
+ std::unique_ptr<char[]> P(new char[1000]);
+ Class3 *C = reinterpret_cast<Class3 *>(P.get());
+ EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1));
+ EXPECT_EQ(C->getTrailingObjects<short>(),
+ reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1));
+ EXPECT_EQ(
+ C->getTrailingObjects<bool>(),
+ reinterpret_cast<bool *>(
+ reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1) +
+ 1));
+}
+
+class Class4 final : public TrailingObjects<Class4, char, long> {
+ friend TrailingObjects;
+ size_t numTrailingObjects(OverloadToken<char>) const { return 1; }
+};
+
+TEST(TrailingObjects, Realignment) {
+ EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)),
+ llvm::alignTo(sizeof(long) + 1, alignof(long)));
+ EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, alignof(long)));
+
+ EXPECT_EQ(
+ alignof(Class4),
+ (alignof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type)));
+ EXPECT_EQ(
+ sizeof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type),
+ llvm::alignTo(Class4::totalSizeToAlloc<char, long>(1, 1),
+ alignof(Class4)));
+
+ std::unique_ptr<char[]> P(new char[1000]);
+ Class4 *C = reinterpret_cast<Class4 *>(P.get());
+ EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1));
+ EXPECT_EQ(C->getTrailingObjects<long>(),
+ reinterpret_cast<long *>(llvm::alignAddr(
+ reinterpret_cast<char *>(C + 1) + 1, alignof(long))));
+}
+}
+
+// Test the use of TrailingObjects with a template class. This
+// previously failed to compile due to a bug in MSVC's member access
+// control/lookup handling for OverloadToken.
+template <typename Derived>
+class Class5Tmpl : private llvm::TrailingObjects<Derived, float, int> {
+ using TrailingObjects = typename llvm::TrailingObjects<Derived, float>;
+ friend TrailingObjects;
+
+ size_t numTrailingObjects(
+ typename TrailingObjects::template OverloadToken<float>) const {
+ return 1;
+ }
+
+ size_t numTrailingObjects(
+ typename TrailingObjects::template OverloadToken<int>) const {
+ return 2;
+ }
+};
+
+class Class5 : public Class5Tmpl<Class5> {};
diff --git a/src/llvm-project/llvm/unittests/Support/TrigramIndexTest.cpp b/src/llvm-project/llvm/unittests/Support/TrigramIndexTest.cpp
new file mode 100644
index 0000000..df42c1e
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TrigramIndexTest.cpp
@@ -0,0 +1,132 @@
+//===- TrigramIndexTest.cpp - Unit tests for TrigramIndex -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TrigramIndex.h"
+#include "llvm/ADT/STLExtras.h"
+#include "gtest/gtest.h"
+
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+class TrigramIndexTest : public ::testing::Test {
+protected:
+ std::unique_ptr<TrigramIndex> makeTrigramIndex(
+ std::vector<std::string> Rules) {
+ std::unique_ptr<TrigramIndex> TI =
+ make_unique<TrigramIndex>();
+ for (auto &Rule : Rules)
+ TI->insert(Rule);
+ return TI;
+ }
+};
+
+TEST_F(TrigramIndexTest, Empty) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, Basic) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*hello*", "*wor.d*"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, NoTrigramsInRules) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"b.r", "za*az"});
+ EXPECT_TRUE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("foo"));
+ EXPECT_FALSE(TI->isDefinitelyOut("bar"));
+ EXPECT_FALSE(TI->isDefinitelyOut("zakaz"));
+}
+
+TEST_F(TrigramIndexTest, NoTrigramsInARule) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*hello*", "*wo.ld*"});
+ EXPECT_TRUE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("foo"));
+}
+
+TEST_F(TrigramIndexTest, RepetitiveRule) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*bar*bar*bar*bar*bar", "bar*bar"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_TRUE(TI->isDefinitelyOut("foo"));
+ EXPECT_TRUE(TI->isDefinitelyOut("bar"));
+ EXPECT_FALSE(TI->isDefinitelyOut("barbara"));
+ EXPECT_FALSE(TI->isDefinitelyOut("bar+bar"));
+}
+
+TEST_F(TrigramIndexTest, PopularTrigram) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*aaa*", "*aaaa*", "*aaaaa*", "*aaaaa*", "*aaaaaa*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, PopularTrigram2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"class1.h", "class2.h", "class3.h", "class4.h", "class.h"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, TooComplicatedRegex) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"[0-9]+"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, TooComplicatedRegex2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"foo|bar"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, EscapedSymbols) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*c\\+\\+*", "*hello\\\\world*", "a\\tb", "a\\0b"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("c++"));
+ EXPECT_TRUE(TI->isDefinitelyOut("c\\+\\+"));
+ EXPECT_FALSE(TI->isDefinitelyOut("hello\\world"));
+ EXPECT_TRUE(TI->isDefinitelyOut("hello\\\\world"));
+ EXPECT_FALSE(TI->isDefinitelyOut("atb"));
+ EXPECT_TRUE(TI->isDefinitelyOut("a\\tb"));
+ EXPECT_TRUE(TI->isDefinitelyOut("a\tb"));
+ EXPECT_FALSE(TI->isDefinitelyOut("a0b"));
+}
+
+TEST_F(TrigramIndexTest, Backreference1) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*foo\\1*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, Backreference2) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"*foo\\2*"});
+ EXPECT_TRUE(TI->isDefeated());
+}
+
+TEST_F(TrigramIndexTest, Sequence) {
+ std::unique_ptr<TrigramIndex> TI =
+ makeTrigramIndex({"class1.h", "class2.h", "class3.h", "class4.h"});
+ EXPECT_FALSE(TI->isDefeated());
+ EXPECT_FALSE(TI->isDefinitelyOut("class1"));
+ EXPECT_TRUE(TI->isDefinitelyOut("class.h"));
+ EXPECT_TRUE(TI->isDefinitelyOut("class"));
+}
+
+} // namespace
diff --git a/src/llvm-project/llvm/unittests/Support/TypeNameTest.cpp b/src/llvm-project/llvm/unittests/Support/TypeNameTest.cpp
new file mode 100644
index 0000000..63381d4
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TypeNameTest.cpp
@@ -0,0 +1,49 @@
+//===- TypeNameTest.cpp ---------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TypeName.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+namespace N1 {
+struct S1 {};
+class C1 {};
+union U1 {};
+}
+
+TEST(TypeNameTest, Names) {
+ struct S2 {};
+
+ StringRef S1Name = getTypeName<N1::S1>();
+ StringRef C1Name = getTypeName<N1::C1>();
+ StringRef U1Name = getTypeName<N1::U1>();
+ StringRef S2Name = getTypeName<S2>();
+
+#if defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) || \
+ defined(_MSC_VER)
+ EXPECT_TRUE(S1Name.endswith("::N1::S1")) << S1Name.str();
+ EXPECT_TRUE(C1Name.endswith("::N1::C1")) << C1Name.str();
+ EXPECT_TRUE(U1Name.endswith("::N1::U1")) << U1Name.str();
+#ifdef __clang__
+ EXPECT_TRUE(S2Name.endswith("S2")) << S2Name.str();
+#else
+ EXPECT_TRUE(S2Name.endswith("::S2")) << S2Name.str();
+#endif
+#else
+ EXPECT_EQ("UNKNOWN_TYPE", S1Name);
+ EXPECT_EQ("UNKNOWN_TYPE", C1Name);
+ EXPECT_EQ("UNKNOWN_TYPE", U1Name);
+ EXPECT_EQ("UNKNOWN_TYPE", S2Name);
+#endif
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/TypeTraitsTest.cpp b/src/llvm-project/llvm/unittests/Support/TypeTraitsTest.cpp
new file mode 100644
index 0000000..7a3ce53
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/TypeTraitsTest.cpp
@@ -0,0 +1,77 @@
+//===- TypeTraitsTest.cpp -------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/type_traits.h"
+
+namespace {
+
+// Compile-time tests using static assert.
+namespace triviality {
+
+// Helper for compile time checking trivially copy constructible and trivially
+// move constructible type traits.
+template <typename T, bool IsTriviallyCopyConstructible,
+ bool IsTriviallyMoveConstructible>
+void TrivialityTester() {
+ static_assert(llvm::is_trivially_copy_constructible<T>::value ==
+ IsTriviallyCopyConstructible,
+ "Mismatch in expected trivial copy construction!");
+ static_assert(llvm::is_trivially_move_constructible<T>::value ==
+ IsTriviallyMoveConstructible,
+ "Mismatch in expected trivial move construction!");
+
+#if defined(_LIBCPP_VERSION) || defined(_MSC_VER)
+ // On compilers with support for the standard traits, make sure they agree.
+ static_assert(std::is_trivially_copy_constructible<T>::value ==
+ IsTriviallyCopyConstructible,
+ "Mismatch in expected trivial copy construction!");
+ static_assert(std::is_trivially_move_constructible<T>::value ==
+ IsTriviallyMoveConstructible,
+ "Mismatch in expected trivial move construction!");
+#endif
+}
+
+template void TrivialityTester<int, true, true>();
+template void TrivialityTester<void *, true, true>();
+template void TrivialityTester<int &, true, true>();
+template void TrivialityTester<int &&, false, true>();
+
+struct X {};
+struct Y {
+ Y(const Y &);
+};
+struct Z {
+ Z(const Z &);
+ Z(Z &&);
+};
+struct A {
+ A(const A &) = default;
+ A(A &&);
+};
+struct B {
+ B(const B &);
+ B(B &&) = default;
+};
+
+template void TrivialityTester<X, true, true>();
+template void TrivialityTester<Y, false, false>();
+template void TrivialityTester<Z, false, false>();
+template void TrivialityTester<A, true, false>();
+template void TrivialityTester<B, false, true>();
+
+template void TrivialityTester<Z &, true, true>();
+template void TrivialityTester<A &, true, true>();
+template void TrivialityTester<B &, true, true>();
+template void TrivialityTester<Z &&, false, true>();
+template void TrivialityTester<A &&, false, true>();
+template void TrivialityTester<B &&, false, true>();
+
+} // namespace triviality
+
+} // end anonymous namespace
diff --git a/src/llvm-project/llvm/unittests/Support/UnicodeTest.cpp b/src/llvm-project/llvm/unittests/Support/UnicodeTest.cpp
new file mode 100644
index 0000000..0733397
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/UnicodeTest.cpp
@@ -0,0 +1,93 @@
+//===- unittests/Support/UnicodeTest.cpp - Unicode.h tests ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Unicode.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace sys {
+namespace unicode {
+namespace {
+
+TEST(Unicode, columnWidthUTF8) {
+ EXPECT_EQ(0, columnWidthUTF8(""));
+ EXPECT_EQ(1, columnWidthUTF8(" "));
+ EXPECT_EQ(1, columnWidthUTF8("a"));
+ EXPECT_EQ(1, columnWidthUTF8("~"));
+
+ EXPECT_EQ(6, columnWidthUTF8("abcdef"));
+
+ EXPECT_EQ(-1, columnWidthUTF8("\x01"));
+ EXPECT_EQ(-1, columnWidthUTF8("aaaaaaaaaa\x01"));
+ EXPECT_EQ(-1, columnWidthUTF8("\342\200\213")); // 200B ZERO WIDTH SPACE
+
+ // 00AD SOFT HYPHEN is displayed on most terminals as a space or a dash. Some
+ // text editors display it only when a line is broken at it, some use it as a
+ // line-break hint, but don't display. We choose terminal-oriented
+ // interpretation.
+ EXPECT_EQ(1, columnWidthUTF8("\302\255"));
+
+ EXPECT_EQ(0, columnWidthUTF8("\314\200")); // 0300 COMBINING GRAVE ACCENT
+ EXPECT_EQ(1, columnWidthUTF8("\340\270\201")); // 0E01 THAI CHARACTER KO KAI
+ EXPECT_EQ(2, columnWidthUTF8("\344\270\200")); // CJK UNIFIED IDEOGRAPH-4E00
+
+ EXPECT_EQ(4, columnWidthUTF8("\344\270\200\344\270\200"));
+ EXPECT_EQ(3, columnWidthUTF8("q\344\270\200"));
+ EXPECT_EQ(3, columnWidthUTF8("\314\200\340\270\201\344\270\200"));
+
+ // Invalid UTF-8 strings, columnWidthUTF8 should error out.
+ EXPECT_EQ(-2, columnWidthUTF8("\344"));
+ EXPECT_EQ(-2, columnWidthUTF8("\344\270"));
+ EXPECT_EQ(-2, columnWidthUTF8("\344\270\033"));
+ EXPECT_EQ(-2, columnWidthUTF8("\344\270\300"));
+ EXPECT_EQ(-2, columnWidthUTF8("\377\366\355"));
+
+ EXPECT_EQ(-2, columnWidthUTF8("qwer\344"));
+ EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270"));
+ EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270\033"));
+ EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270\300"));
+ EXPECT_EQ(-2, columnWidthUTF8("qwer\377\366\355"));
+
+ // UTF-8 sequences longer than 4 bytes correspond to unallocated Unicode
+ // characters.
+ EXPECT_EQ(-2, columnWidthUTF8("\370\200\200\200\200")); // U+200000
+ EXPECT_EQ(-2, columnWidthUTF8("\374\200\200\200\200\200")); // U+4000000
+}
+
+TEST(Unicode, isPrintable) {
+ EXPECT_FALSE(isPrintable(0)); // <control-0000>-<control-001F>
+ EXPECT_FALSE(isPrintable(0x01));
+ EXPECT_FALSE(isPrintable(0x1F));
+ EXPECT_TRUE(isPrintable(' '));
+ EXPECT_TRUE(isPrintable('A'));
+ EXPECT_TRUE(isPrintable('~'));
+ EXPECT_FALSE(isPrintable(0x7F)); // <control-007F>..<control-009F>
+ EXPECT_FALSE(isPrintable(0x90));
+ EXPECT_FALSE(isPrintable(0x9F));
+
+ EXPECT_TRUE(isPrintable(0xAC));
+ EXPECT_TRUE(isPrintable(0xAD)); // SOFT HYPHEN is displayed on most terminals
+ // as either a space or a dash.
+ EXPECT_TRUE(isPrintable(0xAE));
+
+ EXPECT_TRUE(isPrintable(0x0377)); // GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+ EXPECT_FALSE(isPrintable(0x0378)); // <reserved-0378>..<reserved-0379>
+
+ EXPECT_FALSE(isPrintable(0x0600)); // ARABIC NUMBER SIGN
+
+ EXPECT_FALSE(isPrintable(0x1FFFF)); // <reserved-1F774>..<noncharacter-1FFFF>
+ EXPECT_TRUE(isPrintable(0x20000)); // CJK UNIFIED IDEOGRAPH-20000
+
+ EXPECT_FALSE(isPrintable(0x10FFFF)); // noncharacter
+}
+
+} // namespace
+} // namespace unicode
+} // namespace sys
+} // namespace llvm
diff --git a/src/llvm-project/llvm/unittests/Support/VersionTupleTest.cpp b/src/llvm-project/llvm/unittests/Support/VersionTupleTest.cpp
new file mode 100644
index 0000000..cd7ecda
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/VersionTupleTest.cpp
@@ -0,0 +1,50 @@
+//===- VersionTupleTests.cpp - Version Number Handling Tests --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/VersionTuple.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(VersionTuple, getAsString) {
+ EXPECT_EQ("0", VersionTuple().getAsString());
+ EXPECT_EQ("1", VersionTuple(1).getAsString());
+ EXPECT_EQ("1.2", VersionTuple(1, 2).getAsString());
+ EXPECT_EQ("1.2.3", VersionTuple(1, 2, 3).getAsString());
+ EXPECT_EQ("1.2.3.4", VersionTuple(1, 2, 3, 4).getAsString());
+}
+
+TEST(VersionTuple, tryParse) {
+ VersionTuple VT;
+
+ EXPECT_FALSE(VT.tryParse("1"));
+ EXPECT_EQ("1", VT.getAsString());
+
+ EXPECT_FALSE(VT.tryParse("1.2"));
+ EXPECT_EQ("1.2", VT.getAsString());
+
+ EXPECT_FALSE(VT.tryParse("1.2.3"));
+ EXPECT_EQ("1.2.3", VT.getAsString());
+
+ EXPECT_FALSE(VT.tryParse("1.2.3.4"));
+ EXPECT_EQ("1.2.3.4", VT.getAsString());
+
+ EXPECT_TRUE(VT.tryParse(""));
+ EXPECT_TRUE(VT.tryParse("1."));
+ EXPECT_TRUE(VT.tryParse("1.2."));
+ EXPECT_TRUE(VT.tryParse("1.2.3."));
+ EXPECT_TRUE(VT.tryParse("1.2.3.4."));
+ EXPECT_TRUE(VT.tryParse("1.2.3.4.5"));
+ EXPECT_TRUE(VT.tryParse("1-2"));
+ EXPECT_TRUE(VT.tryParse("1+2"));
+ EXPECT_TRUE(VT.tryParse(".1"));
+ EXPECT_TRUE(VT.tryParse(" 1"));
+ EXPECT_TRUE(VT.tryParse("1 "));
+ EXPECT_TRUE(VT.tryParse("."));
+}
diff --git a/src/llvm-project/llvm/unittests/Support/VirtualFileSystemTest.cpp b/src/llvm-project/llvm/unittests/Support/VirtualFileSystemTest.cpp
new file mode 100644
index 0000000..7b42943
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -0,0 +1,1860 @@
+//===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <map>
+#include <string>
+
+using namespace llvm;
+using llvm::sys::fs::UniqueID;
+using testing::ElementsAre;
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+namespace {
+struct DummyFile : public vfs::File {
+ vfs::Status S;
+ explicit DummyFile(vfs::Status S) : S(S) {}
+ llvm::ErrorOr<vfs::Status> status() override { return S; }
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
+ bool IsVolatile) override {
+ llvm_unreachable("unimplemented");
+ }
+ std::error_code close() override { return std::error_code(); }
+};
+
+class DummyFileSystem : public vfs::FileSystem {
+ int FSID; // used to produce UniqueIDs
+ int FileID; // used to produce UniqueIDs
+ std::map<std::string, vfs::Status> FilesAndDirs;
+
+ static int getNextFSID() {
+ static int Count = 0;
+ return Count++;
+ }
+
+public:
+ DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
+
+ ErrorOr<vfs::Status> status(const Twine &Path) override {
+ std::map<std::string, vfs::Status>::iterator I =
+ FilesAndDirs.find(Path.str());
+ if (I == FilesAndDirs.end())
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+ return I->second;
+ }
+ ErrorOr<std::unique_ptr<vfs::File>>
+ openFileForRead(const Twine &Path) override {
+ auto S = status(Path);
+ if (S)
+ return std::unique_ptr<vfs::File>(new DummyFile{*S});
+ return S.getError();
+ }
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return std::string();
+ }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+ return std::error_code();
+ }
+ // Map any symlink to "/symlink".
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override {
+ auto I = FilesAndDirs.find(Path.str());
+ if (I == FilesAndDirs.end())
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+ if (I->second.isSymlink()) {
+ Output.clear();
+ Twine("/symlink").toVector(Output);
+ return std::error_code();
+ }
+ Output.clear();
+ Path.toVector(Output);
+ return std::error_code();
+ }
+
+ struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
+ std::map<std::string, vfs::Status> &FilesAndDirs;
+ std::map<std::string, vfs::Status>::iterator I;
+ std::string Path;
+ bool isInPath(StringRef S) {
+ if (Path.size() < S.size() && S.find(Path) == 0) {
+ auto LastSep = S.find_last_of('/');
+ if (LastSep == Path.size() || LastSep == Path.size() - 1)
+ return true;
+ }
+ return false;
+ }
+ DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
+ const Twine &_Path)
+ : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
+ Path(_Path.str()) {
+ for (; I != FilesAndDirs.end(); ++I) {
+ if (isInPath(I->first)) {
+ CurrentEntry =
+ vfs::directory_entry(I->second.getName(), I->second.getType());
+ break;
+ }
+ }
+ }
+ std::error_code increment() override {
+ ++I;
+ for (; I != FilesAndDirs.end(); ++I) {
+ if (isInPath(I->first)) {
+ CurrentEntry =
+ vfs::directory_entry(I->second.getName(), I->second.getType());
+ break;
+ }
+ }
+ if (I == FilesAndDirs.end())
+ CurrentEntry = vfs::directory_entry();
+ return std::error_code();
+ }
+ };
+
+ vfs::directory_iterator dir_begin(const Twine &Dir,
+ std::error_code &EC) override {
+ return vfs::directory_iterator(
+ std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
+ }
+
+ void addEntry(StringRef Path, const vfs::Status &Status) {
+ FilesAndDirs[Path] = Status;
+ }
+
+ void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 1024,
+ sys::fs::file_type::regular_file, Perms);
+ addEntry(Path, S);
+ }
+
+ void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 0,
+ sys::fs::file_type::directory_file, Perms);
+ addEntry(Path, S);
+ }
+
+ void addSymlink(StringRef Path) {
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 0,
+ sys::fs::file_type::symlink_file, sys::fs::all_all);
+ addEntry(Path, S);
+ }
+};
+
+/// Replace back-slashes by front-slashes.
+std::string getPosixPath(std::string S) {
+ SmallString<128> Result;
+ llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
+ return Result.str();
+}
+} // end anonymous namespace
+
+TEST(VirtualFileSystemTest, StatusQueries) {
+ IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
+ ErrorOr<vfs::Status> Status((std::error_code()));
+
+ D->addRegularFile("/foo");
+ Status = D->status("/foo");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_FALSE(Status->isDirectory());
+ EXPECT_TRUE(Status->isRegularFile());
+ EXPECT_FALSE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ D->addDirectory("/bar");
+ Status = D->status("/bar");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_TRUE(Status->isDirectory());
+ EXPECT_FALSE(Status->isRegularFile());
+ EXPECT_FALSE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ D->addSymlink("/baz");
+ Status = D->status("/baz");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_FALSE(Status->isDirectory());
+ EXPECT_FALSE(Status->isRegularFile());
+ EXPECT_TRUE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ EXPECT_TRUE(Status->equivalent(*Status));
+ ErrorOr<vfs::Status> Status2 = D->status("/foo");
+ ASSERT_FALSE(Status2.getError());
+ EXPECT_FALSE(Status->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
+ IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
+ ErrorOr<vfs::Status> Status((std::error_code()));
+ EXPECT_FALSE(Status = D->status("/foo"));
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
+ EXPECT_FALSE(Status = O->status("/foo"));
+
+ D->addRegularFile("/foo");
+ Status = D->status("/foo");
+ EXPECT_FALSE(Status.getError());
+
+ ErrorOr<vfs::Status> Status2((std::error_code()));
+ Status2 = O->status("/foo");
+ EXPECT_FALSE(Status2.getError());
+ EXPECT_TRUE(Status->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("/foo");
+ Lower->addSymlink("/lower_link");
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ // Regular file.
+ SmallString<16> RealPath;
+ EXPECT_FALSE(O->getRealPath("/foo", RealPath));
+ EXPECT_EQ(RealPath.str(), "/foo");
+
+ // Expect no error getting real path for symlink in lower overlay.
+ EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
+ EXPECT_EQ(RealPath.str(), "/symlink");
+
+ // Try a non-existing link.
+ EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
+ errc::no_such_file_or_directory);
+
+ // Add a new symlink in upper.
+ Upper->addSymlink("/upper_link");
+ EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
+ EXPECT_EQ(RealPath.str(), "/symlink");
+}
+
+TEST(VirtualFileSystemTest, OverlayFiles) {
+ IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Base));
+ O->pushOverlay(Middle);
+ O->pushOverlay(Top);
+
+ ErrorOr<vfs::Status> Status1((std::error_code())),
+ Status2((std::error_code())), Status3((std::error_code())),
+ StatusB((std::error_code())), StatusM((std::error_code())),
+ StatusT((std::error_code()));
+
+ Base->addRegularFile("/foo");
+ StatusB = Base->status("/foo");
+ ASSERT_FALSE(StatusB.getError());
+ Status1 = O->status("/foo");
+ ASSERT_FALSE(Status1.getError());
+ Middle->addRegularFile("/foo");
+ StatusM = Middle->status("/foo");
+ ASSERT_FALSE(StatusM.getError());
+ Status2 = O->status("/foo");
+ ASSERT_FALSE(Status2.getError());
+ Top->addRegularFile("/foo");
+ StatusT = Top->status("/foo");
+ ASSERT_FALSE(StatusT.getError());
+ Status3 = O->status("/foo");
+ ASSERT_FALSE(Status3.getError());
+
+ EXPECT_TRUE(Status1->equivalent(*StatusB));
+ EXPECT_TRUE(Status2->equivalent(*StatusM));
+ EXPECT_TRUE(Status3->equivalent(*StatusT));
+
+ EXPECT_FALSE(Status1->equivalent(*Status2));
+ EXPECT_FALSE(Status2->equivalent(*Status3));
+ EXPECT_FALSE(Status1->equivalent(*Status3));
+}
+
+TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ Lower->addDirectory("/lower-only");
+ Upper->addDirectory("/upper-only");
+
+ // non-merged paths should be the same
+ ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
+ ASSERT_FALSE(Status1.getError());
+ ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
+ ASSERT_FALSE(Status2.getError());
+ EXPECT_TRUE(Status1->equivalent(*Status2));
+
+ Status1 = Upper->status("/upper-only");
+ ASSERT_FALSE(Status1.getError());
+ Status2 = O->status("/upper-only");
+ ASSERT_FALSE(Status2.getError());
+ EXPECT_TRUE(Status1->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, MergedDirPermissions) {
+ // merged directories get the permissions of the upper dir
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ ErrorOr<vfs::Status> Status((std::error_code()));
+ Lower->addDirectory("/both", sys::fs::owner_read);
+ Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
+ Status = O->status("/both");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_EQ(0740, Status->getPermissions());
+
+ // permissions (as usual) are not recursively applied
+ Lower->addRegularFile("/both/foo", sys::fs::owner_read);
+ Upper->addRegularFile("/both/bar", sys::fs::owner_write);
+ Status = O->status("/both/foo");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_EQ(0400, Status->getPermissions());
+ Status = O->status("/both/bar");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_EQ(0200, Status->getPermissions());
+}
+
+namespace {
+struct ScopedDir {
+ SmallString<128> Path;
+ ScopedDir(const Twine &Name, bool Unique = false) {
+ std::error_code EC;
+ if (Unique) {
+ EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
+ } else {
+ Path = Name.str();
+ EC = llvm::sys::fs::create_directory(Twine(Path));
+ }
+ if (EC)
+ Path = "";
+ EXPECT_FALSE(EC);
+ }
+ ~ScopedDir() {
+ if (Path != "") {
+ EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
+ }
+ operator StringRef() { return Path.str(); }
+};
+
+struct ScopedLink {
+ SmallString<128> Path;
+ ScopedLink(const Twine &To, const Twine &From) {
+ Path = From.str();
+ std::error_code EC = sys::fs::create_link(To, From);
+ if (EC)
+ Path = "";
+ EXPECT_FALSE(EC);
+ }
+ ~ScopedLink() {
+ if (Path != "") {
+ EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
+ }
+ operator StringRef() { return Path.str(); }
+};
+} // end anonymous namespace
+
+TEST(VirtualFileSystemTest, BasicRealFSIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ std::error_code EC;
+ vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+ EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
+
+ ScopedDir _a(TestDirectory + "/a");
+ ScopedDir _ab(TestDirectory + "/a/b");
+ ScopedDir _c(TestDirectory + "/c");
+ ScopedDir _cd(TestDirectory + "/c/d");
+
+ I = FS->dir_begin(Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+ ASSERT_NE(vfs::directory_iterator(), I);
+ // Check either a or c, since we can't rely on the iteration order.
+ EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
+ I.increment(EC);
+ ASSERT_FALSE(EC);
+ ASSERT_NE(vfs::directory_iterator(), I);
+ EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
+ I.increment(EC);
+ EXPECT_EQ(vfs::directory_iterator(), I);
+}
+
+#ifdef LLVM_ON_UNIX
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ ScopedLink _a("no_such_file", TestDirectory + "/a");
+ ScopedDir _b(TestDirectory + "/b");
+ ScopedLink _c("no_such_file", TestDirectory + "/c");
+
+ // Should get no iteration error, but a stat error for the broken symlinks.
+ std::map<std::string, std::error_code> StatResults;
+ std::error_code EC;
+ for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
+ I != E; I.increment(EC)) {
+ EXPECT_FALSE(EC);
+ StatResults[sys::path::filename(I->path())] =
+ FS->status(I->path()).getError();
+ }
+ EXPECT_THAT(
+ StatResults,
+ ElementsAre(
+ Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
+ Pair("b", std::error_code()),
+ Pair("c",
+ std::make_error_code(std::errc::no_such_file_or_directory))));
+}
+#endif
+
+TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ std::error_code EC;
+ auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+ EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
+
+ ScopedDir _a(TestDirectory + "/a");
+ ScopedDir _ab(TestDirectory + "/a/b");
+ ScopedDir _c(TestDirectory + "/c");
+ ScopedDir _cd(TestDirectory + "/c/d");
+
+ I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+ ASSERT_NE(vfs::recursive_directory_iterator(), I);
+
+ std::vector<std::string> Contents;
+ for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
+ I.increment(EC)) {
+ Contents.push_back(I->path());
+ }
+
+ // Check contents, which may be in any order
+ EXPECT_EQ(4U, Contents.size());
+ int Counts[4] = {0, 0, 0, 0};
+ for (const std::string &Name : Contents) {
+ ASSERT_FALSE(Name.empty());
+ int Index = Name[Name.size() - 1] - 'a';
+ ASSERT_TRUE(Index >= 0 && Index < 4);
+ Counts[Index]++;
+ }
+ EXPECT_EQ(1, Counts[0]); // a
+ EXPECT_EQ(1, Counts[1]); // b
+ EXPECT_EQ(1, Counts[2]); // c
+ EXPECT_EQ(1, Counts[3]); // d
+}
+
+TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+
+ ScopedDir _a(TestDirectory + "/a");
+ ScopedDir _ab(TestDirectory + "/a/b");
+ ScopedDir _c(TestDirectory + "/c");
+ ScopedDir _cd(TestDirectory + "/c/d");
+ ScopedDir _e(TestDirectory + "/e");
+ ScopedDir _ef(TestDirectory + "/e/f");
+ ScopedDir _g(TestDirectory + "/g");
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ // Test that calling no_push on entries without subdirectories has no effect.
+ {
+ std::error_code EC;
+ auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+
+ std::vector<std::string> Contents;
+ for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
+ I.increment(EC)) {
+ Contents.push_back(I->path());
+ char last = I->path().back();
+ switch (last) {
+ case 'b':
+ case 'd':
+ case 'f':
+ case 'g':
+ I.no_push();
+ break;
+ default:
+ break;
+ }
+ }
+ EXPECT_EQ(7U, Contents.size());
+ }
+
+ // Test that calling no_push skips subdirectories.
+ {
+ std::error_code EC;
+ auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
+ ASSERT_FALSE(EC);
+
+ std::vector<std::string> Contents;
+ for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
+ I.increment(EC)) {
+ Contents.push_back(I->path());
+ char last = I->path().back();
+ switch (last) {
+ case 'a':
+ case 'c':
+ case 'e':
+ I.no_push();
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Check contents, which may be in any order
+ EXPECT_EQ(4U, Contents.size());
+ int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
+ for (const std::string &Name : Contents) {
+ ASSERT_FALSE(Name.empty());
+ int Index = Name[Name.size() - 1] - 'a';
+ ASSERT_TRUE(Index >= 0 && Index < 7);
+ Counts[Index]++;
+ }
+ EXPECT_EQ(1, Counts[0]); // a
+ EXPECT_EQ(0, Counts[1]); // b
+ EXPECT_EQ(1, Counts[2]); // c
+ EXPECT_EQ(0, Counts[3]); // d
+ EXPECT_EQ(1, Counts[4]); // e
+ EXPECT_EQ(0, Counts[5]); // f
+ EXPECT_EQ(1, Counts[6]); // g
+ }
+}
+
+#ifdef LLVM_ON_UNIX
+TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
+ ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
+
+ ScopedLink _a("no_such_file", TestDirectory + "/a");
+ ScopedDir _b(TestDirectory + "/b");
+ ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
+ ScopedDir _bb(TestDirectory + "/b/b");
+ ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
+ ScopedLink _c("no_such_file", TestDirectory + "/c");
+ ScopedDir _d(TestDirectory + "/d");
+ ScopedDir _dd(TestDirectory + "/d/d");
+ ScopedDir _ddd(TestDirectory + "/d/d/d");
+ ScopedLink _e("no_such_file", TestDirectory + "/e");
+
+ std::vector<std::string> VisitedBrokenSymlinks;
+ std::vector<std::string> VisitedNonBrokenSymlinks;
+ std::error_code EC;
+ for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
+ I != E; I.increment(EC)) {
+ EXPECT_FALSE(EC);
+ (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
+ .push_back(I->path());
+ }
+
+ // Check visited file names.
+ EXPECT_THAT(VisitedBrokenSymlinks,
+ UnorderedElementsAre(StringRef(_a), StringRef(_ba),
+ StringRef(_bc), StringRef(_c),
+ StringRef(_e)));
+ EXPECT_THAT(VisitedNonBrokenSymlinks,
+ UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
+ StringRef(_dd), StringRef(_ddd)));
+}
+#endif
+
+template <typename DirIter>
+static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
+ std::error_code EC;
+ SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
+ SmallVector<std::string, 4> InputToCheck;
+
+ // Do not rely on iteration order to check for contents, sort both
+ // content vectors before comparison.
+ for (DirIter E; !EC && I != E; I.increment(EC))
+ InputToCheck.push_back(I->path());
+
+ llvm::sort(InputToCheck);
+ llvm::sort(Expected);
+ EXPECT_EQ(InputToCheck.size(), Expected.size());
+
+ unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
+ for (unsigned Idx = 0; Idx != LastElt; ++Idx)
+ EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
+}
+
+TEST(VirtualFileSystemTest, OverlayIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ std::error_code EC;
+ checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
+
+ Lower->addRegularFile("/file1");
+ checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
+
+ Upper->addRegularFile("/file2");
+ checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
+
+ Lower->addDirectory("/dir1");
+ Lower->addRegularFile("/dir1/foo");
+ Upper->addDirectory("/dir2");
+ Upper->addRegularFile("/dir2/foo");
+ checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
+ checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
+}
+
+TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Middle);
+ O->pushOverlay(Upper);
+
+ std::error_code EC;
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ ArrayRef<StringRef>());
+
+ Lower->addRegularFile("/file1");
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ ArrayRef<StringRef>("/file1"));
+
+ Upper->addDirectory("/dir");
+ Upper->addRegularFile("/dir/file2");
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/file1"});
+
+ Lower->addDirectory("/dir1");
+ Lower->addRegularFile("/dir1/foo");
+ Lower->addDirectory("/dir1/a");
+ Lower->addRegularFile("/dir1/a/b");
+ Middle->addDirectory("/a");
+ Middle->addDirectory("/a/b");
+ Middle->addDirectory("/a/b/c");
+ Middle->addRegularFile("/a/b/c/d");
+ Middle->addRegularFile("/hiddenByUp");
+ Upper->addDirectory("/dir2");
+ Upper->addRegularFile("/dir2/foo");
+ Upper->addRegularFile("/hiddenByUp");
+ checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
+ ArrayRef<StringRef>("/dir2/foo"));
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
+ "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
+ "/dir1/a/b", "/dir1/foo", "/file1"});
+}
+
+TEST(VirtualFileSystemTest, ThreeLevelIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Middle);
+ O->pushOverlay(Upper);
+
+ std::error_code EC;
+ checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
+
+ Middle->addRegularFile("/file2");
+ checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
+
+ Lower->addRegularFile("/file1");
+ Upper->addRegularFile("/file3");
+ checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
+}
+
+TEST(VirtualFileSystemTest, HiddenInIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Middle);
+ O->pushOverlay(Upper);
+
+ std::error_code EC;
+ Lower->addRegularFile("/onlyInLow");
+ Lower->addDirectory("/hiddenByMid");
+ Lower->addDirectory("/hiddenByUp");
+ Middle->addRegularFile("/onlyInMid");
+ Middle->addRegularFile("/hiddenByMid");
+ Middle->addDirectory("/hiddenByUp");
+ Upper->addRegularFile("/onlyInUp");
+ Upper->addRegularFile("/hiddenByUp");
+ checkContents(
+ O->dir_begin("/", EC),
+ {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
+
+ // Make sure we get the top-most entry
+ {
+ std::error_code EC;
+ vfs::directory_iterator I = O->dir_begin("/", EC), E;
+ for (; !EC && I != E; I.increment(EC))
+ if (I->path() == "/hiddenByUp")
+ break;
+ ASSERT_NE(E, I);
+ EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
+ }
+ {
+ std::error_code EC;
+ vfs::directory_iterator I = O->dir_begin("/", EC), E;
+ for (; !EC && I != E; I.increment(EC))
+ if (I->path() == "/hiddenByMid")
+ break;
+ ASSERT_NE(E, I);
+ EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
+ }
+}
+
+TEST(ProxyFileSystemTest, Basic) {
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
+ new vfs::InMemoryFileSystem());
+ vfs::ProxyFileSystem PFS(Base);
+
+ Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
+
+ auto Stat = PFS.status("/a");
+ ASSERT_FALSE(Stat.getError());
+
+ auto File = PFS.openFileForRead("/a");
+ ASSERT_FALSE(File.getError());
+ EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer());
+
+ std::error_code EC;
+ vfs::directory_iterator I = PFS.dir_begin("/", EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ("/a", I->path());
+ I.increment(EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ(vfs::directory_iterator(), I);
+
+ ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/"));
+
+ auto PWD = PFS.getCurrentWorkingDirectory();
+ ASSERT_FALSE(PWD.getError());
+ ASSERT_EQ("/", *PWD);
+
+ SmallString<16> Path;
+ ASSERT_FALSE(PFS.getRealPath("a", Path));
+ ASSERT_EQ("/a", Path);
+
+ bool Local = true;
+ ASSERT_FALSE(PFS.isLocal("/a", Local));
+ ASSERT_EQ(false, Local);
+}
+
+class InMemoryFileSystemTest : public ::testing::Test {
+protected:
+ llvm::vfs::InMemoryFileSystem FS;
+ llvm::vfs::InMemoryFileSystem NormalizedFS;
+
+ InMemoryFileSystemTest()
+ : FS(/*UseNormalizedPaths=*/false),
+ NormalizedFS(/*UseNormalizedPaths=*/true) {}
+};
+
+MATCHER_P2(IsHardLinkTo, FS, Target, "") {
+ StringRef From = arg;
+ StringRef To = Target;
+ auto OpenedFrom = FS->openFileForRead(From);
+ auto OpenedTo = FS->openFileForRead(To);
+ return !OpenedFrom.getError() && !OpenedTo.getError() &&
+ (*OpenedFrom)->status()->getUniqueID() ==
+ (*OpenedTo)->status()->getUniqueID();
+}
+
+TEST_F(InMemoryFileSystemTest, IsEmpty) {
+ auto Stat = FS.status("/a");
+ ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
+ Stat = FS.status("/");
+ ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, WindowsPath) {
+ FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+ auto Stat = FS.status("c:");
+#if !defined(_WIN32)
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+#endif
+ Stat = FS.status("c:/windows/system128/foo.cpp");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+ FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+ Stat = FS.status("d:/windows/foo.cpp");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, OverlayFile) {
+ FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+ NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+ auto Stat = FS.status("/");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+ Stat = FS.status("/.");
+ ASSERT_FALSE(Stat);
+ Stat = NormalizedFS.status("/.");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+ Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_EQ("/a", Stat->getName());
+}
+
+TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
+ auto Buf = MemoryBuffer::getMemBuffer("a");
+ FS.addFileNoOwn("/a", 0, Buf.get());
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_EQ("/a", Stat->getName());
+}
+
+TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
+ FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+ FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
+ FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
+ NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+ NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
+ NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
+ auto File = FS.openFileForRead("/a");
+ ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
+ File = FS.openFileForRead("/a"); // Open again.
+ ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
+ File = NormalizedFS.openFileForRead("/././a"); // Open again.
+ ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
+ File = FS.openFileForRead("/");
+ ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
+ File = FS.openFileForRead("/b");
+ ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
+ File = FS.openFileForRead("./c");
+ ASSERT_FALSE(File);
+ File = FS.openFileForRead("e/../d");
+ ASSERT_FALSE(File);
+ File = NormalizedFS.openFileForRead("./c");
+ ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
+ File = NormalizedFS.openFileForRead("e/../d");
+ ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
+}
+
+TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
+ ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
+ ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
+ ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
+ ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
+}
+
+TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
+ FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
+ FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
+
+ std::error_code EC;
+ vfs::directory_iterator I = FS.dir_begin("/", EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ("/a", I->path());
+ I.increment(EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ("/b", I->path());
+ I.increment(EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ(vfs::directory_iterator(), I);
+
+ I = FS.dir_begin("/b", EC);
+ ASSERT_FALSE(EC);
+ // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
+ // path for the sake of the comparison.
+ ASSERT_EQ("/b/c", getPosixPath(I->path()));
+ I.increment(EC);
+ ASSERT_FALSE(EC);
+ ASSERT_EQ(vfs::directory_iterator(), I);
+}
+
+TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
+ FS.setCurrentWorkingDirectory("/b");
+ FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
+
+ auto Stat = FS.status("/b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_EQ("/b/c", Stat->getName());
+ ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
+
+ Stat = FS.status("c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+
+ NormalizedFS.setCurrentWorkingDirectory("/b/c");
+ NormalizedFS.setCurrentWorkingDirectory(".");
+ ASSERT_EQ("/b/c",
+ getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
+ NormalizedFS.setCurrentWorkingDirectory("..");
+ ASSERT_EQ("/b",
+ getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
+}
+
+TEST_F(InMemoryFileSystemTest, IsLocal) {
+ FS.setCurrentWorkingDirectory("/b");
+ FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
+
+ std::error_code EC;
+ bool IsLocal = true;
+ EC = FS.isLocal("c", IsLocal);
+ ASSERT_FALSE(EC);
+ ASSERT_FALSE(IsLocal);
+}
+
+#if !defined(_WIN32)
+TEST_F(InMemoryFileSystemTest, GetRealPath) {
+ SmallString<16> Path;
+ EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
+
+ auto GetRealPath = [this](StringRef P) {
+ SmallString<16> Output;
+ auto EC = FS.getRealPath(P, Output);
+ EXPECT_FALSE(EC);
+ return Output.str().str();
+ };
+
+ FS.setCurrentWorkingDirectory("a");
+ EXPECT_EQ(GetRealPath("b"), "a/b");
+ EXPECT_EQ(GetRealPath("../b"), "b");
+ EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
+
+ FS.setCurrentWorkingDirectory("/a");
+ EXPECT_EQ(GetRealPath("b"), "/a/b");
+ EXPECT_EQ(GetRealPath("../b"), "/b");
+ EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
+}
+#endif // _WIN32
+
+TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
+ FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_EQ(0xFEEDFACE, Stat->getUser());
+ Stat = FS.status("/a/b");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_EQ(0xFEEDFACE, Stat->getUser());
+ Stat = FS.status("/a/b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+ ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
+ ASSERT_EQ(0xFEEDFACE, Stat->getUser());
+}
+
+TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
+ FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_EQ(0xDABBAD00, Stat->getGroup());
+ Stat = FS.status("/a/b");
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_EQ(0xDABBAD00, Stat->getGroup());
+ Stat = FS.status("/a/b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+ ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
+ ASSERT_EQ(0xDABBAD00, Stat->getGroup());
+}
+
+TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
+ FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
+ sys::fs::file_type::socket_file);
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ Stat = FS.status("/a/b");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ Stat = FS.status("/a/b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
+ ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
+}
+
+TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
+ FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
+ sys::fs::perms::owner_read | sys::fs::perms::owner_write);
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
+ sys::fs::perms::owner_exe,
+ Stat->getPermissions());
+ Stat = FS.status("/a/b");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
+ sys::fs::perms::owner_exe,
+ Stat->getPermissions());
+ Stat = FS.status("/a/b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+ ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
+ Stat->getPermissions());
+}
+
+TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
+ FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
+ /*Group=*/None, sys::fs::file_type::directory_file);
+ FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
+ /*Group=*/None, sys::fs::file_type::regular_file);
+ auto Stat = FS.status("/a");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isDirectory());
+ Stat = FS.status("/a/b");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+}
+
+// Test that the name returned by status() is in the same form as the path that
+// was requested (to match the behavior of RealFileSystem).
+TEST_F(InMemoryFileSystemTest, StatusName) {
+ NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
+ /*User=*/None,
+ /*Group=*/None, sys::fs::file_type::regular_file);
+ NormalizedFS.setCurrentWorkingDirectory("/a/b");
+
+ // Access using InMemoryFileSystem::status.
+ auto Stat = NormalizedFS.status("../b/c");
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
+ << NormalizedFS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+ ASSERT_EQ("../b/c", Stat->getName());
+
+ // Access using InMemoryFileAdaptor::status.
+ auto File = NormalizedFS.openFileForRead("../b/c");
+ ASSERT_FALSE(File.getError()) << File.getError() << "\n"
+ << NormalizedFS.toString();
+ Stat = (*File)->status();
+ ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
+ << NormalizedFS.toString();
+ ASSERT_TRUE(Stat->isRegularFile());
+ ASSERT_EQ("../b/c", Stat->getName());
+
+ // Access using a directory iterator.
+ std::error_code EC;
+ llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
+ // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
+ // path for the sake of the comparison.
+ ASSERT_EQ("../b/c", getPosixPath(It->path()));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
+ StringRef FromLink = "/path/to/FROM/link";
+ StringRef Target = "/path/to/TO/file";
+ FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
+ EXPECT_TRUE(FS.addHardLink(FromLink, Target));
+ EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
+ EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
+ EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
+ FS.getBufferForFile(Target)->get()->getBuffer());
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
+ StringRef Link0 = "/path/to/0/link";
+ StringRef Link1 = "/path/to/1/link";
+ StringRef Link2 = "/path/to/2/link";
+ StringRef Target = "/path/to/target";
+ FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
+ EXPECT_TRUE(FS.addHardLink(Link2, Target));
+ EXPECT_TRUE(FS.addHardLink(Link1, Link2));
+ EXPECT_TRUE(FS.addHardLink(Link0, Link1));
+ EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
+ EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
+ EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
+ EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
+ StringRef Link = "/path/to/link";
+ StringRef Target = "/path/to/target";
+ FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
+ FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
+ EXPECT_FALSE(FS.addHardLink(Link, Target));
+}
+
+TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
+ StringRef Link = "/path/to/link";
+ StringRef Target = "/path/to/target";
+ FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
+ EXPECT_TRUE(FS.addHardLink(Link, Target));
+ EXPECT_FALSE(FS.addHardLink(Link, Target));
+}
+
+TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
+ StringRef Link = "/path/to/link";
+ StringRef Target = "/path/to/target";
+ StringRef Content = "content of target";
+ EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
+ EXPECT_TRUE(FS.addHardLink(Link, Target));
+ EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
+}
+
+TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
+ StringRef Link = "/path/to/link";
+ StringRef Target = "/path/to/target";
+ StringRef Content = "content of target";
+ StringRef LinkContent = "different content of link";
+ EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
+ EXPECT_TRUE(FS.addHardLink(Link, Target));
+ EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
+ StringRef Dir = "path/to/dummy/dir";
+ StringRef Link = "/path/to/link";
+ StringRef File = "path/to/dummy/dir/target";
+ StringRef Content = "content of target";
+ EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
+ EXPECT_FALSE(FS.addHardLink(Link, Dir));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
+ StringRef Dir = "path/to/dummy/dir";
+ StringRef Target = "path/to/dummy/dir/target";
+ StringRef Content = "content of target";
+ EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
+ EXPECT_FALSE(FS.addHardLink(Dir, Target));
+}
+
+TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
+ StringRef CommonContent = "content string";
+ FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
+ FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
+ EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
+}
+
+TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
+ std::error_code EC;
+ FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
+ EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
+ auto I = vfs::recursive_directory_iterator(FS, "/", EC);
+ ASSERT_FALSE(EC);
+ std::vector<std::string> Nodes;
+ for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
+ I.increment(EC)) {
+ Nodes.push_back(getPosixPath(I->path()));
+ }
+ EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
+}
+
+// NOTE: in the tests below, we use '//root/' as our root directory, since it is
+// a legal *absolute* path on Windows as well as *nix.
+class VFSFromYAMLTest : public ::testing::Test {
+public:
+ int NumDiagnostics;
+
+ void SetUp() override { NumDiagnostics = 0; }
+
+ static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
+ VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
+ ++Test->NumDiagnostics;
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem>
+ getFromYAMLRawString(StringRef Content,
+ IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
+ std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
+ return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
+ ExternalFS);
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
+ StringRef Content,
+ IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
+ std::string VersionPlusContent("{\n 'version':0,\n");
+ VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
+ return getFromYAMLRawString(VersionPlusContent, ExternalFS);
+ }
+
+ // This is intended as a "XFAIL" for windows hosts.
+ bool supportsSameDirMultipleYAMLEntries() {
+ Triple Host(Triple::normalize(sys::getProcessTriple()));
+ return !Host.isOSWindows();
+ }
+};
+
+TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
+ IntrusiveRefCntPtr<vfs::FileSystem> FS;
+ FS = getFromYAMLString("");
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("[]");
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("'string'");
+ EXPECT_EQ(nullptr, FS.get());
+ EXPECT_EQ(3, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, MappedFiles) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file1',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " },\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file2',\n"
+ " 'external-contents': '//root/foo/b'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ // file
+ ErrorOr<vfs::Status> S = O->status("//root/file1");
+ ASSERT_FALSE(S.getError());
+ EXPECT_EQ("//root/foo/bar/a", S->getName());
+ EXPECT_TRUE(S->IsVFSMapped);
+
+ ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
+ EXPECT_EQ("//root/foo/bar/a", SLower->getName());
+ EXPECT_TRUE(S->equivalent(*SLower));
+ EXPECT_FALSE(SLower->IsVFSMapped);
+
+ // file after opening
+ auto OpenedF = O->openFileForRead("//root/file1");
+ ASSERT_FALSE(OpenedF.getError());
+ auto OpenedS = (*OpenedF)->status();
+ ASSERT_FALSE(OpenedS.getError());
+ EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
+ EXPECT_TRUE(OpenedS->IsVFSMapped);
+
+ // directory
+ S = O->status("//root/");
+ ASSERT_FALSE(S.getError());
+ EXPECT_TRUE(S->isDirectory());
+ EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
+
+ // broken mapping
+ EXPECT_EQ(O->status("//root/file2").getError(),
+ llvm::errc::no_such_file_or_directory);
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, CaseInsensitive) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'case-sensitive': 'false',\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'XX',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " }\n"
+ " ]\n"
+ "}]}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ ErrorOr<vfs::Status> S = O->status("//root/XX");
+ ASSERT_FALSE(S.getError());
+
+ ErrorOr<vfs::Status> SS = O->status("//root/xx");
+ ASSERT_FALSE(SS.getError());
+ EXPECT_TRUE(S->equivalent(*SS));
+ SS = O->status("//root/xX");
+ EXPECT_TRUE(S->equivalent(*SS));
+ SS = O->status("//root/Xx");
+ EXPECT_TRUE(S->equivalent(*SS));
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, CaseSensitive) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'case-sensitive': 'true',\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'XX',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " }\n"
+ " ]\n"
+ "}]}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ ErrorOr<vfs::Status> SS = O->status("//root/xx");
+ EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
+ SS = O->status("//root/xX");
+ EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
+ SS = O->status("//root/Xx");
+ EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+
+ // invalid YAML at top-level
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ // invalid YAML in roots
+ FS = getFromYAMLString("{ 'roots':[}", Lower);
+ // invalid YAML in directory
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // invalid configuration
+ FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // invalid roots
+ FS = getFromYAMLString("{ 'roots':'' }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("{ 'roots':{} }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // invalid entries
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
+ "'external-contents': 'other' }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // missing mandatory fields
+ FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // duplicate keys
+ FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLString(
+ "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS =
+ getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
+ "'external-contents':'blah' } ] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // missing version
+ FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // bad version number
+ FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
+ EXPECT_EQ(nullptr, FS.get());
+ EXPECT_EQ(24, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, UseExternalName) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/external/file");
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ getFromYAMLString("{ 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/A',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/B',\n"
+ " 'use-external-name': true,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/C',\n"
+ " 'use-external-name': false,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+
+ // default true
+ EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
+ // explicit
+ EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
+ EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
+
+ // global configuration
+ FS = getFromYAMLString("{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/A',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/B',\n"
+ " 'use-external-name': true,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/C',\n"
+ " 'use-external-name': false,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+
+ // default
+ EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
+ // explicit
+ EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
+ EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
+}
+
+TEST_F(VFSFromYAMLTest, MultiComponentPath) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/other");
+
+ // file in roots
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ getFromYAMLString("{ 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/path/to/file',\n"
+ " 'external-contents': '//root/other' }]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+ EXPECT_FALSE(FS->status("//root/path/to/file").getError());
+ EXPECT_FALSE(FS->status("//root/path/to").getError());
+ EXPECT_FALSE(FS->status("//root/path").getError());
+ EXPECT_FALSE(FS->status("//root/").getError());
+
+ // at the start
+ FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/path/to',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+ EXPECT_FALSE(FS->status("//root/path/to/file").getError());
+ EXPECT_FALSE(FS->status("//root/path/to").getError());
+ EXPECT_FALSE(FS->status("//root/path").getError());
+ EXPECT_FALSE(FS->status("//root/").getError());
+
+ // at the end
+ FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+ EXPECT_FALSE(FS->status("//root/path/to/file").getError());
+ EXPECT_FALSE(FS->status("//root/path/to").getError());
+ EXPECT_FALSE(FS->status("//root/path").getError());
+ EXPECT_FALSE(FS->status("//root/").getError());
+}
+
+TEST_F(VFSFromYAMLTest, TrailingSlashes) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/other");
+
+ // file in roots
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/path/to////',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(nullptr != FS.get());
+ EXPECT_FALSE(FS->status("//root/path/to/file").getError());
+ EXPECT_FALSE(FS->status("//root/path/to").getError());
+ EXPECT_FALSE(FS->status("//root/path").getError());
+ EXPECT_FALSE(FS->status("//root/").getError());
+}
+
+TEST_F(VFSFromYAMLTest, DirectoryIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/");
+ Lower->addDirectory("//root/foo");
+ Lower->addDirectory("//root/foo/bar");
+ Lower->addRegularFile("//root/foo/bar/a");
+ Lower->addRegularFile("//root/foo/bar/b");
+ Lower->addRegularFile("//root/file3");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file1',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " },\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file2',\n"
+ " 'external-contents': '//root/foo/bar/b'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ std::error_code EC;
+ checkContents(O->dir_begin("//root/", EC),
+ {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
+
+ checkContents(O->dir_begin("//root/foo/bar", EC),
+ {"//root/foo/bar/a", "//root/foo/bar/b"});
+}
+
+TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
+ // https://llvm.org/bugs/show_bug.cgi?id=27725
+ if (!supportsSameDirMultipleYAMLEntries())
+ return;
+
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/zab");
+ Lower->addDirectory("//root/baz");
+ Lower->addRegularFile("//root/zab/a");
+ Lower->addRegularFile("//root/zab/b");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/baz/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'x',\n"
+ " 'external-contents': '//root/zab/a'\n"
+ " }\n"
+ " ]\n"
+ "},\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/baz/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'y',\n"
+ " 'external-contents': '//root/zab/b'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ std::error_code EC;
+
+ checkContents(O->dir_begin("//root/baz/", EC),
+ {"//root/baz/x", "//root/baz/y"});
+}
+
+TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
+
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/a");
+ Lower->addDirectory("//root/a/b");
+ Lower->addDirectory("//root/a/b/c");
+ Lower->addRegularFile("//root/a/b/c/file");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/a/b/c/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file',\n"
+ " 'external-contents': '//root/a/b/c/file'\n"
+ " }\n"
+ " ]\n"
+ "},\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ std::error_code EC;
+
+ // Test recursive_directory_iterator level()
+ vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
+ *O, "//root", EC),
+ E;
+ ASSERT_FALSE(EC);
+ for (int l = 0; I != E; I.increment(EC), ++l) {
+ ASSERT_FALSE(EC);
+ EXPECT_EQ(I.level(), l);
+ }
+ EXPECT_EQ(I, E);
+}
+
+TEST_F(VFSFromYAMLTest, RelativePaths) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ // Filename at root level without a parent directory.
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // Relative file path.
+ FS = getFromYAMLString("{ 'roots': [\n"
+ " { 'type': 'file', 'name': 'relative/file/path.h',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ // Relative directory path.
+ FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
+ " 'contents': []\n"
+ " }\n"
+ "] }",
+ Lower);
+ EXPECT_EQ(nullptr, FS.get());
+
+ EXPECT_EQ(3, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/");
+ Lower->addRegularFile("//root/a");
+ Lower->addRegularFile("//root/b");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'fallthrough': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'c',\n"
+ " 'external-contents': '//root/a'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ std::error_code EC;
+ checkContents(FS->dir_begin("//root/", EC),
+ {"//root/c"});
+}
+
+TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/");
+ Lower->addRegularFile("//root/a");
+ Lower->addRegularFile("//root/b");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'a',\n"
+ " 'external-contents': '//root/a'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ std::error_code EC;
+ checkContents(FS->dir_begin("//root/", EC),
+ {"//root/a", "//root/b"});
+}
+
+TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//root/");
+ Lower->addDirectory("//root/foo");
+ Lower->addRegularFile("//root/foo/a");
+ Lower->addRegularFile("//root/foo/b");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'bar/a',\n"
+ " 'external-contents': '//root/foo/a'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ std::error_code EC;
+ checkContents(FS->dir_begin("//root/foo", EC),
+ {"//root/foo/a", "//root/foo/b"});
+}
+
+TEST_F(VFSFromYAMLTest, GetRealPath) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addDirectory("//dir/");
+ Lower->addRegularFile("/foo");
+ Lower->addSymlink("/link");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'bar',\n"
+ " 'external-contents': '/link'\n"
+ " }\n"
+ " ]\n"
+ "},\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//dir/',\n"
+ " 'contents': []\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.get() != nullptr);
+
+ // Regular file present in underlying file system.
+ SmallString<16> RealPath;
+ EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
+ EXPECT_EQ(RealPath.str(), "/foo");
+
+ // File present in YAML pointing to symlink in underlying file system.
+ EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
+ EXPECT_EQ(RealPath.str(), "/symlink");
+
+ // Directories should fall back to the underlying file system is possible.
+ EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
+ EXPECT_EQ(RealPath.str(), "//dir/");
+
+ // Try a non-existing file.
+ EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
+ errc::no_such_file_or_directory);
+}
diff --git a/src/llvm-project/llvm/unittests/Support/YAMLIOTest.cpp b/src/llvm-project/llvm/unittests/Support/YAMLIOTest.cpp
new file mode 100644
index 0000000..17f38f9
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/YAMLIOTest.cpp
@@ -0,0 +1,2877 @@
+//===- unittest/Support/YAMLIOTest.cpp ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using llvm::yaml::Hex16;
+using llvm::yaml::Hex32;
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex8;
+using llvm::yaml::Input;
+using llvm::yaml::IO;
+using llvm::yaml::isNumeric;
+using llvm::yaml::MappingNormalization;
+using llvm::yaml::MappingTraits;
+using llvm::yaml::Output;
+using llvm::yaml::ScalarTraits;
+using ::testing::StartsWith;
+
+
+
+
+static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) {
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Test MappingTraits
+//===----------------------------------------------------------------------===//
+
+struct FooBar {
+ int foo;
+ int bar;
+};
+typedef std::vector<FooBar> FooBarSequence;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar)
+
+struct FooBarContainer {
+ FooBarSequence fbs;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<FooBar> {
+ static void mapping(IO &io, FooBar& fb) {
+ io.mapRequired("foo", fb.foo);
+ io.mapRequired("bar", fb.bar);
+ }
+ };
+
+ template <> struct MappingTraits<FooBarContainer> {
+ static void mapping(IO &io, FooBarContainer &fb) {
+ io.mapRequired("fbs", fb.fbs);
+ }
+ };
+}
+}
+
+
+//
+// Test the reading of a yaml mapping
+//
+TEST(YAMLIO, TestMapRead) {
+ FooBar doc;
+ {
+ Input yin("---\nfoo: 3\nbar: 5\n...\n");
+ yin >> doc;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(doc.foo, 3);
+ EXPECT_EQ(doc.bar, 5);
+ }
+
+ {
+ Input yin("{foo: 3, bar: 5}");
+ yin >> doc;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(doc.foo, 3);
+ EXPECT_EQ(doc.bar, 5);
+ }
+}
+
+TEST(YAMLIO, TestMalformedMapRead) {
+ FooBar doc;
+ Input yin("{foo: 3; bar: 5}", nullptr, suppressErrorMessages);
+ yin >> doc;
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test the reading of a yaml sequence of mappings
+//
+TEST(YAMLIO, TestSequenceMapRead) {
+ FooBarSequence seq;
+ Input yin("---\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n");
+ yin >> seq;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq.size(), 2UL);
+ FooBar& map1 = seq[0];
+ FooBar& map2 = seq[1];
+ EXPECT_EQ(map1.foo, 3);
+ EXPECT_EQ(map1.bar, 5);
+ EXPECT_EQ(map2.foo, 7);
+ EXPECT_EQ(map2.bar, 9);
+}
+
+//
+// Test the reading of a map containing a yaml sequence of mappings
+//
+TEST(YAMLIO, TestContainerSequenceMapRead) {
+ {
+ FooBarContainer cont;
+ Input yin2("---\nfbs:\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n");
+ yin2 >> cont;
+
+ EXPECT_FALSE(yin2.error());
+ EXPECT_EQ(cont.fbs.size(), 2UL);
+ EXPECT_EQ(cont.fbs[0].foo, 3);
+ EXPECT_EQ(cont.fbs[0].bar, 5);
+ EXPECT_EQ(cont.fbs[1].foo, 7);
+ EXPECT_EQ(cont.fbs[1].bar, 9);
+ }
+
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs:\n...\n");
+ yin >> cont;
+ // Okay: Empty node represents an empty array.
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs: !!null null\n...\n");
+ yin >> cont;
+ // Okay: null represents an empty array.
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs: ~\n...\n");
+ yin >> cont;
+ // Okay: null represents an empty array.
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs: null\n...\n");
+ yin >> cont;
+ // Okay: null represents an empty array.
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+}
+
+//
+// Test the reading of a map containing a malformed yaml sequence
+//
+TEST(YAMLIO, TestMalformedContainerSequenceMapRead) {
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs:\n foo: 3\n bar: 5\n...\n", nullptr,
+ suppressErrorMessages);
+ yin >> cont;
+ // Error: fbs is not a sequence.
+ EXPECT_TRUE(!!yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+
+ {
+ FooBarContainer cont;
+ Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages);
+ yin >> cont;
+ // This should be an error.
+ EXPECT_TRUE(!!yin.error());
+ EXPECT_EQ(cont.fbs.size(), 0UL);
+ }
+}
+
+//
+// Test writing then reading back a sequence of mappings
+//
+TEST(YAMLIO, TestSequenceMapWriteAndRead) {
+ std::string intermediate;
+ {
+ FooBar entry1;
+ entry1.foo = 10;
+ entry1.bar = -3;
+ FooBar entry2;
+ entry2.foo = 257;
+ entry2.bar = 0;
+ FooBarSequence seq;
+ seq.push_back(entry1);
+ seq.push_back(entry2);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << seq;
+ }
+
+ {
+ Input yin(intermediate);
+ FooBarSequence seq2;
+ yin >> seq2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq2.size(), 2UL);
+ FooBar& map1 = seq2[0];
+ FooBar& map2 = seq2[1];
+ EXPECT_EQ(map1.foo, 10);
+ EXPECT_EQ(map1.bar, -3);
+ EXPECT_EQ(map2.foo, 257);
+ EXPECT_EQ(map2.bar, 0);
+ }
+}
+
+//
+// Test YAML filename handling.
+//
+static void testErrorFilename(const llvm::SMDiagnostic &Error, void *) {
+ EXPECT_EQ(Error.getFilename(), "foo.yaml");
+}
+
+TEST(YAMLIO, TestGivenFilename) {
+ auto Buffer = llvm::MemoryBuffer::getMemBuffer("{ x: 42 }", "foo.yaml");
+ Input yin(*Buffer, nullptr, testErrorFilename);
+ FooBar Value;
+ yin >> Value;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+struct WithStringField {
+ std::string str1;
+ std::string str2;
+ std::string str3;
+};
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<WithStringField> {
+ static void mapping(IO &io, WithStringField &fb) {
+ io.mapRequired("str1", fb.str1);
+ io.mapRequired("str2", fb.str2);
+ io.mapRequired("str3", fb.str3);
+ }
+};
+} // namespace yaml
+} // namespace llvm
+
+TEST(YAMLIO, MultilineStrings) {
+ WithStringField Original;
+ Original.str1 = "a multiline string\nfoobarbaz";
+ Original.str2 = "another one\rfoobarbaz";
+ Original.str3 = "a one-line string";
+
+ std::string Serialized;
+ {
+ llvm::raw_string_ostream OS(Serialized);
+ Output YOut(OS);
+ YOut << Original;
+ }
+ auto Expected = "---\n"
+ "str1: 'a multiline string\n"
+ "foobarbaz'\n"
+ "str2: 'another one\r"
+ "foobarbaz'\n"
+ "str3: a one-line string\n"
+ "...\n";
+ ASSERT_EQ(Serialized, Expected);
+
+ // Also check it parses back without the errors.
+ WithStringField Deserialized;
+ {
+ Input YIn(Serialized);
+ YIn >> Deserialized;
+ ASSERT_FALSE(YIn.error())
+ << "Parsing error occurred during deserialization. Serialized string:\n"
+ << Serialized;
+ }
+ EXPECT_EQ(Original.str1, Deserialized.str1);
+ EXPECT_EQ(Original.str2, Deserialized.str2);
+ EXPECT_EQ(Original.str3, Deserialized.str3);
+}
+
+TEST(YAMLIO, NoQuotesForTab) {
+ WithStringField WithTab;
+ WithTab.str1 = "aba\tcaba";
+ std::string Serialized;
+ {
+ llvm::raw_string_ostream OS(Serialized);
+ Output YOut(OS);
+ YOut << WithTab;
+ }
+ auto ExpectedPrefix = "---\n"
+ "str1: aba\tcaba\n";
+ EXPECT_THAT(Serialized, StartsWith(ExpectedPrefix));
+}
+
+//===----------------------------------------------------------------------===//
+// Test built-in types
+//===----------------------------------------------------------------------===//
+
+struct BuiltInTypes {
+ llvm::StringRef str;
+ std::string stdstr;
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+ uint8_t u8;
+ bool b;
+ int64_t s64;
+ int32_t s32;
+ int16_t s16;
+ int8_t s8;
+ float f;
+ double d;
+ Hex8 h8;
+ Hex16 h16;
+ Hex32 h32;
+ Hex64 h64;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<BuiltInTypes> {
+ static void mapping(IO &io, BuiltInTypes& bt) {
+ io.mapRequired("str", bt.str);
+ io.mapRequired("stdstr", bt.stdstr);
+ io.mapRequired("u64", bt.u64);
+ io.mapRequired("u32", bt.u32);
+ io.mapRequired("u16", bt.u16);
+ io.mapRequired("u8", bt.u8);
+ io.mapRequired("b", bt.b);
+ io.mapRequired("s64", bt.s64);
+ io.mapRequired("s32", bt.s32);
+ io.mapRequired("s16", bt.s16);
+ io.mapRequired("s8", bt.s8);
+ io.mapRequired("f", bt.f);
+ io.mapRequired("d", bt.d);
+ io.mapRequired("h8", bt.h8);
+ io.mapRequired("h16", bt.h16);
+ io.mapRequired("h32", bt.h32);
+ io.mapRequired("h64", bt.h64);
+ }
+ };
+}
+}
+
+
+//
+// Test the reading of all built-in scalar conversions
+//
+TEST(YAMLIO, TestReadBuiltInTypes) {
+ BuiltInTypes map;
+ Input yin("---\n"
+ "str: hello there\n"
+ "stdstr: hello where?\n"
+ "u64: 5000000000\n"
+ "u32: 4000000000\n"
+ "u16: 65000\n"
+ "u8: 255\n"
+ "b: false\n"
+ "s64: -5000000000\n"
+ "s32: -2000000000\n"
+ "s16: -32000\n"
+ "s8: -127\n"
+ "f: 137.125\n"
+ "d: -2.8625\n"
+ "h8: 0xFF\n"
+ "h16: 0x8765\n"
+ "h32: 0xFEDCBA98\n"
+ "h64: 0xFEDCBA9876543210\n"
+ "...\n");
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(map.str.equals("hello there"));
+ EXPECT_TRUE(map.stdstr == "hello where?");
+ EXPECT_EQ(map.u64, 5000000000ULL);
+ EXPECT_EQ(map.u32, 4000000000U);
+ EXPECT_EQ(map.u16, 65000);
+ EXPECT_EQ(map.u8, 255);
+ EXPECT_EQ(map.b, false);
+ EXPECT_EQ(map.s64, -5000000000LL);
+ EXPECT_EQ(map.s32, -2000000000L);
+ EXPECT_EQ(map.s16, -32000);
+ EXPECT_EQ(map.s8, -127);
+ EXPECT_EQ(map.f, 137.125);
+ EXPECT_EQ(map.d, -2.8625);
+ EXPECT_EQ(map.h8, Hex8(255));
+ EXPECT_EQ(map.h16, Hex16(0x8765));
+ EXPECT_EQ(map.h32, Hex32(0xFEDCBA98));
+ EXPECT_EQ(map.h64, Hex64(0xFEDCBA9876543210LL));
+}
+
+
+//
+// Test writing then reading back all built-in scalar types
+//
+TEST(YAMLIO, TestReadWriteBuiltInTypes) {
+ std::string intermediate;
+ {
+ BuiltInTypes map;
+ map.str = "one two";
+ map.stdstr = "three four";
+ map.u64 = 6000000000ULL;
+ map.u32 = 3000000000U;
+ map.u16 = 50000;
+ map.u8 = 254;
+ map.b = true;
+ map.s64 = -6000000000LL;
+ map.s32 = -2000000000;
+ map.s16 = -32000;
+ map.s8 = -128;
+ map.f = 3.25;
+ map.d = -2.8625;
+ map.h8 = 254;
+ map.h16 = 50000;
+ map.h32 = 3000000000U;
+ map.h64 = 6000000000LL;
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+
+ {
+ Input yin(intermediate);
+ BuiltInTypes map;
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(map.str.equals("one two"));
+ EXPECT_TRUE(map.stdstr == "three four");
+ EXPECT_EQ(map.u64, 6000000000ULL);
+ EXPECT_EQ(map.u32, 3000000000U);
+ EXPECT_EQ(map.u16, 50000);
+ EXPECT_EQ(map.u8, 254);
+ EXPECT_EQ(map.b, true);
+ EXPECT_EQ(map.s64, -6000000000LL);
+ EXPECT_EQ(map.s32, -2000000000L);
+ EXPECT_EQ(map.s16, -32000);
+ EXPECT_EQ(map.s8, -128);
+ EXPECT_EQ(map.f, 3.25);
+ EXPECT_EQ(map.d, -2.8625);
+ EXPECT_EQ(map.h8, Hex8(254));
+ EXPECT_EQ(map.h16, Hex16(50000));
+ EXPECT_EQ(map.h32, Hex32(3000000000U));
+ EXPECT_EQ(map.h64, Hex64(6000000000LL));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test endian-aware types
+//===----------------------------------------------------------------------===//
+
+struct EndianTypes {
+ typedef llvm::support::detail::packed_endian_specific_integral<
+ float, llvm::support::little, llvm::support::unaligned>
+ ulittle_float;
+ typedef llvm::support::detail::packed_endian_specific_integral<
+ double, llvm::support::little, llvm::support::unaligned>
+ ulittle_double;
+
+ llvm::support::ulittle64_t u64;
+ llvm::support::ulittle32_t u32;
+ llvm::support::ulittle16_t u16;
+ llvm::support::little64_t s64;
+ llvm::support::little32_t s32;
+ llvm::support::little16_t s16;
+ ulittle_float f;
+ ulittle_double d;
+};
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<EndianTypes> {
+ static void mapping(IO &io, EndianTypes &et) {
+ io.mapRequired("u64", et.u64);
+ io.mapRequired("u32", et.u32);
+ io.mapRequired("u16", et.u16);
+ io.mapRequired("s64", et.s64);
+ io.mapRequired("s32", et.s32);
+ io.mapRequired("s16", et.s16);
+ io.mapRequired("f", et.f);
+ io.mapRequired("d", et.d);
+ }
+};
+}
+}
+
+//
+// Test the reading of all endian scalar conversions
+//
+TEST(YAMLIO, TestReadEndianTypes) {
+ EndianTypes map;
+ Input yin("---\n"
+ "u64: 5000000000\n"
+ "u32: 4000000000\n"
+ "u16: 65000\n"
+ "s64: -5000000000\n"
+ "s32: -2000000000\n"
+ "s16: -32000\n"
+ "f: 3.25\n"
+ "d: -2.8625\n"
+ "...\n");
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(map.u64, 5000000000ULL);
+ EXPECT_EQ(map.u32, 4000000000U);
+ EXPECT_EQ(map.u16, 65000);
+ EXPECT_EQ(map.s64, -5000000000LL);
+ EXPECT_EQ(map.s32, -2000000000L);
+ EXPECT_EQ(map.s16, -32000);
+ EXPECT_EQ(map.f, 3.25f);
+ EXPECT_EQ(map.d, -2.8625);
+}
+
+//
+// Test writing then reading back all endian-aware scalar types
+//
+TEST(YAMLIO, TestReadWriteEndianTypes) {
+ std::string intermediate;
+ {
+ EndianTypes map;
+ map.u64 = 6000000000ULL;
+ map.u32 = 3000000000U;
+ map.u16 = 50000;
+ map.s64 = -6000000000LL;
+ map.s32 = -2000000000;
+ map.s16 = -32000;
+ map.f = 3.25f;
+ map.d = -2.8625;
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+
+ {
+ Input yin(intermediate);
+ EndianTypes map;
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(map.u64, 6000000000ULL);
+ EXPECT_EQ(map.u32, 3000000000U);
+ EXPECT_EQ(map.u16, 50000);
+ EXPECT_EQ(map.s64, -6000000000LL);
+ EXPECT_EQ(map.s32, -2000000000L);
+ EXPECT_EQ(map.s16, -32000);
+ EXPECT_EQ(map.f, 3.25f);
+ EXPECT_EQ(map.d, -2.8625);
+ }
+}
+
+struct StringTypes {
+ llvm::StringRef str1;
+ llvm::StringRef str2;
+ llvm::StringRef str3;
+ llvm::StringRef str4;
+ llvm::StringRef str5;
+ llvm::StringRef str6;
+ llvm::StringRef str7;
+ llvm::StringRef str8;
+ llvm::StringRef str9;
+ llvm::StringRef str10;
+ llvm::StringRef str11;
+ std::string stdstr1;
+ std::string stdstr2;
+ std::string stdstr3;
+ std::string stdstr4;
+ std::string stdstr5;
+ std::string stdstr6;
+ std::string stdstr7;
+ std::string stdstr8;
+ std::string stdstr9;
+ std::string stdstr10;
+ std::string stdstr11;
+ std::string stdstr12;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<StringTypes> {
+ static void mapping(IO &io, StringTypes& st) {
+ io.mapRequired("str1", st.str1);
+ io.mapRequired("str2", st.str2);
+ io.mapRequired("str3", st.str3);
+ io.mapRequired("str4", st.str4);
+ io.mapRequired("str5", st.str5);
+ io.mapRequired("str6", st.str6);
+ io.mapRequired("str7", st.str7);
+ io.mapRequired("str8", st.str8);
+ io.mapRequired("str9", st.str9);
+ io.mapRequired("str10", st.str10);
+ io.mapRequired("str11", st.str11);
+ io.mapRequired("stdstr1", st.stdstr1);
+ io.mapRequired("stdstr2", st.stdstr2);
+ io.mapRequired("stdstr3", st.stdstr3);
+ io.mapRequired("stdstr4", st.stdstr4);
+ io.mapRequired("stdstr5", st.stdstr5);
+ io.mapRequired("stdstr6", st.stdstr6);
+ io.mapRequired("stdstr7", st.stdstr7);
+ io.mapRequired("stdstr8", st.stdstr8);
+ io.mapRequired("stdstr9", st.stdstr9);
+ io.mapRequired("stdstr10", st.stdstr10);
+ io.mapRequired("stdstr11", st.stdstr11);
+ io.mapRequired("stdstr12", st.stdstr12);
+ }
+ };
+}
+}
+
+TEST(YAMLIO, TestReadWriteStringTypes) {
+ std::string intermediate;
+ {
+ StringTypes map;
+ map.str1 = "'aaa";
+ map.str2 = "\"bbb";
+ map.str3 = "`ccc";
+ map.str4 = "@ddd";
+ map.str5 = "";
+ map.str6 = "0000000004000000";
+ map.str7 = "true";
+ map.str8 = "FALSE";
+ map.str9 = "~";
+ map.str10 = "0.2e20";
+ map.str11 = "0x30";
+ map.stdstr1 = "'eee";
+ map.stdstr2 = "\"fff";
+ map.stdstr3 = "`ggg";
+ map.stdstr4 = "@hhh";
+ map.stdstr5 = "";
+ map.stdstr6 = "0000000004000000";
+ map.stdstr7 = "true";
+ map.stdstr8 = "FALSE";
+ map.stdstr9 = "~";
+ map.stdstr10 = "0.2e20";
+ map.stdstr11 = "0x30";
+ map.stdstr12 = "- match";
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+
+ llvm::StringRef flowOut(intermediate);
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'''aaa"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'\"bbb'"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'`ccc'"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'@ddd'"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("''\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0000000004000000'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'true'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'FALSE'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'~'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0.2e20'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0x30'\n"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("'- match'\n"));
+ EXPECT_NE(std::string::npos, flowOut.find("'''eee"));
+ EXPECT_NE(std::string::npos, flowOut.find("'\"fff'"));
+ EXPECT_NE(std::string::npos, flowOut.find("'`ggg'"));
+ EXPECT_NE(std::string::npos, flowOut.find("'@hhh'"));
+ EXPECT_NE(std::string::npos, flowOut.find("''\n"));
+ EXPECT_NE(std::string::npos, flowOut.find("'0000000004000000'\n"));
+
+ {
+ Input yin(intermediate);
+ StringTypes map;
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(map.str1.equals("'aaa"));
+ EXPECT_TRUE(map.str2.equals("\"bbb"));
+ EXPECT_TRUE(map.str3.equals("`ccc"));
+ EXPECT_TRUE(map.str4.equals("@ddd"));
+ EXPECT_TRUE(map.str5.equals(""));
+ EXPECT_TRUE(map.str6.equals("0000000004000000"));
+ EXPECT_TRUE(map.stdstr1 == "'eee");
+ EXPECT_TRUE(map.stdstr2 == "\"fff");
+ EXPECT_TRUE(map.stdstr3 == "`ggg");
+ EXPECT_TRUE(map.stdstr4 == "@hhh");
+ EXPECT_TRUE(map.stdstr5 == "");
+ EXPECT_TRUE(map.stdstr6 == "0000000004000000");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test ScalarEnumerationTraits
+//===----------------------------------------------------------------------===//
+
+enum Colors {
+ cRed,
+ cBlue,
+ cGreen,
+ cYellow
+};
+
+struct ColorMap {
+ Colors c1;
+ Colors c2;
+ Colors c3;
+ Colors c4;
+ Colors c5;
+ Colors c6;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct ScalarEnumerationTraits<Colors> {
+ static void enumeration(IO &io, Colors &value) {
+ io.enumCase(value, "red", cRed);
+ io.enumCase(value, "blue", cBlue);
+ io.enumCase(value, "green", cGreen);
+ io.enumCase(value, "yellow",cYellow);
+ }
+ };
+ template <>
+ struct MappingTraits<ColorMap> {
+ static void mapping(IO &io, ColorMap& c) {
+ io.mapRequired("c1", c.c1);
+ io.mapRequired("c2", c.c2);
+ io.mapRequired("c3", c.c3);
+ io.mapOptional("c4", c.c4, cBlue); // supplies default
+ io.mapOptional("c5", c.c5, cYellow); // supplies default
+ io.mapOptional("c6", c.c6, cRed); // supplies default
+ }
+ };
+}
+}
+
+
+//
+// Test reading enumerated scalars
+//
+TEST(YAMLIO, TestEnumRead) {
+ ColorMap map;
+ Input yin("---\n"
+ "c1: blue\n"
+ "c2: red\n"
+ "c3: green\n"
+ "c5: yellow\n"
+ "...\n");
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(cBlue, map.c1);
+ EXPECT_EQ(cRed, map.c2);
+ EXPECT_EQ(cGreen, map.c3);
+ EXPECT_EQ(cBlue, map.c4); // tests default
+ EXPECT_EQ(cYellow,map.c5); // tests overridden
+ EXPECT_EQ(cRed, map.c6); // tests default
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Test ScalarBitSetTraits
+//===----------------------------------------------------------------------===//
+
+enum MyFlags {
+ flagNone = 0,
+ flagBig = 1 << 0,
+ flagFlat = 1 << 1,
+ flagRound = 1 << 2,
+ flagPointy = 1 << 3
+};
+inline MyFlags operator|(MyFlags a, MyFlags b) {
+ return static_cast<MyFlags>(
+ static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
+}
+
+struct FlagsMap {
+ MyFlags f1;
+ MyFlags f2;
+ MyFlags f3;
+ MyFlags f4;
+};
+
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct ScalarBitSetTraits<MyFlags> {
+ static void bitset(IO &io, MyFlags &value) {
+ io.bitSetCase(value, "big", flagBig);
+ io.bitSetCase(value, "flat", flagFlat);
+ io.bitSetCase(value, "round", flagRound);
+ io.bitSetCase(value, "pointy",flagPointy);
+ }
+ };
+ template <>
+ struct MappingTraits<FlagsMap> {
+ static void mapping(IO &io, FlagsMap& c) {
+ io.mapRequired("f1", c.f1);
+ io.mapRequired("f2", c.f2);
+ io.mapRequired("f3", c.f3);
+ io.mapOptional("f4", c.f4, MyFlags(flagRound));
+ }
+ };
+}
+}
+
+
+//
+// Test reading flow sequence representing bit-mask values
+//
+TEST(YAMLIO, TestFlagsRead) {
+ FlagsMap map;
+ Input yin("---\n"
+ "f1: [ big ]\n"
+ "f2: [ round, flat ]\n"
+ "f3: []\n"
+ "...\n");
+ yin >> map;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(flagBig, map.f1);
+ EXPECT_EQ(flagRound|flagFlat, map.f2);
+ EXPECT_EQ(flagNone, map.f3); // check empty set
+ EXPECT_EQ(flagRound, map.f4); // check optional key
+}
+
+
+//
+// Test writing then reading back bit-mask values
+//
+TEST(YAMLIO, TestReadWriteFlags) {
+ std::string intermediate;
+ {
+ FlagsMap map;
+ map.f1 = flagBig;
+ map.f2 = flagRound | flagFlat;
+ map.f3 = flagNone;
+ map.f4 = flagNone;
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+
+ {
+ Input yin(intermediate);
+ FlagsMap map2;
+ yin >> map2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(flagBig, map2.f1);
+ EXPECT_EQ(flagRound|flagFlat, map2.f2);
+ EXPECT_EQ(flagNone, map2.f3);
+ //EXPECT_EQ(flagRound, map2.f4); // check optional key
+ }
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Test ScalarTraits
+//===----------------------------------------------------------------------===//
+
+struct MyCustomType {
+ int length;
+ int width;
+};
+
+struct MyCustomTypeMap {
+ MyCustomType f1;
+ MyCustomType f2;
+ int f3;
+};
+
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<MyCustomTypeMap> {
+ static void mapping(IO &io, MyCustomTypeMap& s) {
+ io.mapRequired("f1", s.f1);
+ io.mapRequired("f2", s.f2);
+ io.mapRequired("f3", s.f3);
+ }
+ };
+ // MyCustomType is formatted as a yaml scalar. A value of
+ // {length=3, width=4} would be represented in yaml as "3 by 4".
+ template<>
+ struct ScalarTraits<MyCustomType> {
+ static void output(const MyCustomType &value, void* ctxt, llvm::raw_ostream &out) {
+ out << llvm::format("%d by %d", value.length, value.width);
+ }
+ static StringRef input(StringRef scalar, void* ctxt, MyCustomType &value) {
+ size_t byStart = scalar.find("by");
+ if ( byStart != StringRef::npos ) {
+ StringRef lenStr = scalar.slice(0, byStart);
+ lenStr = lenStr.rtrim();
+ if ( lenStr.getAsInteger(0, value.length) ) {
+ return "malformed length";
+ }
+ StringRef widthStr = scalar.drop_front(byStart+2);
+ widthStr = widthStr.ltrim();
+ if ( widthStr.getAsInteger(0, value.width) ) {
+ return "malformed width";
+ }
+ return StringRef();
+ }
+ else {
+ return "malformed by";
+ }
+ }
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+ };
+}
+}
+
+
+//
+// Test writing then reading back custom values
+//
+TEST(YAMLIO, TestReadWriteMyCustomType) {
+ std::string intermediate;
+ {
+ MyCustomTypeMap map;
+ map.f1.length = 1;
+ map.f1.width = 4;
+ map.f2.length = 100;
+ map.f2.width = 400;
+ map.f3 = 10;
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+
+ {
+ Input yin(intermediate);
+ MyCustomTypeMap map2;
+ yin >> map2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(1, map2.f1.length);
+ EXPECT_EQ(4, map2.f1.width);
+ EXPECT_EQ(100, map2.f2.length);
+ EXPECT_EQ(400, map2.f2.width);
+ EXPECT_EQ(10, map2.f3);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Test BlockScalarTraits
+//===----------------------------------------------------------------------===//
+
+struct MultilineStringType {
+ std::string str;
+};
+
+struct MultilineStringTypeMap {
+ MultilineStringType name;
+ MultilineStringType description;
+ MultilineStringType ingredients;
+ MultilineStringType recipes;
+ MultilineStringType warningLabels;
+ MultilineStringType documentation;
+ int price;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<MultilineStringTypeMap> {
+ static void mapping(IO &io, MultilineStringTypeMap& s) {
+ io.mapRequired("name", s.name);
+ io.mapRequired("description", s.description);
+ io.mapRequired("ingredients", s.ingredients);
+ io.mapRequired("recipes", s.recipes);
+ io.mapRequired("warningLabels", s.warningLabels);
+ io.mapRequired("documentation", s.documentation);
+ io.mapRequired("price", s.price);
+ }
+ };
+
+ // MultilineStringType is formatted as a yaml block literal scalar. A value of
+ // "Hello\nWorld" would be represented in yaml as
+ // |
+ // Hello
+ // World
+ template <>
+ struct BlockScalarTraits<MultilineStringType> {
+ static void output(const MultilineStringType &value, void *ctxt,
+ llvm::raw_ostream &out) {
+ out << value.str;
+ }
+ static StringRef input(StringRef scalar, void *ctxt,
+ MultilineStringType &value) {
+ value.str = scalar.str();
+ return StringRef();
+ }
+ };
+}
+}
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MultilineStringType)
+
+//
+// Test writing then reading back custom values
+//
+TEST(YAMLIO, TestReadWriteMultilineStringType) {
+ std::string intermediate;
+ {
+ MultilineStringTypeMap map;
+ map.name.str = "An Item";
+ map.description.str = "Hello\nWorld";
+ map.ingredients.str = "SubItem 1\nSub Item 2\n\nSub Item 3\n";
+ map.recipes.str = "\n\nTest 1\n\n\n";
+ map.warningLabels.str = "";
+ map.documentation.str = "\n\n";
+ map.price = 350;
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+ }
+ {
+ Input yin(intermediate);
+ MultilineStringTypeMap map2;
+ yin >> map2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(map2.name.str, "An Item\n");
+ EXPECT_EQ(map2.description.str, "Hello\nWorld\n");
+ EXPECT_EQ(map2.ingredients.str, "SubItem 1\nSub Item 2\n\nSub Item 3\n");
+ EXPECT_EQ(map2.recipes.str, "\n\nTest 1\n");
+ EXPECT_TRUE(map2.warningLabels.str.empty());
+ EXPECT_TRUE(map2.documentation.str.empty());
+ EXPECT_EQ(map2.price, 350);
+ }
+}
+
+//
+// Test writing then reading back custom values
+//
+TEST(YAMLIO, TestReadWriteBlockScalarDocuments) {
+ std::string intermediate;
+ {
+ std::vector<MultilineStringType> documents;
+ MultilineStringType doc;
+ doc.str = "Hello\nWorld";
+ documents.push_back(doc);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << documents;
+
+ // Verify that the block scalar header was written out on the same line
+ // as the document marker.
+ EXPECT_NE(llvm::StringRef::npos, llvm::StringRef(ostr.str()).find("--- |"));
+ }
+ {
+ Input yin(intermediate);
+ std::vector<MultilineStringType> documents2;
+ yin >> documents2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(documents2.size(), size_t(1));
+ EXPECT_EQ(documents2[0].str, "Hello\nWorld\n");
+ }
+}
+
+TEST(YAMLIO, TestReadWriteBlockScalarValue) {
+ std::string intermediate;
+ {
+ MultilineStringType doc;
+ doc.str = "Just a block\nscalar doc";
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << doc;
+ }
+ {
+ Input yin(intermediate);
+ MultilineStringType doc;
+ yin >> doc;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(doc.str, "Just a block\nscalar doc\n");
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test flow sequences
+//===----------------------------------------------------------------------===//
+
+LLVM_YAML_STRONG_TYPEDEF(int, MyNumber)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyNumber)
+LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, MyString)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyString)
+
+namespace llvm {
+namespace yaml {
+ template<>
+ struct ScalarTraits<MyNumber> {
+ static void output(const MyNumber &value, void *, llvm::raw_ostream &out) {
+ out << value;
+ }
+
+ static StringRef input(StringRef scalar, void *, MyNumber &value) {
+ long long n;
+ if ( getAsSignedInteger(scalar, 0, n) )
+ return "invalid number";
+ value = n;
+ return StringRef();
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+ };
+
+ template <> struct ScalarTraits<MyString> {
+ using Impl = ScalarTraits<StringRef>;
+ static void output(const MyString &V, void *Ctx, raw_ostream &OS) {
+ Impl::output(V, Ctx, OS);
+ }
+ static StringRef input(StringRef S, void *Ctx, MyString &V) {
+ return Impl::input(S, Ctx, V.value);
+ }
+ static QuotingType mustQuote(StringRef S) {
+ return Impl::mustQuote(S);
+ }
+ };
+}
+}
+
+struct NameAndNumbers {
+ llvm::StringRef name;
+ std::vector<MyString> strings;
+ std::vector<MyNumber> single;
+ std::vector<MyNumber> numbers;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<NameAndNumbers> {
+ static void mapping(IO &io, NameAndNumbers& nn) {
+ io.mapRequired("name", nn.name);
+ io.mapRequired("strings", nn.strings);
+ io.mapRequired("single", nn.single);
+ io.mapRequired("numbers", nn.numbers);
+ }
+ };
+}
+}
+
+typedef std::vector<MyNumber> MyNumberFlowSequence;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(MyNumberFlowSequence)
+
+struct NameAndNumbersFlow {
+ llvm::StringRef name;
+ std::vector<MyNumberFlowSequence> sequenceOfNumbers;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<NameAndNumbersFlow> {
+ static void mapping(IO &io, NameAndNumbersFlow& nn) {
+ io.mapRequired("name", nn.name);
+ io.mapRequired("sequenceOfNumbers", nn.sequenceOfNumbers);
+ }
+ };
+}
+}
+
+//
+// Test writing then reading back custom values
+//
+TEST(YAMLIO, TestReadWriteMyFlowSequence) {
+ std::string intermediate;
+ {
+ NameAndNumbers map;
+ map.name = "hello";
+ map.strings.push_back(llvm::StringRef("one"));
+ map.strings.push_back(llvm::StringRef("two"));
+ map.single.push_back(1);
+ map.numbers.push_back(10);
+ map.numbers.push_back(-30);
+ map.numbers.push_back(1024);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+
+ // Verify sequences were written in flow style
+ ostr.flush();
+ llvm::StringRef flowOut(intermediate);
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("one, two"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("10, -30, 1024"));
+ }
+
+ {
+ Input yin(intermediate);
+ NameAndNumbers map2;
+ yin >> map2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(map2.name.equals("hello"));
+ EXPECT_EQ(map2.strings.size(), 2UL);
+ EXPECT_TRUE(map2.strings[0].value.equals("one"));
+ EXPECT_TRUE(map2.strings[1].value.equals("two"));
+ EXPECT_EQ(map2.single.size(), 1UL);
+ EXPECT_EQ(1, map2.single[0]);
+ EXPECT_EQ(map2.numbers.size(), 3UL);
+ EXPECT_EQ(10, map2.numbers[0]);
+ EXPECT_EQ(-30, map2.numbers[1]);
+ EXPECT_EQ(1024, map2.numbers[2]);
+ }
+}
+
+
+//
+// Test writing then reading back a sequence of flow sequences.
+//
+TEST(YAMLIO, TestReadWriteSequenceOfMyFlowSequence) {
+ std::string intermediate;
+ {
+ NameAndNumbersFlow map;
+ map.name = "hello";
+ MyNumberFlowSequence single = { 0 };
+ MyNumberFlowSequence numbers = { 12, 1, -512 };
+ map.sequenceOfNumbers.push_back(single);
+ map.sequenceOfNumbers.push_back(numbers);
+ map.sequenceOfNumbers.push_back(MyNumberFlowSequence());
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << map;
+
+ // Verify sequences were written in flow style
+ // and that the parent sequence used '-'.
+ ostr.flush();
+ llvm::StringRef flowOut(intermediate);
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 0 ]"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 12, 1, -512 ]"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ ]"));
+ }
+
+ {
+ Input yin(intermediate);
+ NameAndNumbersFlow map2;
+ yin >> map2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(map2.name.equals("hello"));
+ EXPECT_EQ(map2.sequenceOfNumbers.size(), 3UL);
+ EXPECT_EQ(map2.sequenceOfNumbers[0].size(), 1UL);
+ EXPECT_EQ(0, map2.sequenceOfNumbers[0][0]);
+ EXPECT_EQ(map2.sequenceOfNumbers[1].size(), 3UL);
+ EXPECT_EQ(12, map2.sequenceOfNumbers[1][0]);
+ EXPECT_EQ(1, map2.sequenceOfNumbers[1][1]);
+ EXPECT_EQ(-512, map2.sequenceOfNumbers[1][2]);
+ EXPECT_TRUE(map2.sequenceOfNumbers[2].empty());
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test normalizing/denormalizing
+//===----------------------------------------------------------------------===//
+
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, TotalSeconds)
+
+typedef std::vector<TotalSeconds> SecondsSequence;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(TotalSeconds)
+
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<TotalSeconds> {
+
+ class NormalizedSeconds {
+ public:
+ NormalizedSeconds(IO &io)
+ : hours(0), minutes(0), seconds(0) {
+ }
+ NormalizedSeconds(IO &, TotalSeconds &secs)
+ : hours(secs/3600),
+ minutes((secs - (hours*3600))/60),
+ seconds(secs % 60) {
+ }
+ TotalSeconds denormalize(IO &) {
+ return TotalSeconds(hours*3600 + minutes*60 + seconds);
+ }
+
+ uint32_t hours;
+ uint8_t minutes;
+ uint8_t seconds;
+ };
+
+ static void mapping(IO &io, TotalSeconds &secs) {
+ MappingNormalization<NormalizedSeconds, TotalSeconds> keys(io, secs);
+
+ io.mapOptional("hours", keys->hours, (uint32_t)0);
+ io.mapOptional("minutes", keys->minutes, (uint8_t)0);
+ io.mapRequired("seconds", keys->seconds);
+ }
+ };
+}
+}
+
+
+//
+// Test the reading of a yaml sequence of mappings
+//
+TEST(YAMLIO, TestReadMySecondsSequence) {
+ SecondsSequence seq;
+ Input yin("---\n - hours: 1\n seconds: 5\n - seconds: 59\n...\n");
+ yin >> seq;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq.size(), 2UL);
+ EXPECT_EQ(seq[0], 3605U);
+ EXPECT_EQ(seq[1], 59U);
+}
+
+
+//
+// Test writing then reading back custom values
+//
+TEST(YAMLIO, TestReadWriteMySecondsSequence) {
+ std::string intermediate;
+ {
+ SecondsSequence seq;
+ seq.push_back(4000);
+ seq.push_back(500);
+ seq.push_back(59);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << seq;
+ }
+ {
+ Input yin(intermediate);
+ SecondsSequence seq2;
+ yin >> seq2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq2.size(), 3UL);
+ EXPECT_EQ(seq2[0], 4000U);
+ EXPECT_EQ(seq2[1], 500U);
+ EXPECT_EQ(seq2[2], 59U);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Test dynamic typing
+//===----------------------------------------------------------------------===//
+
+enum AFlags {
+ a1,
+ a2,
+ a3
+};
+
+enum BFlags {
+ b1,
+ b2,
+ b3
+};
+
+enum Kind {
+ kindA,
+ kindB
+};
+
+struct KindAndFlags {
+ KindAndFlags() : kind(kindA), flags(0) { }
+ KindAndFlags(Kind k, uint32_t f) : kind(k), flags(f) { }
+ Kind kind;
+ uint32_t flags;
+};
+
+typedef std::vector<KindAndFlags> KindAndFlagsSequence;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(KindAndFlags)
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct ScalarEnumerationTraits<AFlags> {
+ static void enumeration(IO &io, AFlags &value) {
+ io.enumCase(value, "a1", a1);
+ io.enumCase(value, "a2", a2);
+ io.enumCase(value, "a3", a3);
+ }
+ };
+ template <>
+ struct ScalarEnumerationTraits<BFlags> {
+ static void enumeration(IO &io, BFlags &value) {
+ io.enumCase(value, "b1", b1);
+ io.enumCase(value, "b2", b2);
+ io.enumCase(value, "b3", b3);
+ }
+ };
+ template <>
+ struct ScalarEnumerationTraits<Kind> {
+ static void enumeration(IO &io, Kind &value) {
+ io.enumCase(value, "A", kindA);
+ io.enumCase(value, "B", kindB);
+ }
+ };
+ template <>
+ struct MappingTraits<KindAndFlags> {
+ static void mapping(IO &io, KindAndFlags& kf) {
+ io.mapRequired("kind", kf.kind);
+ // Type of "flags" field varies depending on "kind" field.
+ // Use memcpy here to avoid breaking strict aliasing rules.
+ if (kf.kind == kindA) {
+ AFlags aflags = static_cast<AFlags>(kf.flags);
+ io.mapRequired("flags", aflags);
+ kf.flags = aflags;
+ } else {
+ BFlags bflags = static_cast<BFlags>(kf.flags);
+ io.mapRequired("flags", bflags);
+ kf.flags = bflags;
+ }
+ }
+ };
+}
+}
+
+
+//
+// Test the reading of a yaml sequence dynamic types
+//
+TEST(YAMLIO, TestReadKindAndFlagsSequence) {
+ KindAndFlagsSequence seq;
+ Input yin("---\n - kind: A\n flags: a2\n - kind: B\n flags: b1\n...\n");
+ yin >> seq;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq.size(), 2UL);
+ EXPECT_EQ(seq[0].kind, kindA);
+ EXPECT_EQ(seq[0].flags, (uint32_t)a2);
+ EXPECT_EQ(seq[1].kind, kindB);
+ EXPECT_EQ(seq[1].flags, (uint32_t)b1);
+}
+
+//
+// Test writing then reading back dynamic types
+//
+TEST(YAMLIO, TestReadWriteKindAndFlagsSequence) {
+ std::string intermediate;
+ {
+ KindAndFlagsSequence seq;
+ seq.push_back(KindAndFlags(kindA,a1));
+ seq.push_back(KindAndFlags(kindB,b1));
+ seq.push_back(KindAndFlags(kindA,a2));
+ seq.push_back(KindAndFlags(kindB,b2));
+ seq.push_back(KindAndFlags(kindA,a3));
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << seq;
+ }
+ {
+ Input yin(intermediate);
+ KindAndFlagsSequence seq2;
+ yin >> seq2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(seq2.size(), 5UL);
+ EXPECT_EQ(seq2[0].kind, kindA);
+ EXPECT_EQ(seq2[0].flags, (uint32_t)a1);
+ EXPECT_EQ(seq2[1].kind, kindB);
+ EXPECT_EQ(seq2[1].flags, (uint32_t)b1);
+ EXPECT_EQ(seq2[2].kind, kindA);
+ EXPECT_EQ(seq2[2].flags, (uint32_t)a2);
+ EXPECT_EQ(seq2[3].kind, kindB);
+ EXPECT_EQ(seq2[3].flags, (uint32_t)b2);
+ EXPECT_EQ(seq2[4].kind, kindA);
+ EXPECT_EQ(seq2[4].flags, (uint32_t)a3);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Test document list
+//===----------------------------------------------------------------------===//
+
+struct FooBarMap {
+ int foo;
+ int bar;
+};
+typedef std::vector<FooBarMap> FooBarMapDocumentList;
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(FooBarMap)
+
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<FooBarMap> {
+ static void mapping(IO &io, FooBarMap& fb) {
+ io.mapRequired("foo", fb.foo);
+ io.mapRequired("bar", fb.bar);
+ }
+ };
+}
+}
+
+
+//
+// Test the reading of a yaml mapping
+//
+TEST(YAMLIO, TestDocRead) {
+ FooBarMap doc;
+ Input yin("---\nfoo: 3\nbar: 5\n...\n");
+ yin >> doc;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(doc.foo, 3);
+ EXPECT_EQ(doc.bar,5);
+}
+
+
+
+//
+// Test writing then reading back a sequence of mappings
+//
+TEST(YAMLIO, TestSequenceDocListWriteAndRead) {
+ std::string intermediate;
+ {
+ FooBarMap doc1;
+ doc1.foo = 10;
+ doc1.bar = -3;
+ FooBarMap doc2;
+ doc2.foo = 257;
+ doc2.bar = 0;
+ std::vector<FooBarMap> docList;
+ docList.push_back(doc1);
+ docList.push_back(doc2);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << docList;
+ }
+
+
+ {
+ Input yin(intermediate);
+ std::vector<FooBarMap> docList2;
+ yin >> docList2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(docList2.size(), 2UL);
+ FooBarMap& map1 = docList2[0];
+ FooBarMap& map2 = docList2[1];
+ EXPECT_EQ(map1.foo, 10);
+ EXPECT_EQ(map1.bar, -3);
+ EXPECT_EQ(map2.foo, 257);
+ EXPECT_EQ(map2.bar, 0);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test document tags
+//===----------------------------------------------------------------------===//
+
+struct MyDouble {
+ MyDouble() : value(0.0) { }
+ MyDouble(double x) : value(x) { }
+ double value;
+};
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDouble)
+
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<MyDouble> {
+ static void mapping(IO &io, MyDouble &d) {
+ if (io.mapTag("!decimal", true)) {
+ mappingDecimal(io, d);
+ } else if (io.mapTag("!fraction")) {
+ mappingFraction(io, d);
+ }
+ }
+ static void mappingDecimal(IO &io, MyDouble &d) {
+ io.mapRequired("value", d.value);
+ }
+ static void mappingFraction(IO &io, MyDouble &d) {
+ double num, denom;
+ io.mapRequired("numerator", num);
+ io.mapRequired("denominator", denom);
+ // convert fraction to double
+ d.value = num/denom;
+ }
+ };
+ }
+}
+
+
+//
+// Test the reading of two different tagged yaml documents.
+//
+TEST(YAMLIO, TestTaggedDocuments) {
+ std::vector<MyDouble> docList;
+ Input yin("--- !decimal\nvalue: 3.0\n"
+ "--- !fraction\nnumerator: 9.0\ndenominator: 2\n...\n");
+ yin >> docList;
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(docList.size(), 2UL);
+ EXPECT_EQ(docList[0].value, 3.0);
+ EXPECT_EQ(docList[1].value, 4.5);
+}
+
+
+
+//
+// Test writing then reading back tagged documents
+//
+TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) {
+ std::string intermediate;
+ {
+ MyDouble a(10.25);
+ MyDouble b(-3.75);
+ std::vector<MyDouble> docList;
+ docList.push_back(a);
+ docList.push_back(b);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << docList;
+ }
+
+ {
+ Input yin(intermediate);
+ std::vector<MyDouble> docList2;
+ yin >> docList2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(docList2.size(), 2UL);
+ EXPECT_EQ(docList2[0].value, 10.25);
+ EXPECT_EQ(docList2[1].value, -3.75);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Test mapping validation
+//===----------------------------------------------------------------------===//
+
+struct MyValidation {
+ double value;
+};
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyValidation)
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<MyValidation> {
+ static void mapping(IO &io, MyValidation &d) {
+ io.mapRequired("value", d.value);
+ }
+ static StringRef validate(IO &io, MyValidation &d) {
+ if (d.value < 0)
+ return "negative value";
+ return StringRef();
+ }
+ };
+ }
+}
+
+
+//
+// Test that validate() is called and complains about the negative value.
+//
+TEST(YAMLIO, TestValidatingInput) {
+ std::vector<MyValidation> docList;
+ Input yin("--- \nvalue: 3.0\n"
+ "--- \nvalue: -1.0\n...\n",
+ nullptr, suppressErrorMessages);
+ yin >> docList;
+ EXPECT_TRUE(!!yin.error());
+}
+
+//===----------------------------------------------------------------------===//
+// Test flow mapping
+//===----------------------------------------------------------------------===//
+
+struct FlowFooBar {
+ int foo;
+ int bar;
+
+ FlowFooBar() : foo(0), bar(0) {}
+ FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {}
+};
+
+typedef std::vector<FlowFooBar> FlowFooBarSequence;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar)
+
+struct FlowFooBarDoc {
+ FlowFooBar attribute;
+ FlowFooBarSequence seq;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<FlowFooBar> {
+ static void mapping(IO &io, FlowFooBar &fb) {
+ io.mapRequired("foo", fb.foo);
+ io.mapRequired("bar", fb.bar);
+ }
+
+ static const bool flow = true;
+ };
+
+ template <>
+ struct MappingTraits<FlowFooBarDoc> {
+ static void mapping(IO &io, FlowFooBarDoc &fb) {
+ io.mapRequired("attribute", fb.attribute);
+ io.mapRequired("seq", fb.seq);
+ }
+ };
+}
+}
+
+//
+// Test writing then reading back custom mappings
+//
+TEST(YAMLIO, TestReadWriteMyFlowMapping) {
+ std::string intermediate;
+ {
+ FlowFooBarDoc doc;
+ doc.attribute = FlowFooBar(42, 907);
+ doc.seq.push_back(FlowFooBar(1, 2));
+ doc.seq.push_back(FlowFooBar(0, 0));
+ doc.seq.push_back(FlowFooBar(-1, 1024));
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << doc;
+
+ // Verify that mappings were written in flow style
+ ostr.flush();
+ llvm::StringRef flowOut(intermediate);
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }"));
+ EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }"));
+ }
+
+ {
+ Input yin(intermediate);
+ FlowFooBarDoc doc2;
+ yin >> doc2;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(doc2.attribute.foo, 42);
+ EXPECT_EQ(doc2.attribute.bar, 907);
+ EXPECT_EQ(doc2.seq.size(), 3UL);
+ EXPECT_EQ(doc2.seq[0].foo, 1);
+ EXPECT_EQ(doc2.seq[0].bar, 2);
+ EXPECT_EQ(doc2.seq[1].foo, 0);
+ EXPECT_EQ(doc2.seq[1].bar, 0);
+ EXPECT_EQ(doc2.seq[2].foo, -1);
+ EXPECT_EQ(doc2.seq[2].bar, 1024);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test error handling
+//===----------------------------------------------------------------------===//
+
+//
+// Test error handling of unknown enumerated scalar
+//
+TEST(YAMLIO, TestColorsReadError) {
+ ColorMap map;
+ Input yin("---\n"
+ "c1: blue\n"
+ "c2: purple\n"
+ "c3: green\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> map;
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling of flow sequence with unknown value
+//
+TEST(YAMLIO, TestFlagsReadError) {
+ FlagsMap map;
+ Input yin("---\n"
+ "f1: [ big ]\n"
+ "f2: [ round, hollow ]\n"
+ "f3: []\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> map;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in uint8_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesUint8Error) {
+ std::vector<uint8_t> seq;
+ Input yin("---\n"
+ "- 255\n"
+ "- 0\n"
+ "- 257\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in uint16_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesUint16Error) {
+ std::vector<uint16_t> seq;
+ Input yin("---\n"
+ "- 65535\n"
+ "- 0\n"
+ "- 66000\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in uint32_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesUint32Error) {
+ std::vector<uint32_t> seq;
+ Input yin("---\n"
+ "- 4000000000\n"
+ "- 0\n"
+ "- 5000000000\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in uint64_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesUint64Error) {
+ std::vector<uint64_t> seq;
+ Input yin("---\n"
+ "- 18446744073709551615\n"
+ "- 0\n"
+ "- 19446744073709551615\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in int8_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint8OverError) {
+ std::vector<int8_t> seq;
+ Input yin("---\n"
+ "- -128\n"
+ "- 0\n"
+ "- 127\n"
+ "- 128\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in int8_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) {
+ std::vector<int8_t> seq;
+ Input yin("---\n"
+ "- -128\n"
+ "- 0\n"
+ "- 127\n"
+ "- -129\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in int16_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) {
+ std::vector<int16_t> seq;
+ Input yin("---\n"
+ "- 32767\n"
+ "- 0\n"
+ "- -32768\n"
+ "- -32769\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in int16_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint16OverError) {
+ std::vector<int16_t> seq;
+ Input yin("---\n"
+ "- 32767\n"
+ "- 0\n"
+ "- -32768\n"
+ "- 32768\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in int32_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) {
+ std::vector<int32_t> seq;
+ Input yin("---\n"
+ "- 2147483647\n"
+ "- 0\n"
+ "- -2147483648\n"
+ "- -2147483649\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in int32_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint32OverError) {
+ std::vector<int32_t> seq;
+ Input yin("---\n"
+ "- 2147483647\n"
+ "- 0\n"
+ "- -2147483648\n"
+ "- 2147483649\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in int64_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) {
+ std::vector<int64_t> seq;
+ Input yin("---\n"
+ "- -9223372036854775808\n"
+ "- 0\n"
+ "- 9223372036854775807\n"
+ "- -9223372036854775809\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in int64_t type
+//
+TEST(YAMLIO, TestReadBuiltInTypesint64OverError) {
+ std::vector<int64_t> seq;
+ Input yin("---\n"
+ "- -9223372036854775808\n"
+ "- 0\n"
+ "- 9223372036854775807\n"
+ "- 9223372036854775809\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in float type
+//
+TEST(YAMLIO, TestReadBuiltInTypesFloatError) {
+ std::vector<float> seq;
+ Input yin("---\n"
+ "- 0.0\n"
+ "- 1000.1\n"
+ "- -123.456\n"
+ "- 1.2.3\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in float type
+//
+TEST(YAMLIO, TestReadBuiltInTypesDoubleError) {
+ std::vector<double> seq;
+ Input yin("---\n"
+ "- 0.0\n"
+ "- 1000.1\n"
+ "- -123.456\n"
+ "- 1.2.3\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in Hex8 type
+//
+LLVM_YAML_IS_SEQUENCE_VECTOR(Hex8)
+TEST(YAMLIO, TestReadBuiltInTypesHex8Error) {
+ std::vector<Hex8> seq;
+ Input yin("---\n"
+ "- 0x12\n"
+ "- 0xFE\n"
+ "- 0x123\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+
+//
+// Test error handling reading built-in Hex16 type
+//
+LLVM_YAML_IS_SEQUENCE_VECTOR(Hex16)
+TEST(YAMLIO, TestReadBuiltInTypesHex16Error) {
+ std::vector<Hex16> seq;
+ Input yin("---\n"
+ "- 0x0012\n"
+ "- 0xFEFF\n"
+ "- 0x12345\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in Hex32 type
+//
+LLVM_YAML_IS_SEQUENCE_VECTOR(Hex32)
+TEST(YAMLIO, TestReadBuiltInTypesHex32Error) {
+ std::vector<Hex32> seq;
+ Input yin("---\n"
+ "- 0x0012\n"
+ "- 0xFEFF0000\n"
+ "- 0x1234556789\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+//
+// Test error handling reading built-in Hex64 type
+//
+LLVM_YAML_IS_SEQUENCE_VECTOR(Hex64)
+TEST(YAMLIO, TestReadBuiltInTypesHex64Error) {
+ std::vector<Hex64> seq;
+ Input yin("---\n"
+ "- 0x0012\n"
+ "- 0xFFEEDDCCBBAA9988\n"
+ "- 0x12345567890ABCDEF0\n"
+ "...\n",
+ /*Ctxt=*/nullptr,
+ suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_TRUE(!!yin.error());
+}
+
+TEST(YAMLIO, TestMalformedMapFailsGracefully) {
+ FooBar doc;
+ {
+ // We pass the suppressErrorMessages handler to handle the error
+ // message generated in the constructor of Input.
+ Input yin("{foo:3, bar: 5}", /*Ctxt=*/nullptr, suppressErrorMessages);
+ yin >> doc;
+ EXPECT_TRUE(!!yin.error());
+ }
+
+ {
+ Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/nullptr, suppressErrorMessages);
+ yin >> doc;
+ EXPECT_TRUE(!!yin.error());
+ }
+}
+
+struct OptionalTest {
+ std::vector<int> Numbers;
+};
+
+struct OptionalTestSeq {
+ std::vector<OptionalTest> Tests;
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(OptionalTest)
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<OptionalTest> {
+ static void mapping(IO& IO, OptionalTest &OT) {
+ IO.mapOptional("Numbers", OT.Numbers);
+ }
+ };
+
+ template <>
+ struct MappingTraits<OptionalTestSeq> {
+ static void mapping(IO &IO, OptionalTestSeq &OTS) {
+ IO.mapOptional("Tests", OTS.Tests);
+ }
+ };
+}
+}
+
+TEST(YAMLIO, SequenceElideTest) {
+ // Test that writing out a purely optional structure with its fields set to
+ // default followed by other data is properly read back in.
+ OptionalTestSeq Seq;
+ OptionalTest One, Two, Three, Four;
+ int N[] = {1, 2, 3};
+ Three.Numbers.assign(N, N + 3);
+ Seq.Tests.push_back(One);
+ Seq.Tests.push_back(Two);
+ Seq.Tests.push_back(Three);
+ Seq.Tests.push_back(Four);
+
+ std::string intermediate;
+ {
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << Seq;
+ }
+
+ Input yin(intermediate);
+ OptionalTestSeq Seq2;
+ yin >> Seq2;
+
+ EXPECT_FALSE(yin.error());
+
+ EXPECT_EQ(4UL, Seq2.Tests.size());
+
+ EXPECT_TRUE(Seq2.Tests[0].Numbers.empty());
+ EXPECT_TRUE(Seq2.Tests[1].Numbers.empty());
+
+ EXPECT_EQ(1, Seq2.Tests[2].Numbers[0]);
+ EXPECT_EQ(2, Seq2.Tests[2].Numbers[1]);
+ EXPECT_EQ(3, Seq2.Tests[2].Numbers[2]);
+
+ EXPECT_TRUE(Seq2.Tests[3].Numbers.empty());
+}
+
+TEST(YAMLIO, TestEmptyStringFailsForMapWithRequiredFields) {
+ FooBar doc;
+ Input yin("");
+ yin >> doc;
+ EXPECT_TRUE(!!yin.error());
+}
+
+TEST(YAMLIO, TestEmptyStringSucceedsForMapWithOptionalFields) {
+ OptionalTest doc;
+ Input yin("");
+ yin >> doc;
+ EXPECT_FALSE(yin.error());
+}
+
+TEST(YAMLIO, TestEmptyStringSucceedsForSequence) {
+ std::vector<uint8_t> seq;
+ Input yin("", /*Ctxt=*/nullptr, suppressErrorMessages);
+ yin >> seq;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_TRUE(seq.empty());
+}
+
+struct FlowMap {
+ llvm::StringRef str1, str2, str3;
+ FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3)
+ : str1(str1), str2(str2), str3(str3) {}
+};
+
+struct FlowSeq {
+ llvm::StringRef str;
+ FlowSeq(llvm::StringRef S) : str(S) {}
+ FlowSeq() = default;
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<FlowMap> {
+ static void mapping(IO &io, FlowMap &fm) {
+ io.mapRequired("str1", fm.str1);
+ io.mapRequired("str2", fm.str2);
+ io.mapRequired("str3", fm.str3);
+ }
+
+ static const bool flow = true;
+ };
+
+template <>
+struct ScalarTraits<FlowSeq> {
+ static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) {
+ out << value.str;
+ }
+ static StringRef input(StringRef scalar, void*, FlowSeq &value) {
+ value.str = scalar;
+ return "";
+ }
+
+ static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
+};
+}
+}
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq)
+
+TEST(YAMLIO, TestWrapFlow) {
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+ FlowMap Map("This is str1", "This is str2", "This is str3");
+ std::vector<FlowSeq> Seq;
+ Seq.emplace_back("This is str1");
+ Seq.emplace_back("This is str2");
+ Seq.emplace_back("This is str3");
+
+ {
+ // 20 is just bellow the total length of the first mapping field.
+ // We should wreap at every element.
+ Output yout(ostr, nullptr, 15);
+
+ yout << Map;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "{ str1: This is str1, \n"
+ " str2: This is str2, \n"
+ " str3: This is str3 }\n"
+ "...\n");
+ out.clear();
+
+ yout << Seq;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "[ This is str1, \n"
+ " This is str2, \n"
+ " This is str3 ]\n"
+ "...\n");
+ out.clear();
+ }
+ {
+ // 25 will allow the second field to be output on the first line.
+ Output yout(ostr, nullptr, 25);
+
+ yout << Map;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "{ str1: This is str1, str2: This is str2, \n"
+ " str3: This is str3 }\n"
+ "...\n");
+ out.clear();
+
+ yout << Seq;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "[ This is str1, This is str2, \n"
+ " This is str3 ]\n"
+ "...\n");
+ out.clear();
+ }
+ {
+ // 0 means no wrapping.
+ Output yout(ostr, nullptr, 0);
+
+ yout << Map;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "{ str1: This is str1, str2: This is str2, str3: This is str3 }\n"
+ "...\n");
+ out.clear();
+
+ yout << Seq;
+ ostr.flush();
+ EXPECT_EQ(out,
+ "---\n"
+ "[ This is str1, This is str2, This is str3 ]\n"
+ "...\n");
+ out.clear();
+ }
+}
+
+struct MappingContext {
+ int A = 0;
+};
+struct SimpleMap {
+ int B = 0;
+ int C = 0;
+};
+
+struct NestedMap {
+ NestedMap(MappingContext &Context) : Context(Context) {}
+ SimpleMap Simple;
+ MappingContext &Context;
+};
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingContextTraits<SimpleMap, MappingContext> {
+ static void mapping(IO &io, SimpleMap &sm, MappingContext &Context) {
+ io.mapRequired("B", sm.B);
+ io.mapRequired("C", sm.C);
+ ++Context.A;
+ io.mapRequired("Context", Context.A);
+ }
+};
+
+template <> struct MappingTraits<NestedMap> {
+ static void mapping(IO &io, NestedMap &nm) {
+ io.mapRequired("Simple", nm.Simple, nm.Context);
+ }
+};
+}
+}
+
+TEST(YAMLIO, TestMapWithContext) {
+ MappingContext Context;
+ NestedMap Nested(Context);
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+
+ Output yout(ostr, nullptr, 15);
+
+ yout << Nested;
+ ostr.flush();
+ EXPECT_EQ(1, Context.A);
+ EXPECT_EQ("---\n"
+ "Simple: \n"
+ " B: 0\n"
+ " C: 0\n"
+ " Context: 1\n"
+ "...\n",
+ out);
+
+ out.clear();
+
+ Nested.Simple.B = 2;
+ Nested.Simple.C = 3;
+ yout << Nested;
+ ostr.flush();
+ EXPECT_EQ(2, Context.A);
+ EXPECT_EQ("---\n"
+ "Simple: \n"
+ " B: 2\n"
+ " C: 3\n"
+ " Context: 2\n"
+ "...\n",
+ out);
+ out.clear();
+}
+
+LLVM_YAML_IS_STRING_MAP(int)
+
+TEST(YAMLIO, TestCustomMapping) {
+ std::map<std::string, int> x;
+ x["foo"] = 1;
+ x["bar"] = 2;
+
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+ Output xout(ostr, nullptr, 0);
+
+ xout << x;
+ ostr.flush();
+ EXPECT_EQ("---\n"
+ "bar: 2\n"
+ "foo: 1\n"
+ "...\n",
+ out);
+
+ Input yin(out);
+ std::map<std::string, int> y;
+ yin >> y;
+ EXPECT_EQ(2ul, y.size());
+ EXPECT_EQ(1, y["foo"]);
+ EXPECT_EQ(2, y["bar"]);
+}
+
+LLVM_YAML_IS_STRING_MAP(FooBar)
+
+TEST(YAMLIO, TestCustomMappingStruct) {
+ std::map<std::string, FooBar> x;
+ x["foo"].foo = 1;
+ x["foo"].bar = 2;
+ x["bar"].foo = 3;
+ x["bar"].bar = 4;
+
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+ Output xout(ostr, nullptr, 0);
+
+ xout << x;
+ ostr.flush();
+ EXPECT_EQ("---\n"
+ "bar: \n"
+ " foo: 3\n"
+ " bar: 4\n"
+ "foo: \n"
+ " foo: 1\n"
+ " bar: 2\n"
+ "...\n",
+ out);
+
+ Input yin(out);
+ std::map<std::string, FooBar> y;
+ yin >> y;
+ EXPECT_EQ(2ul, y.size());
+ EXPECT_EQ(1, y["foo"].foo);
+ EXPECT_EQ(2, y["foo"].bar);
+ EXPECT_EQ(3, y["bar"].foo);
+ EXPECT_EQ(4, y["bar"].bar);
+}
+
+static void TestEscaped(llvm::StringRef Input, llvm::StringRef Expected) {
+ std::string out;
+ llvm::raw_string_ostream ostr(out);
+ Output xout(ostr, nullptr, 0);
+
+ llvm::yaml::EmptyContext Ctx;
+ yamlize(xout, Input, true, Ctx);
+
+ ostr.flush();
+
+ // Make a separate StringRef so we get nice byte-by-byte output.
+ llvm::StringRef Got(out);
+ EXPECT_EQ(Expected, Got);
+}
+
+TEST(YAMLIO, TestEscaped) {
+ // Single quote
+ TestEscaped("@abc@", "'@abc@'");
+ // No quote
+ TestEscaped("abc", "abc");
+ // Forward slash quoted
+ TestEscaped("abc/", "'abc/'");
+ // Double quote non-printable
+ TestEscaped("\01@abc@", "\"\\x01@abc@\"");
+ // Double quote inside single quote
+ TestEscaped("abc\"fdf", "'abc\"fdf'");
+ // Double quote inside double quote
+ TestEscaped("\01bc\"fdf", "\"\\x01bc\\\"fdf\"");
+ // Single quote inside single quote
+ TestEscaped("abc'fdf", "'abc''fdf'");
+ // UTF8
+ TestEscaped("/*параметр*/", "\"/*параметр*/\"");
+ // UTF8 with single quote inside double quote
+ TestEscaped("parameter 'параметр' is unused",
+ "\"parameter 'параметр' is unused\"");
+
+ // String with embedded non-printable multibyte UTF-8 sequence (U+200B
+ // zero-width space). The thing to test here is that we emit a
+ // unicode-scalar level escape like \uNNNN (at the YAML level), and don't
+ // just pass the UTF-8 byte sequence through as with quoted printables.
+ {
+ const unsigned char foobar[10] = {'f', 'o', 'o',
+ 0xE2, 0x80, 0x8B, // UTF-8 of U+200B
+ 'b', 'a', 'r',
+ 0x0};
+ TestEscaped((char const *)foobar, "\"foo\\u200Bbar\"");
+ }
+}
+
+TEST(YAMLIO, Numeric) {
+ EXPECT_TRUE(isNumeric(".inf"));
+ EXPECT_TRUE(isNumeric(".INF"));
+ EXPECT_TRUE(isNumeric(".Inf"));
+ EXPECT_TRUE(isNumeric("-.inf"));
+ EXPECT_TRUE(isNumeric("+.inf"));
+
+ EXPECT_TRUE(isNumeric(".nan"));
+ EXPECT_TRUE(isNumeric(".NaN"));
+ EXPECT_TRUE(isNumeric(".NAN"));
+
+ EXPECT_TRUE(isNumeric("0"));
+ EXPECT_TRUE(isNumeric("0."));
+ EXPECT_TRUE(isNumeric("0.0"));
+ EXPECT_TRUE(isNumeric("-0.0"));
+ EXPECT_TRUE(isNumeric("+0.0"));
+
+ EXPECT_TRUE(isNumeric("12345"));
+ EXPECT_TRUE(isNumeric("012345"));
+ EXPECT_TRUE(isNumeric("+12.0"));
+ EXPECT_TRUE(isNumeric(".5"));
+ EXPECT_TRUE(isNumeric("+.5"));
+ EXPECT_TRUE(isNumeric("-1.0"));
+
+ EXPECT_TRUE(isNumeric("2.3e4"));
+ EXPECT_TRUE(isNumeric("-2E+05"));
+ EXPECT_TRUE(isNumeric("+12e03"));
+ EXPECT_TRUE(isNumeric("6.8523015e+5"));
+
+ EXPECT_TRUE(isNumeric("1.e+1"));
+ EXPECT_TRUE(isNumeric(".0e+1"));
+
+ EXPECT_TRUE(isNumeric("0x2aF3"));
+ EXPECT_TRUE(isNumeric("0o01234567"));
+
+ EXPECT_FALSE(isNumeric("not a number"));
+ EXPECT_FALSE(isNumeric("."));
+ EXPECT_FALSE(isNumeric(".e+1"));
+ EXPECT_FALSE(isNumeric(".1e"));
+ EXPECT_FALSE(isNumeric(".1e+"));
+ EXPECT_FALSE(isNumeric(".1e++1"));
+
+ EXPECT_FALSE(isNumeric("ABCD"));
+ EXPECT_FALSE(isNumeric("+0x2AF3"));
+ EXPECT_FALSE(isNumeric("-0x2AF3"));
+ EXPECT_FALSE(isNumeric("0x2AF3Z"));
+ EXPECT_FALSE(isNumeric("0o012345678"));
+ EXPECT_FALSE(isNumeric("0xZ"));
+ EXPECT_FALSE(isNumeric("-0o012345678"));
+ EXPECT_FALSE(isNumeric("000003A8229434B839616A25C16B0291F77A438B"));
+
+ EXPECT_FALSE(isNumeric(""));
+ EXPECT_FALSE(isNumeric("."));
+ EXPECT_FALSE(isNumeric(".e+1"));
+ EXPECT_FALSE(isNumeric(".e+"));
+ EXPECT_FALSE(isNumeric(".e"));
+ EXPECT_FALSE(isNumeric("e1"));
+
+ // Deprecated formats: as for YAML 1.2 specification, the following are not
+ // valid numbers anymore:
+ //
+ // * Sexagecimal numbers
+ // * Decimal numbers with comma s the delimiter
+ // * "inf", "nan" without '.' prefix
+ EXPECT_FALSE(isNumeric("3:25:45"));
+ EXPECT_FALSE(isNumeric("+12,345"));
+ EXPECT_FALSE(isNumeric("-inf"));
+ EXPECT_FALSE(isNumeric("1,230.15"));
+}
+
+//===----------------------------------------------------------------------===//
+// Test PolymorphicTraits and TaggedScalarTraits
+//===----------------------------------------------------------------------===//
+
+struct Poly {
+ enum NodeKind {
+ NK_Scalar,
+ NK_Seq,
+ NK_Map,
+ } Kind;
+
+ Poly(NodeKind Kind) : Kind(Kind) {}
+
+ virtual ~Poly() = default;
+
+ NodeKind getKind() const { return Kind; }
+};
+
+struct Scalar : Poly {
+ enum ScalarKind {
+ SK_Unknown,
+ SK_Double,
+ SK_Bool,
+ } SKind;
+
+ union {
+ double DoubleValue;
+ bool BoolValue;
+ };
+
+ Scalar() : Poly(NK_Scalar), SKind(SK_Unknown) {}
+ Scalar(double DoubleValue)
+ : Poly(NK_Scalar), SKind(SK_Double), DoubleValue(DoubleValue) {}
+ Scalar(bool BoolValue)
+ : Poly(NK_Scalar), SKind(SK_Bool), BoolValue(BoolValue) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Scalar; }
+};
+
+struct Seq : Poly, std::vector<std::unique_ptr<Poly>> {
+ Seq() : Poly(NK_Seq) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Seq; }
+};
+
+struct Map : Poly, llvm::StringMap<std::unique_ptr<Poly>> {
+ Map() : Poly(NK_Map) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Map; }
+};
+
+namespace llvm {
+namespace yaml {
+
+template <> struct PolymorphicTraits<std::unique_ptr<Poly>> {
+ static NodeKind getKind(const std::unique_ptr<Poly> &N) {
+ if (isa<Scalar>(*N))
+ return NodeKind::Scalar;
+ if (isa<Seq>(*N))
+ return NodeKind::Sequence;
+ if (isa<Map>(*N))
+ return NodeKind::Map;
+ llvm_unreachable("unsupported node type");
+ }
+
+ static Scalar &getAsScalar(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Scalar>(*N))
+ N = llvm::make_unique<Scalar>();
+ return *cast<Scalar>(N.get());
+ }
+
+ static Seq &getAsSequence(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Seq>(*N))
+ N = llvm::make_unique<Seq>();
+ return *cast<Seq>(N.get());
+ }
+
+ static Map &getAsMap(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Map>(*N))
+ N = llvm::make_unique<Map>();
+ return *cast<Map>(N.get());
+ }
+};
+
+template <> struct TaggedScalarTraits<Scalar> {
+ static void output(const Scalar &S, void *Ctxt, raw_ostream &ScalarOS,
+ raw_ostream &TagOS) {
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ report_fatal_error("output unknown scalar");
+ break;
+ case Scalar::SK_Double:
+ TagOS << "!double";
+ ScalarTraits<double>::output(S.DoubleValue, Ctxt, ScalarOS);
+ break;
+ case Scalar::SK_Bool:
+ TagOS << "!bool";
+ ScalarTraits<bool>::output(S.BoolValue, Ctxt, ScalarOS);
+ break;
+ }
+ }
+
+ static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt,
+ Scalar &S) {
+ S.SKind = StringSwitch<Scalar::ScalarKind>(Tag)
+ .Case("!double", Scalar::SK_Double)
+ .Case("!bool", Scalar::SK_Bool)
+ .Default(Scalar::SK_Unknown);
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ return StringRef("unknown scalar tag");
+ case Scalar::SK_Double:
+ return ScalarTraits<double>::input(ScalarStr, Ctxt, S.DoubleValue);
+ case Scalar::SK_Bool:
+ return ScalarTraits<bool>::input(ScalarStr, Ctxt, S.BoolValue);
+ }
+ llvm_unreachable("unknown scalar kind");
+ }
+
+ static QuotingType mustQuote(const Scalar &S, StringRef Str) {
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ report_fatal_error("quote unknown scalar");
+ case Scalar::SK_Double:
+ return ScalarTraits<double>::mustQuote(Str);
+ case Scalar::SK_Bool:
+ return ScalarTraits<bool>::mustQuote(Str);
+ }
+ llvm_unreachable("unknown scalar kind");
+ }
+};
+
+template <> struct CustomMappingTraits<Map> {
+ static void inputOne(IO &IO, StringRef Key, Map &M) {
+ IO.mapRequired(Key.str().c_str(), M[Key]);
+ }
+
+ static void output(IO &IO, Map &M) {
+ for (auto &N : M)
+ IO.mapRequired(N.getKey().str().c_str(), N.getValue());
+ }
+};
+
+template <> struct SequenceTraits<Seq> {
+ static size_t size(IO &IO, Seq &A) { return A.size(); }
+
+ static std::unique_ptr<Poly> &element(IO &IO, Seq &A, size_t Index) {
+ if (Index >= A.size())
+ A.resize(Index + 1);
+ return A[Index];
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+TEST(YAMLIO, TestReadWritePolymorphicScalar) {
+ std::string intermediate;
+ std::unique_ptr<Poly> node = llvm::make_unique<Scalar>(true);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+ EXPECT_DEATH(yout << node, "plain scalar documents are not supported");
+#endif
+#endif
+}
+
+TEST(YAMLIO, TestReadWritePolymorphicSeq) {
+ std::string intermediate;
+ {
+ auto seq = llvm::make_unique<Seq>();
+ seq->push_back(llvm::make_unique<Scalar>(true));
+ seq->push_back(llvm::make_unique<Scalar>(1.0));
+ auto node = llvm::unique_dyn_cast<Poly>(seq);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << node;
+ }
+ {
+ Input yin(intermediate);
+ std::unique_ptr<Poly> node;
+ yin >> node;
+
+ EXPECT_FALSE(yin.error());
+ auto seq = llvm::dyn_cast<Seq>(node.get());
+ ASSERT_TRUE(seq);
+ ASSERT_EQ(seq->size(), 2u);
+ auto first = llvm::dyn_cast<Scalar>((*seq)[0].get());
+ ASSERT_TRUE(first);
+ EXPECT_EQ(first->SKind, Scalar::SK_Bool);
+ EXPECT_TRUE(first->BoolValue);
+ auto second = llvm::dyn_cast<Scalar>((*seq)[1].get());
+ ASSERT_TRUE(second);
+ EXPECT_EQ(second->SKind, Scalar::SK_Double);
+ EXPECT_EQ(second->DoubleValue, 1.0);
+ }
+}
+
+TEST(YAMLIO, TestReadWritePolymorphicMap) {
+ std::string intermediate;
+ {
+ auto map = llvm::make_unique<Map>();
+ (*map)["foo"] = llvm::make_unique<Scalar>(false);
+ (*map)["bar"] = llvm::make_unique<Scalar>(2.0);
+ std::unique_ptr<Poly> node = llvm::unique_dyn_cast<Poly>(map);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << node;
+ }
+ {
+ Input yin(intermediate);
+ std::unique_ptr<Poly> node;
+ yin >> node;
+
+ EXPECT_FALSE(yin.error());
+ auto map = llvm::dyn_cast<Map>(node.get());
+ ASSERT_TRUE(map);
+ auto foo = llvm::dyn_cast<Scalar>((*map)["foo"].get());
+ ASSERT_TRUE(foo);
+ EXPECT_EQ(foo->SKind, Scalar::SK_Bool);
+ EXPECT_FALSE(foo->BoolValue);
+ auto bar = llvm::dyn_cast<Scalar>((*map)["bar"].get());
+ ASSERT_TRUE(bar);
+ EXPECT_EQ(bar->SKind, Scalar::SK_Double);
+ EXPECT_EQ(bar->DoubleValue, 2.0);
+ }
+}
diff --git a/src/llvm-project/llvm/unittests/Support/YAMLParserTest.cpp b/src/llvm-project/llvm/unittests/Support/YAMLParserTest.cpp
new file mode 100644
index 0000000..7962f3c
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/YAMLParserTest.cpp
@@ -0,0 +1,335 @@
+//===- unittest/Support/YAMLParserTest ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+
+namespace llvm {
+
+static void SuppressDiagnosticsOutput(const SMDiagnostic &, void *) {
+ // Prevent SourceMgr from writing errors to stderr
+ // to reduce noise in unit test runs.
+}
+
+// Assumes Ctx is an SMDiagnostic where Diag can be stored.
+static void CollectDiagnosticsOutput(const SMDiagnostic &Diag, void *Ctx) {
+ SMDiagnostic* DiagOut = static_cast<SMDiagnostic*>(Ctx);
+ *DiagOut = Diag;
+}
+
+// Checks that the given input gives a parse error. Makes sure that an error
+// text is available and the parse fails.
+static void ExpectParseError(StringRef Message, StringRef Input) {
+ SourceMgr SM;
+ yaml::Stream Stream(Input, SM);
+ SM.setDiagHandler(SuppressDiagnosticsOutput);
+ EXPECT_FALSE(Stream.validate()) << Message << ": " << Input;
+ EXPECT_TRUE(Stream.failed()) << Message << ": " << Input;
+}
+
+// Checks that the given input can be parsed without error.
+static void ExpectParseSuccess(StringRef Message, StringRef Input) {
+ SourceMgr SM;
+ yaml::Stream Stream(Input, SM);
+ EXPECT_TRUE(Stream.validate()) << Message << ": " << Input;
+}
+
+TEST(YAMLParser, ParsesEmptyArray) {
+ ExpectParseSuccess("Empty array", "[]");
+}
+
+TEST(YAMLParser, FailsIfNotClosingArray) {
+ ExpectParseError("Not closing array", "[");
+ ExpectParseError("Not closing array", " [ ");
+ ExpectParseError("Not closing array", " [x");
+}
+
+TEST(YAMLParser, ParsesEmptyArrayWithWhitespace) {
+ ExpectParseSuccess("Array with spaces", " [ ] ");
+ ExpectParseSuccess("All whitespaces", "\t\r\n[\t\n \t\r ]\t\r \n\n");
+}
+
+TEST(YAMLParser, ParsesEmptyObject) {
+ ExpectParseSuccess("Empty object", "[{}]");
+}
+
+TEST(YAMLParser, ParsesObject) {
+ ExpectParseSuccess("Object with an entry", "[{\"a\":\"/b\"}]");
+}
+
+TEST(YAMLParser, ParsesMultipleKeyValuePairsInObject) {
+ ExpectParseSuccess("Multiple key, value pairs",
+ "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]");
+}
+
+TEST(YAMLParser, FailsIfNotClosingObject) {
+ ExpectParseError("Missing close on empty", "[{]");
+ ExpectParseError("Missing close after pair", "[{\"a\":\"b\"]");
+}
+
+TEST(YAMLParser, FailsIfMissingColon) {
+ ExpectParseError("Missing colon between key and value", "[{\"a\"\"/b\"}]");
+ ExpectParseError("Missing colon between key and value", "[{\"a\" \"b\"}]");
+}
+
+TEST(YAMLParser, FailsOnMissingQuote) {
+ ExpectParseError("Missing open quote", "[{a\":\"b\"}]");
+ ExpectParseError("Missing closing quote", "[{\"a\":\"b}]");
+}
+
+TEST(YAMLParser, ParsesEscapedQuotes) {
+ ExpectParseSuccess("Parses escaped string in key and value",
+ "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]");
+}
+
+TEST(YAMLParser, ParsesEmptyString) {
+ ExpectParseSuccess("Parses empty string in value", "[{\"a\":\"\"}]");
+}
+
+TEST(YAMLParser, ParsesMultipleObjects) {
+ ExpectParseSuccess(
+ "Multiple objects in array",
+ "["
+ " { \"a\" : \"b\" },"
+ " { \"a\" : \"b\" },"
+ " { \"a\" : \"b\" }"
+ "]");
+}
+
+TEST(YAMLParser, FailsOnMissingComma) {
+ ExpectParseError(
+ "Missing comma",
+ "["
+ " { \"a\" : \"b\" }"
+ " { \"a\" : \"b\" }"
+ "]");
+}
+
+TEST(YAMLParser, ParsesSpacesInBetweenTokens) {
+ ExpectParseSuccess(
+ "Various whitespace between tokens",
+ " \t \n\n \r [ \t \n\n \r"
+ " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+ " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
+ " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+ " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r");
+}
+
+TEST(YAMLParser, ParsesArrayOfArrays) {
+ ExpectParseSuccess("Array of arrays", "[[]]");
+}
+
+TEST(YAMLParser, ParsesBlockLiteralScalars) {
+ ExpectParseSuccess("Block literal scalar", "test: |\n Hello\n World\n");
+ ExpectParseSuccess("Block literal scalar EOF", "test: |\n Hello\n World");
+ ExpectParseSuccess("Empty block literal scalar header EOF", "test: | ");
+ ExpectParseSuccess("Empty block literal scalar", "test: |\ntest2: 20");
+ ExpectParseSuccess("Empty block literal scalar 2", "- | \n \n\n \n- 42");
+ ExpectParseSuccess("Block literal scalar in sequence",
+ "- |\n Testing\n Out\n\n- 22");
+ ExpectParseSuccess("Block literal scalar in document",
+ "--- |\n Document\n...");
+ ExpectParseSuccess("Empty non indented lines still count",
+ "- |\n First line\n \n\n Another line\n\n- 2");
+ ExpectParseSuccess("Comment in block literal scalar header",
+ "test: | # Comment \n No Comment\ntest 2: | # Void");
+ ExpectParseSuccess("Chomping indicators in block literal scalar header",
+ "test: |- \n Hello\n\ntest 2: |+ \n\n World\n\n\n");
+ ExpectParseSuccess("Indent indicators in block literal scalar header",
+ "test: |1 \n \n Hello \n World\n");
+ ExpectParseSuccess("Chomping and indent indicators in block literals",
+ "test: |-1\n Hello\ntest 2: |9+\n World");
+ ExpectParseSuccess("Trailing comments in block literals",
+ "test: |\n Content\n # Trailing\n #Comment\ntest 2: 3");
+ ExpectParseError("Invalid block scalar header", "test: | failure");
+ ExpectParseError("Invalid line indentation", "test: |\n First line\n Error");
+ ExpectParseError("Long leading space line", "test: |\n \n Test\n");
+}
+
+TEST(YAMLParser, NullTerminatedBlockScalars) {
+ SourceMgr SM;
+ yaml::Stream Stream("test: |\n Hello\n World\n", SM);
+ yaml::Document &Doc = *Stream.begin();
+ yaml::MappingNode *Map = cast<yaml::MappingNode>(Doc.getRoot());
+ StringRef Value =
+ cast<yaml::BlockScalarNode>(Map->begin()->getValue())->getValue();
+
+ EXPECT_EQ(Value, "Hello\nWorld\n");
+ EXPECT_EQ(Value.data()[Value.size()], '\0');
+}
+
+TEST(YAMLParser, HandlesEndOfFileGracefully) {
+ ExpectParseError("In string starting with EOF", "[\"");
+ ExpectParseError("In string hitting EOF", "[\" ");
+ ExpectParseError("In string escaping EOF", "[\" \\");
+ ExpectParseError("In array starting with EOF", "[");
+ ExpectParseError("In array element starting with EOF", "[[], ");
+ ExpectParseError("In array hitting EOF", "[[] ");
+ ExpectParseError("In array hitting EOF", "[[]");
+ ExpectParseError("In object hitting EOF", "{\"\"");
+}
+
+TEST(YAMLParser, HandlesNullValuesInKeyValueNodesGracefully) {
+ ExpectParseError("KeyValueNode with null key", "? \"\n:");
+ ExpectParseError("KeyValueNode with null value", "test: '");
+}
+
+// Checks that the given string can be parsed into an identical string inside
+// of an array.
+static void ExpectCanParseString(StringRef String) {
+ std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str();
+ SourceMgr SM;
+ yaml::Stream Stream(StringInArray, SM);
+ yaml::SequenceNode *ParsedSequence
+ = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot());
+ StringRef ParsedString
+ = dyn_cast<yaml::ScalarNode>(
+ static_cast<yaml::Node*>(ParsedSequence->begin()))->getRawValue();
+ ParsedString = ParsedString.substr(1, ParsedString.size() - 2);
+ EXPECT_EQ(String, ParsedString.str());
+}
+
+// Checks that parsing the given string inside an array fails.
+static void ExpectCannotParseString(StringRef String) {
+ std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str();
+ ExpectParseError((Twine("When parsing string \"") + String + "\"").str(),
+ StringInArray);
+}
+
+TEST(YAMLParser, ParsesStrings) {
+ ExpectCanParseString("");
+ ExpectCannotParseString("\\");
+ ExpectCannotParseString("\"");
+ ExpectCanParseString(" ");
+ ExpectCanParseString("\\ ");
+ ExpectCanParseString("\\\"");
+ ExpectCannotParseString("\"\\");
+ ExpectCannotParseString(" \\");
+ ExpectCanParseString("\\\\");
+ ExpectCannotParseString("\\\\\\");
+ ExpectCanParseString("\\\\\\\\");
+ ExpectCanParseString("\\\" ");
+ ExpectCannotParseString("\\\\\" ");
+ ExpectCanParseString("\\\\\\\" ");
+ ExpectCanParseString(" \\\\ \\\" \\\\\\\" ");
+}
+
+TEST(YAMLParser, WorksWithIteratorAlgorithms) {
+ SourceMgr SM;
+ yaml::Stream Stream("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]", SM);
+ yaml::SequenceNode *Array
+ = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot());
+ EXPECT_EQ(6, std::distance(Array->begin(), Array->end()));
+}
+
+TEST(YAMLParser, DefaultDiagnosticFilename) {
+ SourceMgr SM;
+
+ SMDiagnostic GeneratedDiag;
+ SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag);
+
+ // When we construct a YAML stream over an unnamed string,
+ // the filename is hard-coded as "YAML".
+ yaml::Stream UnnamedStream("[]", SM);
+ UnnamedStream.printError(UnnamedStream.begin()->getRoot(), "Hello, World!");
+ EXPECT_EQ("YAML", GeneratedDiag.getFilename());
+}
+
+TEST(YAMLParser, DiagnosticFilenameFromBufferID) {
+ SourceMgr SM;
+
+ SMDiagnostic GeneratedDiag;
+ SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag);
+
+ // When we construct a YAML stream over a named buffer,
+ // we get its ID as filename in diagnostics.
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBuffer("[]", "buffername.yaml");
+ yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
+ Stream.printError(Stream.begin()->getRoot(), "Hello, World!");
+ EXPECT_EQ("buffername.yaml", GeneratedDiag.getFilename());
+}
+
+TEST(YAMLParser, SameNodeIteratorOperatorNotEquals) {
+ SourceMgr SM;
+ yaml::Stream Stream("[\"1\", \"2\"]", SM);
+
+ yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>(
+ Stream.begin()->getRoot());
+
+ auto Begin = Node->begin();
+ auto End = Node->end();
+
+ EXPECT_TRUE(Begin != End);
+ EXPECT_FALSE(Begin != Begin);
+ EXPECT_FALSE(End != End);
+}
+
+TEST(YAMLParser, SameNodeIteratorOperatorEquals) {
+ SourceMgr SM;
+ yaml::Stream Stream("[\"1\", \"2\"]", SM);
+
+ yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>(
+ Stream.begin()->getRoot());
+
+ auto Begin = Node->begin();
+ auto End = Node->end();
+
+ EXPECT_FALSE(Begin == End);
+ EXPECT_TRUE(Begin == Begin);
+ EXPECT_TRUE(End == End);
+}
+
+TEST(YAMLParser, DifferentNodesIteratorOperatorNotEquals) {
+ SourceMgr SM;
+ yaml::Stream Stream("[\"1\", \"2\"]", SM);
+ yaml::Stream AnotherStream("[\"1\", \"2\"]", SM);
+
+ yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>(
+ Stream.begin()->getRoot());
+ yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>(
+ AnotherStream.begin()->getRoot());
+
+ auto Begin = Node->begin();
+ auto End = Node->end();
+
+ auto AnotherBegin = AnotherNode->begin();
+ auto AnotherEnd = AnotherNode->end();
+
+ EXPECT_TRUE(Begin != AnotherBegin);
+ EXPECT_TRUE(Begin != AnotherEnd);
+ EXPECT_FALSE(End != AnotherEnd);
+}
+
+TEST(YAMLParser, DifferentNodesIteratorOperatorEquals) {
+ SourceMgr SM;
+ yaml::Stream Stream("[\"1\", \"2\"]", SM);
+ yaml::Stream AnotherStream("[\"1\", \"2\"]", SM);
+
+ yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>(
+ Stream.begin()->getRoot());
+ yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>(
+ AnotherStream.begin()->getRoot());
+
+ auto Begin = Node->begin();
+ auto End = Node->end();
+
+ auto AnotherBegin = AnotherNode->begin();
+ auto AnotherEnd = AnotherNode->end();
+
+ EXPECT_FALSE(Begin == AnotherBegin);
+ EXPECT_FALSE(Begin == AnotherEnd);
+ EXPECT_TRUE(End == AnotherEnd);
+}
+
+} // end namespace llvm
diff --git a/src/llvm-project/llvm/unittests/Support/formatted_raw_ostream_test.cpp b/src/llvm-project/llvm/unittests/Support/formatted_raw_ostream_test.cpp
new file mode 100644
index 0000000..2b8f065
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/formatted_raw_ostream_test.cpp
@@ -0,0 +1,33 @@
+//===- llvm/unittest/Support/formatted_raw_ostream_test.cpp ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(formatted_raw_ostreamTest, Test_Tell) {
+ // Check offset when underlying stream has buffer contents.
+ SmallString<128> A;
+ raw_svector_ostream B(A);
+ formatted_raw_ostream C(B);
+ char tmp[100] = "";
+
+ for (unsigned i = 0; i != 3; ++i) {
+ C.write(tmp, 100);
+
+ EXPECT_EQ(100*(i+1), (unsigned) C.tell());
+ }
+}
+
+}
diff --git a/src/llvm-project/llvm/unittests/Support/raw_ostream_test.cpp b/src/llvm-project/llvm/unittests/Support/raw_ostream_test.cpp
new file mode 100644
index 0000000..a75f446
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/raw_ostream_test.cpp
@@ -0,0 +1,346 @@
+//===- llvm/unittest/Support/raw_ostream_test.cpp - raw_ostream tests -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+template<typename T> std::string printToString(const T &Value) {
+ std::string res;
+ llvm::raw_string_ostream(res) << Value;
+ return res;
+}
+
+/// printToString - Print the given value to a stream which only has \arg
+/// BytesLeftInBuffer bytes left in the buffer. This is useful for testing edge
+/// cases in the buffer handling logic.
+template<typename T> std::string printToString(const T &Value,
+ unsigned BytesLeftInBuffer) {
+ // FIXME: This is relying on internal knowledge of how raw_ostream works to
+ // get the buffer position right.
+ SmallString<256> SVec;
+ assert(BytesLeftInBuffer < 256 && "Invalid buffer count!");
+ llvm::raw_svector_ostream OS(SVec);
+ unsigned StartIndex = 256 - BytesLeftInBuffer;
+ for (unsigned i = 0; i != StartIndex; ++i)
+ OS << '?';
+ OS << Value;
+ return OS.str().substr(StartIndex);
+}
+
+template<typename T> std::string printToStringUnbuffered(const T &Value) {
+ std::string res;
+ llvm::raw_string_ostream OS(res);
+ OS.SetUnbuffered();
+ OS << Value;
+ return res;
+}
+
+TEST(raw_ostreamTest, Types_Buffered) {
+ // Char
+ EXPECT_EQ("c", printToString('c'));
+
+ // String
+ EXPECT_EQ("hello", printToString("hello"));
+ EXPECT_EQ("hello", printToString(std::string("hello")));
+
+ // Int
+ EXPECT_EQ("0", printToString(0));
+ EXPECT_EQ("2425", printToString(2425));
+ EXPECT_EQ("-2425", printToString(-2425));
+
+ // Long long
+ EXPECT_EQ("0", printToString(0LL));
+ EXPECT_EQ("257257257235709", printToString(257257257235709LL));
+ EXPECT_EQ("-257257257235709", printToString(-257257257235709LL));
+
+ // Double
+ EXPECT_EQ("1.100000e+00", printToString(1.1));
+
+ // void*
+ EXPECT_EQ("0x0", printToString((void*) nullptr));
+ EXPECT_EQ("0xbeef", printToString((void*) 0xbeefLL));
+ EXPECT_EQ("0xdeadbeef", printToString((void*) 0xdeadbeefLL));
+
+ // Min and max.
+ EXPECT_EQ("18446744073709551615", printToString(UINT64_MAX));
+ EXPECT_EQ("-9223372036854775808", printToString(INT64_MIN));
+}
+
+TEST(raw_ostreamTest, Types_Unbuffered) {
+ // Char
+ EXPECT_EQ("c", printToStringUnbuffered('c'));
+
+ // String
+ EXPECT_EQ("hello", printToStringUnbuffered("hello"));
+ EXPECT_EQ("hello", printToStringUnbuffered(std::string("hello")));
+
+ // Int
+ EXPECT_EQ("0", printToStringUnbuffered(0));
+ EXPECT_EQ("2425", printToStringUnbuffered(2425));
+ EXPECT_EQ("-2425", printToStringUnbuffered(-2425));
+
+ // Long long
+ EXPECT_EQ("0", printToStringUnbuffered(0LL));
+ EXPECT_EQ("257257257235709", printToStringUnbuffered(257257257235709LL));
+ EXPECT_EQ("-257257257235709", printToStringUnbuffered(-257257257235709LL));
+
+ // Double
+ EXPECT_EQ("1.100000e+00", printToStringUnbuffered(1.1));
+
+ // void*
+ EXPECT_EQ("0x0", printToStringUnbuffered((void*) nullptr));
+ EXPECT_EQ("0xbeef", printToStringUnbuffered((void*) 0xbeefLL));
+ EXPECT_EQ("0xdeadbeef", printToStringUnbuffered((void*) 0xdeadbeefLL));
+
+ // Min and max.
+ EXPECT_EQ("18446744073709551615", printToStringUnbuffered(UINT64_MAX));
+ EXPECT_EQ("-9223372036854775808", printToStringUnbuffered(INT64_MIN));
+}
+
+TEST(raw_ostreamTest, BufferEdge) {
+ EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 1));
+ EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 2));
+ EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 3));
+ EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 4));
+ EXPECT_EQ("1.20", printToString(format("%.2f", 1.2), 10));
+}
+
+TEST(raw_ostreamTest, TinyBuffer) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS.SetBufferSize(1);
+ OS << "hello";
+ OS << 1;
+ OS << 'w' << 'o' << 'r' << 'l' << 'd';
+ EXPECT_EQ("hello1world", OS.str());
+}
+
+TEST(raw_ostreamTest, WriteEscaped) {
+ std::string Str;
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("hi");
+ EXPECT_EQ("hi", Str);
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("\\\t\n\"");
+ EXPECT_EQ("\\\\\\t\\n\\\"", Str);
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("\1\10\200");
+ EXPECT_EQ("\\001\\010\\200", Str);
+}
+
+TEST(raw_ostreamTest, Justify) {
+ EXPECT_EQ("xyz ", printToString(left_justify("xyz", 6), 6));
+ EXPECT_EQ("abc", printToString(left_justify("abc", 3), 3));
+ EXPECT_EQ("big", printToString(left_justify("big", 1), 3));
+ EXPECT_EQ(" xyz", printToString(right_justify("xyz", 6), 6));
+ EXPECT_EQ("abc", printToString(right_justify("abc", 3), 3));
+ EXPECT_EQ("big", printToString(right_justify("big", 1), 3));
+ EXPECT_EQ(" on ", printToString(center_justify("on", 9), 9));
+ EXPECT_EQ(" off ", printToString(center_justify("off", 10), 10));
+ EXPECT_EQ("single ", printToString(center_justify("single", 7), 7));
+ EXPECT_EQ("none", printToString(center_justify("none", 1), 4));
+ EXPECT_EQ("none", printToString(center_justify("none", 1), 1));
+}
+
+TEST(raw_ostreamTest, FormatHex) {
+ EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 6), 6));
+ EXPECT_EQ("0x001234", printToString(format_hex(0x1234, 8), 8));
+ EXPECT_EQ("0x00001234", printToString(format_hex(0x1234, 10), 10));
+ EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 4), 6));
+ EXPECT_EQ("0xff", printToString(format_hex(255, 4), 4));
+ EXPECT_EQ("0xFF", printToString(format_hex(255, 4, true), 4));
+ EXPECT_EQ("0x1", printToString(format_hex(1, 3), 3));
+ EXPECT_EQ("0x12", printToString(format_hex(0x12, 3), 4));
+ EXPECT_EQ("0x123", printToString(format_hex(0x123, 3), 5));
+ EXPECT_EQ("FF", printToString(format_hex_no_prefix(0xFF, 2, true), 4));
+ EXPECT_EQ("ABCD", printToString(format_hex_no_prefix(0xABCD, 2, true), 4));
+ EXPECT_EQ("0xffffffffffffffff",
+ printToString(format_hex(UINT64_MAX, 18), 18));
+ EXPECT_EQ("0x8000000000000000",
+ printToString(format_hex((INT64_MIN), 18), 18));
+}
+
+TEST(raw_ostreamTest, FormatDecimal) {
+ EXPECT_EQ(" 0", printToString(format_decimal(0, 4), 4));
+ EXPECT_EQ(" -1", printToString(format_decimal(-1, 4), 4));
+ EXPECT_EQ(" -1", printToString(format_decimal(-1, 6), 6));
+ EXPECT_EQ("1234567890", printToString(format_decimal(1234567890, 10), 10));
+ EXPECT_EQ(" 9223372036854775807",
+ printToString(format_decimal(INT64_MAX, 21), 21));
+ EXPECT_EQ(" -9223372036854775808",
+ printToString(format_decimal(INT64_MIN, 21), 21));
+}
+
+static std::string formatted_bytes_str(ArrayRef<uint8_t> Bytes,
+ llvm::Optional<uint64_t> Offset = None,
+ uint32_t NumPerLine = 16,
+ uint8_t ByteGroupSize = 4) {
+ std::string S;
+ raw_string_ostream Str(S);
+ Str << format_bytes(Bytes, Offset, NumPerLine, ByteGroupSize);
+ Str.flush();
+ return S;
+}
+
+static std::string format_bytes_with_ascii_str(ArrayRef<uint8_t> Bytes,
+ Optional<uint64_t> Offset = None,
+ uint32_t NumPerLine = 16,
+ uint8_t ByteGroupSize = 4) {
+ std::string S;
+ raw_string_ostream Str(S);
+ Str << format_bytes_with_ascii(Bytes, Offset, NumPerLine, ByteGroupSize);
+ Str.flush();
+ return S;
+}
+
+TEST(raw_ostreamTest, FormattedHexBytes) {
+ std::vector<uint8_t> Buf = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
+ '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+ ArrayRef<uint8_t> B(Buf);
+
+ // Test invalid input.
+ EXPECT_EQ("", formatted_bytes_str(ArrayRef<uint8_t>()));
+ EXPECT_EQ("", format_bytes_with_ascii_str(ArrayRef<uint8_t>()));
+ //----------------------------------------------------------------------
+ // Test hex byte output with the default 4 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61", formatted_bytes_str(B.take_front()));
+ EXPECT_EQ("61626364 65", formatted_bytes_str(B.take_front(5)));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70",
+ formatted_bytes_str(B.take_front(16)));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70\n71",
+ formatted_bytes_str(B.take_front(17)));
+ // Test raw bytes with 1 bytes per line wrapping.
+ EXPECT_EQ("61\n62\n63\n64\n65\n66",
+ formatted_bytes_str(B.take_front(6), None, 1));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("61626364 656667\n68696a6b 6c6d6e\n6f7071",
+ formatted_bytes_str(B.take_front(17), None, 7));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("61626364 65666768\n696a6b6c 6d6e6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8));
+ //----------------------------------------------------------------------
+ // Test hex byte output with the 1 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61 62 63 64 65",
+ formatted_bytes_str(B.take_front(5), None, 16, 1));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70",
+ formatted_bytes_str(B.take_front(16), None, 16, 1));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70\n71",
+ formatted_bytes_str(B.take_front(17), None, 16, 1));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67\n68 69 6a 6b 6c 6d 6e\n6f 70 71",
+ formatted_bytes_str(B.take_front(17), None, 7, 1));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("61 62 63 64 65 66 67 68\n69 6a 6b 6c 6d 6e 6f 70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8, 1));
+
+ //----------------------------------------------------------------------
+ // Test hex byte output with the 2 byte groups
+ //----------------------------------------------------------------------
+ EXPECT_EQ("6162 6364 65", formatted_bytes_str(B.take_front(5), None, 16, 2));
+ // Test that 16 bytes get written to a line correctly.
+ EXPECT_EQ("6162 6364 6566 6768 696a 6b6c 6d6e 6f70",
+ formatted_bytes_str(B.take_front(16), None, 16, 2));
+ // Test raw bytes with default 16 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 6768 696a 6b6c 6d6e 6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 16, 2));
+ // Test raw bytes with 7 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 67\n6869 6a6b 6c6d 6e\n6f70 71",
+ formatted_bytes_str(B.take_front(17), None, 7, 2));
+ // Test raw bytes with 8 bytes per line wrapping.
+ EXPECT_EQ("6162 6364 6566 6768\n696a 6b6c 6d6e 6f70\n71",
+ formatted_bytes_str(B.take_front(17), None, 8, 2));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with offset with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61", formatted_bytes_str(B.take_front(), 0x0));
+ EXPECT_EQ("1000: 61", formatted_bytes_str(B.take_front(), 0x1000));
+ EXPECT_EQ("1000: 61\n1001: 62",
+ formatted_bytes_str(B.take_front(2), 0x1000, 1));
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("61626364 65666768 696a6b6c 6d6e6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16)));
+ EXPECT_EQ("61626364 65666768 |abcdefgh|\n"
+ "696a6b6c 6d6e6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), None, 8));
+ EXPECT_EQ("61626364 65666768 |abcdefgh|\n696a6b6c |ijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), None, 8));
+ std::vector<uint8_t> Unprintable = {'a', '\x1e', 'b', '\x1f'};
+ // Make sure the ASCII is still lined up correctly when fewer bytes than 16
+ // bytes per line are available. The ASCII should still be aligned as if 16
+ // bytes of hex might be displayed.
+ EXPECT_EQ("611e621f |a.b.|",
+ format_bytes_with_ascii_str(Unprintable));
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 4 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61626364 65666768 "
+ "696a6b6c 6d6e6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0));
+ EXPECT_EQ("0000: 61626364 65666768 |abcdefgh|\n"
+ "0008: 696a6b6c 6d6e6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8));
+ EXPECT_EQ("0000: 61626364 656667 |abcdefg|\n"
+ "0007: 68696a6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 2 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 6162 6364 6566 6768 "
+ "696a 6b6c 6d6e 6f70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 16, 2));
+ EXPECT_EQ("0000: 6162 6364 6566 6768 |abcdefgh|\n"
+ "0008: 696a 6b6c 6d6e 6f70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8, 2));
+ EXPECT_EQ("0000: 6162 6364 6566 67 |abcdefg|\n"
+ "0007: 6869 6a6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7, 2));
+
+ //----------------------------------------------------------------------
+ // Test hex bytes with ASCII with offsets with the default 1 byte groups.
+ //----------------------------------------------------------------------
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 68 "
+ "69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 16, 1));
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 68 |abcdefgh|\n"
+ "0008: 69 6a 6b 6c 6d 6e 6f 70 |ijklmnop|",
+ format_bytes_with_ascii_str(B.take_front(16), 0, 8, 1));
+ EXPECT_EQ("0000: 61 62 63 64 65 66 67 |abcdefg|\n"
+ "0007: 68 69 6a 6b 6c |hijkl|",
+ format_bytes_with_ascii_str(B.take_front(12), 0, 7, 1));
+}
+
+TEST(raw_fd_ostreamTest, multiple_raw_fd_ostream_to_stdout) {
+ std::error_code EC;
+
+ { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); }
+ { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); }
+}
+}
diff --git a/src/llvm-project/llvm/unittests/Support/raw_pwrite_stream_test.cpp b/src/llvm-project/llvm/unittests/Support/raw_pwrite_stream_test.cpp
new file mode 100644
index 0000000..a528fd2
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/raw_pwrite_stream_test.cpp
@@ -0,0 +1,95 @@
+//===- raw_pwrite_stream_test.cpp - raw_pwrite_stream tests ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ SmallString<128> MessageStorage; \
+ raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
+namespace {
+
+TEST(raw_pwrite_ostreamTest, TestSVector) {
+ SmallVector<char, 0> Buffer;
+ raw_svector_ostream OS(Buffer);
+ OS << "abcd";
+ StringRef Test = "test";
+ OS.pwrite(Test.data(), Test.size(), 0);
+ EXPECT_EQ(Test, OS.str());
+
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+ EXPECT_DEATH(OS.pwrite("12345", 5, 0),
+ "We don't support extending the stream");
+#endif
+#endif
+}
+
+#ifdef _WIN32
+#define setenv(name, var, ignore) _putenv_s(name, var)
+#endif
+
+TEST(raw_pwrite_ostreamTest, TestFD) {
+ SmallString<64> Path;
+ int FD;
+
+ // If we want to clean up from a death test, we have to remove the file from
+ // the parent process. Have the parent create the file, pass it via
+ // environment variable to the child, let the child crash, and then remove it
+ // in the parent.
+ const char *ParentPath = getenv("RAW_PWRITE_TEST_FILE");
+ if (ParentPath) {
+ Path = ParentPath;
+ ASSERT_NO_ERROR(sys::fs::openFileForRead(Path, FD));
+ } else {
+ ASSERT_NO_ERROR(sys::fs::createTemporaryFile("foo", "bar", FD, Path));
+ setenv("RAW_PWRITE_TEST_FILE", Path.c_str(), true);
+ }
+ FileRemover Cleanup(Path);
+
+ raw_fd_ostream OS(FD, true);
+ OS << "abcd";
+ StringRef Test = "test";
+ OS.pwrite(Test.data(), Test.size(), 0);
+ OS.pwrite(Test.data(), Test.size(), 0);
+
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+ EXPECT_DEATH(OS.pwrite("12345", 5, 0),
+ "We don't support extending the stream");
+#endif
+#endif
+}
+
+#ifdef LLVM_ON_UNIX
+TEST(raw_pwrite_ostreamTest, TestDevNull) {
+ int FD;
+ sys::fs::openFileForWrite("/dev/null", FD, sys::fs::CD_OpenExisting);
+ raw_fd_ostream OS(FD, true);
+ OS << "abcd";
+ StringRef Test = "test";
+ OS.pwrite(Test.data(), Test.size(), 0);
+ OS.pwrite(Test.data(), Test.size(), 0);
+}
+#endif
+}
diff --git a/src/llvm-project/llvm/unittests/Support/raw_sha1_ostream_test.cpp b/src/llvm-project/llvm/unittests/Support/raw_sha1_ostream_test.cpp
new file mode 100644
index 0000000..e176f3f
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/raw_sha1_ostream_test.cpp
@@ -0,0 +1,78 @@
+//===- llvm/unittest/Support/raw_ostream_test.cpp - raw_ostream tests -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_sha1_ostream.h"
+#include "gtest/gtest.h"
+
+#include <string>
+
+using namespace llvm;
+
+static std::string toHex(StringRef Input) {
+ static const char *const LUT = "0123456789ABCDEF";
+ size_t Length = Input.size();
+
+ std::string Output;
+ Output.reserve(2 * Length);
+ for (size_t i = 0; i < Length; ++i) {
+ const unsigned char c = Input[i];
+ Output.push_back(LUT[c >> 4]);
+ Output.push_back(LUT[c & 15]);
+ }
+ return Output;
+}
+
+TEST(raw_sha1_ostreamTest, Basic) {
+ llvm::raw_sha1_ostream Sha1Stream;
+ Sha1Stream << "Hello World!";
+ auto Hash = toHex(Sha1Stream.sha1());
+
+ ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash);
+}
+
+TEST(sha1_hash_test, Basic) {
+ ArrayRef<uint8_t> Input((const uint8_t *)"Hello World!", 12);
+ std::array<uint8_t, 20> Vec = SHA1::hash(Input);
+ std::string Hash = toHex({(const char *)Vec.data(), 20});
+ ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash);
+}
+
+// Check that getting the intermediate hash in the middle of the stream does
+// not invalidate the final result.
+TEST(raw_sha1_ostreamTest, Intermediate) {
+ llvm::raw_sha1_ostream Sha1Stream;
+ Sha1Stream << "Hello";
+ auto Hash = toHex(Sha1Stream.sha1());
+
+ ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash);
+ Sha1Stream << " World!";
+ Hash = toHex(Sha1Stream.sha1());
+
+ // Compute the non-split hash separately as a reference.
+ llvm::raw_sha1_ostream NonSplitSha1Stream;
+ NonSplitSha1Stream << "Hello World!";
+ auto NonSplitHash = toHex(NonSplitSha1Stream.sha1());
+
+ ASSERT_EQ(NonSplitHash, Hash);
+}
+
+TEST(raw_sha1_ostreamTest, Reset) {
+ llvm::raw_sha1_ostream Sha1Stream;
+ Sha1Stream << "Hello";
+ auto Hash = toHex(Sha1Stream.sha1());
+
+ ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash);
+
+ Sha1Stream.resetHash();
+ Sha1Stream << " World!";
+ Hash = toHex(Sha1Stream.sha1());
+
+ ASSERT_EQ("7447F2A5A42185C8CF91E632789C431830B59067", Hash);
+}
diff --git a/src/llvm-project/llvm/unittests/Support/xxhashTest.cpp b/src/llvm-project/llvm/unittests/Support/xxhashTest.cpp
new file mode 100644
index 0000000..6a88a2d
--- /dev/null
+++ b/src/llvm-project/llvm/unittests/Support/xxhashTest.cpp
@@ -0,0 +1,20 @@
+//===- llvm/unittest/Support/xxhashTest.cpp -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/xxhash.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(xxhashTest, Basic) {
+ EXPECT_EQ(0x33bf00a859c4ba3fU, xxHash64("foo"));
+ EXPECT_EQ(0x48a37c90ad27a659U, xxHash64("bar"));
+ EXPECT_EQ(0x69196c1b3af0bff9U,
+ xxHash64("0123456789abcdefghijklmnopqrstuvwxyz"));
+}