about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/container/inlined_vector_benchmark.cc110
-rw-r--r--absl/flags/internal/flag.h2
-rw-r--r--absl/flags/marshalling.h9
-rw-r--r--absl/time/internal/cctz/include/cctz/civil_time.h4
-rw-r--r--absl/time/internal/cctz/src/civil_time_test.cc2
-rw-r--r--absl/time/internal/cctz/src/time_zone_info.cc3
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc95
-rw-r--r--absl/time/internal/cctz/src/zone_info_source.cc18
-rw-r--r--absl/types/internal/variant.h12
-rw-r--r--absl/types/variant_test.cc5
10 files changed, 182 insertions, 78 deletions
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index b57fc1de9e3b..a8368d418c53 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -379,6 +379,10 @@ constexpr size_t kLargeSize = kInlinedCapacity * 2;
 constexpr size_t kSmallSize = kInlinedCapacity / 2;
 constexpr size_t kBatchSize = 100;
 
+#define ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_FunctionTemplate, T) \
+  BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize);        \
+  BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize)
+
 template <typename T>
 using InlVec = absl::InlinedVector<T, kInlinedCapacity>;
 
@@ -420,29 +424,115 @@ void BatchedBenchmark(benchmark::State& state, PrepareVecFn prepare_vec,
   while (state.KeepRunningBatch(kBatchSize)) {
     // Prepare batch
     state.PauseTiming();
-    for (auto& vec : vector_batch) {
-      prepare_vec(&vec);
+    for (size_t i = 0; i < kBatchSize; ++i) {
+      prepare_vec(vector_batch.data() + i, i);
     }
     benchmark::DoNotOptimize(vector_batch);
     state.ResumeTiming();
 
     // Test batch
-    for (auto& vec : vector_batch) {
-      test_vec(&vec);
+    for (size_t i = 0; i < kBatchSize; ++i) {
+      test_vec(vector_batch.data() + i, i);
     }
   }
 }
 
+template <typename T, size_t ToSize>
+void BM_ConstructFromSize(benchmark::State& state) {
+  using VecT = InlVec<T>;
+  auto size = ToSize;
+  BatchedBenchmark<T>(
+      state,
+      /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+      /* test_vec = */
+      [&](void* ptr, size_t) {
+        benchmark::DoNotOptimize(size);
+        ::new (ptr) VecT(size);
+      });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromSizeRef(benchmark::State& state) {
+  using VecT = InlVec<T>;
+  auto size = ToSize;
+  auto ref = T();
+  BatchedBenchmark<T>(
+      state,
+      /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+      /* test_vec = */
+      [&](void* ptr, size_t) {
+        benchmark::DoNotOptimize(size);
+        benchmark::DoNotOptimize(ref);
+        ::new (ptr) VecT(size, ref);
+      });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromRange(benchmark::State& state) {
+  using VecT = InlVec<T>;
+  std::array<T, ToSize> arr{};
+  BatchedBenchmark<T>(
+      state,
+      /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+      /* test_vec = */
+      [&](void* ptr, size_t) {
+        benchmark::DoNotOptimize(arr);
+        ::new (ptr) VecT(arr.begin(), arr.end());
+      });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromCopy(benchmark::State& state) {
+  using VecT = InlVec<T>;
+  VecT other_vec(ToSize);
+  BatchedBenchmark<T>(
+      state,
+      /* prepare_vec = */
+      [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+      /* test_vec = */
+      [&](void* ptr, size_t) {
+        benchmark::DoNotOptimize(other_vec);
+        ::new (ptr) VecT(other_vec);
+      });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromMove(benchmark::State& state) {
+  using VecT = InlVec<T>;
+  std::array<VecT, kBatchSize> vector_batch{};
+  BatchedBenchmark<T>(
+      state,
+      /* prepare_vec = */
+      [&](InlVec<T>* vec, size_t i) {
+        vector_batch[i].clear();
+        vector_batch[i].resize(ToSize);
+        vec->~VecT();
+      },
+      /* test_vec = */
+      [&](void* ptr, size_t i) {
+        benchmark::DoNotOptimize(vector_batch[i]);
+        ::new (ptr) VecT(std::move(vector_batch[i]));
+      });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
+
 template <typename T, size_t FromSize>
 void BM_Clear(benchmark::State& state) {
   BatchedBenchmark<T>(
       state,
-      /* prepare_vec = */ [](InlVec<T>* vec) { vec->resize(FromSize); },
-      /* test_vec = */ [](InlVec<T>* vec) { vec->clear(); });
+      /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+      /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->clear(); });
 }
-BENCHMARK_TEMPLATE(BM_Clear, TrivialType, kLargeSize);
-BENCHMARK_TEMPLATE(BM_Clear, TrivialType, kSmallSize);
-BENCHMARK_TEMPLATE(BM_Clear, NontrivialType, kLargeSize);
-BENCHMARK_TEMPLATE(BM_Clear, NontrivialType, kSmallSize);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, NontrivialType);
 
 }  // namespace
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 6402866f2249..9b32f46735b6 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -56,7 +56,7 @@ class Flag {
   // forward declared types.
   //  auto IsCopyConstructible(const T& v) -> decltype(T(v));
   //  auto HasAbslParseFlag(absl::string_view in, T* dst, std::string* err)
-  //      -> decltype(AbslParseFlag(in, dst, GlobalStringADLGuard(err)));
+  //      -> decltype(AbslParseFlag(in, dst, err));
   //  auto HasAbslUnparseFlag(const T& v) -> decltype(AbslUnparseFlag(v));
 };
 
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 669cf452c4b0..7eb75cde7623 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -185,18 +185,11 @@ bool AbslParseFlag(absl::string_view, double*, std::string*);
 bool AbslParseFlag(absl::string_view, std::string*, std::string*);
 bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*);
 
-struct GlobalStringADLGuard {
-  explicit GlobalStringADLGuard(std::string* p) : ptr(p) {}
-  operator std::string*() { return ptr; }  // NOLINT
-  std::string* ptr;
-};
-
 template <typename T>
 bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) {
   // Comment on next line provides a good compiler error message if T
   // does not have AbslParseFlag(absl::string_view, T*, std::string*).
-  return AbslParseFlag(  // Is T missing AbslParseFlag?
-      input, dst, GlobalStringADLGuard(err));
+  return AbslParseFlag(input, dst, err);  // Is T missing AbslParseFlag?
 }
 
 // Strings and std:: containers do not have the same overload resolution
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h
index f844182b1c90..aa578ee3648c 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -306,9 +306,9 @@ using detail::get_weekday;
 //
 //   civil_day d = ...
 //   // Gets the following Thursday if d is not already Thursday
-//   civil_day thurs1 = prev_weekday(d, weekday::thursday) + 7;
+//   civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
 //   // Gets the previous Thursday if d is not already Thursday
-//   civil_day thurs2 = next_weekday(d, weekday::thursday) - 7;
+//   civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
 //
 using detail::next_weekday;
 using detail::prev_weekday;
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index dc7e5a1d35c6..b1f46f1284e0 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -1035,7 +1035,7 @@ TEST(CivilTime, LeapYears) {
 
 TEST(CivilTime, FirstThursdayInMonth) {
   const civil_day nov1(2014, 11, 1);
-  const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7;
+  const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
   EXPECT_EQ("2014-11-06", Format(thursday));
 
   // Bonus: Date of Thanksgiving in the United States
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index 50f7de54014f..184bd434c2d2 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -682,7 +682,6 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
   // Use of the "file:" prefix is intended for testing purposes only.
   if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
 
-#if defined(__ANDROID__)
   // See Android's libc/tzcode/bionic.cpp for additional information.
   for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
                              "/system/usr/share/zoneinfo/tzdata"}) {
@@ -717,7 +716,7 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
       }
     }
   }
