Improve ABSL_ASSERT performance by guaranteeing it is optimized away under NDEBUG in C++20

Also fix the old definition by verifying that the condition is contextually convertible to bool.

The new C++20 definition reduces codegen bloat and guarantees fast performance while still retaining the expression (so that unused-variable warnings don't trigger).

As an example where this makes a difference, compare the following snippet under `-DABSL_INTERNAL_CPLUSPLUS_LANG=202002`: https://godbolt.org/z/hjf59n84v
```
#include <stdlib.h>
template<class T> struct S { S() { abort(); } static S const s; };
template<class T> S<T> const S<T>::s = {};
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
#define ABSL_ASSERT(expr) (decltype((expr) ? void() : void())())
#else
#define ABSL_ASSERT(expr) (false ? ((expr) ? void() : void()) : void())
#endif
void foo() { ABSL_ASSERT(((void)&S<int>::s, true)); }
```

We see that, in unoptimized builds, code is still generated with the old definition of `ABSL_ASSERT`. Moreover, even under optimizations (with `-O2`), the call to abort() still lingers with the old definition of `ABSL_ASSERT`.

Therefore the extra generated code can affect both compile- and run-time performance.

PiperOrigin-RevId: 681563573
Change-Id: I7fbfadcc7fd198e8e1daf14615c33687f6b23af7
diff --git a/absl/base/macros.h b/absl/base/macros.h
index ccc86ab..ff89944 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -82,8 +82,9 @@
 // ABSL_ASSERT()
 //
 // In C++11, `assert` can't be used portably within constexpr functions.
+// `assert` also generates spurious unused-symbol warnings.
 // ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
-// functions.  Example:
+// functions, and maintains references to symbols.  Example:
 //
 // constexpr double Divide(double a, double b) {
 //   return ABSL_ASSERT(b != 0), a / b;
@@ -92,8 +93,18 @@
 // This macro is inspired by
 // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
 #if defined(NDEBUG)
-#define ABSL_ASSERT(expr) \
-  (false ? static_cast<void>(expr) : static_cast<void>(0))
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+// We use `decltype` here to avoid generating unnecessary code that the
+// optimizer then has to optimize away.
+// This not only improves compilation performance by reducing codegen bloat
+// and optimization work, but also guarantees fast run-time performance without
+// having to rely on the optimizer.
+#define ABSL_ASSERT(expr) (decltype((expr) ? void() : void())())
+#else
+// Pre-C++20, lambdas can't be inside unevaluated operands, so we're forced to
+// rely on the optimizer.
+#define ABSL_ASSERT(expr) (false ? ((expr) ? void() : void()) : void())
+#endif
 #else
 #define ABSL_ASSERT(expr)                           \
   (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \