summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/base/exception_safety_testing_test.cc2
-rw-r--r--absl/base/internal/direct_mmap.h4
-rw-r--r--absl/flags/BUILD.bazel1
-rw-r--r--absl/flags/CMakeLists.txt1
-rw-r--r--absl/flags/flag_test.cc64
-rw-r--r--absl/flags/marshalling.cc12
-rw-r--r--absl/flags/marshalling.h2
-rw-r--r--absl/flags/marshalling_test.cc34
-rw-r--r--absl/strings/char_formatting_test.cc54
-rw-r--r--absl/strings/internal/str_format/arg.cc16
-rw-r--r--absl/strings/internal/str_format/arg.h16
-rw-r--r--absl/strings/str_cat.h18
-rw-r--r--absl/strings/str_format.h1
13 files changed, 164 insertions, 61 deletions
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 7c0007ad..bf5aa7cf 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -148,7 +148,7 @@ TEST(ThrowingValueTest, ThrowingBitwiseOps) {
ThrowingValue<> bomb1, bomb2;
TestOp([&bomb1]() { ~bomb1; });
- TestOp([&]() { bomb1& bomb2; });
+ TestOp([&]() { bomb1 & bomb2; });
TestOp([&]() { bomb1 | bomb2; });
TestOp([&]() { bomb1 ^ bomb2; });
}
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h
index 815b8d23..1beb2ee4 100644
--- a/absl/base/internal/direct_mmap.h
+++ b/absl/base/internal/direct_mmap.h
@@ -72,7 +72,7 @@ namespace base_internal {
// Platform specific logic extracted from
// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
- off64_t offset) noexcept {
+ off_t offset) noexcept {
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
defined(__m68k__) || defined(__sh__) || \
(defined(__hppa__) && !defined(__LP64__)) || \
@@ -102,7 +102,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
#else
return reinterpret_cast<void*>(
syscall(SYS_mmap2, start, length, prot, flags, fd,
- static_cast<off_t>(offset / pagesize)));
+ static_cast<unsigned long>(offset / pagesize))); // NOLINT
#endif
#elif defined(__s390x__)
// On s390x, mmap() arguments are passed in memory.
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 583e6d94..50bf387c 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -388,6 +388,7 @@ cc_test(
":reflection",
"//absl/base:core_headers",
"//absl/base:malloc_internal",
+ "//absl/numeric:int128",
"//absl/strings",
"//absl/time",
"@com_google_googletest//:gtest_main",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 6525eb2a..b20463f5 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -346,6 +346,7 @@ absl_cc_test(
absl::flags_internal
absl::flags_marshalling
absl::flags_reflection
+ absl::int128
absl::strings
absl::time
GTest::gtest_main
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 845b4eba..f9cda02e 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -34,6 +34,7 @@
#include "absl/flags/marshalling.h"
#include "absl/flags/reflection.h"
#include "absl/flags/usage_config.h"
+#include "absl/numeric/int128.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
@@ -127,6 +128,11 @@ TEST_F(FlagTest, Traits) {
flags::FlagValueStorageKind::kAlignedBuffer);
EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
flags::FlagValueStorageKind::kAlignedBuffer);
+
+ EXPECT_EQ(flags::StorageKind<absl::int128>(),
+ flags::FlagValueStorageKind::kSequenceLocked);
+ EXPECT_EQ(flags::StorageKind<absl::uint128>(),
+ flags::FlagValueStorageKind::kSequenceLocked);
}
// --------------------------------------------------------------------
@@ -135,6 +141,8 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
flags::FlagHelpKind::kLiteral};
using String = std::string;
+using int128 = absl::int128;
+using uint128 = absl::uint128;
#if !defined(_MSC_VER) || defined(__clang__)
#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \
@@ -171,6 +179,8 @@ DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord);
DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord);
DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(int128, 13, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(uint128, 14, kGenFunc);
template <typename T>
bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
@@ -202,6 +212,8 @@ TEST_F(FlagTest, TestConstruction) {
TEST_CONSTRUCTED_FLAG(double);
TEST_CONSTRUCTED_FLAG(String);
TEST_CONSTRUCTED_FLAG(UDT);
+ TEST_CONSTRUCTED_FLAG(int128);
+ TEST_CONSTRUCTED_FLAG(uint128);
}
// --------------------------------------------------------------------
@@ -220,6 +232,8 @@ ABSL_DECLARE_FLAG(double, test_flag_09);
ABSL_DECLARE_FLAG(float, test_flag_10);
ABSL_DECLARE_FLAG(std::string, test_flag_11);
ABSL_DECLARE_FLAG(absl::Duration, test_flag_12);
+ABSL_DECLARE_FLAG(absl::int128, test_flag_13);
+ABSL_DECLARE_FLAG(absl::uint128, test_flag_14);
namespace {
@@ -251,6 +265,10 @@ TEST_F(FlagTest, TestFlagDeclaration) {
"test_flag_11");
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
"test_flag_12");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(),
+ "test_flag_13");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(),
+ "test_flag_14");
}
#endif // !ABSL_FLAGS_STRIP_NAMES
@@ -270,6 +288,9 @@ ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12");
+ABSL_FLAG(absl::int128, test_flag_13, absl::MakeInt128(-1, 0), "test flag 13");
+ABSL_FLAG(absl::uint128, test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD),
+ "test flag 14");
namespace {
@@ -384,6 +405,24 @@ TEST_F(FlagTest, TestFlagDefinition) {
absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(),
expected_file_name))
<< absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename();
+
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(),
+ "test_flag_13");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Help(),
+ "test flag 13");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename();
+
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(),
+ "test_flag_14");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Help(),
+ "test flag 14");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename();
}
#endif // !ABSL_FLAGS_STRIP_NAMES
@@ -414,6 +453,10 @@ TEST_F(FlagTest, TestDefault) {
"");
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(),
"10m");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).DefaultValue(),
+ "-18446744073709551616");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).DefaultValue(),
+ "1152827684197027293");
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(),
"true");
@@ -439,6 +482,10 @@ TEST_F(FlagTest, TestDefault) {
"");
EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(),
"10m");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).CurrentValue(),
+ "-18446744073709551616");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).CurrentValue(),
+ "1152827684197027293");
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
@@ -452,6 +499,9 @@ TEST_F(FlagTest, TestDefault) {
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14),
+ absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
}
// --------------------------------------------------------------------
@@ -553,6 +603,13 @@ TEST_F(FlagTest, TestGetSet) {
absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110));
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110));
+
+ absl::SetFlag(&FLAGS_test_flag_13, absl::MakeInt128(-1, 0));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0));
+
+ absl::SetFlag(&FLAGS_test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14),
+ absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
}
// --------------------------------------------------------------------
@@ -582,6 +639,11 @@ TEST_F(FlagTest, TestGetViaReflection) {
EXPECT_EQ(*handle->TryGet<std::string>(), "");
handle = absl::FindCommandLineFlag("test_flag_12");
EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
+ handle = absl::FindCommandLineFlag("test_flag_13");
+ EXPECT_EQ(*handle->TryGet<absl::int128>(), absl::MakeInt128(-1, 0));
+ handle = absl::FindCommandLineFlag("test_flag_14");
+ EXPECT_EQ(*handle->TryGet<absl::uint128>(),
+ absl::MakeUint128(0, 0xFFFAAABBBCCCDDD));
}
// --------------------------------------------------------------------
@@ -980,7 +1042,7 @@ TEST_F(FlagTest, TesTypeWrappingEnum) {
// This is a compile test to ensure macros are expanded within ABSL_FLAG and
// ABSL_DECLARE_FLAG.
-#define FLAG_NAME_MACRO(name) prefix_ ## name
+#define FLAG_NAME_MACRO(name) prefix_##name
ABSL_DECLARE_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag));
ABSL_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag), 0,
"Testing macro expansion within ABSL_FLAG");
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc
index cf6312b1..50b7b331 100644
--- a/absl/flags/marshalling.cc
+++ b/absl/flags/marshalling.cc
@@ -19,6 +19,7 @@
#include <cmath>
#include <limits>
+#include <sstream>
#include <string>
#include <type_traits>
#include <vector>
@@ -198,6 +199,17 @@ std::string Unparse(long v) { return absl::StrCat(v); }
std::string Unparse(unsigned long v) { return absl::StrCat(v); }
std::string Unparse(long long v) { return absl::StrCat(v); }
std::string Unparse(unsigned long long v) { return absl::StrCat(v); }
+std::string Unparse(absl::int128 v) {
+ std::stringstream ss;
+ ss << v;
+ return ss.str();
+}
+std::string Unparse(absl::uint128 v) {
+ std::stringstream ss;
+ ss << v;
+ return ss.str();
+}
+
template <typename T>
std::string UnparseFloatingPointVal(T v) {
// digits10 is guaranteed to roundtrip correctly in string -> value -> string
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 21d955d5..301213a9 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -313,6 +313,8 @@ std::string Unparse(long v); // NOLINT
std::string Unparse(unsigned long v); // NOLINT
std::string Unparse(long long v); // NOLINT
std::string Unparse(unsigned long long v); // NOLINT
+std::string Unparse(absl::int128 v);
+std::string Unparse(absl::uint128 v);
std::string Unparse(float v);
std::string Unparse(double v);
diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc
index d996ca7f..57356672 100644
--- a/absl/flags/marshalling_test.cc
+++ b/absl/flags/marshalling_test.cc
@@ -981,6 +981,40 @@ TEST(MarshallingTest, TestUint64Unparsing) {
// --------------------------------------------------------------------
+TEST(MarshallingTest, TestInt128Unparsing) {
+ absl::int128 value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = -1;
+ EXPECT_EQ(absl::UnparseFlag(value), "-1");
+ value = 123456789L;
+ EXPECT_EQ(absl::UnparseFlag(value), "123456789");
+ value = -987654321L;
+ EXPECT_EQ(absl::UnparseFlag(value), "-987654321");
+ value = 0x7FFFFFFFFFFFFFFF;
+ EXPECT_EQ(absl::UnparseFlag(value), "9223372036854775807");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint128Unparsing) {
+ absl::uint128 value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = 123456789L;
+ EXPECT_EQ(absl::UnparseFlag(value), "123456789");
+ value = absl::MakeUint128(0, 0xFFFFFFFFFFFFFFFF);
+ EXPECT_EQ(absl::UnparseFlag(value), "18446744073709551615");
+}
+
+// --------------------------------------------------------------------
+
TEST(MarshallingTest, TestFloatUnparsing) {
float value;
diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc
index 60416af3..1692da70 100644
--- a/absl/strings/char_formatting_test.cc
+++ b/absl/strings/char_formatting_test.cc
@@ -37,17 +37,12 @@ TEST(CharFormatting, CharEnum) {
auto v = static_cast<CharEnum>('A');
// Desired behavior: format as decimal
- // (No APIs do this today.)
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
-
- // Legacy behavior: does not compile:
- // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
// Legacy behavior: format as character:
- // Some older versions of gcc behave differently in this one case.
+ // Some older versions of gcc behave differently in this one case
#if !defined(__GNUC__) || defined(__clang__)
EXPECT_EQ(absl::Substitute("$0B", v), "AB");
#endif
@@ -57,14 +52,9 @@ enum class CharEnumClass: char {};
TEST(CharFormatting, CharEnumClass) {
auto v = static_cast<CharEnumClass>('A');
- // Desired behavior: format as decimal
- // (No APIs do this today.)
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
-
- // Legacy behavior: does not compile:
- // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
// Legacy behavior: format as character:
EXPECT_EQ(absl::Substitute("$0B", v), "AB");
@@ -76,9 +66,7 @@ TEST(CharFormatting, UnsignedChar) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // Legacy behavior: does not compile:
- // EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
const unsigned char w = 255;
@@ -93,9 +81,7 @@ TEST(CharFormatting, SignedChar) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // Legacy behavior: does not compile:
- // EXPECT_EQ(absl::StrFormat("%vB", v), "AB");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
const signed char w = -128;
@@ -110,14 +96,13 @@ TEST(CharFormatting, UnsignedCharEnum) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
auto w = static_cast<UnsignedCharEnum>(255);
EXPECT_EQ(absl::StrCat(w, "B"), "255B");
EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+ EXPECT_EQ(absl::StrFormat("%vB", w), "255B");
}
enum SignedCharEnum : signed char {};
@@ -127,14 +112,13 @@ TEST(CharFormatting, SignedCharEnum) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
auto w = static_cast<SignedCharEnum>(-128);
EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+ EXPECT_EQ(absl::StrFormat("%vB", w), "-128B");
}
enum class UnsignedCharEnumClass : unsigned char {};
@@ -144,14 +128,13 @@ TEST(CharFormatting, UnsignedCharEnumClass) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
auto w = static_cast<UnsignedCharEnumClass>(255);
EXPECT_EQ(absl::StrCat(w, "B"), "255B");
EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+ EXPECT_EQ(absl::StrFormat("%vB", w), "255B");
}
enum SignedCharEnumClass : signed char {};
@@ -161,14 +144,13 @@ TEST(CharFormatting, SignedCharEnumClass) {
// Desired behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
-
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
// Signedness check
auto w = static_cast<SignedCharEnumClass>(-128);
EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+ EXPECT_EQ(absl::StrFormat("%vB", w), "-128B");
}
#ifdef __cpp_lib_byte
@@ -177,12 +159,10 @@ TEST(CharFormatting, StdByte) {
// Desired behavior: format as 0xff
// (No APIs do this today.)
- // BUG: internally fails
- EXPECT_EQ(absl::StrFormat("%vB", v), "");
-
// Legacy behavior: format as decimal:
EXPECT_EQ(absl::StrCat(v, "B"), "65B");
EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+ EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
}
#endif // _cpp_lib_byte
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index 6033a75a..7f4057f9 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -461,18 +461,18 @@ CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-CharConvertResult FormatConvertImpl(signed char v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+
+// ==================== Ints ====================
+IntegralConvertResult FormatConvertImpl(signed char v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-CharConvertResult FormatConvertImpl(unsigned char v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-
-// ==================== Ints ====================
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index e4b16628..3ce30feb 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -279,14 +279,14 @@ FloatingConvertResult FormatConvertImpl(long double v,
// Chars.
CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-CharConvertResult FormatConvertImpl(signed char v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
-CharConvertResult FormatConvertImpl(unsigned char v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
// Ints.
+IntegralConvertResult FormatConvertImpl(signed char v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
@@ -441,7 +441,7 @@ class FormatArgImpl {
// For everything else:
// - Decay char* and char arrays into `const char*`
// - Decay any other pointer to `const void*`
- // - Decay all enums to their underlying type.
+ // - Decay all enums to the integral promotion of their underlying type.
// - Decay function pointers to void*.
template <typename T, typename = void>
struct DecayType {
@@ -461,7 +461,7 @@ class FormatArgImpl {
!str_format_internal::HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value &&
std::is_enum<T>::value>::type> {
- using type = typename std::underlying_type<T>::type;
+ using type = decltype(+typename std::underlying_type<T>::type());
};
public:
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index fcd48c4e..d5f71ff0 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -374,14 +374,24 @@ class AlphaNum {
const char* data() const { return piece_.data(); }
absl::string_view Piece() const { return piece_; }
- // Normal enums are already handled by the integer formatters.
- // This overload matches only scoped enums.
+ // Match unscoped enums. Use integral promotion so that a `char`-backed
+ // enum becomes a wider integral type AlphaNum will accept.
template <typename T,
typename = typename std::enable_if<
- std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
+ std::is_enum<T>{} && std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value>::type>
AlphaNum(T e) // NOLINT(runtime/explicit)
- : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
+ : AlphaNum(+e) {}
+
+ // This overload matches scoped enums. We must explicitly cast to the
+ // underlying type, but use integral promotion for the same reason as above.
+ template <typename T,
+ typename std::enable_if<
+ std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
+ !strings_internal::HasAbslStringify<T>::value,
+ char*>::type = nullptr>
+ AlphaNum(T e) // NOLINT(runtime/explicit)
+ : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {}
// vector<bool>::reference and const_reference require special help to
// convert to `AlphaNum` because it requires two user defined conversions.
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index fc4bf39e..023e4350 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -259,6 +259,7 @@ class FormatCountCapture {
// * Characters: `char`, `signed char`, `unsigned char`
// * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`,
// `unsigned long`, `long long`, `unsigned long long`
+// * Enums: printed as their underlying integral value
// * Floating-point: `float`, `double`, `long double`
//
// However, in the `str_format` library, a format conversion specifies a broader