summaryrefslogtreecommitdiff
path: root/absl/base/optimization.h
diff options
context:
space:
mode:
authorGravatar Derek Mauro <dmauro@google.com>2022-12-21 07:31:39 -0800
committerGravatar Copybara-Service <copybara-worker@google.com>2022-12-21 07:33:17 -0800
commit6a876051b118c86e8bfa51961270055da5948813 (patch)
tree6743ba90a11607eb92365ab96073dc95f5770fd3 /absl/base/optimization.h
parent8caa47cfcddbcddd36d22bbab13f4cd9bccbf5c2 (diff)
Adds ABSL_UNREACHABLE(), a public symbol to replace ABSL_INTERNAL_UNREACHABLE
ABSL_UNREACHABLE() is an unreachable statement. A program which reaches one has undefined behavior, and the compiler may optimize accordingly. The behavior is changed to abort the program in !NDEBUG or ABSL_OPTION_HARDENED modes. PiperOrigin-RevId: 496917150 Change-Id: If036b2d9567933fa266fbcd33f3f98c682ad7f41
Diffstat (limited to 'absl/base/optimization.h')
-rw-r--r--absl/base/optimization.h59
1 files changed, 55 insertions, 4 deletions
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index d706100c..04870cba 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -181,6 +181,52 @@
#define ABSL_PREDICT_TRUE(x) (x)
#endif
+// `ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL()` aborts the program in the fastest
+// possible way, with no attempt at logging. One use is to implement hardening
+// aborts with ABSL_OPTION_HARDENED. Since this is an internal symbol, it
+// should not be used directly outside of Abseil.
+#if ABSL_HAVE_BUILTIN(__builtin_trap) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() __builtin_trap()
+#else
+#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() abort()
+#endif
+
+// `ABSL_INTERNAL_UNREACHABLE_IMPL()` is the platform specific directive to
+// indicate that a statement is unreachable, and to allow the compiler to
+// optimize accordingly. Clients should use `ABSL_UNREACHABLE()`, which is
+// defined below.
+#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
+#define ABSL_INTERNAL_UNREACHABLE_IMPL() std::unreachable()
+#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_unreachable()
+#elif ABSL_HAVE_BUILTIN(__builtin_assume)
+#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_assume(false)
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_UNREACHABLE_IMPL() __assume(false)
+#else
+#define ABSL_INTERNAL_UNREACHABLE_IMPL()
+#endif
+
+// `ABSL_UNREACHABLE()` is an unreachable statement. A program which reaches
+// one has undefined behavior, and the compiler may optimize accordingly.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+// Abort in hardened mode to avoid dangerous undefined behavior.
+#define ABSL_UNREACHABLE() \
+ do { \
+ ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
+ ABSL_INTERNAL_UNREACHABLE_IMPL(); \
+ } while (false)
+#else
+// The assert only fires in debug mode to aid in debugging.
+// When NDEBUG is defined, reaching ABSL_UNREACHABLE() is undefined behavior.
+#define ABSL_UNREACHABLE() \
+ do { \
+ assert(false && "ABSL_UNREACHABLE reached"); \
+ ABSL_INTERNAL_UNREACHABLE_IMPL(); \
+ } while (false)
+#endif
+
// ABSL_ASSUME(cond)
//
// Informs the compiler that a condition is always true and that it can assume
@@ -209,18 +255,23 @@
#define ABSL_ASSUME(cond) assert(cond)
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_ASSUME(cond) __builtin_assume(cond)
+#elif defined(_MSC_VER)
+#define ABSL_ASSUME(cond) __assume(cond)
+#elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
+#define ABSL_ASSUME(cond) \
+ do { \
+ if (!(cond)) std::unreachable(); \
+ } while (false)
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_ASSUME(cond) \
do { \
if (!(cond)) __builtin_unreachable(); \
- } while (0)
-#elif defined(_MSC_VER)
-#define ABSL_ASSUME(cond) __assume(cond)
+ } while (false)
#else
#define ABSL_ASSUME(cond) \
do { \
static_cast<void>(false && (cond)); \
- } while (0)
+ } while (false)
#endif
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)