[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