about summary refs log tree commit diff
path: root/absl/flags
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags')
-rw-r--r--absl/flags/BUILD.bazel4
-rw-r--r--absl/flags/declare.h2
-rw-r--r--absl/flags/flag.cc2
-rw-r--r--absl/flags/flag.h10
-rw-r--r--absl/flags/flag_test.cc9
-rw-r--r--absl/flags/internal/commandlineflag.cc333
-rw-r--r--absl/flags/internal/commandlineflag.h187
-rw-r--r--absl/flags/internal/flag.cc337
-rw-r--r--absl/flags/internal/flag.h237
-rw-r--r--absl/flags/internal/registry.cc45
-rw-r--r--absl/flags/internal/registry.h6
11 files changed, 580 insertions, 592 deletions
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 2e0dc3891f56..cf4491985548 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -40,6 +40,7 @@ cc_library(
     deps = [
         ":handle",
         ":registry",
+        "//absl/base:core_headers",
         "//absl/memory",
         "//absl/strings",
         "//absl/synchronization",
@@ -135,9 +136,6 @@ cc_library(
         ":config",
         ":marshalling",
         "//absl/base:core_headers",
-        "//absl/base:raw_logging_internal",
-        "//absl/strings",
-        "//absl/synchronization",
         "//absl/types:optional",
     ],
 )
diff --git a/absl/flags/declare.h b/absl/flags/declare.h
index 0a113a2b27a3..4926a09ef4dd 100644
--- a/absl/flags/declare.h
+++ b/absl/flags/declare.h
@@ -39,7 +39,7 @@ class Flag;
 // Flag
 //
 // Forward declaration of the `absl::Flag` type for use in defining the macro.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 template <typename T>
 class Flag;
 #else
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
index 69038bbf48a0..37bbce233117 100644
--- a/absl/flags/flag.cc
+++ b/absl/flags/flag.cc
@@ -43,7 +43,7 @@ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_ATOMIC_GET)
 
 // This global nutex protects on-demand construction of flag objects in MSVC
 // builds.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 
 namespace flags_internal {
 
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 85900ef81b33..c0060b449a82 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -63,7 +63,7 @@ namespace absl {
 //      ABSL_FLAG(int, count, 0, "Count of items to process");
 //
 // No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
-#if !defined(_MSC_VER)
+#if !defined(_MSC_VER) || defined(__clang__)
 template <typename T>
 using Flag = flags_internal::Flag<T>;
 #else
@@ -119,7 +119,6 @@ class Flag {
   absl::string_view Name() const { return GetImpl()->Name(); }
   std::string Help() const { return GetImpl()->Help(); }
   bool IsModified() const { return GetImpl()->IsModified(); }
-  void SetModified(bool is_modified) { GetImpl()->SetModified(is_modified); }
   bool IsSpecifiedOnCommandLine() const {
     return GetImpl()->IsSpecifiedOnCommandLine();
   }
@@ -127,9 +126,6 @@ class Flag {
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
-  bool InvokeValidator(const void* value) const {
-    return GetImpl()->InvokeValidator(value);
-  }
   template <typename T1>
   inline bool IsOfType() const {
     return GetImpl()->template IsOfType<T1>();
@@ -272,7 +268,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
 #if ABSL_FLAGS_STRIP_NAMES
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
 #define ABSL_FLAG_IMPL_FILENAME() ""
-#if !defined(_MSC_VER)
+#if !defined(_MSC_VER) || defined(__clang__)
 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
   absl::flags_internal::FlagRegistrar<T, false>(&flag)
 #else
@@ -282,7 +278,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
 #else
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
-#if !defined(_MSC_VER)
+#if !defined(_MSC_VER) || defined(__clang__)
 #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
   absl::flags_internal::FlagRegistrar<T, true>(&flag)
 #else
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index a652042c8aae..59dc579ce029 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -42,15 +42,14 @@ void TestCallback() {}
 template <typename T>
 bool TestConstructionFor() {
   constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
-                              &absl::flags_internal::FlagMarshallingOps<T>,
-                              &TestMakeDflt<T>);
+                              &flags::FlagMarshallingOps<T>, &TestMakeDflt<T>);
   EXPECT_EQ(f1.Name(), "f1");
   EXPECT_EQ(f1.Help(), "help");
   EXPECT_EQ(f1.Filename(), "file");
 
-  ABSL_CONST_INIT static flags::Flag<T> f2(
-      "f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
-      &TestMakeDflt<T>);
+  ABSL_CONST_INIT static flags::Flag<T> f2("f2", &TestHelpMsg, "file",
+                                           &flags::FlagMarshallingOps<T>,
+                                           &TestMakeDflt<T>);
   flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
 
   EXPECT_EQ(f2.Name(), "f2");
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 99f73611d8f1..caf33bc4892b 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -15,14 +15,7 @@
 
 #include "absl/flags/internal/commandlineflag.h"
 
-#include <cassert>
-
-#include "absl/base/internal/raw_logging.h"
-#include "absl/base/optimization.h"
-#include "absl/flags/config.h"
 #include "absl/flags/usage_config.h"
-#include "absl/strings/str_cat.h"
-#include "absl/synchronization/mutex.h"
 
 namespace absl {
 namespace flags_internal {
@@ -35,80 +28,6 @@ namespace flags_internal {
 // This is used by this file, and also in commandlineflags_reporting.cc
 const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
 
-namespace {
-
-// Currently we only validate flag values for user-defined flag types.
-bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
-#define DONT_VALIDATE(T) \
-  if (flag.IsOfType<T>()) return false;
-  ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
-  DONT_VALIDATE(std::string)
-  DONT_VALIDATE(std::vector<std::string>)
-#undef DONT_VALIDATE
-
-  return true;
-}
-
-}  // namespace
-
-absl::Mutex* InitFlag(CommandLineFlag* flag) {
-  ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
-  absl::Mutex* mu;
-
-  {
-    absl::MutexLock lock(&init_lock);
-
-    if (flag->locks_ == nullptr) {  // Must initialize Mutexes for this flag.
-      flag->locks_ = new flags_internal::CommandLineFlagLocks;
-    }
-
-    mu = &flag->locks_->primary_mu;
-  }
-
-  {
-    absl::MutexLock lock(mu);
-
-    if (!flag->IsRetired() && flag->def_ == nullptr) {
-      // Need to initialize def and cur fields.
-      flag->def_ = (*flag->make_init_value_)();
-      flag->cur_ = Clone(flag->op_, flag->def_);
-      UpdateCopy(flag);
-      flag->inited_.store(true, std::memory_order_release);
-      flag->InvokeCallback();
-    }
-  }
-
-  flag->inited_.store(true, std::memory_order_release);
-  return mu;
-}
-
-// Ensure that the lazily initialized fields of *flag have been initialized,
-// and return &flag->locks_->primary_mu.
-absl::Mutex* CommandLineFlag::InitFlagIfNecessary() const
-    ABSL_LOCK_RETURNED(locks_->primary_mu) {
-  if (!inited_.load(std::memory_order_acquire)) {
-    return InitFlag(const_cast<CommandLineFlag*>(this));
-  }
-
-  // All fields initialized; locks_ is therefore safe to read.
-  return &locks_->primary_mu;
-}
-
-bool CommandLineFlag::IsModified() const {
-  absl::MutexLock l(InitFlagIfNecessary());
-  return modified_;
-}
-
-void CommandLineFlag::SetModified(bool is_modified) {
-  absl::MutexLock l(InitFlagIfNecessary());
-  modified_ = is_modified;
-}
-
-bool CommandLineFlag::IsSpecifiedOnCommandLine() const {
-  absl::MutexLock l(InitFlagIfNecessary());
-  return on_command_line_;
-}
-
 absl::string_view CommandLineFlag::Typename() const {
   // We do not store/report type in Abseil Flags, so that user do not rely on in
   // at runtime
@@ -137,223 +56,6 @@ std::string CommandLineFlag::Filename() const {
   return flags_internal::GetUsageConfig().normalize_filename(filename_);
 }
 
-std::string CommandLineFlag::DefaultValue() const {
-  absl::MutexLock l(InitFlagIfNecessary());
-
-  return Unparse(marshalling_op_, def_);
-}
-
-std::string CommandLineFlag::CurrentValue() const {
-  absl::MutexLock l(InitFlagIfNecessary());
-
-  return Unparse(marshalling_op_, cur_);
-}
-
-int64_t CommandLineFlag::MutationCounter() const {
-  absl::MutexLock l(InitFlagIfNecessary());
-
-  return counter_;
-}
-
-// Attempts to parse supplied `value` string using parsing routine in the `flag`
-// argument. If parsing is successful, it will try to validate that the parsed
-// value is valid for the specified 'flag'. Finally this function stores the
-// parsed value in 'dst' assuming it is a pointer to the flag's value type. In
-// case if any error is encountered in either step, the error message is stored
-// in 'err'
-bool TryParseLocked(CommandLineFlag* flag, void* dst, absl::string_view value,
-                    std::string* err)
-    ABSL_EXCLUSIVE_LOCKS_REQUIRED(flag->locks_->primary_mu) {
-  void* tentative_value = Clone(flag->op_, flag->def_);
-  std::string parse_err;
-  if (!Parse(flag->marshalling_op_, value, tentative_value, &parse_err)) {
-    auto type_name = flag->Typename();
-    absl::string_view err_sep = parse_err.empty() ? "" : "; ";
-    absl::string_view typename_sep = type_name.empty() ? "" : " ";
-    *err = absl::StrCat("Illegal value '", value, "' specified for",
-                        typename_sep, type_name, " flag '", flag->Name(), "'",
-                        err_sep, parse_err);
-    Delete(flag->op_, tentative_value);
-    return false;
-  }
-
-  if (!flag->InvokeValidator(tentative_value)) {
-    *err = absl::StrCat("Failed validation of new value '",
-                        Unparse(flag->marshalling_op_, tentative_value),
-                        "' for flag '", flag->Name(), "'");
-    Delete(flag->op_, tentative_value);
-    return false;
-  }
-
-  flag->counter_++;
-  Copy(flag->op_, tentative_value, dst);
-  Delete(flag->op_, tentative_value);
-  return true;
-}
-
-// Sets the value of the flag based on specified string `value`. If the flag
-// was successfully set to new value, it returns true. Otherwise, sets `err`
-// to indicate the error, leaves the flag unchanged, and returns false. There
-// are three ways to set the flag's value:
-//  * Update the current flag value
-//  * Update the flag's default value
-//  * Update the current flag value if it was never set before
-// The mode is selected based on 'set_mode' parameter.
-bool CommandLineFlag::SetFromString(absl::string_view value,
-                                    FlagSettingMode set_mode,
-                                    ValueSource source, std::string* err) {
-  if (IsRetired()) return false;
-
-  absl::MutexLock l(InitFlagIfNecessary());
-
-  // Direct-access flags can be modified without going through the
-  // flag API. Detect such changes and update the flag->modified_ bit.
-  if (!IsAbseilFlag()) {
-    if (!modified_ && ChangedDirectly(this, cur_, def_)) {
-      modified_ = true;
-    }
-  }
-
-  switch (set_mode) {
-    case SET_FLAGS_VALUE: {
-      // set or modify the flag's value
-      if (!TryParseLocked(this, cur_, value, err)) return false;
-      modified_ = true;
-      UpdateCopy(this);
-      InvokeCallback();
-
-      if (source == kCommandLine) {
-        on_command_line_ = true;
-      }
-      break;
-    }
-    case SET_FLAG_IF_DEFAULT: {
-      // set the flag's value, but only if it hasn't been set by someone else
-      if (!modified_) {
-        if (!TryParseLocked(this, cur_, value, err)) return false;
-        modified_ = true;
-        UpdateCopy(this);
-        InvokeCallback();
-      } else {
-        // TODO(rogeeff): review and fix this semantic. Currently we do not fail
-        // in this case if flag is modified. This is misleading since the flag's
-        // value is not updated even though we return true.
-        // *err = absl::StrCat(Name(), " is already set to ",
-        //                     CurrentValue(), "\n");
-        // return false;
-        return true;
-      }
-      break;
-    }
-    case SET_FLAGS_DEFAULT: {
-      // modify the flag's default-value
-      if (!TryParseLocked(this, def_, value, err)) return false;
-
-      if (!modified_) {
-        // Need to set both defvalue *and* current, in this case
-        Copy(op_, def_, cur_);
-        UpdateCopy(this);
-        InvokeCallback();
-      }
-      break;
-    }
-    default: {
-      // unknown set_mode
-      assert(false);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-void CommandLineFlag::CheckDefaultValueParsingRoundtrip() const {
-  std::string v = DefaultValue();
-
-  absl::MutexLock lock(InitFlagIfNecessary());
-
-  void* dst = Clone(op_, def_);
-  std::string error;
-  if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
-    ABSL_INTERNAL_LOG(
-        FATAL,
-        absl::StrCat("Flag ", Name(), " (from ", Filename(),
-                     "): std::string form of default value '", v,
-                     "' could not be parsed; error=", error));
-  }
-
-  // We do not compare dst to def since parsing/unparsing may make
-  // small changes, e.g., precision loss for floating point types.
-  Delete(op_, dst);
-}
-
-bool CommandLineFlag::ValidateDefaultValue() const {
-  absl::MutexLock lock(InitFlagIfNecessary());
-  return InvokeValidator(def_);
-}
-
-bool CommandLineFlag::ValidateInputValue(absl::string_view value) const {
-  absl::MutexLock l(InitFlagIfNecessary());  // protect default value access
-
-  void* obj = Clone(op_, def_);
-  std::string ignored_error;
-  const bool result =
-      flags_internal::Parse(marshalling_op_, value, obj, &ignored_error) &&
-      InvokeValidator(obj);
-  Delete(op_, obj);
-  return result;
-}
-
-void CommandLineFlag::Read(void* dst,
-                           const flags_internal::FlagOpFn dst_op) const {
-  absl::ReaderMutexLock l(InitFlagIfNecessary());
-
-  // `dst_op` is the unmarshaling operation corresponding to the declaration
-  // visibile at the call site. `op` is the Flag's defined unmarshalling
-  // operation. They must match for this operation to be well-defined.
-  if (ABSL_PREDICT_FALSE(dst_op != op_)) {
-    ABSL_INTERNAL_LOG(
-        ERROR,
-        absl::StrCat("Flag '", Name(),
-                     "' is defined as one type and declared as another"));
-  }
-  CopyConstruct(op_, cur_, dst);
-}
-
-void CommandLineFlag::Write(const void* src,
-                            const flags_internal::FlagOpFn src_op) {
-  absl::MutexLock l(InitFlagIfNecessary());
-
-  // `src_op` is the marshalling operation corresponding to the declaration
-  // visible at the call site. `op` is the Flag's defined marshalling operation.
-  // They must match for this operation to be well-defined.
-  if (ABSL_PREDICT_FALSE(src_op != op_)) {
-    ABSL_INTERNAL_LOG(
-        ERROR,
-        absl::StrCat("Flag '", Name(),
-                     "' is defined as one type and declared as another"));
-  }
-
-  if (ShouldValidateFlagValue(*this)) {
-    void* obj = Clone(op_, src);
-    std::string ignored_error;
-    std::string src_as_str = Unparse(marshalling_op_, src);
-    if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error) ||
-        !InvokeValidator(obj)) {
-      ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
-                                            "' to invalid value ", src_as_str));
-    }
-    Delete(op_, obj);
-  }
-
-  modified_ = true;
-  counter_++;
-  Copy(op_, src, cur_);
-
-  UpdateCopy(this);
-  InvokeCallback();
-}
-
 std::string HelpText::GetHelpText() const {
   if (help_function_) return help_function_();
   if (help_message_) return help_message_;
@@ -361,40 +63,5 @@ std::string HelpText::GetHelpText() const {
   return {};
 }
 
-// Update any copy of the flag value that is stored in an atomic word.
-// In addition if flag has a mutation callback this function invokes it.
-void UpdateCopy(CommandLineFlag* flag) {
-#define STORE_ATOMIC(T)           \
-  else if (flag->IsOfType<T>()) { \
-    flag->StoreAtomic();          \
-  }
-
-  if (false) {
-  }
-  ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(STORE_ATOMIC)
-#undef STORE_ATOMIC
-}
-
-// Return true iff flag value was changed via direct-access.
-bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b) {
-  if (!flag->IsAbseilFlag()) {
-// Need to compare values for direct-access flags.
-#define CHANGED_FOR_TYPE(T)                                                  \
-  if (flag->IsOfType<T>()) {                                                 \
-    return *reinterpret_cast<const T*>(a) != *reinterpret_cast<const T*>(b); \
-  }
-
-    CHANGED_FOR_TYPE(bool);
-    CHANGED_FOR_TYPE(int32_t);
-    CHANGED_FOR_TYPE(int64_t);
-    CHANGED_FOR_TYPE(uint64_t);
-    CHANGED_FOR_TYPE(double);
-    CHANGED_FOR_TYPE(std::string);
-#undef CHANGED_FOR_TYPE
-  }
-
-  return false;
-}
-
 }  // namespace flags_internal
 }  // namespace absl
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 528d3106bfa8..13a3352e80f4 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -16,12 +16,10 @@
 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
-#include <atomic>
 #include <memory>
 
 #include "absl/base/macros.h"
 #include "absl/flags/marshalling.h"
-#include "absl/synchronization/mutex.h"
 #include "absl/types/optional.h"
 
 namespace absl {
@@ -151,14 +149,6 @@ inline size_t Sizeof(FlagOpFn op) {
       op(flags_internal::kSizeof, nullptr, nullptr)));
 }
 
-// The following struct contains the locks in a CommandLineFlag struct.
-// They are in a separate struct that is lazily allocated to avoid problems
-// with static initialization and to avoid multiple allocations.
-struct CommandLineFlagLocks {
-  absl::Mutex primary_mu;   // protects several fields in CommandLineFlag
-  absl::Mutex callback_mu;  // used to serialize callbacks
-};
-
 // Holds either a pointer to help text or a function which produces it.  This is
 // needed for supporting both static initialization of Flags while supporting
 // the legacy registration framework.  We can't use absl::variant<const char*,
@@ -200,25 +190,9 @@ class FlagStateInterface {
 // Holds all information for a flag.
 class CommandLineFlag {
  public:
-  constexpr CommandLineFlag(
-      const char* name, HelpText help_text, const char* filename,
-      const flags_internal::FlagOpFn op,
-      const flags_internal::FlagMarshallingOpFn marshalling_op,
-      const flags_internal::InitialValGenFunc initial_value_gen, void* def,
-      void* cur)
-      : name_(name),
-        help_(help_text),
-        filename_(filename),
-        op_(op),
-        marshalling_op_(marshalling_op),
-        make_init_value_(initial_value_gen),
-        inited_(false),
-        modified_(false),
-        on_command_line_(false),
-        def_(def),
-        cur_(cur),
-        counter_(0),
-        locks_(nullptr) {}
+  constexpr CommandLineFlag(const char* name, HelpText help_text,
+                            const char* filename)
+      : name_(name), help_(help_text), filename_(filename) {}
 
   // Virtual destructor
   virtual void Destroy() const = 0;
@@ -227,60 +201,73 @@ class CommandLineFlag {
   CommandLineFlag(const CommandLineFlag&) = delete;
   CommandLineFlag& operator=(const CommandLineFlag&) = delete;
 
-  // Access methods.
-
-  // Returns true iff this object corresponds to retired flag
-  virtual bool IsRetired() const { return false; }
-  // Returns true iff this is a handle to an Abseil Flag.
-  virtual bool IsAbseilFlag() const { return true; }
-
+  // Non-polymorphic access methods.
   absl::string_view Name() const { return name_; }
   std::string Help() const { return help_.GetHelpText(); }
-  bool IsModified() const;
-  void SetModified(bool is_modified);
-  bool IsSpecifiedOnCommandLine() const;
-
   absl::string_view Typename() const;
   std::string Filename() const;
-  std::string DefaultValue() const;
-  std::string CurrentValue() const;
-
-  // Interface to store the value in atomic if one used. This is short term
-  // interface. To be reworked once cur_ is moved.
-  virtual void StoreAtomic() {}
-
-  // Interfaces to operate on validators.
-  virtual bool InvokeValidator(const void* /*value*/) const { return true; }
-  // Invoke the flag validators for old flags.
-  // TODO(rogeeff): implement proper validators for Abseil Flags
-  bool ValidateDefaultValue() const;
-  bool ValidateInputValue(absl::string_view value) const;
 
   // Return true iff flag has type T.
   template <typename T>
   inline bool IsOfType() const {
-    return op_ == &flags_internal::FlagOps<T>;
+    return TypeId() == &flags_internal::FlagOps<T>;
   }
 
   // Attempts to retrieve the flag value. Returns value on success,
   // absl::nullopt otherwise.
   template <typename T>
   absl::optional<T> Get() const {
-    if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
-
-    T res;
-    Read(&res, flags_internal::FlagOps<T>);
+    if (IsRetired() || !IsOfType<T>()) {
+      return absl::nullopt;
+    }
 
-    return res;
+    // Implementation notes:
+    //
+    // We are wrapping a union around the value of `T` to serve three purposes:
+    //
+    //  1. `U.value` has correct size and alignment for a value of type `T`
+    //  2. The `U.value` constructor is not invoked since U's constructor does
+    //  not
+    //     do it explicitly.
+    //  3. The `U.value` destructor is invoked since U's destructor does it
+    //     explicitly. This makes `U` a kind of RAII wrapper around non default
+    //     constructible value of T, which is destructed when we leave the
+    //     scope. We do need to destroy U.value, which is constructed by
+    //     CommandLineFlag::Read even though we left it in a moved-from state
+    //     after std::move.
+    //
+    // All of this serves to avoid requiring `T` being default constructible.
+    union U {
+      T value;
+      U() {}
+      ~U() { value.~T(); }
+    };
+    U u;
+
+    Read(&u.value);
+    return std::move(u.value);
   }
 
+  // Polymorphic access methods
+
+  // Returns true iff this object corresponds to retired flag
+  virtual bool IsRetired() const { return false; }
+  // Returns true iff this is a handle to an Abseil Flag.
+  virtual bool IsAbseilFlag() const { return true; }
+  // Returns id of the flag's value type.
+  virtual flags_internal::FlagOpFn TypeId() const = 0;
+  virtual bool IsModified() const = 0;
+  virtual bool IsSpecifiedOnCommandLine() const = 0;
+  virtual std::string DefaultValue() const = 0;
+  virtual std::string CurrentValue() const = 0;
+
+  // Interfaces to operate on validators.
+  virtual bool ValidateInputValue(absl::string_view value) const = 0;
+
   // Interface to save flag to some persistent state. Returns current flag state
   // or nullptr if flag does not support saving and restoring a state.
   virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
 
-  // Interfaces to overate on callbacks.
-  virtual void InvokeCallback() {}
-
   // Sets the value of the flag based on specified std::string `value`. If the flag
   // was successfully set to new value, it returns true. Otherwise, sets `error`
   // to indicate the error, leaves the flag unchanged, and returns false. There
@@ -289,74 +276,28 @@ class CommandLineFlag {
   //  * Update the flag's default value
   //  * Update the current flag value if it was never set before
   // The mode is selected based on `set_mode` parameter.
-  bool SetFromString(absl::string_view value,
-                     flags_internal::FlagSettingMode set_mode,
-                     flags_internal::ValueSource source, std::string* error);
+  virtual bool SetFromString(absl::string_view value,
+                             flags_internal::FlagSettingMode set_mode,
+                             flags_internal::ValueSource source,
+                             std::string* error) = 0;
 
-  void CheckDefaultValueParsingRoundtrip() const;
+  // Checks that flags default value can be converted to std::string and back to the
+  // flag's value type.
+  virtual void CheckDefaultValueParsingRoundtrip() const = 0;
 
   // Constant configuration for a particular flag.
  protected:
   ~CommandLineFlag() = default;
 
-  // Thread safe access to mutation counter.
-  int64_t MutationCounter() const;
-
-  const char* const name_;
-  const HelpText help_;
-  const char* const filename_;
-
-  const FlagOpFn op_;                         // Type-specific handler
-  const FlagMarshallingOpFn marshalling_op_;  // Marshalling ops handler
-  const InitialValGenFunc make_init_value_;  // Makes initial value for the flag
-  std::atomic<bool> inited_;  // fields have been lazily initialized
-
-  // Mutable state (guarded by locks_->primary_mu).
-  bool modified_;         // Has flag value been modified?
-  bool on_command_line_;  // Specified on command line.
-  void* def_;             // Lazily initialized pointer to default value
-  void* cur_;             // Lazily initialized pointer to current value
-  int64_t counter_;         // Mutation counter
-
-  // Lazily initialized mutexes for this flag value.  We cannot inline a
-  // SpinLock or Mutex here because those have non-constexpr constructors and
-  // so would prevent constant initialization of this type.
-  // TODO(rogeeff): fix it once Mutex has constexpr constructor
-  struct CommandLineFlagLocks* locks_;  // locks, laziliy allocated.
-
-  // Ensure that the lazily initialized fields of *flag have been initialized,
-  // and return the lock which should be locked when flag's state is mutated.
-  absl::Mutex* InitFlagIfNecessary() const ABSL_LOCK_RETURNED(locks_->primary_mu);
-
-  // copy construct new value of flag's type in a memory referenced by dst
-  // based on current flag's value
-  void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
-  // updates flag's value to *src (locked)
-  void Write(const void* src, const flags_internal::FlagOpFn src_op);
-
-  friend class FlagRegistry;
-  friend class FlagPtrMap;
-  friend class FlagSaverImpl;
-  friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
-                             absl::string_view value, std::string* err);
-  friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-};
+  const char* const name_;      // Flags name passed to ABSL_FLAG as second arg.
+  const HelpText help_;         // The function generating help message.
+  const char* const filename_;  // The file name where ABSL_FLAG resides.
 
-// Update any copy of the flag value that is stored in an atomic word.
-// In addition if flag has a mutation callback this function invokes it. While
-// callback is being invoked the primary flag's mutex is unlocked and it is
-// re-locked back after call to callback is completed. Callback invocation is
-// guarded by flag's secondary mutex instead which prevents concurrent callback
-// invocation. Note that it is possible for other thread to grab the primary
-// lock and update flag's value at any time during the callback invocation.
-// This is by design. Callback can get a value of the flag if necessary, but it
-// might be different from the value initiated the callback and it also can be
-// different by the time the callback invocation is completed.
-// Requires that *primary_lock be held in exclusive mode; it may be released
-// and reacquired by the implementation.
-void UpdateCopy(CommandLineFlag* flag);
-// Return true iff flag value was changed via direct-access.
-bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
+ private:
+  // Copy-construct a new value of the flag's type in a memory referenced by
+  // the dst based on the current flag's value.
+  virtual void Read(void* dst) const = 0;
+};
 
 // This macro is the "source of truth" for the list of supported flag types we
 // expect to perform lock free operations on. Specifically it generates code,
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 0f4035819cdb..061113d76557 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -15,36 +15,331 @@
 
 #include "absl/flags/internal/flag.h"
 
+#include "absl/base/optimization.h"
 #include "absl/synchronization/mutex.h"
 
 namespace absl {
 namespace flags_internal {
+namespace {
 
-// 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
-// re-locked back after call to callback is completed. Callback invocation is
-// guarded by flag's secondary mutex instead which prevents concurrent
-// callback invocation. Note that it is possible for other thread to grab the
-// primary lock and update flag's value at any time during the callback
-// invocation. This is by design. Callback can get a value of the flag if
-// necessary, but it might be different from the value initiated the callback
-// and it also can be different by the time the callback invocation is
-// completed. Requires that *primary_lock be held in exclusive mode; it may be
-// released and reacquired by the implementation.
-void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
-                    FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu) {
-  if (!cb) return;
-
-  // When executing the callback we need the primary flag's mutex to be
-  // unlocked so that callback can retrieve the flag's value.
-  primary_mu->Unlock();
+// Currently we only validate flag values for user-defined flag types.
+bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
+#define DONT_VALIDATE(T) \
+  if (flag.IsOfType<T>()) return false;
+  ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
+  DONT_VALIDATE(std::string)
+  DONT_VALIDATE(std::vector<std::string>)
+#undef DONT_VALIDATE
 
+  return true;
+}
+
+}  // namespace
+
+void FlagImpl::Init() {
+  ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
+
+  {
+    absl::MutexLock lock(&init_lock);
+
+    if (locks_ == nullptr) {  // Must initialize Mutexes for this flag.
+      locks_ = new FlagImpl::CommandLineFlagLocks;
+    }
+  }
+
+  absl::MutexLock lock(&locks_->primary_mu);
+
+  if (def_ != nullptr) {
+    inited_.store(true, std::memory_order_release);
+  } else {
+    // Need to initialize def and cur fields.
+    def_ = (*initial_value_gen_)();
+    cur_ = Clone(op_, def_);
+    StoreAtomic();
+    inited_.store(true, std::memory_order_release);
+    InvokeCallback();
+  }
+}
+
+// Ensures that the lazily initialized data is initialized,
+// and returns pointer to the mutex guarding flags data.
+absl::Mutex* FlagImpl::DataGuard() const
+    ABSL_LOCK_RETURNED(locks_->primary_mu) {
+  if (ABSL_PREDICT_FALSE(!inited_.load(std::memory_order_acquire))) {
+    const_cast<FlagImpl*>(this)->Init();
+  }
+
+  // All fields initialized; locks_ is therefore safe to read.
+  return &locks_->primary_mu;
+}
+
+void FlagImpl::Destroy() const {
   {
-    absl::MutexLock lock(callback_mu);
-    cb();
+    absl::MutexLock l(DataGuard());
+
+    // Values are heap allocated for Abseil Flags.
+    if (cur_) Delete(op_, cur_);
+    if (def_) Delete(op_, def_);
   }
 
-  primary_mu->Lock();
+  delete locks_;
+}
+
+bool FlagImpl::IsModified() const {
+  absl::MutexLock l(DataGuard());
+  return modified_;
+}
+
+bool FlagImpl::IsSpecifiedOnCommandLine() const {
+  absl::MutexLock l(DataGuard());
+  return on_command_line_;
+}
+
+std::string FlagImpl::DefaultValue() const {
+  absl::MutexLock l(DataGuard());
+
+  return Unparse(marshalling_op_, def_);
+}
+
+std::string FlagImpl::CurrentValue() const {
+  absl::MutexLock l(DataGuard());
+
+  return Unparse(marshalling_op_, cur_);
+}
+
+void FlagImpl::SetCallback(
+    const flags_internal::FlagCallback mutation_callback) {
+  absl::MutexLock l(DataGuard());
+
+  callback_ = mutation_callback;
+
+  InvokeCallback();
+}
+
+void FlagImpl::InvokeCallback() const
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+  if (!callback_) return;
+
+  // 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
+  // re-locked back after call to callback is completed. Callback invocation is
+  // guarded by flag's secondary mutex instead which prevents concurrent
+  // callback invocation. Note that it is possible for other thread to grab the
+  // primary lock and update flag's value at any time during the callback
+  // invocation. This is by design. Callback can get a value of the flag if
+  // necessary, but it might be different from the value initiated the callback
+  // and it also can be different by the time the callback invocation is
+  // completed. Requires that *primary_lock be held in exclusive mode; it may be
+  // released and reacquired by the implementation.
+  DataGuard()->Unlock();
+
+  {
+    absl::MutexLock lock(&locks_->callback_mu);
+    callback_();
+  }
+
+  DataGuard()->Lock();
+}
+
+bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value,
+                            bool modified, bool on_command_line,
+                            int64_t counter) {
+  {
+    absl::MutexLock l(DataGuard());
+
+    if (counter_ == counter) return false;
+  }
+
+  Write(flag, value, op_);
+
+  {
+    absl::MutexLock l(DataGuard());
+
+    modified_ = modified;
+    on_command_line_ = on_command_line;
+  }
+
+  return true;
+}
+
+// Attempts to parse supplied `value` string using parsing routine in the `flag`
+// argument. If parsing successful, this function stores the parsed value in
+// 'dst' assuming it is a pointer to the flag's value type. In case if any error
+// is encountered in either step, the error message is stored in 'err'
+bool FlagImpl::TryParse(const CommandLineFlag& flag, void* dst,
+                        absl::string_view value, std::string* err) const
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+  void* tentative_value = Clone(op_, def_);
+  std::string parse_err;
+  if (!Parse(marshalling_op_, value, tentative_value, &parse_err)) {
+    auto type_name = flag.Typename();
+    absl::string_view err_sep = parse_err.empty() ? "" : "; ";
+    absl::string_view typename_sep = type_name.empty() ? "" : " ";
+    *err = absl::StrCat("Illegal value '", value, "' specified for",
+                        typename_sep, type_name, " flag '", flag.Name(), "'",
+                        err_sep, parse_err);
+    Delete(op_, tentative_value);
+    return false;
+  }
+
+  Copy(op_, tentative_value, dst);
+  Delete(op_, tentative_value);
+  return true;
+}
+
+void FlagImpl::Read(const CommandLineFlag& flag, void* dst,
+                    const flags_internal::FlagOpFn dst_op) const {
+  absl::ReaderMutexLock l(DataGuard());
+
+  // `dst_op` is the unmarshaling operation corresponding to the declaration
+  // visibile at the call site. `op` is the Flag's defined unmarshalling
+  // operation. They must match for this operation to be well-defined.
+  if (ABSL_PREDICT_FALSE(dst_op != op_)) {
+    ABSL_INTERNAL_LOG(
+        ERROR,
+        absl::StrCat("Flag '", flag.Name(),
+                     "' is defined as one type and declared as another"));
+  }
+  CopyConstruct(op_, cur_, dst);
+}
+
+void FlagImpl::StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+  size_t data_size = Sizeof(op_);
+
+  if (data_size <= sizeof(int64_t)) {
+    int64_t t = 0;
+    std::memcpy(&t, cur_, data_size);
+    atomic_.store(t, std::memory_order_release);
+  }
+}
+
+void FlagImpl::Write(const CommandLineFlag& flag, const void* src,
+                     const flags_internal::FlagOpFn src_op) {
+  absl::MutexLock l(DataGuard());
+
+  // `src_op` is the marshalling operation corresponding to the declaration
+  // visible at the call site. `op` is the Flag's defined marshalling operation.
+  // They must match for this operation to be well-defined.
+  if (ABSL_PREDICT_FALSE(src_op != op_)) {
+    ABSL_INTERNAL_LOG(
+        ERROR,
+        absl::StrCat("Flag '", flag.Name(),
+                     "' is defined as one type and declared as another"));
+  }
+
+  if (ShouldValidateFlagValue(flag)) {
+    void* obj = Clone(op_, src);
+    std::string ignored_error;
+    std::string src_as_str = Unparse(marshalling_op_, src);
+    if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error)) {
+      ABSL_INTERNAL_LOG(ERROR,
+                        absl::StrCat("Attempt to set flag '", flag.Name(),
+                                     "' to invalid value ", src_as_str));
+    }
+    Delete(op_, obj);
+  }
+
+  modified_ = true;
+  counter_++;
+  Copy(op_, src, cur_);
+
+  StoreAtomic();
+  InvokeCallback();
+}
+
+// Sets the value of the flag based on specified string `value`. If the flag
+// was successfully set to new value, it returns true. Otherwise, sets `err`
+// to indicate the error, leaves the flag unchanged, and returns false. There
+// are three ways to set the flag's value:
+//  * Update the current flag value
+//  * Update the flag's default value
+//  * Update the current flag value if it was never set before
+// The mode is selected based on 'set_mode' parameter.
+bool FlagImpl::SetFromString(const CommandLineFlag& flag,
+                             absl::string_view value, FlagSettingMode set_mode,
+                             ValueSource source, std::string* err) {
+  absl::MutexLock l(DataGuard());
+
+  switch (set_mode) {
+    case SET_FLAGS_VALUE: {
+      // set or modify the flag's value
+      if (!TryParse(flag, cur_, value, err)) return false;
+      modified_ = true;
+      counter_++;
+      StoreAtomic();
+      InvokeCallback();
+
+      if (source == kCommandLine) {
+        on_command_line_ = true;
+      }
+      break;
+    }
+    case SET_FLAG_IF_DEFAULT: {
+      // set the flag's value, but only if it hasn't been set by someone else
+      if (!modified_) {
+        if (!TryParse(flag, cur_, value, err)) return false;
+        modified_ = true;
+        counter_++;
+        StoreAtomic();
+        InvokeCallback();
+      } else {
+        // TODO(rogeeff): review and fix this semantic. Currently we do not fail
+        // in this case if flag is modified. This is misleading since the flag's
+        // value is not updated even though we return true.
+        // *err = absl::StrCat(Name(), " is already set to ",
+        //                     CurrentValue(), "\n");
+        // return false;
+        return true;
+      }
+      break;
+    }
+    case SET_FLAGS_DEFAULT: {
+      // modify the flag's default-value
+      if (!TryParse(flag, def_, value, err)) return false;
+
+      if (!modified_) {
+        // Need to set both default value *and* current, in this case
+        Copy(op_, def_, cur_);
+        StoreAtomic();
+        InvokeCallback();
+      }
+      break;
+    }
+  }
+
+  return true;
+}
+
+void FlagImpl::CheckDefaultValueParsingRoundtrip(
+    const CommandLineFlag& flag) const {
+  std::string v = DefaultValue();
+
+  absl::MutexLock lock(DataGuard());
+
+  void* dst = Clone(op_, def_);
+  std::string error;
+  if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
+    ABSL_INTERNAL_LOG(
+        FATAL,
+        absl::StrCat("Flag ", flag.Name(), " (from ", flag.Filename(),
+                     "): std::string form of default value '", v,
+                     "' could not be parsed; error=", error));
+  }
+
+  // We do not compare dst to def since parsing/unparsing may make
+  // small changes, e.g., precision loss for floating point types.
+  Delete(op_, dst);
+}
+
+bool FlagImpl::ValidateInputValue(absl::string_view value) const {
+  absl::MutexLock l(DataGuard());
+
+  void* obj = Clone(op_, def_);
+  std::string ignored_error;
+  const bool result =
+      flags_internal::Parse(marshalling_op_, value, obj, &ignored_error);
+  Delete(op_, obj);
+  return result;
 }
 
 }  // namespace flags_internal
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 2b21c4407363..ce0ccf2d31d2 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -16,12 +16,15 @@
 #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
 #define ABSL_FLAGS_INTERNAL_FLAG_H_
 
