summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Martijn Vels <mvels@google.com>2023-01-20 07:20:05 -0800
committerGravatar Copybara-Service <copybara-worker@google.com>2023-01-20 07:21:07 -0800
commita0b102c35bae9dea68be21a718c8c7b459e239c8 (patch)
tree9123391c09f15b2f49ea725636d2b449796dad20
parentc611e5ce1de222eb995f5aeabf3fa8cd57ae124b (diff)
Add absl::is_constant_evaluated for pre-c++20 support
PiperOrigin-RevId: 503437019 Change-Id: I3630fec690f1472130fef21b16dfcd3c5208aa69
-rw-r--r--absl/base/config.h11
-rw-r--r--absl/meta/BUILD.bazel2
-rw-r--r--absl/meta/CMakeLists.txt2
-rw-r--r--absl/meta/type_traits.h39
-rw-r--r--absl/meta/type_traits_test.cc32
5 files changed, 86 insertions, 0 deletions
diff --git a/absl/base/config.h b/absl/base/config.h
index 1058ce74..5cbc9855 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -928,4 +928,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
#endif
+// ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of
+// constant evaluation support through `absl::is_constant_evaluated`.
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+#error ABSL_HAVE_CONSTANT_EVALUATED cannot be directly set
+#endif
+#ifdef __cpp_lib_is_constant_evaluated
+#define ABSL_HAVE_CONSTANT_EVALUATED 1
+#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
+#define ABSL_HAVE_CONSTANT_EVALUATED 1
+#endif
+
#endif // ABSL_BASE_CONFIG_H_
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index 4478ccf7..125446f9 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -42,7 +42,9 @@ cc_test(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":type_traits",
+ "//absl/base:config",
"//absl/base:core_headers",
+ "//absl/time",
"@com_google_googletest//:gtest_main",
],
)
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index f16f17bd..bb767d12 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -34,6 +34,8 @@ absl_cc_test(
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::config
+ absl::time
absl::core_headers
absl::type_traits
GTest::gmock_main
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index dd9de42f..b1656c39 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -844,6 +844,45 @@ template <class T>
struct is_trivially_relocatable : std::integral_constant<bool, false> {};
#endif
+// absl::is_constant_evaluated()
+//
+// Detects whether the function call occurs within a constant-evaluated context.
+// Returns true if the evaluation of the call occurs within the evaluation of an
+// expression or conversion that is manifestly constant-evaluated; otherwise
+// returns false.
+//
+// This function is implemented in terms of `std::is_constant_evaluated` for
+// c++20 and up. For older c++ versions, the function is implemented in terms
+// of `__builtin_is_constant_evaluated` if available, otherwise the function
+// will fail to compile.
+//
+// Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time
+// to check if this function is supported.
+//
+// Example:
+//
+// constexpr MyClass::MyClass(int param) {
+// #ifdef ABSL_HAVE_CONSTANT_EVALUATED
+// if (!absl::is_constant_evaluated()) {
+// ABSL_LOG(INFO) << "MyClass(" << param << ")";
+// }
+// #endif // ABSL_HAVE_CONSTANT_EVALUATED
+// }
+//
+// Upstream documentation:
+//
+// http://en.cppreference.com/w/cpp/types/is_constant_evaluated
+// http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated
+//
+#if defined(ABSL_HAVE_CONSTANT_EVALUATED)
+constexpr bool is_constant_evaluated() noexcept {
+#ifdef __cpp_lib_is_constant_evaluated
+ return std::is_constant_evaluated();
+#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
+ return __builtin_is_constant_evaluated();
+#endif
+}
+#endif // ABSL_HAVE_CONSTANT_EVALUATED
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index d08d9ad9..b2a7a67b 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -22,6 +22,9 @@
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
namespace {
@@ -1413,4 +1416,33 @@ TEST(TrivallyRelocatable, Sanity) {
EXPECT_TRUE(absl::is_trivially_relocatable<TrivialAbi>::value);
}
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+
+constexpr int64_t NegateIfConstantEvaluated(int64_t i) {
+ if (absl::is_constant_evaluated()) {
+ return -i;
+ } else {
+ return i;
+ }
+}
+
+#endif // ABSL_HAVE_CONSTANT_EVALUATED
+
+TEST(TrivallyRelocatable, is_constant_evaluated) {
+#ifdef ABSL_HAVE_CONSTANT_EVALUATED
+ constexpr int64_t constant = NegateIfConstantEvaluated(42);
+ EXPECT_EQ(constant, -42);
+
+ int64_t now = absl::ToUnixSeconds(absl::Now());
+ int64_t not_constant = NegateIfConstantEvaluated(now);
+ EXPECT_EQ(not_constant, now);
+
+ static int64_t const_init = NegateIfConstantEvaluated(42);
+ EXPECT_EQ(const_init, -42);
+#else
+ GTEST_SKIP() << "absl::is_constant_evaluated is not defined";
+#endif // ABSL_HAVE_CONSTANT_EVALUATED
+}
+
+
} // namespace