Move rare flag callbacks and dynamic defaults into process-wide maps.

Few `absl::Flag` instances ever register a mutation callback or override their default value at runtime. Despite that, every `absl::flags_internal::FlagImpl` in writable data reserves an 8-byte callback pointer and mutates its default-value union in place.

Store registered callbacks and dynamic default overrides in process-wide `ThreadSafeMap` instances instead, gated by a 1-bit callback indicator and the existing 2-bit default-kind field so flags without overrides never acquire a map lock. Removing the inline callback pointer shrinks `FlagImpl` from 80 bytes to 72 bytes and scalar flags from 88 bytes to 80 bytes, while keeping the initial default-value union immutable for upcoming descriptor splitting.

PiperOrigin-RevId: 1006216114
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 59771c7..a43151f 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -240,6 +240,7 @@
         "//absl/base:dynamic_annotations",
         "//absl/base:fast_type_id",
         "//absl/base:no_destructor",
+        "//absl/container:flat_hash_map",
         "//absl/memory",
         "//absl/meta:type_traits",
         "//absl/strings",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 162b654..788ff0a 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -201,6 +201,7 @@
     absl::flags_commandlineflag_internal
     absl::flags_config
     absl::flags_marshalling
+    absl::flat_hash_map
     absl::meta
     absl::no_destructor
     absl::synchronization
diff --git a/absl/flags/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc
index b6d01b2..35ce567 100644
--- a/absl/flags/commandlineflag_test.cc
+++ b/absl/flags/commandlineflag_test.cc
@@ -16,7 +16,9 @@
 #include "absl/flags/commandlineflag.h"
 
 #include <memory>
+#include <optional>
 #include <string>
+#include <vector>
 
 #include "gtest/gtest.h"
 #include "absl/flags/config.h"
@@ -38,6 +40,21 @@
 ABSL_FLAG(int, int_flag2, 201, "");
 ABSL_FLAG(std::string, string_flag2, "dflt", "");
 
+using CustomIntAlias = int;
+using CustomStringListAlias = std::vector<std::string>;
+
+struct CustomFlagUDT {};
+bool AbslParseFlag(absl::string_view, CustomFlagUDT*, std::string*) {
+  return true;
+}
+std::string AbslUnparseFlag(const CustomFlagUDT&) { return ""; }
+
+ABSL_FLAG(CustomIntAlias, int_alias_flag, 7, "");
+ABSL_FLAG(CustomStringListAlias, string_list_alias_flag, {}, "");
+ABSL_FLAG(std::vector<std::string>, string_vec_flag, {}, "");
+ABSL_FLAG(std::optional<int>, optional_int_flag, std::nullopt, "");
+ABSL_FLAG(CustomFlagUDT, custom_udt_flag, {}, "");
+
 namespace {
 
 namespace flags = absl::flags_internal;
@@ -233,4 +250,67 @@
   // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
 }
 