+#include <atomic>
 #include <cstring>
 
+#include "absl/base/thread_annotations.h"
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
 #include "absl/memory/memory.h"
 #include "absl/strings/str_cat.h"
+#include "absl/synchronization/mutex.h"
 
 namespace absl {
 namespace flags_internal {
@@ -66,6 +69,124 @@ using FlagCallback = void (*)();
 void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
                     FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
 
+// The class encapsulates the Flag's data and safe access to it.
+class FlagImpl {
+ public:
+  constexpr FlagImpl(const flags_internal::FlagOpFn op,
+                     const flags_internal::FlagMarshallingOpFn marshalling_op,
+                     const flags_internal::InitialValGenFunc initial_value_gen)
+      : op_(op),
+        marshalling_op_(marshalling_op),
+        initial_value_gen_(initial_value_gen) {}
+
+  // Forces destruction of the Flag's data.
+  void Destroy() const;
+
+  // Constant access methods
+  bool IsModified() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  void Read(const CommandLineFlag& flag, void* dst,
+            const flags_internal::FlagOpFn dst_op) const
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  // Attempts to parse supplied `value` std::string.
+  bool TryParse(const CommandLineFlag& flag, void* dst, absl::string_view value,
+                std::string* err) const
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
+  template <typename T>
+  bool AtomicGet(T* v) const {
+    const int64_t r = atomic_.load(std::memory_order_acquire);
+    if (r != flags_internal::AtomicInit()) {
+      std::memcpy(v, &r, sizeof(T));
+      return true;
+    }
+
+    return false;
+  }
+
+  // Mutating access methods
+  void Write(const CommandLineFlag& flag, const void* src,
+             const flags_internal::FlagOpFn src_op)
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  bool SetFromString(const CommandLineFlag& flag, absl::string_view value,
+                     FlagSettingMode set_mode, ValueSource source,
+                     std::string* err) ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  // If possible, updates copy of the Flag's value that is stored in an
+  // atomic word.
+  void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
+
+  // Interfaces to operate on callbacks.
+  void SetCallback(const flags_internal::FlagCallback mutation_callback)
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
+
+  // Interfaces to save/restore mutable flag data
+  template <typename T>
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState(
+      Flag<T>* flag) const ABSL_LOCKS_EXCLUDED(locks_->primary_mu) {
+    T&& cur_value = flag->Get();
+    absl::MutexLock l(DataGuard());
+
+    return absl::make_unique<flags_internal::FlagState<T>>(
+        flag, std::move(cur_value), modified_, on_command_line_, counter_);
+  }
+  bool RestoreState(const CommandLineFlag& flag, const void* value,
+                    bool modified, bool on_command_line, int64_t counter)
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+
+  // Value validation interfaces.
+  void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag) const
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+  bool ValidateInputValue(absl::string_view value) const
+      ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
+
+ private:
+  // Lazy initialization of the Flag's data.
+  void Init();
+  // Ensures that the lazily initialized data is initialized,
+  // and returns pointer to the mutex guarding flags data.
+  absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED(locks_->primary_mu);
+
+  // Immutable Flag's data.
+  const FlagOpFn op_;                          // Type-specific handler
+  const FlagMarshallingOpFn marshalling_op_;   // Marshalling ops handler
+  const InitialValGenFunc initial_value_gen_;  // Makes flag's initial value
+
+  // Mutable Flag's data. (guarded by locks_->primary_mu).
+  // Indicates that locks_, cur_ and def_ fields have been lazily initialized.
+  std::atomic<bool> inited_{false};
+  // Has flag value been modified?
+  bool modified_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
+  // Specified on command line.
+  bool on_command_line_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
+  // Lazily initialized pointer to default value
+  void* def_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
+  // Lazily initialized pointer to current value
+  void* cur_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
+  // Mutation counter
+  int64_t counter_ ABSL_GUARDED_BY(locks_->primary_mu) = 0;
+  // For some types, a copy of the current value is kept in an atomically
+  // accessible field.
+  std::atomic<int64_t> atomic_{flags_internal::AtomicInit()};
+  // Mutation callback
+  FlagCallback callback_ = nullptr;
+
+  // Lazily initialized mutexes for this flag value.  We cannot inline a
+  // SpinLock or Mutex here because those have non-constexpr constructors and
+  // so would prevent constant initialization of this type.
+  // TODO(rogeeff): fix it once Mutex has constexpr constructor
+  // The following struct contains the locks in a CommandLineFlag struct.
+  // They are in a separate struct that is lazily allocated to avoid problems
+  // with static initialization and to avoid multiple allocations.
+  struct CommandLineFlagLocks {
+    absl::Mutex primary_mu;   // protects several fields in CommandLineFlag
+    absl::Mutex callback_mu;  // used to serialize callbacks
+  };
+
+  CommandLineFlagLocks* locks_ = nullptr;  // locks, laziliy allocated.
+};
+
 // This is "unspecified" implementation of absl::Flag<T> type.
 template <typename T>
 class Flag final : public flags_internal::CommandLineFlag {
@@ -76,30 +197,11 @@ class Flag final : public flags_internal::CommandLineFlag {
                  const flags_internal::InitialValGenFunc initial_value_gen)
       : flags_internal::CommandLineFlag(
             name, flags_internal::HelpText::FromFunctionPointer(help_gen),
-            filename, &flags_internal::FlagOps<T>, marshalling_op,
-            initial_value_gen,
-            /*def=*/nullptr,
-            /*cur=*/nullptr),
-        atomic_(flags_internal::AtomicInit()),
-        callback_(nullptr) {}
+            filename),
+        impl_(&flags_internal::FlagOps<T>, marshalling_op, initial_value_gen) {}
 
   T Get() const {
-    // Implementation notes:
-    //
-    // We are wrapping a union around the value of `T` to serve three purposes:
-    //
-    //  1. `U.value` has correct size and alignment for a value of type `T`
-    //  2. The `U.value` constructor is not invoked since U's constructor does
-    //  not
-    //     do it explicitly.
-    //  3. The `U.value` destructor is invoked since U's destructor does it
-    //     explicitly. This makes `U` a kind of RAII wrapper around non default
-    //     constructible value of T, which is destructed when we leave the
-    //     scope. We do need to destroy U.value, which is constructed by
-    //     CommandLineFlag::Read even though we left it in a moved-from state
-    //     after std::move.
-    //
-    // All of this serves to avoid requiring `T` being default constructible.
+    // See implementation notes in CommandLineFlag::Get().
     union U {
       T value;
       U() {}
@@ -107,89 +209,70 @@ class Flag final : public flags_internal::CommandLineFlag {
     };
     U u;
 
-    Read(&u.value, &flags_internal::FlagOps<T>);
+    impl_.Read(*this, &u.value, &flags_internal::FlagOps<T>);
     return std::move(u.value);
   }
 
-  bool AtomicGet(T* v) const {
-    const int64_t r = atomic_.load(std::memory_order_acquire);
-    if (r != flags_internal::AtomicInit()) {
-      std::memcpy(v, &r, sizeof(T));
-      return true;
-    }
-
-    return false;
-  }
+  bool AtomicGet(T* v) const { return impl_.AtomicGet(v); }
 
-  void Set(const T& v) { Write(&v, &flags_internal::FlagOps<T>); }
+  void Set(const T& v) { impl_.Write(*this, &v, &flags_internal::FlagOps<T>); }
 
   void SetCallback(const flags_internal::FlagCallback mutation_callback) {
-    absl::MutexLock l(InitFlagIfNecessary());
-
-    callback_ = mutation_callback;
-
-    InvokeCallback();
+    impl_.SetCallback(mutation_callback);
   }
 
- private:
-  friend class FlagState<T>;
-
-  void Destroy() const override {
-    // Values are heap allocated for Abseil Flags.
-    if (cur_) Delete(op_, cur_);
-    if (def_) Delete(op_, def_);
-
-    delete locks_;
+  // CommandLineFlag interface
+  bool IsModified() const override { return impl_.IsModified(); }
+  bool IsSpecifiedOnCommandLine() const override {
+    return impl_.IsSpecifiedOnCommandLine();
   }
+  std::string DefaultValue() const override { return impl_.DefaultValue(); }
+  std::string CurrentValue() const override { return impl_.CurrentValue(); }
 
-  void StoreAtomic() override {
-    if (sizeof(T) <= sizeof(int64_t)) {
-      int64_t t = 0;
-      std::memcpy(&t, cur_, (std::min)(sizeof(T), sizeof(int64_t)));
-      atomic_.store(t, std::memory_order_release);
-    }
+  bool ValidateInputValue(absl::string_view value) const override {
+    return impl_.ValidateInputValue(value);
   }
 
   // Interfaces to save and restore flags to/from persistent state.
   // Returns current flag state or nullptr if flag does not support
   // saving and restoring a state.
   std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
-    T curr_value = Get();
-
-    absl::MutexLock l(InitFlagIfNecessary());
-
-    return absl::make_unique<flags_internal::FlagState<T>>(
-        this, std::move(curr_value), modified_, on_command_line_, counter_);
+    return impl_.SaveState(this);
   }
 
   // Restores the flag state to the supplied state object. If there is
   // nothing to restore returns false. Otherwise returns true.
   bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
-    if (MutationCounter() == flag_state.counter_) return false;
-
-    Set(flag_state.cur_value_);
+    return impl_.RestoreState(*this, &flag_state.cur_value_,
+                              flag_state.modified_, flag_state.on_command_line_,
+                              flag_state.counter_);
+  }
 
-    // Race condition here? This should disappear once we move the rest of the
-    // flag's data into Flag's internals.
+  bool SetFromString(absl::string_view value,
+                     flags_internal::FlagSettingMode set_mode,
+                     flags_internal::ValueSource source,
+                     std::string* error) override {
+    return impl_.SetFromString(*this, value, set_mode, source, error);
+  }
 
-    absl::MutexLock l(InitFlagIfNecessary());
-    modified_ = flag_state.modified_;
-    on_command_line_ = flag_state.on_command_line_;
-    return true;
+  void CheckDefaultValueParsingRoundtrip() const override {
+    impl_.CheckDefaultValueParsingRoundtrip(*this);
   }
 
-  // Interfaces to overate on callbacks.
-  void InvokeCallback() override
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
-    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
-                                   callback_);
+ private:
+  friend class FlagState<T>;
+
+  void Destroy() const override { impl_.Destroy(); }
+
+  void Read(void* dst) const override {
+    impl_.Read(*this, dst, &flags_internal::FlagOps<T>);
+  }
+  flags_internal::FlagOpFn TypeId() const override {
+    return &flags_internal::FlagOps<T>;
   }
 
   // Flag's data
-  // For some types, a copy of the current value is kept in an atomically
-  // accessible field.
-  std::atomic<int64_t> atomic_;
-  FlagCallback callback_;  // Mutation callback
+  FlagImpl impl_;
 };
 
 template <typename T>
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 6b2564d13a78..ae7671a967e8 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -118,7 +118,7 @@ void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
               (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
               "'."),
           true);