-#endif  // __ANDROID__
+
   return nullptr;
 }
 
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 3ab1623cbd17..6095e764df0d 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -21,7 +21,6 @@
 #include <chrono>
 #include <ctime>
 #include <limits>
-#include <tuple>
 #include <utility>
 
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
@@ -33,57 +32,75 @@ namespace cctz {
 
 namespace {
 
-// .first is seconds east of UTC; .second is the time-zone abbreviation.
-using OffsetAbbr = std::pair<int, const char*>;
-
-// Defines a function that can be called as follows:
-//
-//   std::tm tm = ...;
-//   OffsetAbbr off_abbr = get_offset_abbr(tm);
-//
 #if defined(_WIN32) || defined(_WIN64)
 // Uses the globals: '_timezone', '_dstbias' and '_tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
   const bool is_dst = tm.tm_isdst > 0;
-  const int off = _timezone + (is_dst ? _dstbias : 0);
-  const char* abbr = _tzname[is_dst];
-  return {off, abbr};
+  return _timezone + (is_dst ? _dstbias : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return _tzname[is_dst];
 }
 #elif defined(__sun)
 // Uses the globals: 'timezone', 'altzone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
   const bool is_dst = tm.tm_isdst > 0;
-  const int off = is_dst ? altzone : timezone;
-  const char* abbr = tzname[is_dst];
-  return {off, abbr};
+  return is_dst ? altzone : timezone;
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return tzname[is_dst];
 }
 #elif defined(__native_client__) || defined(__myriad2__) || \
     defined(__EMSCRIPTEN__)
 // Uses the globals: 'timezone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return _timezone + (is_dst ? 60 * 60 : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
   const bool is_dst = tm.tm_isdst > 0;
-  const int off = _timezone + (is_dst ? 60 * 60 : 0);
-  const char* abbr = tzname[is_dst];
-  return {off, abbr};
+  return tzname[is_dst];
+}
+#else
+// Adapt to different spellings of the struct std::tm extension fields.
+#if defined(tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
+  return tm.tm_gmtoff;
+}
+#elif defined(__tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
+  return tm.__tm_gmtoff;
+}
+#else
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
+  return tm.tm_gmtoff;
+}
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
+  return tm.__tm_gmtoff;
+}
+#endif  // tm_gmtoff
+#if defined(tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
+  return tm.tm_zone;
+}
+#elif defined(__tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
+  return tm.__tm_zone;
 }
 #else
