pw_polyfill: Update language feature support

- Support using C++20's consteval and constinit keywords in older C++
  versions.
- Support C++ language features through an implicitly included header.
  This allows all C++ code to use modern-style static_assert and the
  consteval or constinit keywords without including any headers.

Change-Id: I53a05ab6d6cdd801996498e7f93c5e68bf14d315
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/15662
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_polyfill/BUILD b/pw_polyfill/BUILD
index 36affb2..c37bde3 100644
--- a/pw_polyfill/BUILD
+++ b/pw_polyfill/BUILD
@@ -25,7 +25,7 @@
 pw_cc_library(
     name = "pw_polyfill",
     hdrs = [
-        "public/pw_polyfill/language_features.h",
+        "public/pw_polyfill/language_feature_macros.h",
         "public/pw_polyfill/standard.h",
     ],
     includes = ["public"],
@@ -34,12 +34,17 @@
 
 pw_cc_library(
     name = "overrides",
+    srcs = ["language_features.h"],
     hdrs = [
         "public_overrides/assert.h",
         "public_overrides/cstddef",
         "public_overrides/iterator",
         "public_overrides/type_traits",
     ],
+    copts = [
+        "-include",
+        "language_features.h",
+    ],
     includes = ["public_overrides"],
     deps = [":standard_library"],
 )
diff --git a/pw_polyfill/BUILD.gn b/pw_polyfill/BUILD.gn
index 2dcb666..59d44fe 100644
--- a/pw_polyfill/BUILD.gn
+++ b/pw_polyfill/BUILD.gn
@@ -20,6 +20,7 @@
 import("$dir_pw_unit_test/test.gni")
 config("public") {
   include_dirs = [ "public" ]
+  visibility = [ ":*" ]
 }
 
 pw_source_set("pw_polyfill") {
@@ -27,13 +28,21 @@
   remove_public_deps = [ "*" ]
   public_deps = [ ":standard_library" ]
   public = [
-    "public/pw_polyfill/language_features.h",
+    "public/pw_polyfill/language_feature_macros.h",
     "public/pw_polyfill/standard.h",
   ]
 }
 
 config("overrides_config") {
   include_dirs = [ "public_overrides" ]
+  cflags_cc = [
+    # Use -include to include the language features header in dependent files,
+    # without requiring a #include. This allows the use of newer C++ language
+    # features in older C++ versions without an explicit include.
+    "-include",
+    rebase_path("language_features.h"),
+  ]
+  visibility = [ ":*" ]
 }
 
 pw_source_set("overrides") {
@@ -46,6 +55,7 @@
     "public_overrides/iterator",
     "public_overrides/type_traits",
   ]
+  sources = [ "language_features.h" ]
 }
 
 config("standard_library_public") {
diff --git a/pw_polyfill/CMakeLists.txt b/pw_polyfill/CMakeLists.txt
index 0914577..583b500 100644
--- a/pw_polyfill/CMakeLists.txt
+++ b/pw_polyfill/CMakeLists.txt
@@ -22,3 +22,6 @@
     public_overrides
     standard_library_public
 )
