Adds support for "%v" in absl::StrFormat and related functions for bool values. Note that %v prints bool values as "true" and "false" rather than "1" and "0".

PiperOrigin-RevId: 475651689
Change-Id: I24b3749d85b5bb7cbc18653d629271a8b2b07d08
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index b0e06bf..967fe9c 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -344,7 +344,7 @@
       return ConvertFloatImpl(static_cast<double>(v), conv, sink);
 
     default:
-       ABSL_ASSUME(false);
+      ABSL_ASSUME(false);
   }
 
   if (conv.is_basic()) {
@@ -376,6 +376,15 @@
 
 }  // namespace
 
+bool ConvertBoolArg(bool v, FormatSinkImpl *sink) {
+  if (v) {
+    sink->Append("true");
+  } else {
+    sink->Append("false");
+  }
+  return true;
+}
+
 // ==================== Strings ====================
 StringConvertResult FormatConvertImpl(const std::string &v,
                                       const FormatConversionSpecImpl conv,
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 3c2bb3e..2dfbf72 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -186,6 +186,8 @@
     FormatConversionCharSetInternal::kNumeric,
     FormatConversionCharSetInternal::kStar)>;
 
+bool ConvertBoolArg(bool v, FormatSinkImpl* sink);
+
 // Floats.
 FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
@@ -234,9 +236,16 @@
 IntegralConvertResult FormatConvertImpl(uint128 v,
                                         FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink);
+
+// This function needs to be a template due to ambiguity regarding type
+// conversions.
 template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
 IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
                                         FormatSinkImpl* sink) {
+  if (conv.conversion_char() == FormatConversionCharInternal::v) {
+    return {ConvertBoolArg(v, sink)};
+  }
+
   return FormatConvertImpl(static_cast<int>(v), conv, sink);
 }
 
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 2774cfe..4b77805 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -265,7 +265,7 @@
     std::ostringstream oss;
     oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
     int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(),  //
-                                 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
+                              123, 3, 49, "multistreaming!!!", 1.01, 1.01);
     ASSERT_TRUE(oss) << fmt;
     ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
         << fmt_result;
@@ -644,6 +644,11 @@
   EXPECT_EQ(StrFormat("%zd", int{1}), "1");
   EXPECT_EQ(StrFormat("%td", int{1}), "1");
   EXPECT_EQ(StrFormat("%qd", int{1}), "1");
+
+  // Bool is handled correctly depending on whether %v is used
+  EXPECT_EQ(StrFormat("%v", true), "true");
+  EXPECT_EQ(StrFormat("%v", false), "false");
+  EXPECT_EQ(StrFormat("%d", true), "1");
 }
 
 using str_format_internal::ExtendedParsedFormat;