about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/container/flat_hash_map.h9
-rw-r--r--absl/container/flat_hash_map_test.cc38
-rw-r--r--absl/container/flat_hash_set.h8
-rw-r--r--absl/container/flat_hash_set_test.cc36
-rw-r--r--absl/container/internal/raw_hash_set.h11
-rw-r--r--absl/container/node_hash_map.h9
-rw-r--r--absl/container/node_hash_map_test.cc38
-rw-r--r--absl/container/node_hash_set.h8
-rw-r--r--absl/container/node_hash_set_test.cc36
-rw-r--r--absl/flags/BUILD.bazel4
-rw-r--r--absl/flags/CMakeLists.txt3
-rw-r--r--absl/flags/flag.h48
-rw-r--r--absl/flags/flag_test.cc31
-rw-r--r--absl/flags/internal/commandlineflag.cc62
-rw-r--r--absl/flags/internal/commandlineflag.h26
-rw-r--r--absl/flags/internal/flag.cc69
-rw-r--r--absl/flags/internal/flag.h85
-rw-r--r--absl/flags/internal/registry.cc8
-rw-r--r--absl/strings/substitute.h7
-rw-r--r--absl/strings/substitute_test.cc4
-rwxr-xr-xci/cmake_install_test.sh2
-rwxr-xr-xci/linux_clang-latest_libcxx_asan_bazel.sh3
-rwxr-xr-xci/linux_clang-latest_libcxx_bazel.sh2
-rwxr-xr-xci/linux_clang-latest_libcxx_tsan_bazel.sh3
-rwxr-xr-xci/linux_clang-latest_libstdcxx_bazel.sh2
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_bazel.sh2
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_cmake.sh2
27 files changed, 327 insertions, 229 deletions
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index fb570cd495ee..fcb70d861f39 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -532,6 +532,15 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
   using Base::key_eq;
 };
 
+// erase_if(flat_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+          typename Predicate>
+void erase_if(flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
 namespace container_internal {
 
 template <class K, class V>
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index dae8e00389bc..fd9c5604b1d6 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -30,6 +30,7 @@ namespace {
 using ::absl::container_internal::hash_internal::Enum;
 using ::absl::container_internal::hash_internal::EnumClass;
 using ::testing::_;
+using ::testing::IsEmpty;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
@@ -215,6 +216,43 @@ TEST(FlatHashMap, MergeExtractInsert) {
   EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
 }
 
+bool FirstIsEven(std::pair<const int, int> p) { return p.first % 2 == 0; }
+
+TEST(FlatHashMap, EraseIf) {
+  // Erase all elements.
+  {
+    flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, [](std::pair<const int, int>) { return true; });
+    EXPECT_THAT(s, IsEmpty());
+  }
+  // Erase no elements.
+  {
+    flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, [](std::pair<const int, int>) { return false; });
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3),
+                                        Pair(4, 4), Pair(5, 5)));
+  }
+  // Erase specific elements.
+  {
+    flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s,
+             [](std::pair<const int, int> kvp) { return kvp.first % 2 == 1; });
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4)));
+  }
+  // Predicate is function reference.
+  {
+    flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, FirstIsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+  }
+  // Predicate is function pointer.
+  {
+    flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, &FirstIsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+  }
+}
+
 #if (defined(ABSL_USES_STD_ANY) || !defined(_LIBCPP_VERSION)) && \
     !defined(__EMSCRIPTEN__)
 TEST(FlatHashMap, Any) {
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index 930107ea212d..94be6e3d13f1 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -439,6 +439,14 @@ class flat_hash_set
   using Base::key_eq;
 };
 