+void MakeEmptyString(void* dst) { new (dst) std::string(); }
+
+constexpr flags::FlagHelpArg kCompatHelpArg{flags::FlagHelpMsg("help"),
+                                            flags::FlagHelpKind::kLiteral};
+constexpr flags::FlagDefaultArg kCompatStringDefaultArg{
+    flags::FlagDefaultSrc(&MakeEmptyString), flags::FlagDefaultKind::kGenFunc};
+constexpr absl::Flag<std::string> kCompat4ArgFlag{"compat4", "file",
+                                                  kCompatHelpArg,
+                                                  kCompatStringDefaultArg};
+constexpr absl::Flag<std::string> kCompat5ArgCommonFlag{
+    "compat5_common", "std::string", "file", kCompatHelpArg,
+    kCompatStringDefaultArg};
+constexpr absl::Flag<std::string> kCompat5ArgCustomFlag{
+    "compat5_custom", "UnlistedStringAlias", "file", kCompatHelpArg,
+    kCompatStringDefaultArg};
+
+TEST_F(CommandLineFlagTest, TestTypeName) {
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("int_flag")),
+            "int");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("string_flag")),
+            "std::string");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("string_vec_flag")),
+            "std::vector<std::string>");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("optional_int_flag")),
+            "std::optional<int>");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("int_alias_flag")),
+            "CustomIntAlias");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("string_list_alias_flag")),
+            "CustomStringListAlias");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                *absl::FindCommandLineFlag("custom_udt_flag")),
+            "CustomFlagUDT");
+
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                absl::GetFlagReflectionHandle(kCompat4ArgFlag)),
+            "");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                absl::GetFlagReflectionHandle(kCompat5ArgCommonFlag)),
+            "std::string");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                absl::GetFlagReflectionHandle(kCompat5ArgCustomFlag)),
+            "");
+}
+
+TEST(CommandLineFlagStrippedTest, TestStrippedTypeName) {
+#if ABSL_FLAGS_STRIP_NAMES
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_int_flag).Name(), "");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                absl::GetFlagReflectionHandle(FLAGS_int_flag)),
+            "");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_custom_udt_flag).Name(), "");
+  EXPECT_EQ(flags::PrivateHandleAccessor::TypeName(
+                absl::GetFlagReflectionHandle(FLAGS_custom_udt_flag)),
+            "");
+#endif
+}
+
 }  // namespace
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 2e9a9e6..ea2b889 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -207,6 +207,9 @@
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
 #define ABSL_FLAG_IMPL_TYPENAME(txt) ""
 #define ABSL_FLAG_IMPL_FILENAME() ""
+#define ABSL_FLAG_IMPL_NAME_ARG(name) \
+  absl::flags_internal::FlagNameArg{"", absl::flags_internal::kEmptyFlagTypeId}
+#define ABSL_FLAG_IMPL_DECLARE_NAME_METHODS(name, Type)
 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                      \
   absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
                                                 nullptr)
@@ -214,6 +217,18 @@
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
 #define ABSL_FLAG_IMPL_TYPENAME(txt) txt
 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
+#define ABSL_FLAG_IMPL_NAME_ARG(name) \
+  absl::flags_internal::MakeFlagNameArg<AbslFlagDefaultGenFor##name>()
+#define ABSL_FLAG_IMPL_DECLARE_NAME_METHODS(name, Type)      \
+  static constexpr const char* AbslFlagName() {              \
+    return #name;                                            \
+  }                                                          \
+  static constexpr absl::string_view AbslFlagTypeName() {    \
+    return absl::string_view(#Type, sizeof(#Type) - 1);      \
+  }                                                          \
+  static constexpr const char* AbslFlagPackedNameAndType() { \
+    return #name "\0" #Type;                                 \
+  }
 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag)                                     \
   absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
                                                __FILE__)
@@ -241,7 +256,7 @@
     /* default value argument. That keeps temporaries alive */               \
     /* long enough for NonConst to work correctly.          */               \
     static constexpr absl::string_view Value(                                \
-        absl::string_view absl_flag_help ABSL_ATTRIBUTE_LIFETIME_BOUND  =     \
+        absl::string_view absl_flag_help ABSL_ATTRIBUTE_LIFETIME_BOUND =     \
             ABSL_FLAG_IMPL_FLAGHELP(txt)) {                                  \
       return absl_flag_help;                                                 \
     }                                                                        \
@@ -258,6 +273,7 @@
     static void Gen(void* absl_flag_default_loc) {                            \
       new (absl_flag_default_loc) Type(AbslFlagDefaultGenFor##name{}.value);  \
     }                                                                         \
+    ABSL_FLAG_IMPL_DECLARE_NAME_METHODS(name, Type)                           \
   };
 
 // ABSL_FLAG_IMPL
@@ -265,17 +281,16 @@
 // Note: Name of registrar object is not arbitrary. It is used to "grab"
 // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
 // of defining two flags with names foo and nofoo.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
