summaryrefslogtreecommitdiff
path: root/absl/base
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
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')
-rw-r--r--absl/base/macros.h26
-rw-r--r--absl/base/optimization.h59
2 files changed, 61 insertions, 24 deletions
diff --git a/absl/base/macros.h b/absl/base/macros.h
index 3e085a91..bbf7494f 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -103,17 +103,11 @@ ABSL_NAMESPACE_END
// aborts the program in release mode (when NDEBUG is defined). The
// implementation should abort the program as quickly as possible and ideally it
// should not be possible to ignore the abort request.
-#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \
- ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
- (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_INTERNAL_HARDENING_ABORT() \
- do { \
- __builtin_trap(); \
- __builtin_unreachable(); \
+#define ABSL_INTERNAL_HARDENING_ABORT() \
+ do { \
+ ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
+ ABSL_INTERNAL_UNREACHABLE_IMPL(); \
} while (false)
-#else
-#define ABSL_INTERNAL_HARDENING_ABORT() abort()
-#endif
// ABSL_HARDENING_ASSERT()
//
@@ -144,15 +138,7 @@ ABSL_NAMESPACE_END
#define ABSL_INTERNAL_RETHROW do {} while (false)
#endif // ABSL_HAVE_EXCEPTIONS
-// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which
-// reaches one has undefined behavior, and the compiler may optimize
-// accordingly.
-#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
-#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
-#elif defined(_MSC_VER)
-#define ABSL_INTERNAL_UNREACHABLE __assume(0)
-#else
-#define ABSL_INTERNAL_UNREACHABLE
-#endif
+// TODO(b/261916195): Replace ABSL_INTERNAL_UNREACHABLE with ABSL_UNREACHABLE().
+#define ABSL_INTERNAL_UNREACHABLE ABSL_UNREACHABLE()
#endif // ABSL_BASE_MACROS_H_
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)