[stdcompat]: Update utility.

utility polyfill providing in_place_t* tags and added test into
utility_test.cc. The test is simply checking that when we are
not using our polyfills (and version appropiate) we default to using the
std::* version of the tags.

Bug: 57349
Test: stdcompat-test
Change-Id: Ida71246d8583ed8c589ba031a783be2608f99311
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/466480
Commit-Queue: Gianfranco Valentino <gevalentino@google.com>
Reviewed-by: Roland McGrath <mcgrathr@google.com>
diff --git a/zircon/system/ulib/stdcompat/BUILD.gn b/zircon/system/ulib/stdcompat/BUILD.gn
index 2e43543..f95361f 100644
--- a/zircon/system/ulib/stdcompat/BUILD.gn
+++ b/zircon/system/ulib/stdcompat/BUILD.gn
@@ -18,6 +18,7 @@
   sdk_headers = [
     "lib/stdcompat/version.h",
     "lib/stdcompat/type_traits.h",
+    "lib/stdcompat/utility.h",
   ]
   sources = [
     "include/lib/stdcompat/internal/constructors.h",
diff --git a/zircon/system/ulib/stdcompat/BUILD.zircon.gn b/zircon/system/ulib/stdcompat/BUILD.zircon.gn
index e80e5af..3caf68d 100644
--- a/zircon/system/ulib/stdcompat/BUILD.zircon.gn
+++ b/zircon/system/ulib/stdcompat/BUILD.zircon.gn
@@ -18,6 +18,7 @@
   sdk_headers = [
     "lib/stdcompat/version.h",
     "lib/stdcompat/type_traits.h",
+    "lib/stdcompat/utility.h",
   ]
   sources = [
     "include/lib/stdcompat/internal/constructors.h",
diff --git a/zircon/system/ulib/stdcompat/include/lib/stdcompat/internal/utility.h b/zircon/system/ulib/stdcompat/include/lib/stdcompat/internal/utility.h
index a000609..f029508 100644
--- a/zircon/system/ulib/stdcompat/include/lib/stdcompat/internal/utility.h
+++ b/zircon/system/ulib/stdcompat/include/lib/stdcompat/internal/utility.h
@@ -5,7 +5,6 @@
 #ifndef LIB_STDCOMPAT_INTERNAL_UTILITY_H_
 #define LIB_STDCOMPAT_INTERNAL_UTILITY_H_
 
-#include <type_traits>
 #include <utility>
 
 #include "../type_traits.h"
@@ -13,6 +12,11 @@
 namespace cpp17 {
 namespace internal {
 
+template <typename Tag>
+struct instantiate_templated_tag {
+  static constexpr Tag storage;
+};
+
 // Utility to return the first type in a parameter pack.
 template <typename... Ts>
 struct first;
diff --git a/zircon/system/ulib/stdcompat/include/lib/stdcompat/utility.h b/zircon/system/ulib/stdcompat/include/lib/stdcompat/utility.h
index e08a72d..5f77a5db 100644
--- a/zircon/system/ulib/stdcompat/include/lib/stdcompat/utility.h
+++ b/zircon/system/ulib/stdcompat/include/lib/stdcompat/utility.h
@@ -2,12 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef LIB_STDCOMPAT_INTERNAL_IN_PLACE_INTERNAL_H_
-#define LIB_STDCOMPAT_INTERNAL_IN_PLACE_INTERNAL_H_
+#ifndef LIB_STDCOMPAT_UTILITY_H_
+#define LIB_STDCOMPAT_UTILITY_H_
 
-#include <cstddef>
+#include <lib/stdcompat/internal/utility.h>
 
-namespace fit {
+#include <utility>
+
+namespace cpp17 {
+// Use alias for cpp17 and above.
+#if __cplusplus >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS)
+
+using std::in_place;
+using std::in_place_t;
+
+using std::in_place_index;
+using std::in_place_index_t;
+
+using std::in_place_type;
+using std::in_place_type_t;
+
+#else  // Provide provide polyfills for |in_place*| types and variables.
 
 // Tag for requesting in-place initialization.
 struct in_place_t {
@@ -26,58 +41,34 @@
   explicit constexpr in_place_index_t() = default;
 };
 
-#ifdef __cpp_inline_variables
+// Use inline variables if available.
+#if __cpp_inline_variables >= 201606L && !defined(LIB_STDCOMPAT_USE_POLYFILLS)
 
-// Inline variables are only available on C++ 17 and beyond.
-
-inline constexpr in_place_t in_place{};
+constexpr in_place_t in_place{};
 
 template <typename T>
-inline constexpr in_place_type_t<T> in_place_type{};
+constexpr in_place_type_t<T> in_place_type{};
 
 template <size_t Index>
-inline constexpr in_place_index_t<Index> in_place_index{};
+constexpr in_place_index_t<Index> in_place_index{};
 
-#else
+#else  // Provide polyfill reference to provided variable storage.
 
-// For C++ 14 we need to provide storage for the variable so we define
-// a reference instead.
-
-template <typename Placeholder = void>
-struct in_place_holder {
-  static constexpr in_place_t instance{};
-};
+static constexpr const in_place_t& in_place =
+    internal::instantiate_templated_tag<in_place_t>::storage;
 
 template <typename T>
-struct in_place_type_holder {
-  static constexpr in_place_type_t<T> instance{};
-};
-
-template <size_t Index>
-struct in_place_index_holder {
-  static constexpr in_place_index_t<Index> instance{};
-};
-
-template <typename Placeholder>
-constexpr in_place_t in_place_holder<Placeholder>::instance;
-
-template <typename T>
-constexpr in_place_type_t<T> in_place_type_holder<T>::instance;
-
-template <size_t Index>
-constexpr in_place_index_t<Index> in_place_index_holder<Index>::instance;
-
-static constexpr const in_place_t& in_place = in_place_holder<>::instance;
-
-template <typename T>
-static constexpr const in_place_type_t<T>& in_place_type = in_place_type_holder<T>::instance;
+static constexpr const in_place_type_t<T>& in_place_type =
+    internal::instantiate_templated_tag<in_place_type_t<T>>::storage;
 
 template <size_t Index>
 static constexpr const in_place_index_t<Index>& in_place_index =
-    in_place_index_holder<Index>::instance;
+    internal::instantiate_templated_tag<in_place_index_t<Index>>::storage;
 
-#endif  // __cpp_inline_variables
+#endif  // __cpp_inline_variables >= 201606L && !defined(LIB_STDCOMPAT_USE_POLYFILLS)
 
-}  // namespace fit
+#endif  // __cplusplus >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS)
 
-#endif  // LIB_STDCOMPAT_INTERNAL_IN_PLACE_INTERNAL_H_
+}  // namespace cpp17
+
+#endif  // LIB_STDCOMPAT_UTILITY_H_
diff --git a/zircon/system/ulib/stdcompat/test/BUILD.gn b/zircon/system/ulib/stdcompat/test/BUILD.gn
index 28e5d28..9e1d941 100644
--- a/zircon/system/ulib/stdcompat/test/BUILD.gn
+++ b/zircon/system/ulib/stdcompat/test/BUILD.gn
@@ -19,6 +19,7 @@
   "constructors_internal_test.cc",
   "traits_test.cc",
   "utility_internal_test.cc",
+  "utility_test.cc",
   "version_test.cc",
 ]
 
diff --git a/zircon/system/ulib/stdcompat/test/utility_internal_test.cc b/zircon/system/ulib/stdcompat/test/utility_internal_test.cc
index a647403..3daa3ba 100644
--- a/zircon/system/ulib/stdcompat/test/utility_internal_test.cc
+++ b/zircon/system/ulib/stdcompat/test/utility_internal_test.cc
@@ -2,9 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <lib/stdcompat/internal/utility.h>
-
-#include <type_traits>
+#include <lib/stdcompat/type_traits.h>
+#include <lib/stdcompat/utility.h>
 
 #include <gtest/gtest.h>
 
@@ -12,9 +11,9 @@
 
 TEST(InternalTypeTraitsTest, FirstTReturnsFirstTypeInParameterPack) {
   using cpp17::internal::first_t;
-  static_assert(std::is_same_v<int, first_t<int>>, "");
-  static_assert(std::is_same_v<int, first_t<int, char>>, "");
-  static_assert(std::is_same_v<int, first_t<int, char, bool>>, "");
+  static_assert(std::is_same<int, first_t<int>>::value, "");
+  static_assert(std::is_same<int, first_t<int, char>>::value, "");
+  static_assert(std::is_same<int, first_t<int, char, bool>>::value, "");
 }
 
 TEST(InternalTypeTraitsTest, OccurrencesOfReturnsNumberOfTimesTypeIsPresent) {
@@ -164,4 +163,4 @@
   static_assert(!is_comparable(comparable_c{}, comparable_c{}), "");
 }
 
-}  // anonymous namespace
+}  // namespace
diff --git a/zircon/system/ulib/stdcompat/test/utility_test.cc b/zircon/system/ulib/stdcompat/test/utility_test.cc
new file mode 100644
index 0000000..72ce89e
--- /dev/null
+++ b/zircon/system/ulib/stdcompat/test/utility_test.cc
@@ -0,0 +1,36 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/stdcompat/utility.h>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+TEST(InplaceTagTest, InplaceTagsSwitchToStdProvidedOnStd17) {
+  static_assert(std::is_trivially_default_constructible<cpp17::in_place_t>::value);
+  static_assert(std::is_trivially_default_constructible<cpp17::in_place_index_t<0>>::value);
+  static_assert(std::is_trivially_default_constructible<cpp17::in_place_type_t<void>>::value);
+
+#if __cplusplus >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS)
+  static_assert(std::is_same<cpp17::in_place_t, std::in_place_t>::value);
+  static_assert(std::is_same<cpp17::in_place_type_t<void>, std::in_place_type_t<void>>::value);
+  static_assert(std::is_same<cpp17::in_place_index_t<0>, std::in_place_index_t<0>>::value);
+
+  static_assert(std::addressof(cpp17::in_place) == std::addressof(std::in_place));
+  static_assert(std::addressof(cpp17::in_place_type<void>) ==
+                std::addressof(std::in_place_type<void>));
+  static_assert(std::addressof(cpp17::in_place_index<0>) == std::addressof(std::in_place_index<0>));
+#else  // Force template instantiation.
+
+  // Sanity checks that the instantiations are actually different for the polyfills.
+  static_assert(std::addressof(cpp17::in_place) != nullptr);
+  static_assert(static_cast<const void*>(std::addressof(cpp17::in_place_type<void>)) !=
+                static_cast<const void*>(std::addressof(std::in_place_type<int>)));
+  static_assert(static_cast<const void*>(std::addressof(cpp17::in_place_index<0>)) !=
+                static_cast<const void*>(std::addressof(std::in_place_index<1>)));
+#endif
+}
+
+}  // namespace