-  extern ::absl::Flag<Type> FLAGS_##name;                             \
-  namespace absl /* block flags in namespaces */ {}                   \
-  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)   \
-  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help)                     \
-  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                      \
-      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_TYPENAME(#Type), \
-      ABSL_FLAG_IMPL_FILENAME(), ABSL_FLAG_IMPL_HELP_ARG(name),       \
-      ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)};                        \
-  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;     \
-  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =           \
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)                       \
+  extern ::absl::Flag<Type> FLAGS_##name;                                     \
+  namespace absl /* block flags in namespaces */ {}                           \
+  ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value)           \
+  ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help)                             \
+  ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{                              \
+      ABSL_FLAG_IMPL_NAME_ARG(name), ABSL_FLAG_IMPL_FILENAME(),               \
+      ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
+  extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name;             \
+  absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name =                   \
       ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 
 // ABSL_RETIRED_FLAG
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 5cacf64..5990e10 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -137,6 +137,17 @@
             flags::FlagValueStorageKind::kSequenceLocked);
   EXPECT_EQ(flags::StorageKind<absl::uint128>(),
             flags::FlagValueStorageKind::kSequenceLocked);
+
+  // These sizes are not hard limits, but we want to keep per-flag size as
+  // small as possible because production binaries may define thousands of
+  // flags.
+  if (sizeof(void*) == 8) {
+    EXPECT_EQ(sizeof(flags::FlagImpl), 72);
+    EXPECT_EQ(sizeof(absl::Flag<bool>), 80);
+    EXPECT_EQ(sizeof(absl::Flag<int>), 80);
+    EXPECT_EQ(sizeof(absl::Flag<int64_t>), 80);
+    EXPECT_EQ(sizeof(absl::Flag<double>), 80);
+  }
 }
 
 // --------------------------------------------------------------------
@@ -151,9 +162,9 @@
 #define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                        \
   constexpr flags::FlagDefaultArg f1default##T{                            \
       flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};     \
-  constexpr absl::Flag<T> f1##T{"f1", #T, "file", help_arg, f1default##T}; \
+  constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T};     \
   ABSL_CONST_INIT absl::Flag<T> f2##T {                                    \
-    "f2", #T, "file",                                                      \
+    "f2", "file",                                                          \
         {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
         flags::FlagDefaultArg {                                            \
       flags::FlagDefaultSrc(&TestMakeDflt<T>),                             \
@@ -175,6 +186,11 @@
 DEFINE_CONSTRUCTED_FLAG(int128, 13, kGenFunc);
 DEFINE_CONSTRUCTED_FLAG(uint128, 14, kGenFunc);
 
+constexpr absl::Flag<String> f_compat_5arg{
+    "f_compat", "std::string", "file", help_arg,
+    flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<String>),
+                          flags::FlagDefaultKind::kGenFunc}};
+
 template <typename T>
 bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
   EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1");
@@ -207,6 +223,10 @@
   TEST_CONSTRUCTED_FLAG(UDT);
   TEST_CONSTRUCTED_FLAG(int128);
   TEST_CONSTRUCTED_FLAG(uint128);
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f_compat_5arg).Name(), "f_compat");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f_compat_5arg).Help(),
+            "literal help");
+  EXPECT_EQ(absl::GetFlagReflectionHandle(f_compat_5arg).Filename(), "file");
 }
 
 // --------------------------------------------------------------------
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 662b342..d32992a 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -39,6 +39,7 @@
 #include "absl/base/no_destructor.h"
 #include "absl/base/optimization.h"
 #include "absl/base/thread_annotations.h"
+#include "absl/container/flat_hash_map.h"
 #include "absl/flags/config.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/usage_config.h"
@@ -104,6 +105,55 @@
   s_freelist->push_back(p);
 }
 