-    } else if (flag->op_ != old_flag->op_) {
+    } else if (flag->TypeId() != old_flag->TypeId()) {
       flags_internal::ReportUsageError(
           absl::StrCat("Flag '", flag->Name(),
                        "' was defined more than once but with "
@@ -275,38 +275,49 @@ namespace {
 
 class RetiredFlagObj final : public flags_internal::CommandLineFlag {
  public:
-  constexpr RetiredFlagObj(const char* name, FlagOpFn ops,
-                           FlagMarshallingOpFn marshalling_ops)
+  constexpr RetiredFlagObj(const char* name, FlagOpFn ops)
       : flags_internal::CommandLineFlag(
             name, flags_internal::HelpText::FromStaticCString(nullptr),
-            /*filename=*/"RETIRED", ops, marshalling_ops,
-            /*initial_value_gen=*/nullptr,
-            /*def=*/nullptr,
-            /*cur=*/nullptr) {}
+            /*filename=*/"RETIRED"),
+        op_(ops) {}
 
  private:
-  bool IsRetired() const override { return true; }
-
   void Destroy() const override {
     // Values are heap allocated for Retired Flags.
-    if (cur_) Delete(op_, cur_);
-    if (def_) Delete(op_, def_);
-
-    if (locks_) delete locks_;
-
     delete this;
   }
 
+  flags_internal::FlagOpFn TypeId() const override { return op_; }
+  bool IsRetired() const override { return true; }
+  bool IsModified() const override { return false; }
+  bool IsSpecifiedOnCommandLine() const override { return false; }
+  std::string DefaultValue() const override { return ""; }
+  std::string CurrentValue() const override { return ""; }
+
+  // Any input is valid
+  bool ValidateInputValue(absl::string_view) const override { return true; }
+
   std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
     return nullptr;
   }
+
+  bool SetFromString(absl::string_view, flags_internal::FlagSettingMode,
+                     flags_internal::ValueSource, std::string*) override {
+    return false;
+  }
+
+  void CheckDefaultValueParsingRoundtrip() const override {}
+
+  void Read(void*) const override {}
+
+  // Data members
+  const FlagOpFn op_;
 };
 
 }  // namespace
 
-bool Retire(const char* name, FlagOpFn ops,
-            FlagMarshallingOpFn marshalling_ops) {
-  auto* flag = new flags_internal::RetiredFlagObj(name, ops, marshalling_ops);
+bool Retire(const char* name, FlagOpFn ops) {
+  auto* flag = new flags_internal::RetiredFlagObj(name, ops);
   FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
   return true;
 }
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index eb134a9f81e9..1889f3a076dd 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -76,14 +76,12 @@ bool RegisterCommandLineFlag(CommandLineFlag*);
 //
 
 // Retire flag with name "name" and type indicated by ops.
-bool Retire(const char* name, FlagOpFn ops,
-            FlagMarshallingOpFn marshalling_ops);
+bool Retire(const char* name, FlagOpFn ops);
 
 // Registered a retired flag with name 'flag_name' and type 'T'.
 template <typename T>
 inline bool RetiredFlag(const char* flag_name) {
-  return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>,
-                                flags_internal::FlagMarshallingOps<T>);
+  return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>);
 }
 
 // If the flag is retired, returns true and indicates in |*type_is_bool|