Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions llvm/include/llvm/Support/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T> struct decay_if_c_char_array {
using type = T;
};
template <std::size_t N> struct decay_if_c_char_array<char[N]> {
using type = const char *;
};
template <typename T>
using decay_if_c_char_array_t = typename decay_if_c_char_array<T>::type;
} // namespace detail

template <typename... Ts>
class format_object final : public format_object_base {
std::tuple<Ts...> Vals;
std::tuple<detail::decay_if_c_char_array_t<Ts>...> Vals;

template <std::size_t... Is>
int snprint_tuple(char *Buffer, unsigned BufferSize,
Expand All @@ -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<Ts> && ...),
(std::is_scalar_v<detail::decay_if_c_char_array_t<Ts>> && ...),
"format can't be used with non fundamental / non pointer type");
}

Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ add_llvm_unittest(SupportTests
ExtensibleRTTITest.cpp
FileCollectorTest.cpp
FileOutputBufferTest.cpp
Format.cpp
FormatVariadicTest.cpp
FSUniqueIDTest.cpp
GenericDomTreeTest.cpp
Expand Down
56 changes: 56 additions & 0 deletions llvm/unittests/Support/Format.cpp
Original file line number Diff line number Diff line change
@@ -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 <typename FormatTy>
std::string printToString(unsigned MaxN, FormatTy &&Fmt) {
std::vector<char> Dst(MaxN + 2);
int N = Fmt.snprint(Dst.data(), Dst.size());
Dst.back() = 0;
return N < 0 ? "" : Dst.data();
}

template <typename Expected, typename Arg>
constexpr bool checkDecayTypeEq(const Arg &arg) {
return std::is_same_v<detail::decay_if_c_char_array_t<Arg>, 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<const char *>("Literal"));
EXPECT_TRUE(checkDecayTypeEq<const char *>(Array));
EXPECT_TRUE(checkDecayTypeEq<const char *>(ConstArray));
EXPECT_TRUE(checkDecayTypeEq<char *>(Ptr));
EXPECT_TRUE(checkDecayTypeEq<const char *>(PtrToConst));
EXPECT_TRUE(checkDecayTypeEq<char>(PtrToConst[0]));
EXPECT_TRUE(
checkDecayTypeEq<const char *>(static_cast<const char *>("Literal")));

wchar_t WCharArray[] = L"WCharArray";
EXPECT_TRUE(checkDecayTypeEq<wchar_t[11]>(WCharArray));
EXPECT_TRUE(checkDecayTypeEq<wchar_t>(WCharArray[0]));
}

} // namespace