+template <typename K, typename V>
+class ThreadSafeMap {
+ public:
+  V Get(const K& key) {
+    absl::MutexLock l(mutex_);
+    auto it = map_.find(key);
+    return it != map_.end() ? it->second : V{};
+  }
+
+  V Set(const K& key, V new_val) {
+    absl::MutexLock l(mutex_);
+    return std::exchange(map_[key], new_val);
+  }
+
+  template <typename Factory>
+  V GetOrCreate(const K& key, Factory factory) {
+    absl::MutexLock l(mutex_);
+    V& val = map_[key];
+    if (val == V{}) {
+      val = factory();
+    }
+    return val;
+  }
+
+ private:
+  absl::Mutex mutex_;
+  absl::flat_hash_map<K, V> map_ ABSL_GUARDED_BY(mutex_);
+};
+
+FlagCallback* GetOrCreateCallback(const FlagImpl* flag) {
+  static absl::NoDestructor<ThreadSafeMap<const FlagImpl*, FlagCallback*>>
+      callbacks;
+  return callbacks->GetOrCreate(flag, [] { return new FlagCallback; });
+}
+
+ThreadSafeMap<const FlagImpl*, void*>& DynamicDefaults() {
+  static absl::NoDestructor<ThreadSafeMap<const FlagImpl*, void*>>
+      dynamic_defaults;
+  return *dynamic_defaults;
+}
+
+void* GetDynamicDefault(const FlagImpl* flag) {
+  return DynamicDefaults().Get(flag);
+}
+
+void* SetDynamicDefault(const FlagImpl* flag, void* new_val) {
+  return DynamicDefaults().Set(flag, new_val);
+}
+
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -296,7 +346,7 @@
   void* res = nullptr;
   switch (DefaultKind()) {
     case FlagDefaultKind::kDynamicValue:
-      res = flags_internal::Clone(op_, default_value_.dynamic_value);
+      res = flags_internal::Clone(op_, GetDynamicDefault(this));
       break;
     case FlagDefaultKind::kGenFunc:
       res = flags_internal::Alloc(op_);
@@ -354,7 +404,12 @@
 
 absl::string_view FlagImpl::Name() const { return name_; }
 
-absl::string_view FlagImpl::TypeName() const { return type_name_; }
+absl::string_view FlagImpl::TypeName() const {
+  if (ABSL_PREDICT_TRUE(type_id_ != kCustomFlagTypeId)) {
+    return kCommonFlagTypeNames[type_id_];
+  }
+  return name_ + std::strlen(name_) + 1;
+}
 
 std::string FlagImpl::Filename() const {
   return flags_internal::GetUsageConfig().normalize_filename(filename_);
@@ -414,20 +469,20 @@
 void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
   absl::MutexLock l(DataGuard());
 
-  if (callback_ == nullptr) {
-    callback_ = new FlagCallback;
-  }
-  callback_->func = mutation_callback;
+  FlagCallback* cb = GetOrCreateCallback(this);
+  cb->func = mutation_callback;
+  has_callback_ = true;
 
   InvokeCallback();
 }
 
 void FlagImpl::InvokeCallback() const {
-  if (!callback_) return;
+  if (!has_callback_) return;
 
+  FlagCallback* cb_entry = GetOrCreateCallback(this);
   // Make a copy of the C-style function pointer that we are about to invoke
   // before we release the lock guarding it.
-  FlagCallbackFunc cb = callback_->func;
+  FlagCallbackFunc cb = cb_entry->func;
 
   // If the flag has a mutation callback this function invokes it. While the
   // callback is being invoked the primary flag's mutex is unlocked and it is
@@ -441,7 +496,7 @@
   // completed. Requires that *primary_lock be held in exclusive mode; it may be
   // released and reacquired by the implementation.
   MutexRelock relock(DataGuard());
-  absl::MutexLock lock(callback_->guard);
+  absl::MutexLock lock(cb_entry->guard);
   cb();
 }
 
@@ -712,18 +767,17 @@
       auto tentative_value = TryParse(value, err);
       if (!tentative_value) return false;
 
+      void* new_default = tentative_value.release();
+      void* old_value = SetDynamicDefault(this, new_default);
       if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
-        void* old_value = default_value_.dynamic_value;
-        default_value_.dynamic_value = tentative_value.release();
         tentative_value.reset(old_value);
       } else {
-        default_value_.dynamic_value = tentative_value.release();
         def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue);
       }
 
       if (!modified_) {
         // Need to set both default value *and* current, in this case.
-        StoreValue(default_value_.dynamic_value, source);
+        StoreValue(new_default, source);
         modified_ = false;
       }
       break;
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index c12c924..6793202 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -21,6 +21,7 @@
 
 #include <atomic>
 #include <cstring>