+target_compile_options(pw_polyfill.overrides INTERFACE
+    -include "${CMAKE_CURRENT_SOURCE_DIR}/language_features.h"
+)
diff --git a/pw_polyfill/language_features.h b/pw_polyfill/language_features.h
new file mode 100644
index 0000000..0a0e5cb
--- /dev/null
+++ b/pw_polyfill/language_features.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Pigweed 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.
+
+// This file provides adapters for newer C++ language features so that they can
+// be used in older versions of C++ (though the code will not function exactly
+// the same). This file is not on an include path and is intended to be used
+// with -include when compiling C++.
+//
+// pw_polyfill/language_feature_macros.h provides macro wrappers for a few
+// specific uses of modern C++ keywords.
+#pragma once
+
+// C++11 is required for the features in this header.
+#if __cplusplus >= 201103L
+
+// If consteval is not supported, use constexpr. This does not guarantee
+// compile-time execution, but works equivalently in constant expressions.
+#ifndef __cpp_consteval
+#define consteval constexpr
+#endif  // __cpp_consteval
+
+// If constinit is not supported, use a compiler attribute or omit it. If
+// omitted, the compiler may still constant initialize the variable, but there
+// is no guarantee.
+#ifndef __cpp_constinit
+#ifdef __clang__
+#define constinit [[clang::require_constant_initialization]]
+#else
+#define constinit
+#endif  // __clang__
+#endif  // __cpp_constinit
+
+// This is an adapter for supporting static_assert with a single argument in
+// C++11 or C++14. Macros don't correctly parse commas in template expressions,
+// so the static_assert arguments are passed to an overloaded C++ function. The
+// full stringified static_assert arguments are used as the message.
+#if __cpp_static_assert < 201411L
+
+#define static_assert(...)                                                     \
+  static_assert(::pw::polyfill::internal::StaticAssertExpression(__VA_ARGS__), \
+                #__VA_ARGS__)
+
+namespace pw {
+namespace polyfill {
+namespace internal {
+
+constexpr bool StaticAssertExpression(bool expression) { return expression; }
+
+constexpr bool StaticAssertExpression(bool expression, const char*) {
+  return expression;
+}
+
+}  // namespace internal
+}  // namespace polyfill
+}  // namespace pw
+
+#endif  // __cpp_static_assert < 201411L
+#endif  // __cplusplus >= 201103L
diff --git a/pw_polyfill/public/pw_polyfill/language_feature_macros.h b/pw_polyfill/public/pw_polyfill/language_feature_macros.h
new file mode 100644
index 0000000..389493f
--- /dev/null
+++ b/pw_polyfill/public/pw_polyfill/language_feature_macros.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Pigweed 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.
+
+// Macros for adapting to older versions of C++. A few keywords (consteval,
+// constinit) are handled by pw_polfyill/language_features.h, which is directly
+// -included by users of pw_polyfill.
+#pragma once
+
+#ifdef __cpp_inline_variables
+#define PW_INLINE_VARIABLE inline
+#else
+#define PW_INLINE_VARIABLE
+#endif  // __cpp_inline_variables
+
+// Mark functions as constexpr if the relaxed constexpr rules are supported.
+#if __cpp_constexpr >= 201304L
+#define PW_CONSTEXPR_FUNCTION constexpr
+#else
+#define PW_CONSTEXPR_FUNCTION
+#endif  // __cpp_constexpr >= 201304L
diff --git a/pw_polyfill/public/pw_polyfill/language_features.h b/pw_polyfill/public/pw_polyfill/language_features.h
deleted file mode 100644
index 0e9477a..0000000
--- a/pw_polyfill/public/pw_polyfill/language_features.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2020 The Pigweed 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.
-#pragma once
-
-#ifdef __cpp_inline_variables
-#define PW_INLINE_VARIABLE inline
-#else
-#define PW_INLINE_VARIABLE
-#endif  // __cpp_inline_variables
-
-// Mark functions as constexpr if the relaxed constexpr rules are supported.
-#if __cpp_constexpr >= 201304L
-#define PW_CONSTEXPR_FUNCTION constexpr
-#else
-#define PW_CONSTEXPR_FUNCTION
-#endif  // __cpp_constexpr >= 201304L
-
-// This is an adapter for supporting static_assert with a single argument in
-// C++11 or C++14. Macros don't correctly parse commas in template expressions,
-// so the static_assert arguments are passed to an overloaded C++ function. The
-// full stringified static_assert arguments are used as the message.
-#if __cpp_static_assert < 201411L
-
-#define static_assert(...)                                                     \
-  static_assert(::pw::polyfill::internal::StaticAssertExpression(__VA_ARGS__), \
-                #__VA_ARGS__)
-
-namespace pw {
-namespace polyfill {
-namespace internal {
-
-constexpr bool StaticAssertExpression(bool expression) { return expression; }
-
-constexpr bool StaticAssertExpression(bool expression, const char*) {
-  return expression;
-}
-
-}  // namespace internal
-}  // namespace polyfill
-}  // namespace pw
-
-#endif  // __cpp_static_assert < 201411L
diff --git a/pw_polyfill/test.cc b/pw_polyfill/test.cc
index dfc50c1..cf9a24c 100644
--- a/pw_polyfill/test.cc
+++ b/pw_polyfill/test.cc
@@ -15,7 +15,7 @@
 #include <array>
 
 #include "gtest/gtest.h"
-#include "pw_polyfill/language_features.h"
+#include "pw_polyfill/language_feature_macros.h"
 #include "pw_polyfill/standard.h"
 #include "pw_polyfill/standard_library/cstddef.h"
 #include "pw_polyfill/standard_library/iterator.h"
@@ -63,7 +63,11 @@
   EXPECT_TRUE((value >>= 5) == std::byte(0x6));
 }
 
-int c_array[5423];
+// Check that consteval is at least equivalent to constexpr.
+consteval int ConstevalFunction() { return 123; }
+static_assert(ConstevalFunction() == 123);
+
+int c_array[5423] = {};
 std::array<int, 32> array;
 
 TEST(Iterator, Size) {
@@ -76,6 +80,15 @@
   EXPECT_TRUE(std::data(array) == array.data());
 }
 
+constinit bool mutable_value = true;
+
+TEST(Constinit, ValueIsMutable) {
+  ASSERT_TRUE(mutable_value);
+  mutable_value = false;
+  ASSERT_FALSE(mutable_value);
+  mutable_value = true;
+}
+
 TEST(TypeTraits, Aliases) {
   static_assert(
       std::is_same<std::aligned_storage_t<40, 40>,
diff --git a/pw_span/public/pw_span/internal/span.h b/pw_span/public/pw_span/internal/span.h
index a39859b..3a71c6f 100644
--- a/pw_span/public/pw_span/internal/span.h
+++ b/pw_span/public/pw_span/internal/span.h
@@ -43,7 +43,7 @@
 #include <type_traits>
 #include <utility>
 
-#include "pw_polyfill/language_features.h"
+#include "pw_polyfill/language_feature_macros.h"
 #include "pw_polyfill/standard_library/namespace.h"
 
 // Pigweed: Disable the asserts from Chromium for now.
diff --git a/pw_tokenizer/tokenize.cc b/pw_tokenizer/tokenize.cc
index c7e3699..8b1a20a 100644
--- a/pw_tokenizer/tokenize.cc
+++ b/pw_tokenizer/tokenize.cc
@@ -20,7 +20,6 @@
 
 #include <cstring>
 
-#include "pw_polyfill/language_features.h"  // static_assert
 #include "pw_tokenizer_private/encode_args.h"
 
 namespace pw {
diff --git a/pw_varint/public/pw_varint/varint.h b/pw_varint/public/pw_varint/varint.h
index b9f6e59..254dd39 100644
--- a/pw_varint/public/pw_varint/varint.h
+++ b/pw_varint/public/pw_varint/varint.h
@@ -43,7 +43,7 @@
 #include <span>
 #include <type_traits>
 
-#include "pw_polyfill/language_features.h"
+#include "pw_polyfill/language_feature_macros.h"
 
 namespace pw {
 namespace varint {