diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h --- a/llvm/include/llvm/Support/JSON.h +++ b/llvm/include/llvm/Support/JSON.h @@ -74,6 +74,11 @@ // - When retrieving strings from Values (e.g. asString()), the result will // always be valid UTF-8. +template +constexpr bool is_uint_64_bit_v = + std::is_integral_v && std::is_unsigned_v && + sizeof(T) == sizeof(uint64_t); + /// Returns true if \p S is valid UTF-8, which is required for use as JSON. /// If it returns false, \p Offset is set to a byte offset near the first error. bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr); @@ -336,19 +341,17 @@ create(B); } - // Unsigned 64-bit long integers. - template ::value>, - bool = false, bool = false> + // Unsigned 64-bit integers. + template >> Value(T V) : Type(T_UINT64) { create(uint64_t{V}); } // Integers (except boolean and uint64_t). // Must be non-narrowing convertible to int64_t. - template ::value>, - typename = std::enable_if_t::value>, - typename = std::enable_if_t::value>> + template >, + typename = std::enable_if_t>, + typename = std::enable_if_t>> Value(T I) : Type(T_Integer) { create(int64_t{I}); } @@ -424,6 +427,12 @@ std::optional getAsInteger() const { if (LLVM_LIKELY(Type == T_Integer)) return as(); + if (LLVM_LIKELY(Type == T_UINT64)) { + uint64_t U = as(); + if (LLVM_LIKELY(U <= uint64_t(std::numeric_limits::max()))) { + return U; + } + } if (LLVM_LIKELY(Type == T_Double)) { double D = as(); if (LLVM_LIKELY(std::modf(D, &D) == 0.0 && diff --git a/llvm/include/llvm/Support/ScopedPrinter.h b/llvm/include/llvm/Support/ScopedPrinter.h --- a/llvm/include/llvm/Support/ScopedPrinter.h +++ b/llvm/include/llvm/Support/ScopedPrinter.h @@ -198,36 +198,48 @@ printFlagsImpl(Label, hex(Value), SetFlags); } - virtual void printNumber(StringRef Label, uint64_t Value) { + virtual void printNumber(StringRef Label, char Value) { + startLine() << Label << ": " << static_cast(Value) << "\n"; + } + + virtual void printNumber(StringRef Label, signed char Value) { + startLine() << Label << ": " << static_cast(Value) << "\n"; + } + + virtual void printNumber(StringRef Label, unsigned char Value) { + startLine() << Label << ": " << static_cast(Value) << "\n"; + } + + virtual void printNumber(StringRef Label, short Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, uint32_t Value) { + virtual void printNumber(StringRef Label, unsigned short Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, uint16_t Value) { + virtual void printNumber(StringRef Label, int Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, uint8_t Value) { - startLine() << Label << ": " << unsigned(Value) << "\n"; + virtual void printNumber(StringRef Label, unsigned int Value) { + startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, int64_t Value) { + virtual void printNumber(StringRef Label, long Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, int32_t Value) { + virtual void printNumber(StringRef Label, unsigned long Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, int16_t Value) { + virtual void printNumber(StringRef Label, long long Value) { startLine() << Label << ": " << Value << "\n"; } - virtual void printNumber(StringRef Label, int8_t Value) { - startLine() << Label << ": " << int(Value) << "\n"; + virtual void printNumber(StringRef Label, unsigned long long Value) { + startLine() << Label << ": " << Value << "\n"; } virtual void printNumber(StringRef Label, const APSInt &Value) { @@ -562,35 +574,47 @@ return SP->getKind() == ScopedPrinter::ScopedPrinterKind::JSON; } - void printNumber(StringRef Label, uint64_t Value) override { + void printNumber(StringRef Label, char Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, signed char Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, unsigned char Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, short Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, uint32_t Value) override { + void printNumber(StringRef Label, unsigned short Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, uint16_t Value) override { + void printNumber(StringRef Label, int Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, uint8_t Value) override { + void printNumber(StringRef Label, unsigned int Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, int64_t Value) override { + void printNumber(StringRef Label, long Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, int32_t Value) override { + void printNumber(StringRef Label, unsigned long Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, int16_t Value) override { + void printNumber(StringRef Label, long long Value) override { JOS.attribute(Label, Value); } - void printNumber(StringRef Label, int8_t Value) override { + void printNumber(StringRef Label, unsigned long long Value) override { JOS.attribute(Label, Value); } diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -7275,14 +7275,14 @@ StringRef BucketName = IsGnu ? "Bucket" : "Chain"; StringRef ListName = IsGnu ? "Buckets" : "Chains"; DictScope Outer(W, HistName); - W.printNumber("TotalBuckets", static_cast(NBucket)); + W.printNumber("TotalBuckets", NBucket); ListScope Buckets(W, ListName); size_t CumulativeNonZero = 0; for (size_t I = 0; I < MaxChain; ++I) { CumulativeNonZero += Count[I] * I; DictScope Bucket(W, BucketName); - W.printNumber("Length", static_cast(I)); - W.printNumber("Count", static_cast(Count[I])); + W.printNumber("Length", I); + W.printNumber("Count", Count[I]); W.printNumber("Percentage", (float)(Count[I] * 100.0) / NBucket); W.printNumber("Coverage", (float)(CumulativeNonZero * 100.0) / TotalSyms); } diff --git a/llvm/unittests/Support/JSONTest.cpp b/llvm/unittests/Support/JSONTest.cpp --- a/llvm/unittests/Support/JSONTest.cpp +++ b/llvm/unittests/Support/JSONTest.cpp @@ -442,6 +442,39 @@ } } +template void checkCppIntegers() { + Value Val = T{10}; + T Var = 10; + EXPECT_EQ(Val, Var); + + Val = T{std::numeric_limits::max()}; + Var = std::numeric_limits::max(); + EXPECT_EQ(Val, Var); + + Val = T{std::numeric_limits::min()}; + Var = std::numeric_limits::min(); + EXPECT_EQ(Val, Var); +} + +// Test that underlying C++ integer types behave as expected. +TEST(JSONTest, CppIntegers) { + checkCppIntegers(); + checkCppIntegers(); + checkCppIntegers(); + + checkCppIntegers(); + checkCppIntegers(); + + checkCppIntegers(); + checkCppIntegers(); + + checkCppIntegers(); + checkCppIntegers(); + + checkCppIntegers(); + checkCppIntegers(); +} + // Sample struct with typical JSON-mapping rules. struct CustomStruct { CustomStruct() : B(false) {}