+#include <iterator>
 #include <memory>
 #include <string>
 #include <type_traits>
@@ -166,7 +167,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Flag help auxiliary structs.
+// Flag help and name/type-name auxiliary structs.
 
 // This is help argument for absl::Flag encapsulating the string literal pointer
 // or pointer to function generating it as well as enum discriminating two
@@ -184,6 +185,81 @@
   }
 };
 
+inline constexpr uint8_t kEmptyFlagTypeId = 0;
+inline constexpr uint8_t kCustomFlagTypeId = 31;
+
+// Common macro-stringified `#Type` spellings stored as a 5-bit ID in `FlagImpl`
+// so common flags avoid emitting a per-flag type-name string. Entry 0 (`""`) is
+// used when flag names are stripped or omitted; ID 31 (`kCustomFlagTypeId`)
+// indicates that `name_` points to a packed `"<name>\0<type_name>\0"` array.
+inline constexpr absl::string_view kCommonFlagTypeNames[] = {
+    "",
+    "bool",
+    "int",
+    "int16_t",
+    "uint16_t",
+    "int32_t",
+    "uint32_t",
+    "int64_t",
+    "uint64_t",
+    "size_t",
+    "float",
+    "double",
+    "std::string",
+    "string",
+    "std::vector<std::string>",
+    "absl::Duration",
+    "absl::Time",
+    "absl::int128",
+    "absl::uint128",
+    "std::int32_t",
+    "std::int64_t",
+    "std::optional<bool>",
+    "std::optional<int>",
+    "std::optional<int32_t>",
+    "std::optional<uint32_t>",
+    "std::optional<int64_t>",
+    "std::optional<uint64_t>",
+    "std::optional<size_t>",
+    "std::optional<double>",
+    "std::optional<std::string>",
+    "std::optional<absl::Duration>",
+};
+static_assert(std::size(kCommonFlagTypeNames) == kCustomFlagTypeId,
+              "kCommonFlagTypeNames must have kCustomFlagTypeId entries");
+
+constexpr uint8_t LookupCommonFlagTypeId(absl::string_view type_name) {
+  for (size_t i = 0; i < kCustomFlagTypeId; ++i) {
+    if (kCommonFlagTypeNames[i] == type_name) {
+      return static_cast<uint8_t>(i);
+    }
+  }
+  return kCustomFlagTypeId;
+}
+
+constexpr uint8_t LookupCommonOrEmptyFlagTypeId(const char* type_name) {
+  if (type_name == nullptr) return kEmptyFlagTypeId;
+  size_t len = 0;
+  while (type_name[len] != '\0') ++len;
+  const uint8_t id = LookupCommonFlagTypeId(absl::string_view(type_name, len));
+  return id == kCustomFlagTypeId ? kEmptyFlagTypeId : id;
+}
+
+struct FlagNameArg {
+  const char* name;
+  uint8_t type_id;
+};
+
+template <typename Gen>
+constexpr FlagNameArg MakeFlagNameArg() {
+  constexpr uint8_t kTypeId = LookupCommonFlagTypeId(Gen::AbslFlagTypeName());
+  if constexpr (kTypeId != kCustomFlagTypeId) {
+    return {Gen::AbslFlagName(), kTypeId};
+  } else {
+    return {Gen::AbslFlagPackedNameAndType(), kCustomFlagTypeId};
+  }
+}
+
 template <typename Gen, size_t N = Gen::Value().size()>
 constexpr FixedCharArray<N + 1> HelpStringAsArray(int) {
   return FixedCharArray<N + 1>::FromLiteralString(
@@ -581,21 +657,20 @@
 #endif
 class FlagImpl final : public CommandLineFlag {
  public:
-  constexpr FlagImpl(const char* name, const char* type_name,
-                     const char* filename, FlagOpFn op, FlagHelpArg help,
-                     FlagValueStorageKind value_kind,
+  constexpr FlagImpl(FlagNameArg name, const char* filename, FlagOpFn op,
+                     FlagHelpArg help, FlagValueStorageKind value_kind,
                      FlagDefaultArg default_arg)
-      : name_(name),
-        type_name_(type_name),
+      : name_(name.name),
         filename_(filename),
         op_(op),
         help_(help.source),
         help_source_kind_(static_cast<uint8_t>(help.kind)),
         value_storage_kind_(static_cast<uint8_t>(value_kind)),
+        type_id_(name.type_id),
         def_kind_(static_cast<uint8_t>(default_arg.kind)),
         modified_(false),
         on_command_line_(false),
-        callback_(nullptr),
+        has_callback_(false),
         default_value_(default_arg.source),
         data_guard_{} {}
 
@@ -731,12 +806,10 @@
 
   // Immutable flag's state.
 
-  // Flags name passed to ABSL_FLAG as second arg.
+  // Flags name passed to ABSL_FLAG as second arg (followed by NUL-terminated
+  // type name when `type_id_ == kCustomFlagTypeId`).
   const char* const name_;
 
-  // Flags type passed to ABSL_FLAG as first arg.
-  const char* const type_name_;
-
   // The file name where ABSL_FLAG resides.
   const char* const filename_;
   // Type-specific operations vtable.
@@ -747,6 +820,9 @@
   const uint8_t help_source_kind_ : 1;
   // Kind of storage this flag is using for the flag's value.
   const uint8_t value_storage_kind_ : 2;
+  // Index into `kCommonFlagTypeNames`, or `kCustomFlagTypeId` when `name_`
+  // stores `"<name>\0<type_name>\0"`.
+  const uint8_t type_id_ : 5;
 
   uint8_t : 0;  // The bytes containing the const bitfields must not be
                 // shared with bytes containing the mutable bitfields.
@@ -760,6 +836,8 @@
   bool modified_ : 1 ABSL_GUARDED_BY(DataGuard());
   // Has this flag been specified on command line.
   bool on_command_line_ : 1 ABSL_GUARDED_BY(DataGuard());
+  // Has a mutation callback been registered on this flag?
+  bool has_callback_ : 1 ABSL_GUARDED_BY(DataGuard());
 
   // Unique tag for absl::call_once call to initialize this flag.
   absl::once_flag init_control_;
@@ -767,13 +845,9 @@
   // Sequence lock / mutation counter.
   flags_internal::SequenceLock seq_lock_;
 
-  // Optional flag's callback and absl::Mutex to guard the invocations.
-  FlagCallback* callback_ ABSL_GUARDED_BY(DataGuard());
-  // Either a pointer to the function generating the default value based on the
-  // value specified in ABSL_FLAG or pointer to the dynamically set default
-  // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
-  // these two cases.
-  FlagDefaultSrc default_value_;
+  // Initial default value source specified in ABSL_FLAG. Dynamic default
+  // overrides set via SET_FLAGS_DEFAULT are stored in a side table.
+  const FlagDefaultSrc default_value_;
 
   // This is reserved space for an absl::Mutex to guard flag data. It will be
   // initialized in FlagImpl::Init via placement new.
@@ -803,11 +877,21 @@
 template <typename T>
 class Flag {
  public:
-  constexpr Flag(const char* name, const char* type_name, const char* filename,
-                 FlagHelpArg help, const FlagDefaultArg default_arg)
-      : impl_(name, type_name, filename, &FlagOps<T>, help,
+  constexpr Flag(FlagNameArg name, const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
+      : impl_(name, filename, &FlagOps<T>, help,
               flags_internal::StorageKind<T>(), default_arg),
         value_() {}
+  constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
+      : Flag(FlagNameArg{name, kEmptyFlagTypeId}, filename, help, default_arg) {
+  }
+  // Kept for backwards compatibility.
+  constexpr Flag(const char* name, const char* type_name,
+                 const char* filename, FlagHelpArg help,
+                 const FlagDefaultArg default_arg)
+      : Flag(FlagNameArg{name, LookupCommonOrEmptyFlagTypeId(type_name)},
+             filename, help, default_arg) {}
 
   // CommandLineFlag interface
   absl::string_view Name() const { return impl_.Name(); }