diff --git a/llvm/include/llvm/Support/Format.h b/llvm/include/llvm/Support/Format.h index 34b224dba5407..b549341a40e7f 100644 --- a/llvm/include/llvm/Support/Format.h +++ b/llvm/include/llvm/Support/Format.h @@ -78,9 +78,20 @@ class LLVM_ABI format_object_base { /// printed, this synthesizes the string into a temporary buffer provided and /// returns whether or not it is big enough. +namespace detail { +template struct decay_if_c_char_array { + using type = T; +}; +template struct decay_if_c_char_array { + using type = const char *; +}; +template +using decay_if_c_char_array_t = typename decay_if_c_char_array::type; +} // namespace detail + template class format_object final : public format_object_base { - std::tuple Vals; + std::tuple...> Vals; template int snprint_tuple(char *Buffer, unsigned BufferSize, @@ -96,7 +107,7 @@ class format_object final : public format_object_base { format_object(const char *fmt, const Ts &... vals) : format_object_base(fmt), Vals(vals...) { static_assert( - (std::is_scalar_v && ...), + (std::is_scalar_v> && ...), "format can't be used with non fundamental / non pointer type"); } diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index d1dfb1dc4a722..1f2a68545d107 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -44,6 +44,7 @@ add_llvm_unittest(SupportTests ExtensibleRTTITest.cpp FileCollectorTest.cpp FileOutputBufferTest.cpp + Format.cpp FormatVariadicTest.cpp FSUniqueIDTest.cpp GenericDomTreeTest.cpp diff --git a/llvm/unittests/Support/Format.cpp b/llvm/unittests/Support/Format.cpp new file mode 100644 index 0000000000000..c4e421fe9dc4c --- /dev/null +++ b/llvm/unittests/Support/Format.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Format.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +template +std::string printToString(unsigned MaxN, FormatTy &&Fmt) { + std::vector Dst(MaxN + 2); + int N = Fmt.snprint(Dst.data(), Dst.size()); + Dst.back() = 0; + return N < 0 ? "" : Dst.data(); +} + +template +constexpr bool checkDecayTypeEq(const Arg &arg) { + return std::is_same_v, Expected>; +} + +TEST(Format, DecayIfCCharArray) { + char Array[] = "Array"; + const char ConstArray[] = "ConstArray"; + char PtrBuf[] = "Ptr"; + char *Ptr = PtrBuf; + const char *PtrToConst = "PtrToConst"; + + EXPECT_EQ(" Literal", printToString(20, format("%15s", "Literal"))); + EXPECT_EQ(" Array", printToString(20, format("%15s", Array))); + EXPECT_EQ(" ConstArray", printToString(20, format("%15s", ConstArray))); + EXPECT_EQ(" Ptr", printToString(20, format("%15s", Ptr))); + EXPECT_EQ(" PtrToConst", printToString(20, format("%15s", PtrToConst))); + + EXPECT_TRUE(checkDecayTypeEq("Literal")); + EXPECT_TRUE(checkDecayTypeEq(Array)); + EXPECT_TRUE(checkDecayTypeEq(ConstArray)); + EXPECT_TRUE(checkDecayTypeEq(Ptr)); + EXPECT_TRUE(checkDecayTypeEq(PtrToConst)); + EXPECT_TRUE(checkDecayTypeEq(PtrToConst[0])); + EXPECT_TRUE( + checkDecayTypeEq(static_cast("Literal"))); + + wchar_t WCharArray[] = L"WCharArray"; + EXPECT_TRUE(checkDecayTypeEq(WCharArray)); + EXPECT_TRUE(checkDecayTypeEq(WCharArray[0])); +} + +} // namespace