Improve compiler errors for mismatched ParsedFormat inputs.

PiperOrigin-RevId: 448582508
Change-Id: I67fbff5f42a083e093ea2c20749e073ca03feb0b
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 1cf58ca..e909216 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -1116,6 +1116,7 @@
         "//absl/numeric:representation",
         "//absl/types:optional",
         "//absl/types:span",
+        "//absl/utility",
     ],
 )
 
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index c4358a1..a1b8d6e 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -414,6 +414,7 @@
     absl::core_headers
     absl::numeric_representation
     absl::type_traits
+    absl::utility
     absl::int128
     absl::span
 )
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index b26cff6..dcaa5dd 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -25,6 +25,7 @@
 #include "absl/strings/internal/str_format/checker.h"
 #include "absl/strings/internal/str_format/parser.h"
 #include "absl/types/span.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -87,6 +88,36 @@
     : public MakeDependent<UntypedFormatSpec, Args...>::type {
   using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
 
+  template <bool res>
+  struct ErrorMaker {
+    constexpr bool operator()(int) const { return res; }
+  };
+
+  template <int i, int j>
+  static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {},
+                                   ErrorMaker<i == j> ParametersPassed = {}) {
+    static_assert(SpecifierCount(i) == ParametersPassed(j),
+                  "Number of arguments passed must match the number of "
+                  "conversion specifiers.");
+    return true;
+  }
+
+  template <FormatConversionCharSet specified, FormatConversionCharSet passed,
+            int arg>
+  static constexpr bool CheckMatch(
+      ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) {
+    static_assert(MismatchedArgumentNumber(arg),
+                  "Passed argument must match specified format.");
+    return true;
+  }
+
+  template <FormatConversionCharSet... C, size_t... I>
+  static bool CheckMatches(absl::index_sequence<I...>) {
+    bool res[] = {true, CheckMatch<Args, C, I + 1>()...};
+    (void)res;
+    return true;
+  }
+
  public:
 #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
@@ -133,13 +164,12 @@
 
 #endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
 
-  template <
-      FormatConversionCharSet... C,
-      typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
-      typename = typename std::enable_if<AllOf(Contains(Args,
-                                                        C)...)>::type>
+  template <FormatConversionCharSet... C>
   FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
-      : Base(&pc) {}
+      : Base(&pc) {
+    CheckArity<sizeof...(C), sizeof...(Args)>();
+    CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{});
+  }
 };
 
 class Streamable {