about summary refs log tree commit diff
path: root/absl/base
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base')
-rw-r--r--absl/base/config.h24
-rw-r--r--absl/base/exception_safety_testing_test.cc4
-rw-r--r--absl/base/internal/exception_safety_testing.h19
-rw-r--r--absl/base/thread_annotations.h31
4 files changed, 54 insertions, 24 deletions
diff --git a/absl/base/config.h b/absl/base/config.h
index 500bc8c810b3..3eb24abf2331 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -382,6 +382,19 @@
 #endif
 #endif
 
+// ABSL_HAVE_STD_VARIANT
+//
+// Checks whether C++17 std::optional is available.
+#ifdef ABSL_HAVE_STD_VARIANT
+#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_VARIANT 1
+#endif
+#endif
+
 // ABSL_HAVE_STD_STRING_VIEW
 //
 // Checks whether C++17 std::string_view is available.
@@ -396,17 +409,18 @@
 #endif
 
 // For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
-// the support for <optional>, <any>, <string_view>. So we use _MSC_VER to check
-// whether we have VS 2017 RTM (when <optional>, <any>, <string_view> is
-// implemented) or higher.
-// Also, `__cplusplus` is not correctly set by MSVC, so we use `_MSVC_LANG` to
-// check the language version.
+// the support for <optional>, <any>, <string_view>, <variant>. So we use
+// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
+// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
+// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
+// version.
 // TODO(zhangxy): fix tests before enabling aliasing for `std::any`,
 // `std::string_view`.
 #if defined(_MSC_VER) && _MSC_VER >= 1910 && \
     ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
 // #define ABSL_HAVE_STD_ANY 1
 #define ABSL_HAVE_STD_OPTIONAL 1
+#define ABSL_HAVE_STD_VARIANT 1
 // #define ABSL_HAVE_STD_STRING_VIEW 1
 #endif
 
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 041d780fa5be..94a7e4f7480c 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -27,7 +27,9 @@
 
 namespace absl {
 namespace {
+using ::absl::exceptions_internal::SetCountdown;
 using ::absl::exceptions_internal::TestException;
+using ::absl::exceptions_internal::UnsetCountdown;
 
 // EXPECT_NO_THROW can't inspect the thrown inspection in general.
 template <typename F>
@@ -54,7 +56,7 @@ TEST_F(ThrowingValueTest, Throws) {
   // It's not guaranteed that every operator only throws *once*.  The default
   // ctor only throws once, though, so use it to make sure we only throw when
   // the countdown hits 0
-  exceptions_internal::countdown = 2;
+  SetCountdown(2);
   ExpectNoThrow([]() { ThrowingValue<> bomb; });
   ExpectNoThrow([]() { ThrowingValue<> bomb; });
   EXPECT_THROW(ThrowingValue<> bomb, TestException);
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index 3493b5e2325d..48a292b3e1af 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -94,6 +94,12 @@ class TestBadAllocException : public std::bad_alloc, public TestException {
 
 extern int countdown;
 
+// Allows the countdown variable to be set manually (defaulting to the initial
+// value of 0)
+inline void SetCountdown(int i = 0) { countdown = i; }
+// Sets the countdown to the terminal value -1
+inline void UnsetCountdown() { SetCountdown(-1); }
+
 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
 
 testing::AssertionResult FailureMessage(const TestException& e,
@@ -134,7 +140,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
     const Invariant& invariant) {
   auto t_ptr = factory();
   absl::optional<testing::AssertionResult> current_res;
-  exceptions_internal::countdown = count;
+  SetCountdown(count);
   try {
     operation(t_ptr.get());
   } catch (const exceptions_internal::TestException& e) {
@@ -143,7 +149,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
       *current_res << e.what() << " failed invariant check";
     }
   }
-  exceptions_internal::countdown = -1;
+  UnsetCountdown();
   return current_res;
 }
 
@@ -196,11 +202,6 @@ inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
 extern exceptions_internal::NoThrowTag no_throw_ctor;
 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
 
-// These are useful for tests which just construct objects and make sure there
-// are no leaks.
-inline void SetCountdown() { exceptions_internal::countdown = 0; }
-inline void UnsetCountdown() { exceptions_internal::countdown = -1; }
-
 // A test class which is convertible to bool.  The conversion can be
 // instrumented to throw at a controlled time.
 class ThrowingBool {
@@ -731,10 +732,10 @@ struct ConstructorTracker {
 template <typename T, typename... Args>
 T TestThrowingCtor(Args&&... args) {
   struct Cleanup {
-    ~Cleanup() { UnsetCountdown(); }
+    ~Cleanup() { exceptions_internal::UnsetCountdown(); }
   } c;
   for (int count = 0;; ++count) {
-    exceptions_internal::countdown = count;
+    exceptions_internal::SetCountdown(count);
     try {
       return T(std::forward<Args>(args)...);
     } catch (const exceptions_internal::TestException&) {
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index 0da3badc4e2d..8d30b9324b52 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -47,10 +47,17 @@
 // mutex. GUARDED_BY() allows the user to specify a particular mutex that
 // should be held when accessing the annotated variable.
 //
+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
 // Example:
 //
-//   Mutex mu;
-//   int p1 GUARDED_BY(mu);
+//   class Foo {
+//     Mutex mu_;
+//     int p1_ GUARDED_BY(mu_);
+//     ...
+//   };
 #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
 
 // PT_GUARDED_BY()
@@ -59,17 +66,20 @@
 // by a mutex when dereferencing the pointer.
 //
 // Example:
-//   Mutex mu;
-//   int *p1 PT_GUARDED_BY(mu);
+//   class Foo {
+//     Mutex mu_;
+//     int *p1_ PT_GUARDED_BY(mu_);
+//     ...
+//   };
 //
 // Note that a pointer variable to a shared memory location could itself be a
 // shared variable.
 //
 // Example:
 //
-//     // `q`, guarded by `mu1`, points to a shared memory location that is
-//     // guarded by `mu2`:
-//     int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+//   // `q_`, guarded by `mu1_`, points to a shared memory location that is
+//   // guarded by `mu2_`:
+//   int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
 #define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
 
 // ACQUIRED_AFTER() / ACQUIRED_BEFORE()
@@ -80,10 +90,13 @@
 // (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
 // and ACQUIRED_BEFORE.)
 //
+// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
 // Example:
 //
-//   Mutex m1;
-//   Mutex m2 ACQUIRED_AFTER(m1);
+//   Mutex m1_;
+//   Mutex m2_ ACQUIRED_AFTER(m1_);
 #define ACQUIRED_AFTER(...) \
   THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))