-//
-// Returns an OffsetAbbr using std::tm fields with various spellings.
-//
-#if !defined(tm_gmtoff) && !defined(tm_zone)
 template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
-                           decltype(&T::tm_zone) = nullptr) {
-  return {tm.tm_gmtoff, tm.tm_zone};
+auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
+  return tm.tm_zone;
 }
-#endif  // !defined(tm_gmtoff) && !defined(tm_zone)
-#if !defined(__tm_gmtoff) && !defined(__tm_zone)
 template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
-                           decltype(&T::__tm_zone) = nullptr) {
-  return {tm.__tm_gmtoff, tm.__tm_zone};
+auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
+  return tm.__tm_zone;
 }
-#endif  // !defined(__tm_gmtoff) && !defined(__tm_zone)
+#endif  // tm_zone
 #endif
 
 inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
@@ -126,7 +143,7 @@ bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
       return false;
     }
   }
-  *off = get_offset_abbr(tm).first;
+  *off = static_cast<int>(tm_gmtoff(tm));
   return true;
 }
 
@@ -137,7 +154,7 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
   while (lo + 1 != hi) {
     const std::time_t mid = lo + (hi - lo) / 2;
     if (std::tm* tmp = local_time(&mid, &tm)) {
-      if (get_offset_abbr(*tmp).first == offset) {
+      if (tm_gmtoff(*tmp) == offset) {
         hi = mid;
       } else {
         lo = mid;
@@ -147,7 +164,7 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
       // ignoring all failed conversions.  Slow, but never really happens.
       while (++lo != hi) {
         if (std::tm* tmp = local_time(&lo, &tm)) {
-          if (get_offset_abbr(*tmp).first == offset) break;
+          if (tm_gmtoff(*tmp) == offset) break;
         }
       }
       return lo;
@@ -193,8 +210,8 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime(
   const year_t year = tmp->tm_year + year_t{1900};
   al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
                        tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-  std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
-  if (!local_) al.abbr = "UTC";  // as expected by cctz
+  al.offset = static_cast<int>(tm_gmtoff(*tmp));
+  al.abbr = local_ ? tm_zone(*tmp) : "UTC";  // as expected by cctz
   al.is_dst = tmp->tm_isdst > 0;
   return al;
 }
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index 132484628cd9..42f50c5e8fb4 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -46,7 +46,13 @@ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
 // A "weak" definition for cctz_extension::zone_info_source_factory.
 // The user may override this with their own "strong" definition (see
 // zone_info_source.h).
-#if defined(_MSC_VER)
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+#if __has_attribute(weak) || defined(__GNUC__)
+ZoneInfoSourceFactory zone_info_source_factory
+    __attribute__((weak)) = DefaultFactory;
+#elif defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
 extern ZoneInfoSourceFactory zone_info_source_factory;
 extern ZoneInfoSourceFactory default_factory;
 ZoneInfoSourceFactory default_factory = DefaultFactory;
@@ -60,19 +66,11 @@ ZoneInfoSourceFactory default_factory = DefaultFactory;
     "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
 #else
 #error Unsupported MSVC platform
-#endif
-#else  // _MSC_VER
-#if !defined(__has_attribute)
-#define __has_attribute(x) 0
-#endif
-#if __has_attribute(weak) || defined(__GNUC__)
-ZoneInfoSourceFactory zone_info_source_factory
-    __attribute__((weak)) = DefaultFactory;
+#endif  // _M_<PLATFORM>
 #else
 // Make it a "strong" definition if we have no other choice.
 ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
 #endif
-#endif  // _MSC_VER
 
 }  // namespace cctz_extension
 }  // namespace time_internal
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index 5ca66e2902c6..85201b4ae1f9 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -837,8 +837,8 @@ struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
   // NOTE: const& and && are used instead of by-value due to lack of guaranteed
   // move elision of C++17. This may have other minor differences, but tests
   // pass.
-  static SizeT<I> Run(const H&);
-  static SizeT<I> Run(H&&);
+  static SizeT<I> Run(const H&, SizeT<I>);
+  static SizeT<I> Run(H&&, SizeT<I>);
 };
 
 // The following metafunctions are used in constructor and assignment
@@ -860,7 +860,8 @@ struct ConversionIsPossibleImpl : std::false_type {};
 
 template <class Variant, class T>
 struct ConversionIsPossibleImpl<
-    Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+    Variant, T,
+    void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
     : std::true_type {};
 
 template <class Variant, class T>
@@ -868,8 +869,9 @@ struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {};
 
 template <class Variant, class T>
 struct IndexOfConstructedType<
-    Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
-    : decltype(ImaginaryFun<Variant>::Run(std::declval<T>())) {};
+    Variant, T,
+    void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
+    : decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {})) {};
 
 template <std::size_t... Is>
 struct ContainsVariantNPos
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index b9c981181c50..d702482768a4 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -460,6 +460,11 @@ TYPED_TEST(VariantTypesTest, TestValueCtor) {
   EXPECT_EQ(value.value, mutable_valptr->value);
 }
 
+TEST(VariantTest, AmbiguousValueConstructor) {
+  EXPECT_FALSE((std::is_convertible<int, absl::variant<int, int>>::value));
+  EXPECT_FALSE((std::is_constructible<absl::variant<int, int>, int>::value));
+}
+
 TEST(VariantTest, InPlaceType) {
   using Var = variant<int, std::string, NonCopyable, std::vector<int>>;