[meta] Add constexpr testing helper.

PiperOrigin-RevId: 846383067
Change-Id: Ia8dbbb805f59eb4cb5334290c3e24e0117777ca2
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index 406e524..26468c6 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -35,6 +35,32 @@
 licenses(["notice"])
 
 cc_library(
+    name = "constexpr_testing",
+    testonly = 1,
+    hdrs = ["internal/constexpr_testing.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "constexpr_testing_test",
+    srcs = ["internal/constexpr_testing_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":constexpr_testing",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "requires",
     hdrs = ["internal/requires.h"],
     copts = ABSL_DEFAULT_COPTS,
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index 20650cc..c98c360 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -16,6 +16,29 @@
 
 absl_cc_library(
   NAME
+    constexpr_testing_internal
+  HDRS
+    "internal/constexpr_testing.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+)
+
+absl_cc_test(
+  NAME
+    constexpr_testing_test
+  SRCS
+    "internal/constexpr_testing_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::constexpr_testing_internal
+    GTest::gmock_main
+)
+
+absl_cc_library(
+  NAME
     requires_internal
   HDRS
     "internal/requires.h"
diff --git a/absl/meta/internal/constexpr_testing.h b/absl/meta/internal/constexpr_testing.h
new file mode 100644
index 0000000..eddf64b
--- /dev/null
+++ b/absl/meta/internal/constexpr_testing.h
@@ -0,0 +1,73 @@
+// Copyright 2025 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
+#define ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace meta_internal {
+
+// HasConstexprEvaluation([] { ... }) will evaluate to `true` if the
+// lambda can be evaluated in a constant expression and `false`
+// otherwise.
+// The return type of the lambda is not relevant, as long as the whole
+// evaluation works in a constant expression.
+template <typename F>
+constexpr bool HasConstexprEvaluation(F f);
+
+/// Implementation details below ///
+
+namespace internal_constexpr_evaluation {
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wuninitialized"
+#endif
+// This will give a constexpr instance of `F`.
+// This works for captureless lambdas because they have no state and the copy
+// constructor does not look at the input reference.
+template <typename F>
+constexpr F default_instance = default_instance<F>;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+template <typename F>
+constexpr std::integral_constant<bool, (default_instance<F>(), true)> Tester(
+    int) {
+  return {};
+}
+
+template <typename S>
+constexpr std::false_type Tester(char) {
+  return {};
+}
+
+}  // namespace internal_constexpr_evaluation
+
+template <typename F>
+constexpr bool HasConstexprEvaluation(F) {
+  return internal_constexpr_evaluation::Tester<F>(0);
+}
+
+}  // namespace meta_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_META_INTERNAL_CONSTEXPR_TESTING_H_
diff --git a/absl/meta/internal/constexpr_testing_test.cc b/absl/meta/internal/constexpr_testing_test.cc
new file mode 100644
index 0000000..50c8c53
--- /dev/null
+++ b/absl/meta/internal/constexpr_testing_test.cc
@@ -0,0 +1,40 @@
+// Copyright 2025 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/meta/internal/constexpr_testing.h"
+
+#include <map>
+#include <string_view>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(ConstexprTesting, Basic) {
+  using absl::meta_internal::HasConstexprEvaluation;
+
+  EXPECT_TRUE(HasConstexprEvaluation([] {}));
+  static constexpr int const_global = 7;
+  EXPECT_TRUE(HasConstexprEvaluation([] { return const_global; }));
+  EXPECT_TRUE(HasConstexprEvaluation([] { return 0; }));
+  EXPECT_TRUE(HasConstexprEvaluation([] { return std::string_view{}; }));
+
+  static int nonconst_global;
+  EXPECT_FALSE(HasConstexprEvaluation([] { return nonconst_global; }));
+  EXPECT_FALSE(HasConstexprEvaluation([] { std::abort(); }));
+  EXPECT_FALSE(HasConstexprEvaluation([] { return std::map<int, int>(); }));
+}
+
+}  // namespace