+// erase_if(flat_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(flat_hash_set<T, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
 namespace container_internal {
 
 template <class T>
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index 6eacb1bb653c..40d7f85c5db0 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -31,6 +31,7 @@ namespace {
 
 using ::absl::container_internal::hash_internal::Enum;
 using ::absl::container_internal::hash_internal::EnumClass;
+using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
@@ -124,6 +125,41 @@ TEST(FlatHashSet, MergeExtractInsert) {
   EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
 }
 
+bool IsEven(int k) { return k % 2 == 0; }
+
+TEST(FlatHashSet, EraseIf) {
+  // Erase all elements.
+  {
+    flat_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int) { return true; });
+    EXPECT_THAT(s, IsEmpty());
+  }
+  // Erase no elements.
+  {
+    flat_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int) { return false; });
+    EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
+  }
+  // Erase specific elements.
+  {
+    flat_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int k) { return k % 2 == 1; });
+    EXPECT_THAT(s, UnorderedElementsAre(2, 4));
+  }
+  // Predicate is function reference.
+  {
+    flat_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, IsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+  }
+  // Predicate is function pointer.
+  {
+    flat_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, &IsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+  }
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 4103e02ab0b0..b1c686edf28c 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1801,6 +1801,17 @@ class raw_hash_set {
       settings_{0, hasher{}, key_equal{}, allocator_type{}};
 };
 
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename P, typename H, typename E, typename A, typename Predicate>
+void EraseIf(Predicate pred, raw_hash_set<P, H, E, A>* c) {
+  for (auto it = c->begin(), last = c->end(); it != last;) {
+    auto copy_it = it++;
+    if (pred(*copy_it)) {
+      c->erase(copy_it);
+    }
+  }
+}
+
 namespace hashtable_debug_internal {
 template <typename Set>
 struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index e8065a98a987..fccea1841c08 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -522,6 +522,15 @@ class node_hash_map
   void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
+// erase_if(node_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+          typename Predicate>
+void erase_if(node_hash_map<K, V, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
 namespace container_internal {
 
 template <class Key, class Value>
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
index f923e91513a5..5d74b814b584 100644
--- a/absl/container/node_hash_map_test.cc
+++ b/absl/container/node_hash_map_test.cc
@@ -26,6 +26,7 @@ namespace container_internal {
 namespace {
 
 using ::testing::Field;
+using ::testing::IsEmpty;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
@@ -216,6 +217,43 @@ TEST(NodeHashMap, MergeExtractInsert) {
   EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70), Elem(17, 23)));
 }
 
+bool FirstIsEven(std::pair<const int, int> p) { return p.first % 2 == 0; }
+
+TEST(NodeHashMap, EraseIf) {
+  // Erase all elements.
+  {
+    node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, [](std::pair<const int, int>) { return true; });
+    EXPECT_THAT(s, IsEmpty());
+  }
+  // Erase no elements.
+  {
+    node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, [](std::pair<const int, int>) { return false; });
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3),
+                                        Pair(4, 4), Pair(5, 5)));
+  }
+  // Erase specific elements.
+  {
+    node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s,
+             [](std::pair<const int, int> kvp) { return kvp.first % 2 == 1; });
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4)));
+  }
+  // Predicate is function reference.
+  {
+    node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, FirstIsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+  }
+  // Predicate is function pointer.
+  {
+    node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+    erase_if(s, &FirstIsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+  }
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index 43ada3f9df24..0e2dee54aa19 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -435,6 +435,14 @@ class node_hash_set
   void resize(typename Base::size_type hint) { this->rehash(hint); }
 };
 
+// erase_if(node_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(node_hash_set<T, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
 namespace container_internal {
 
 template <class T>
diff --git a/absl/container/node_hash_set_test.cc b/absl/container/node_hash_set_test.cc
index e1d544ff882e..7ddad2021d2f 100644
--- a/absl/container/node_hash_set_test.cc
+++ b/absl/container/node_hash_set_test.cc
@@ -25,6 +25,7 @@ namespace container_internal {
 namespace {
 using ::absl::container_internal::hash_internal::Enum;
 using ::absl::container_internal::hash_internal::EnumClass;
+using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
 
@@ -101,6 +102,41 @@ TEST(NodeHashSet, MergeExtractInsert) {
   EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
 }
 
+bool IsEven(int k) { return k % 2 == 0; }
+
+TEST(NodeHashSet, EraseIf) {
+  // Erase all elements.
+  {
+    node_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int) { return true; });
+    EXPECT_THAT(s, IsEmpty());
+  }
+  // Erase no elements.
+  {
+    node_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int) { return false; });
+    EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
+  }
+  // Erase specific elements.
+  {
+    node_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, [](int k) { return k % 2 == 1; });
+    EXPECT_THAT(s, UnorderedElementsAre(2, 4));
+  }
+  // Predicate is function reference.
+  {
+    node_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, IsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+  }
+  // Predicate is function pointer.
+  {
+    node_hash_set<int> s = {1, 2, 3, 4, 5};
+    erase_if(s, &IsEven);
+    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+  }
+}
+
 }  // namespace
 }  // namespace container_internal
 ABSL_NAMESPACE_END
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index cf4491985548..504acde8624b 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -38,6 +38,7 @@ cc_library(
     linkopts = ABSL_DEFAULT_LINKOPTS,
     visibility = ["//visibility:private"],
     deps = [
+        ":config",
         ":handle",
         ":registry",
         "//absl/base:core_headers",
@@ -121,9 +122,6 @@ cc_library(
 
 cc_library(
     name = "handle",
-    srcs = [
-        "internal/commandlineflag.cc",
-    ],
     hdrs = [
         "internal/commandlineflag.h",
     ],
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 3a7162f9347b..7c63821e13eb 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -27,6 +27,7 @@ absl_cc_library(
   LINKOPTS
     ${ABSL_DEFAULT_LINKOPTS}
   DEPS
+    absl::flags_config
     absl::flags_handle
     absl::flags_registry
     absl::synchronization
@@ -108,8 +109,6 @@ absl_cc_library(
 absl_cc_library(
   NAME
     flags_handle
-  SRCS
-    "internal/commandlineflag.cc"
   HDRS
     "internal/commandlineflag.h"
   COPTS
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index f18e9f56a5cc..326fb8ee6894 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -94,14 +94,14 @@ class Flag {
   // Visual Studio 2015 still requires the constructor for class to be
   // constexpr initializable.
 #if _MSC_VER <= 1900
-  constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
-                 const char* filename,
+  constexpr Flag(const char* name, const char* filename,
                  const flags_internal::FlagMarshallingOpFn marshalling_op,
+                 const flags_internal::HelpGenFunc help_gen,
                  const flags_internal::FlagDfltGenFunc default_value_gen)
       : name_(name),
-        help_gen_(help_gen),
         filename_(filename),
         marshalling_op_(marshalling_op),
+        help_gen_(help_gen),
         default_value_gen_(default_value_gen),
         inited_(false),
         impl_(nullptr) {}
@@ -116,10 +116,10 @@ class Flag {
       }
 
       impl_ = new flags_internal::Flag<T>(
-          name_,
+          name_, filename_, marshalling_op_,
           {flags_internal::FlagHelpSrc(help_gen_),
            flags_internal::FlagHelpSrcKind::kGenFunc},
-          filename_, marshalling_op_, default_value_gen_);
+          default_value_gen_);
       inited_.store(true, std::memory_order_release);
     }
 
@@ -155,9 +155,9 @@ class Flag {
   // The data members are logically private, but they need to be public for
   // this to be an aggregate type.
   const char* name_;
-  const flags_internal::HelpGenFunc help_gen_;
   const char* filename_;
   const flags_internal::FlagMarshallingOpFn marshalling_op_;
+  const flags_internal::HelpGenFunc help_gen_;
   const flags_internal::FlagDfltGenFunc default_value_gen_;
 
   mutable std::atomic<bool> inited_;
@@ -342,26 +342,24 @@ ABSL_NAMESPACE_END
   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::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
-      ABSL_FLAG_IMPL_FILENAME(),                                    \
+      ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(),    \
       &absl::flags_internal::FlagMarshallingOps<Type>,              \
+      absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0),   \
       &AbslFlagsInitFlag##name};                                    \
   extern bool FLAGS_no##name;                                       \
   bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #else
 // MSVC version uses aggregate initialization. We also do not try to
 // optimize away help wrapper.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help)                    \
-  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), &AbslFlagHelpGenFor##name::NonConst, \
-      ABSL_FLAG_IMPL_FILENAME(),                                           \
-      &absl::flags_internal::FlagMarshallingOps<Type>,                     \
-      &AbslFlagsInitFlag##name};                                           \
-  extern bool FLAGS_no##name;                                              \
+#define ABSL_FLAG_IMPL(Type, name, default_value, help)               \
+  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_FILENAME(),      \
+      &absl::flags_internal::FlagMarshallingOps<Type>,                \
+      &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \
+  extern bool FLAGS_no##name;                                         \
   bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
 #endif
 
@@ -384,19 +382,11 @@ ABSL_NAMESPACE_END
 //
 // `default_value` is only used as a double check on the type. `explanation` is
 // unused.
-//
-// ABSL_RETIRED_FLAG support omitting the default value for default
-// constructible value type, so that users can delete the code generatring this
-// value.
-//
 // TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
 // the unnamed namespace.
 #define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
-  ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname =             \
-      ([] {                                                                \
-           return absl::flags_internal::MakeFromDefaultValueOrEmpty<type>( \
-                   default_value);                                         \
-       },                                                                  \
+  ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname =        \
+      ([] { return type(default_value); },                            \
        absl::flags_internal::RetiredFlag<type>(#flagname))
 
 #endif  // ABSL_FLAGS_FLAG_H_
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 465f018c5e4f..28c513b020a8 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -43,16 +43,16 @@ template <typename T>
 bool TestConstructionFor() {
   constexpr flags::HelpInitArg help_arg{flags::FlagHelpSrc("literal help"),
                                         flags::FlagHelpSrcKind::kLiteral};
-  constexpr flags::Flag<T> f1("f1", help_arg, "file",
-                              &flags::FlagMarshallingOps<T>, &TestMakeDflt<T>);
+  constexpr flags::Flag<T> f1("f1", "file", &flags::FlagMarshallingOps<T>,
+                              help_arg, &TestMakeDflt<T>);
   EXPECT_EQ(f1.Name(), "f1");
   EXPECT_EQ(f1.Help(), "literal help");
   EXPECT_EQ(f1.Filename(), "file");
 
   ABSL_CONST_INIT static flags::Flag<T> f2(
-      "f2",
+      "f2", "file", &flags::FlagMarshallingOps<T>,
       {flags::FlagHelpSrc(&TestHelpMsg), flags::FlagHelpSrcKind::kGenFunc},
-      "file", &flags::FlagMarshallingOps<T>, &TestMakeDflt<T>);
+      &TestMakeDflt<T>);
   flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
 
   EXPECT_EQ(f2.Name(), "f2");
@@ -486,30 +486,11 @@ TEST_F(FlagTest, TestNonDefaultConstructibleType) {
 
 // --------------------------------------------------------------------
 
-struct Wrapper {
-  Wrapper() {}
-
-  // NOLINTNEXTLINE(runtime/explicit)
-  Wrapper(const std::string& val) : val(val) {}
-
-  // NOLINTNEXTLINE(runtime/explicit)
-  template <typename T>
-  Wrapper(T&& t) : val(std::forward<T>(t)) {}
-
-  // NOLINTNEXTLINE(runtime/explicit)
-  operator std::string() const& { return val; }
-
-  std::string val;
-};
-
 }  // namespace
 
 ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
 ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
 ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
-ABSL_RETIRED_FLAG(Wrapper, old_wrapper_flag, {}, "old wrapper");
-ABSL_RETIRED_FLAG(Wrapper, old_wrapper_no_default_flag, ,
-                  "old wrapper no default");
 
 namespace {
 
@@ -521,10 +502,6 @@ TEST_F(FlagTest, TestRetiredFlagRegistration) {
   EXPECT_FALSE(is_bool);
   EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
   EXPECT_FALSE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_wrapper_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
-  EXPECT_TRUE(flags::IsRetiredFlag("old_wrapper_no_default_flag", &is_bool));
-  EXPECT_FALSE(is_bool);
   EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
 }
 
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
deleted file mode 100644
index 09249274c3e7..000000000000
--- a/absl/flags/internal/commandlineflag.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/commandlineflag.h"
-
-#include "absl/flags/usage_config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace flags_internal {
-
-// The help message indicating that the commandline flag has been
-// 'stripped'. It will not show up when doing "-help" and its
-// variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
-// before including absl/flags/flag.h
-
-// This is used by this file, and also in commandlineflags_reporting.cc
-const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
-
-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
-  if (IsAbseilFlag() || IsRetired()) return "";
-
-#define HANDLE_V1_BUILTIN_TYPE(t) \
-  if (IsOfType<t>()) {            \
-    return #t;                    \
-  }
-
-  HANDLE_V1_BUILTIN_TYPE(bool);
-  HANDLE_V1_BUILTIN_TYPE(int32_t);
-  HANDLE_V1_BUILTIN_TYPE(int64_t);
-  HANDLE_V1_BUILTIN_TYPE(uint64_t);
-  HANDLE_V1_BUILTIN_TYPE(double);
-#undef HANDLE_V1_BUILTIN_TYPE
-
-  if (IsOfType<std::string>()) {
-    return "string";
-  }
-
-  return "";
-}
-
-std::string CommandLineFlag::Filename() const {
-  return flags_internal::GetUsageConfig().normalize_filename(filename_);
-}
-
-}  // namespace flags_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 49e13d1e726b..a0c18e80b6c7 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -61,8 +61,6 @@ enum ValueSource {
   kProgrammaticChange,
 };
 
-extern const char kStrippedFlagHelp[];
-
 // The per-type function
 template <typename T>
 void* FlagOps(FlagOp op, const void* v1, void* v2) {
@@ -155,8 +153,7 @@ class FlagStateInterface {
 // Holds all information for a flag.
 class CommandLineFlag {
  public:
-  constexpr CommandLineFlag(const char* name, const char* filename)
-      : name_(name), filename_(filename) {}
+  constexpr CommandLineFlag() = default;
 
   // Virtual destructor
   virtual void Destroy() = 0;
@@ -166,9 +163,6 @@ class CommandLineFlag {
   CommandLineFlag& operator=(const CommandLineFlag&) = delete;
 
   // Non-polymorphic access methods.
-  absl::string_view Name() const { return name_; }
-  absl::string_view Typename() const;
-  std::string Filename() const;
 
   // Return true iff flag has type T.
   template <typename T>
@@ -190,8 +184,7 @@ class CommandLineFlag {
     //
     //  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.
+    //     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
@@ -213,9 +206,16 @@ class CommandLineFlag {
 
   // Polymorphic access methods
 
-  // Returns help message associated with this flag
+  // Returns name of this flag.
+  virtual absl::string_view Name() const = 0;
+  // Returns name of the file where this flag is defined.
+  virtual std::string Filename() const = 0;
+  // Returns name of the flag's value type for some built-in types or empty
+  // std::string.
+  virtual absl::string_view Typename() const = 0;
+  // Returns help message associated with this flag.
   virtual std::string Help() const = 0;
-  // Returns true iff this object corresponds to retired flag
+  // 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; }
@@ -253,10 +253,6 @@ class CommandLineFlag {
  protected:
   ~CommandLineFlag() = default;
 
-  // Constant configuration for a particular flag.
-  const char* const name_;      // Flags name passed to ABSL_FLAG as second arg.
-  const char* const filename_;  // The file name where ABSL_FLAG resides.
-
  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.
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 599bd7a45561..bb9a98f34404 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -16,17 +16,25 @@
 #include "absl/flags/internal/flag.h"
 
 #include "absl/base/optimization.h"
+#include "absl/flags/usage_config.h"
 #include "absl/synchronization/mutex.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
+
+// The help message indicating that the commandline flag has been
+// 'stripped'. It will not show up when doing "-help" and its
+// variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
+// before including absl/flags/flag.h
+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) {
+bool ShouldValidateFlagValue(FlagOpFn flag_type_id) {
 #define DONT_VALIDATE(T) \
-  if (flag.IsOfType<T>()) return false;
+  if (flag_type_id == &flags_internal::FlagOps<T>) return false;
   ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
   DONT_VALIDATE(std::string)
   DONT_VALIDATE(std::vector<std::string>)
@@ -123,6 +131,12 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
   return {res, DynValueDeleter{op_}};
 }
 
+absl::string_view FlagImpl::Name() const { return name_; }
+
+std::string FlagImpl::Filename() const {
+  return flags_internal::GetUsageConfig().normalize_filename(filename_);
+}
+
 std::string FlagImpl::Help() const {
   return help_source_kind_ == FlagHelpSrcKind::kLiteral ? help_.literal
                                                         : help_.gen_func();
@@ -186,16 +200,15 @@ void FlagImpl::InvokeCallback() const {
   cb();
 }
 
-bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value,
-                            bool modified, bool on_command_line,
-                            int64_t counter) {
+bool FlagImpl::RestoreState(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_);
+  Write(value, op_);
 
   {
     absl::MutexLock l(DataGuard());
@@ -211,18 +224,15 @@ bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value,
 // argument. If parsing successful, this function replaces the dst with newly
 // parsed value. 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 {
+bool FlagImpl::TryParse(void** dst, absl::string_view value,
+                        std::string* err) const {
   auto tentative_value = MakeInitValue();
 
   std::string parse_err;
   if (!Parse(marshalling_op_, value, tentative_value.get(), &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);
+    *err = absl::StrCat("Illegal value '", value, "' specified for flag '",
+                        Name(), "'", err_sep, parse_err);
     return false;
   }
 
@@ -233,8 +243,7 @@ bool FlagImpl::TryParse(const CommandLineFlag& flag, void** dst,
   return true;
 }
 
-void FlagImpl::Read(const CommandLineFlag& flag, void* dst,
-                    const flags_internal::FlagOpFn dst_op) const {
+void FlagImpl::Read(void* dst, const flags_internal::FlagOpFn dst_op) const {
   absl::ReaderMutexLock l(DataGuard());
 
   // `dst_op` is the unmarshaling operation corresponding to the declaration
@@ -243,7 +252,7 @@ void FlagImpl::Read(const CommandLineFlag& flag, void* dst,
   if (ABSL_PREDICT_FALSE(dst_op != op_)) {
     ABSL_INTERNAL_LOG(
         ERROR,
-        absl::StrCat("Flag '", flag.Name(),
+        absl::StrCat("Flag '", Name(),
                      "' is defined as one type and declared as another"));
   }
   CopyConstruct(op_, cur_, dst);
@@ -259,8 +268,7 @@ void FlagImpl::StoreAtomic() {
   }
 }
 
-void FlagImpl::Write(const CommandLineFlag& flag, const void* src,
-                     const flags_internal::FlagOpFn src_op) {
+void FlagImpl::Write(const void* src, const flags_internal::FlagOpFn src_op) {
   absl::MutexLock l(DataGuard());
 
   // `src_op` is the marshalling operation corresponding to the declaration
@@ -269,18 +277,17 @@ void FlagImpl::Write(const CommandLineFlag& flag, const void* src,
   if (ABSL_PREDICT_FALSE(src_op != op_)) {
     ABSL_INTERNAL_LOG(
         ERROR,
-        absl::StrCat("Flag '", flag.Name(),
+        absl::StrCat("Flag '", Name(),
                      "' is defined as one type and declared as another"));
   }
 
-  if (ShouldValidateFlagValue(flag)) {
+  if (ShouldValidateFlagValue(op_)) {
     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));
+      ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
+                                            "' to invalid value ", src_as_str));
     }
     Delete(op_, obj);
   }
@@ -301,15 +308,14 @@ void FlagImpl::Write(const CommandLineFlag& flag, const void* src,
 //  * 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,
+bool FlagImpl::SetFromString(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;
+      if (!TryParse(&cur_, value, err)) return false;
       modified_ = true;
       counter_++;
       StoreAtomic();
@@ -323,7 +329,7 @@ bool FlagImpl::SetFromString(const CommandLineFlag& flag,
     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;
+        if (!TryParse(&cur_, value, err)) return false;
         modified_ = true;
         counter_++;
         StoreAtomic();
@@ -341,12 +347,12 @@ bool FlagImpl::SetFromString(const CommandLineFlag& flag,
     }
     case SET_FLAGS_DEFAULT: {
       if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) {
-        if (!TryParse(flag, &default_src_.dynamic_value, value, err)) {
+        if (!TryParse(&default_src_.dynamic_value, value, err)) {
           return false;
         }
       } else {
         void* new_default_val = nullptr;
-        if (!TryParse(flag, &new_default_val, value, err)) {
+        if (!TryParse(&new_default_val, value, err)) {
           return false;
         }
 
@@ -367,8 +373,7 @@ bool FlagImpl::SetFromString(const CommandLineFlag& flag,
   return true;
 }
 
-void FlagImpl::CheckDefaultValueParsingRoundtrip(
-    const CommandLineFlag& flag) const {
+void FlagImpl::CheckDefaultValueParsingRoundtrip() const {
   std::string v = DefaultValue();
 
   absl::MutexLock lock(DataGuard());
@@ -378,7 +383,7 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip(
   if (!flags_internal::Parse(marshalling_op_, v, dst.get(), &error)) {
     ABSL_INTERNAL_LOG(
         FATAL,
-        absl::StrCat("Flag ", flag.Name(), " (from ", flag.Filename(),
+        absl::StrCat("Flag ", Name(), " (from ", Filename(),
                      "): std::string form of default value '", v,
                      "' could not be parsed; error=", error));
   }
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 21a10c7f85f8..7d5271c40de6 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -82,6 +82,8 @@ struct HelpInitArg {
   FlagHelpSrcKind kind;
 };
 
+extern const char kStrippedFlagHelp[];
+
 // HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by
 // ABSL_FLAG macro. It is only used to silence the compiler in the case where
 // help message expression is not constexpr and does not have type const char*.
@@ -148,11 +150,14 @@ struct DynValueDeleter {
 // The class encapsulates the Flag's data and safe access to it.
 class FlagImpl {
  public:
-  constexpr FlagImpl(const flags_internal::FlagOpFn op,
+  constexpr FlagImpl(const char* name, const char* filename,
+                     const flags_internal::FlagOpFn op,
                      const flags_internal::FlagMarshallingOpFn marshalling_op,
-                     const flags_internal::FlagDfltGenFunc default_value_gen,
-                     const HelpInitArg help)
-      : op_(op),
+                     const HelpInitArg help,
+                     const flags_internal::FlagDfltGenFunc default_value_gen)
+      : name_(name),
+        filename_(filename),
+        op_(op),
         marshalling_op_(marshalling_op),
         help_(help.source),
         help_source_kind_(help.kind),
@@ -164,18 +169,18 @@ class FlagImpl {
   void Destroy();
 
   // Constant access methods
+  absl::string_view Name() const;
+  std::string Filename() const;
   std::string Help() const;
   bool IsModified() const ABSL_LOCKS_EXCLUDED(*DataGuard());
   bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(*DataGuard());
   std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
   std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard());
-  void Read(const CommandLineFlag& flag, void* dst,
-            const flags_internal::FlagOpFn dst_op) const
+  void Read(void* dst, const flags_internal::FlagOpFn dst_op) const
       ABSL_LOCKS_EXCLUDED(*DataGuard());
   // Attempts to parse supplied `value` std::string. If parsing is successful, then
   // it replaces `dst` with the new value.
-  bool TryParse(const CommandLineFlag& flag, void** dst,
-                absl::string_view value, std::string* err) const
+  bool TryParse(void** dst, absl::string_view value, std::string* err) const
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
   template <typename T>
   bool AtomicGet(T* v) const {
@@ -189,12 +194,11 @@ class FlagImpl {
   }
 
   // Mutating access methods
-  void Write(const CommandLineFlag& flag, const void* src,
-             const flags_internal::FlagOpFn src_op)
+  void Write(const void* src, const flags_internal::FlagOpFn src_op)
+      ABSL_LOCKS_EXCLUDED(*DataGuard());
+  bool SetFromString(absl::string_view value, FlagSettingMode set_mode,
+                     ValueSource source, std::string* err)
       ABSL_LOCKS_EXCLUDED(*DataGuard());
-  bool SetFromString(const CommandLineFlag& flag, absl::string_view value,
-                     FlagSettingMode set_mode, ValueSource source,
-                     std::string* err) ABSL_LOCKS_EXCLUDED(*DataGuard());
   // If possible, updates copy of the Flag's value that is stored in an
   // atomic word.
   void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
@@ -214,12 +218,11 @@ class FlagImpl {
     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(*DataGuard());
+  bool RestoreState(const void* value, bool modified, bool on_command_line,
+                    int64_t counter) ABSL_LOCKS_EXCLUDED(*DataGuard());
 
   // Value validation interfaces.
-  void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag) const
+  void CheckDefaultValueParsingRoundtrip() const
       ABSL_LOCKS_EXCLUDED(*DataGuard());
   bool ValidateInputValue(absl::string_view value) const
       ABSL_LOCKS_EXCLUDED(*DataGuard());
@@ -235,7 +238,10 @@ class FlagImpl {
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
 
   // Immutable Flag's data.
-  const FlagOpFn op_;                         // Type-specific handler.
+  // Constant configuration for a particular flag.
+  const char* const name_;      // Flags name passed to ABSL_FLAG as second arg.
+  const char* const filename_;  // The file name where ABSL_FLAG resides.
+  const FlagOpFn op_;           // Type-specific handler.
   const FlagMarshallingOpFn marshalling_op_;  // Marshalling ops handler.
   const FlagHelpSrc help_;  // Help message literal or function to generate it.
   // Indicates if help message was supplied as literal or generator func.
@@ -286,13 +292,12 @@ class FlagImpl {
 template <typename T>
 class Flag final : public flags_internal::CommandLineFlag {
  public:
-  constexpr Flag(const char* name, const flags_internal::HelpInitArg help,
-                 const char* filename,
+  constexpr Flag(const char* name, const char* filename,
                  const flags_internal::FlagMarshallingOpFn marshalling_op,
-                 const flags_internal::FlagDfltGenFunc initial_value_gen)
-      : flags_internal::CommandLineFlag(name, filename),
-        impl_(&flags_internal::FlagOps<T>, marshalling_op, initial_value_gen,
-              help) {}
+                 const flags_internal::HelpInitArg help,
+                 const flags_internal::FlagDfltGenFunc default_value_gen)
+      : impl_(name, filename, &flags_internal::FlagOps<T>, marshalling_op, help,
+              default_value_gen) {}
 
   T Get() const {
     // See implementation notes in CommandLineFlag::Get().
@@ -303,19 +308,22 @@ class Flag final : public flags_internal::CommandLineFlag {
     };
     U u;
 
-    impl_.Read(*this, &u.value, &flags_internal::FlagOps<T>);
+    impl_.Read(&u.value, &flags_internal::FlagOps<T>);
     return std::move(u.value);
   }
 
   bool AtomicGet(T* v) const { return impl_.AtomicGet(v); }
 
-  void Set(const T& v) { impl_.Write(*this, &v, &flags_internal::FlagOps<T>); }
+  void Set(const T& v) { impl_.Write(&v, &flags_internal::FlagOps<T>); }
 
   void SetCallback(const flags_internal::FlagCallback mutation_callback) {
     impl_.SetCallback(mutation_callback);
   }
 
   // CommandLineFlag interface
+  absl::string_view Name() const override { return impl_.Name(); }
+  std::string Filename() const override { return impl_.Filename(); }
+  absl::string_view Typename() const override { return ""; }
   std::string Help() const override { return impl_.Help(); }
   bool IsModified() const override { return impl_.IsModified(); }
   bool IsSpecifiedOnCommandLine() const override {
@@ -338,20 +346,19 @@ class Flag final : public flags_internal::CommandLineFlag {
   // 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) {
-    return impl_.RestoreState(*this, &flag_state.cur_value_,
-                              flag_state.modified_, flag_state.on_command_line_,
-                              flag_state.counter_);
+    return impl_.RestoreState(&flag_state.cur_value_, flag_state.modified_,
+                              flag_state.on_command_line_, flag_state.counter_);
   }
 
   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);
+    return impl_.SetFromString(value, set_mode, source, error);
   }
 
   void CheckDefaultValueParsingRoundtrip() const override {
-    impl_.CheckDefaultValueParsingRoundtrip(*this);
+    impl_.CheckDefaultValueParsingRoundtrip();
   }
 
  private:
@@ -360,7 +367,7 @@ class Flag final : public flags_internal::CommandLineFlag {
   void Destroy() override { impl_.Destroy(); }
 
   void Read(void* dst) const override {
-    impl_.Read(*this, dst, &flags_internal::FlagOps<T>);
+    impl_.Read(dst, &flags_internal::FlagOps<T>);
   }
   flags_internal::FlagOpFn TypeId() const override {
     return &flags_internal::FlagOps<T>;
@@ -416,20 +423,6 @@ T* MakeFromDefaultValue(EmptyBraces) {
   return new T;
 }
 
-// MakeFromDefaultValueOrEmpty is basically the same as MakeFromDefaultValue. It
-// also allows for empty macro parameter (hence no argument), which was somehow
-// widely used for ABSL_RETIRED_FLAG().
-
-template <typename T>
-T* MakeFromDefaultValueOrEmpty(T t) {
-  return MakeFromDefaultValue(std::move(t));
-}
-
-template <typename T>
-T* MakeFromDefaultValueOrEmpty() {
-  return MakeFromDefaultValue<T>(EmptyBraces());
-}
-
 }  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 5eae933c3fa3..ae5afd42ee36 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -277,9 +277,7 @@ namespace {
 class RetiredFlagObj final : public flags_internal::CommandLineFlag {
  public:
   constexpr RetiredFlagObj(const char* name, FlagOpFn ops)
-      : flags_internal::CommandLineFlag(name,
-                                        /*filename=*/"RETIRED"),
-        op_(ops) {}
+      : name_(name), op_(ops) {}
 
  private:
   void Destroy() override {
@@ -287,6 +285,9 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
     delete this;
   }
 
+  absl::string_view Name() const override { return name_; }
+  std::string Filename() const override { return "RETIRED"; }
+  absl::string_view Typename() const override { return ""; }
   flags_internal::FlagOpFn TypeId() const override { return op_; }
   std::string Help() const override { return ""; }
   bool IsRetired() const override { return true; }
@@ -312,6 +313,7 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
   void Read(void*) const override {}
 
   // Data members
+  const char* const name_;
   const FlagOpFn op_;
 };
 
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 766aca42b313..4d0984d3d1fc 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -190,7 +190,12 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format,
 
 #if defined(ABSL_BAD_CALL_IF)
 constexpr int CalculateOneBit(const char* format) {
-  return (*format < '0' || *format > '9') ? 0 : (1 << (*format - '0'));
+  // Returns:
+  // * 2^N for '$N' when N is in [0-9]
+  // * 0 for correct '$' escaping: '$$'.
+  // * -1 otherwise.
+  return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
+                                          : (1 << (*format - '0'));
 }
 
 constexpr const char* SkipNumber(const char* format) {
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
index b005f0f47caa..450cd2bcfffe 100644
--- a/absl/strings/substitute_test.cc
+++ b/absl/strings/substitute_test.cc
@@ -192,10 +192,10 @@ TEST(SubstituteDeathTest, SubstituteDeath) {
       "Invalid absl::Substitute\\(\\) format std::string: asked for \"\\$2\", "
       "but only 2 args were given.");
   EXPECT_DEBUG_DEATH(
-      static_cast<void>(absl::Substitute("-$z-")),
+      static_cast<void>(absl::Substitute(absl::string_view("-$z-"))),
       "Invalid absl::Substitute\\(\\) format std::string: \"-\\$z-\"");
   EXPECT_DEBUG_DEATH(
-      static_cast<void>(absl::Substitute("-$")),
+      static_cast<void>(absl::Substitute(absl::string_view("-$"))),
       "Invalid absl::Substitute\\(\\) format std::string: \"-\\$\"");
 }
 
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh
index 6a3c19bddbdd..e85474c20a72 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -28,5 +28,5 @@ time docker run \
     --rm \
     -e CFLAGS="-Werror" \
     -e CXXFLAGS="-Werror" \
-    gcr.io/google.com/absl-177019/linux_gcc-latest:20191018 \
+    gcr.io/google.com/absl-177019/linux_gcc-latest:20200102 \
     /bin/bash CMake/install_test_project/test.sh $@
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index fa38ff20f7ba..24efe3b7a035 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
@@ -76,6 +76,7 @@ for std in ${STD}; do
           --copt="-fsanitize=float-divide-by-zero" \
           --copt="-fsanitize=nullability" \
           --copt="-fsanitize=undefined" \
+          --copt="-fno-sanitize-blacklist" \
           --copt=-Werror \
           --keep_going \
           --linkopt="-fsanitize=address" \
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index c3319a1b8e8c..40a27c0ba1d5 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 200541b9e9c0..00257b36ad82 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
@@ -73,6 +73,7 @@ for std in ${STD}; do
           --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
           --copt="-DTHREAD_SANITIZER" \
           --copt="-fsanitize=thread" \
+          --copt="-fno-sanitize-blacklist" \
           --copt=-Werror \
           --keep_going \
           --linkopt="-fsanitize=thread" \
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index 5ea18373570e..9fe71d3760f9 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200102"
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index a6efa197d9d1..70d24d79d6f1 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
   EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
 fi
 
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20191018"
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200102"
 
 # USE_BAZEL_CACHE=1 only works on Kokoro.
 # Without access to the credentials this won't work.
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index ec3287481c47..7effa0c09f24 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -47,7 +47,7 @@ for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
       --rm \
       -e CFLAGS="-Werror" \
       -e CXXFLAGS="-Werror" \
-      gcr.io/google.com/absl-177019/linux_gcc-latest:20191018 \
+      gcr.io/google.com/absl-177019/linux_gcc-latest:20200102 \
       /bin/bash -c "
         cd /buildfs && \
         cmake /abseil-cpp \