about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2019-12-04T22·13-0800
committerMark Barolak <mbar@google.com>2019-12-05T16·46-0500
commitd659fe54b35ab9b8e35c72e50a4b8814167d5a84 (patch)
treedd21b4e5d1d3980a6a38c5a445853d4e1b744b90
parenta4b757b5d42694306a9de853cee0a5fba9c7bbe9 (diff)
Export of internal Abseil changes
--
c385118b3ef0528d150bfe7aeeb63e77f9e463cd by Matt Calabrese <calabrese@google.com>:

Internal-only Archetype generation for testing generic code with user-defined types of various properties.

PiperOrigin-RevId: 283833099

--
4ccf340d3b295aa5b796ee5c97128b61d38899ea by Derek Mauro <dmauro@google.com>:

Fixes the flags parse_test.
Windows doesn't like consecutive path separators.

PiperOrigin-RevId: 283614649

--
5df6d83acb1e49cd1da785cfaf7551f05149f3c9 by Andy Getzendanner <durandal@google.com>:

ABSL_INTERNAL_LOG: forward complete __FILE__ to internal_log_function; not just basename.

PiperOrigin-RevId: 283406080
GitOrigin-RevId: c385118b3ef0528d150bfe7aeeb63e77f9e463cd
Change-Id: Ib0782354691a73fc40185c3262cfd507085b3393
-rw-r--r--absl/base/internal/raw_logging.h12
-rw-r--r--absl/flags/parse_test.cc16
-rw-r--r--absl/meta/type_traits.h45
-rw-r--r--absl/meta/type_traits_test.cc21
-rw-r--r--absl/types/BUILD.bazel34
-rw-r--r--absl/types/CMakeLists.txt46
-rw-r--r--absl/types/internal/conformance_aliases.h445
-rw-r--r--absl/types/internal/conformance_archetype.h976
-rw-r--r--absl/types/internal/conformance_profile.h374
-rw-r--r--absl/types/internal/conformance_testing_test.cc1186
10 files changed, 3112 insertions, 43 deletions
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
index 6a4c093603f0..49c8dfbf1b01 100644
--- a/absl/base/internal/raw_logging.h
+++ b/absl/base/internal/raw_logging.h
@@ -70,14 +70,10 @@
 //
 // The API is a subset of the above: each macro only takes two arguments.  Use
 // StrCat if you need to build a richer message.
-#define ABSL_INTERNAL_LOG(severity, message)                          \
-  do {                                                                \
-    constexpr const char* absl_raw_logging_internal_basename =        \
-        ::absl::raw_logging_internal::Basename(__FILE__,              \
-                                               sizeof(__FILE__) - 1); \
-    ::absl::raw_logging_internal::internal_log_function(              \
-        ABSL_RAW_LOGGING_INTERNAL_##severity,                         \
-        absl_raw_logging_internal_basename, __LINE__, message);       \
+#define ABSL_INTERNAL_LOG(severity, message)                                \
+  do {                                                                      \
+    ::absl::raw_logging_internal::internal_log_function(                    \
+        ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, message); \
   } while (0)
 
 #define ABSL_INTERNAL_CHECK(condition, message)                    \
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index 447a3bc7bdcb..f89fa96527b7 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -22,6 +22,7 @@
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/internal/scoped_set_env.h"
 #include "absl/flags/flag.h"
+#include "absl/strings/match.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/substitute.h"
 #include "absl/types/span.h"
@@ -92,8 +93,11 @@ const std::string& GetTestTempDir() {
 
       auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
       if (len < MAX_PATH && len != 0) {
-        std::string temp_dir_name = absl::StrCat(
-            temp_path_buffer, "\\parse_test.", GetCurrentProcessId());
+        std::string temp_dir_name = temp_path_buffer;
+        if (!absl::EndsWith(temp_dir_name, "\\")) {
+          temp_dir_name.push_back('\\');
+        }
+        absl::StrAppend(&temp_dir_name, "parse_test.", GetCurrentProcessId());
         if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
           *res = temp_dir_name;
         }
@@ -104,11 +108,11 @@ const std::string& GetTestTempDir() {
         *res = unique_name;
       }
 #endif
+    }
 
-      if (res->empty()) {
-        ABSL_INTERNAL_LOG(FATAL,
-                          "Failed to make temporary directory for data files");
-      }
+    if (res->empty()) {
+      ABSL_INTERNAL_LOG(FATAL,
+                        "Failed to make temporary directory for data files");
     }
 
 #ifdef _WIN32
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index d57a87923136..8cd5f043e0b7 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -41,10 +41,20 @@
 
 #include "absl/base/config.h"
 
+// MSVC constructibility traits do not detect destructor properties and so our
+// implementations should not use them as a source-of-truth.
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
+#define ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION 1
+#endif
+
 namespace absl {
 
 // Defined and documented later on in this file.
 template <typename T>
+struct is_trivially_destructible;
+
+// Defined and documented later on in this file.
+template <typename T>
 struct is_trivially_move_assignable;
 
 namespace type_traits_internal {
@@ -66,6 +76,20 @@ union SingleMemberUnion {
 #endif  // defined(_MSC_VER) && !defined(__GNUC__)
 
 template <class T>
+struct IsTriviallyMoveConstructibleObject
+    : std::integral_constant<
+          bool, std::is_move_constructible<
+                    type_traits_internal::SingleMemberUnion<T>>::value &&
+                    absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
+struct IsTriviallyCopyConstructibleObject
+    : std::integral_constant<
+          bool, std::is_copy_constructible<
+                    type_traits_internal::SingleMemberUnion<T>>::value &&
+                    absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
 struct IsTriviallyMoveAssignableReference : std::false_type {};
 
 template <class T>
@@ -323,7 +347,9 @@ struct is_trivially_default_constructible
     : std::integral_constant<bool, __has_trivial_constructor(T) &&
                                    std::is_default_constructible<T>::value &&
                                    is_trivially_destructible<T>::value> {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
  private:
   static constexpr bool compliant =
       std::is_trivially_default_constructible<T>::value ==
@@ -354,10 +380,11 @@ template <typename T>
 struct is_trivially_move_constructible
     : std::conditional<
           std::is_object<T>::value && !std::is_array<T>::value,
-          std::is_move_constructible<
-              type_traits_internal::SingleMemberUnion<T>>,
+          type_traits_internal::IsTriviallyMoveConstructibleObject<T>,
           std::is_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
  private:
   static constexpr bool compliant =
       std::is_trivially_move_constructible<T>::value ==
@@ -388,10 +415,11 @@ template <typename T>
 struct is_trivially_copy_constructible
     : std::conditional<
           std::is_object<T>::value && !std::is_array<T>::value,
-          std::is_copy_constructible<
-              type_traits_internal::SingleMemberUnion<T>>,
+          type_traits_internal::IsTriviallyCopyConstructibleObject<T>,
           std::is_lvalue_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
  private:
   static constexpr bool compliant =
       std::is_trivially_copy_constructible<T>::value ==
@@ -423,7 +451,8 @@ struct is_trivially_copy_constructible
 template <typename T>
 struct is_trivially_move_assignable
     : std::conditional<
-          std::is_object<T>::value && !std::is_array<T>::value,
+          std::is_object<T>::value && !std::is_array<T>::value &&
+              std::is_move_assignable<T>::value,
           std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
           type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
           type {
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index 6fbb42f82e06..1aafd0d49a83 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -347,21 +347,6 @@ class Base {
   virtual ~Base() {}
 };
 
-// In GCC/Clang, std::is_trivially_constructible requires that the destructor is
-// trivial. However, MSVC doesn't require that. This results in different
-// behavior when checking is_trivially_constructible on any type with
-// nontrivial destructor. Since absl::is_trivially_default_constructible and
-// absl::is_trivially_copy_constructible both follows Clang/GCC's interpretation
-// and check is_trivially_destructible, it results in inconsistency with
-// std::is_trivially_xxx_constructible on MSVC. This macro is used to work
-// around this issue in test. In practice, a trivially constructible type
-// should also be trivially destructible.
-// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
-// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116
-#ifndef _MSC_VER
-#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE 1
-#endif
-
 // Old versions of libc++, around Clang 3.5 to 3.6, consider deleted destructors
 // as also being trivial. With the resolution of CWG 1928 and CWG 1734, this
 // is no longer considered true and has thus been amended.
@@ -499,11 +484,9 @@ TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
   EXPECT_FALSE(
       absl::is_trivially_default_constructible<DeletedDefaultCtor>::value);
 
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
   // types with nontrivial destructor are nontrivial
   EXPECT_FALSE(
       absl::is_trivially_default_constructible<NontrivialDestructor>::value);
-#endif
 
   // types with vtables
   EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value);
@@ -607,11 +590,9 @@ TEST(TypeTraitsTest, TestTrivialMoveCtor) {
   EXPECT_FALSE(
       absl::is_trivially_move_constructible<NonCopyableOrMovable>::value);
 
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
   // type with nontrivial destructor are nontrivial move construbtible
   EXPECT_FALSE(
       absl::is_trivially_move_constructible<NontrivialDestructor>::value);
-#endif
 
   // types with vtables
   EXPECT_FALSE(absl::is_trivially_move_constructible<Base>::value);
@@ -682,11 +663,9 @@ TEST(TypeTraitsTest, TestTrivialCopyCtor) {
   EXPECT_FALSE(
       absl::is_trivially_copy_constructible<NonCopyableOrMovable>::value);
 
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
   // type with nontrivial destructor are nontrivial copy construbtible
   EXPECT_FALSE(
       absl::is_trivially_copy_constructible<NontrivialDestructor>::value);
-#endif
 
   // types with vtables
   EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value);
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index 236c24bc34d6..f2ea9f395afc 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -209,6 +209,40 @@ cc_test(
 )
 
 cc_library(
+    name = "conformance_testing",
+    testonly = 1,
+    hdrs = [
+        "internal/conformance_aliases.h",
+        "internal/conformance_archetype.h",
+        "internal/conformance_profile.h",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/debugging:demangle_internal",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "//absl/utility",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_test(
+    name = "conformance_testing_test",
+    size = "small",
+    srcs = [
+        "internal/conformance_testing_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":conformance_testing",
+        "//absl/meta:type_traits",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "variant",
     srcs = ["internal/variant.h"],
     hdrs = ["variant.h"],
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 952efc34f634..c7c882507f6e 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -240,6 +240,52 @@ absl_cc_test(
 
 absl_cc_library(
   NAME
+    conformance_testing
+  HDRS
+    "internal/conformance_aliases.h"
+    "internal/conformance_archetype.h"
+    "internal/conformance_profile.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::debugging
+    absl::type_traits
+    absl::strings
+    absl::utility
+    gmock_main
+  PUBLIC
+)
+
+absl_cc_test(
+  NAME
+    conformance_testing_test
+  SRCS
+    "internal/conformance_testing_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+    ${ABSL_EXCEPTIONS_FLAG}
+  LINKOPTS
+    ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+  DEPS
+    absl::conformance_testing
+    absl::type_traits
+    gmock_main
+)
+
+absl_cc_test(
+  NAME
+    conformance_testing_test_no_exceptions
+  SRCS
+    "internal/conformance_testing_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::conformance_testing
+    gmock_main
+)
+
+absl_cc_library(
+  NAME
     variant
   HDRS
     "variant.h"
diff --git a/absl/types/internal/conformance_aliases.h b/absl/types/internal/conformance_aliases.h
new file mode 100644
index 000000000000..7d5d0e092a47
--- /dev/null
+++ b/absl/types/internal/conformance_aliases.h
@@ -0,0 +1,445 @@
+// Copyright 2018 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.
+//
+// -----------------------------------------------------------------------------
+// regularity_aliases.h
+// -----------------------------------------------------------------------------
+//
+// This file contains type aliases of common ConformanceProfiles and Archetypes
+// so that they can be directly used by name without creating them from scratch.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+
+#include "absl/types/internal/conformance_archetype.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+namespace types_internal {
+
+// Creates both a Profile and a corresponding Archetype with root name "name".
+#define ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(name, ...)                \
+  struct name##Profile : __VA_ARGS__ {};                                    \
+                                                                            \
+  using name##Archetype = ::absl::types_internal::Archetype<name##Profile>; \
+                                                                            \
+  template <class AbslInternalProfileTag>                                   \
+  using name##Archetype##_ = ::absl::types_internal::Archetype<             \
+      ::absl::types_internal::StrongProfileTypedef<name##Profile,           \
+                                                   AbslInternalProfileTag>>
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialDefaultConstructor,
+    ConformanceProfile<default_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowDefaultConstructor,
+    ConformanceProfile<default_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasDefaultConstructor, ConformanceProfile<default_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialMoveConstructor, ConformanceProfile<default_constructible::maybe,
+                                                  move_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowMoveConstructor, ConformanceProfile<default_constructible::maybe,
+                                                  move_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasMoveConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowEquality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasEquality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowInequality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe,
+                       inequality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasInequality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowLessThan,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasLessThan,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowLessEqual,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::maybe,
+                       less_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasLessEqual,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::maybe,
+                       less_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowGreaterEqual,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasGreaterEqual,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowGreaterThan,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasGreaterThan,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowSwap,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasSwap,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasStdHashSpecialization,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::maybe, hashable::yes>);
+
+////////////////////////////////////////////////////////////////////////////////
+////     The remaining aliases are combinations of the previous aliases.    ////
+////////////////////////////////////////////////////////////////////////////////
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Equatable, CombineProfiles<HasEqualityProfile, HasInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Comparable,
+    CombineProfiles<EquatableProfile, HasLessThanProfile, HasLessEqualProfile,
+                    HasGreaterEqualProfile, HasGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowEquatable,
+    CombineProfiles<HasNothrowEqualityProfile, HasNothrowInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowComparable,
+    CombineProfiles<NothrowEquatableProfile, HasNothrowLessThanProfile,
+                    HasNothrowLessEqualProfile, HasNothrowGreaterEqualProfile,
+                    HasNothrowGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Value,
+    CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+                    HasNothrowMoveAssignProfile, HasCopyAssignProfile,
+                    HasNothrowDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableValue, CombineProfiles<EquatableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableValue, CombineProfiles<ComparableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleValue,
+    CombineProfiles<HasDefaultConstructorProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowMoveConstructible, CombineProfiles<HasNothrowMoveConstructorProfile,
+                                              HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableNothrowMoveConstructible,
+    CombineProfiles<EquatableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableNothrowMoveConstructible,
+    CombineProfiles<ComparableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleNothrowMoveConstructible,
+    CombineProfiles<HasDefaultConstructorProfile,
+                    NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    CopyConstructible,
+    CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+                    HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableCopyConstructible,
+    CombineProfiles<EquatableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableCopyConstructible,
+    CombineProfiles<ComparableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleCopyConstructible,
+    CombineProfiles<HasDefaultConstructorProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowMovable,
+    CombineProfiles<HasNothrowMoveConstructorProfile,
+                    HasNothrowMoveAssignProfile, HasNothrowDestructorProfile,
+                    HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableNothrowMovable,
+    CombineProfiles<EquatableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableNothrowMovable,
+    CombineProfiles<ComparableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleNothrowMovable,
+    CombineProfiles<HasDefaultConstructorProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    TrivialSpecialMemberFunctions,
+    CombineProfiles<HasTrivialDefaultConstructorProfile,
+                    HasTrivialMoveConstructorProfile,
+                    HasTrivialCopyConstructorProfile,
+                    HasTrivialMoveAssignProfile, HasTrivialCopyAssignProfile,
+                    HasTrivialDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    TriviallyComplete,
+    CombineProfiles<TrivialSpecialMemberFunctionsProfile, ComparableProfile,
+                    HasStdHashSpecializationProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableNothrowMoveConstructible,
+    CombineProfiles<HasStdHashSpecializationProfile,
+                    NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableCopyConstructible,
+    CombineProfiles<HasStdHashSpecializationProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableNothrowMovable,
+    CombineProfiles<HasStdHashSpecializationProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableValue,
+    CombineProfiles<HasStdHashSpecializationProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableHashableValue,
+    CombineProfiles<HashableValueProfile, ComparableProfile>);
+
+// The "preferred" profiles that we support in Abseil.
+template <template <class...> class Receiver>
+using ExpandBasicProfiles =
+    Receiver<NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+             NothrowMovableProfile, ValueProfile>;
+
+// The basic profiles except that they are also all Equatable.
+template <template <class...> class Receiver>
+using ExpandBasicEquatableProfiles =
+    Receiver<EquatableNothrowMoveConstructibleProfile,
+             EquatableCopyConstructibleProfile, EquatableNothrowMovableProfile,
+             EquatableValueProfile>;
+
+// The basic profiles except that they are also all Comparable.
+template <template <class...> class Receiver>
+using ExpandBasicComparableProfiles =
+    Receiver<ComparableNothrowMoveConstructibleProfile,
+             ComparableCopyConstructibleProfile,
+             ComparableNothrowMovableProfile, ComparableValueProfile>;
+
+// The basic profiles except that they are also all Hashable.
+template <template <class...> class Receiver>
+using ExpandBasicHashableProfiles =
+    Receiver<HashableNothrowMoveConstructibleProfile,
+             HashableCopyConstructibleProfile, HashableNothrowMovableProfile,
+             HashableValueProfile>;
+
+// The basic profiles except that they are also all DefaultConstructible.
+template <template <class...> class Receiver>
+using ExpandBasicDefaultConstructibleProfiles =
+    Receiver<DefaultConstructibleNothrowMoveConstructibleProfile,
+             DefaultConstructibleCopyConstructibleProfile,
+             DefaultConstructibleNothrowMovableProfile,
+             DefaultConstructibleValueProfile>;
+
+// The type profiles that we support in Abseil (all of the previous lists).
+template <template <class...> class Receiver>
+using ExpandSupportedProfiles = Receiver<
+    NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+    NothrowMovableProfile, ValueProfile,
+    EquatableNothrowMoveConstructibleProfile, EquatableCopyConstructibleProfile,
+    EquatableNothrowMovableProfile, EquatableValueProfile,
+    ComparableNothrowMoveConstructibleProfile,
+    ComparableCopyConstructibleProfile, ComparableNothrowMovableProfile,
+    ComparableValueProfile, DefaultConstructibleNothrowMoveConstructibleProfile,
+    DefaultConstructibleCopyConstructibleProfile,
+    DefaultConstructibleNothrowMovableProfile, DefaultConstructibleValueProfile,
+    HashableNothrowMoveConstructibleProfile, HashableCopyConstructibleProfile,
+    HashableNothrowMovableProfile, HashableValueProfile>;
+
+// TODO(calabrese) Include types that have throwing move constructors, since in
+// practice we still need to support them because of standard library types with
+// (potentially) non-noexcept moves.
+
+}  // namespace types_internal
+}  // namespace absl
+
+#undef ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
diff --git a/absl/types/internal/conformance_archetype.h b/absl/types/internal/conformance_archetype.h
new file mode 100644
index 000000000000..97ee726528aa
--- /dev/null
+++ b/absl/types/internal/conformance_archetype.h
@@ -0,0 +1,976 @@
+// Copyright 2019 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.
+//
+// -----------------------------------------------------------------------------
+// conformance_archetype.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a facility for generating "archetypes" of out of
+// "Conformance Profiles" (see "conformance_profiles.h" for more information
+// about Conformance Profiles). An archetype is a type that aims to support the
+// bare minimum requirements of a given Conformance Profile. For instance, an
+// archetype that corresponds to an ImmutableProfile has exactly a nothrow
+// move-constructor, a potentially-throwing copy constructor, a nothrow
+// destructor, with all other special-member-functions deleted. These archetypes
+// are useful for testing to make sure that templates are able to work with the
+// kinds of types that they claim to support (i.e. that they do not accidentally
+// under-constrain),
+//
+// The main type template in this file is the Archetype template, which takes
+// a Conformance Profile as a template argument and its instantiations are a
+// minimum-conforming model of that profile.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+namespace types_internal {
+
+// A minimum-conforming implementation of a type with properties specified in
+// `Prof`, where `Prof` is a valid Conformance Profile.
+template <class Prof, class /*Enabler*/ = void>
+class Archetype;
+
+// Given an Archetype, obtain the properties of the profile associated with that
+// archetype.
+template <class Archetype>
+struct PropertiesOfArchetype;
+
+template <class Prof>
+struct PropertiesOfArchetype<Archetype<Prof>> {
+  using type = PropertiesOfT<Prof>;
+};
+
+template <class Archetype>
+using PropertiesOfArchetypeT = typename PropertiesOfArchetype<Archetype>::type;
+
+// A metafunction to determine if a type is an `Archetype`.
+template <class T>
+struct IsArchetype : std::false_type {};
+
+template <class Prof>
+struct IsArchetype<Archetype<Prof>> : std::true_type {};
+
+// A constructor tag type used when creating an Archetype with internal state.
+struct MakeArchetypeState {};
+
+// Data stored within an archetype that is copied/compared/hashed when the
+// corresponding operations are used.
+using ArchetypeState = std::size_t;
+
+////////////////////////////////////////////////////////////////////////////////
+//   This section of the file defines a chain of base classes for Archetype,  //
+//   where each base defines a specific special member function with the      //
+//   appropriate properties (deleted, noexcept(false), noexcept, or trivial). //
+////////////////////////////////////////////////////////////////////////////////
+
+// The bottom-most base, which contains the state and the default constructor.
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeStateBase {
+  static_assert(DefaultConstructibleValue == default_constructible::yes ||
+                    DefaultConstructibleValue == default_constructible::nothrow,
+                "");
+
+  ArchetypeStateBase() noexcept(
+      DefaultConstructibleValue ==
+      default_constructible::
+          nothrow) /*Vacuous archetype_state initialization*/ {}
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::maybe> {
+  explicit ArchetypeStateBase() = delete;
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::trivial> {
+  ArchetypeStateBase() = default;
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+// The move-constructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeMoveConstructor
+    : ArchetypeStateBase<DefaultConstructibleValue> {
+  static_assert(MoveConstructibleValue == move_constructible::yes ||
+                    MoveConstructibleValue == move_constructible::nothrow,
+                "");
+
+  explicit ArchetypeMoveConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      state) {}
+
+  ArchetypeMoveConstructor() = default;
+  ArchetypeMoveConstructor(ArchetypeMoveConstructor&& other) noexcept(
+      MoveConstructibleValue == move_constructible::nothrow)
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      other.archetype_state) {}
+  ArchetypeMoveConstructor(const ArchetypeMoveConstructor&) = default;
+  ArchetypeMoveConstructor& operator=(ArchetypeMoveConstructor&&) = default;
+  ArchetypeMoveConstructor& operator=(const ArchetypeMoveConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                move_constructible::trivial>
+    : ArchetypeStateBase<DefaultConstructibleValue> {
+  explicit ArchetypeMoveConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      state) {}
+
+  ArchetypeMoveConstructor() = default;
+};
+
+// The copy-constructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue>
+struct ArchetypeCopyConstructor
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  static_assert(CopyConstructibleValue == copy_constructible::yes ||
+                    CopyConstructibleValue == copy_constructible::nothrow,
+                "");
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+  ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor(const ArchetypeCopyConstructor& other) noexcept(
+      CopyConstructibleValue == copy_constructible::nothrow)
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(
+            MakeArchetypeState(), other.archetype_state) {}
+  ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                MoveConstructibleValue,
+                                copy_constructible::maybe>
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+  ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor(const ArchetypeCopyConstructor&) = delete;
+  ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                MoveConstructibleValue,
+                                copy_constructible::trivial>
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+};
+
+// The move-assign base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeMoveAssign
+    : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue, CopyConstructibleValue> {
+  static_assert(MoveAssignableValue == move_assignable::yes ||
+                    MoveAssignableValue == move_assignable::nothrow,
+                "");
+  explicit ArchetypeMoveAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue,
+                                 CopyConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeMoveAssign() = default;
+  ArchetypeMoveAssign(ArchetypeMoveAssign&&) = default;
+  ArchetypeMoveAssign(const ArchetypeMoveAssign&) = default;
+  ArchetypeMoveAssign& operator=(ArchetypeMoveAssign&& other) noexcept(
+      MoveAssignableValue == move_assignable::nothrow) {
+    this->archetype_state = other.archetype_state;
+    return *this;
+  }
+
+  ArchetypeMoveAssign& operator=(const ArchetypeMoveAssign&) = default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue>
+struct ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, move_assignable::trivial>
+    : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue, CopyConstructibleValue> {
+  explicit ArchetypeMoveAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue,
+                                 CopyConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeMoveAssign() = default;
+};
+
+// The copy-assign base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue>
+struct ArchetypeCopyAssign
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  static_assert(CopyAssignableValue == copy_assignable::yes ||
+                    CopyAssignableValue == copy_assignable::nothrow,
+                "");
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+  ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+  ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+
+  ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign& other) noexcept(
+      CopyAssignableValue == copy_assignable::nothrow) {
+    this->archetype_state = other.archetype_state;
+    return *this;
+  }
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           copy_assignable::maybe>
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+  ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+  ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign&) = delete;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           copy_assignable::trivial>
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+};
+
+// The destructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue, destructible DestructibleValue>
+struct ArchetypeDestructor
+    : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue,
+                          CopyAssignableValue> {
+  static_assert(DestructibleValue == destructible::yes ||
+                    DestructibleValue == destructible::nothrow,
+                "");
+
+  explicit ArchetypeDestructor(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue,
+                            CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+  ArchetypeDestructor() = default;
+  ArchetypeDestructor(ArchetypeDestructor&&) = default;
+  ArchetypeDestructor(const ArchetypeDestructor&) = default;
+  ArchetypeDestructor& operator=(ArchetypeDestructor&&) = default;
+  ArchetypeDestructor& operator=(const ArchetypeDestructor&) = default;
+  ~ArchetypeDestructor() noexcept(DestructibleValue == destructible::nothrow) {}
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue>
+struct ArchetypeDestructor<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           CopyAssignableValue, destructible::trivial>
+    : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue,
+                          CopyAssignableValue> {
+  explicit ArchetypeDestructor(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue,
+                            CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+  ArchetypeDestructor() = default;
+};
+
+// An alias to the top of the chain of bases for special-member functions.
+// NOTE: move_constructible::maybe, move_assignable::maybe, and
+// destructible::maybe are handled in the top-level type by way of SFINAE.
+// Because of this, we never instantiate the base classes with
+// move_constructible::maybe, move_assignable::maybe, or destructible::maybe so
+// that we minimize the number of different possible type-template
+// instantiations.
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue, destructible DestructibleValue>
+using ArchetypeSpecialMembersBase = ArchetypeDestructor<
+    DefaultConstructibleValue,
+    MoveConstructibleValue != move_constructible::maybe
+        ? MoveConstructibleValue
+        : move_constructible::nothrow,
+    CopyConstructibleValue,
+    MoveAssignableValue != move_assignable::maybe ? MoveAssignableValue
+                                                  : move_assignable::nothrow,
+    CopyAssignableValue,
+    DestructibleValue != destructible::maybe ? DestructibleValue
+                                             : destructible::nothrow>;
+
+// A function that is used to create an archetype with some associated state.
+template <class Arch>
+Arch MakeArchetype(ArchetypeState state) noexcept {
+  static_assert(IsArchetype<Arch>::value,
+                "The explicit template argument to MakeArchetype is required "
+                "to be an Archetype.");
+  return Arch(MakeArchetypeState(), state);
+}
+
+// This is used to conditionally delete "copy" and "move" constructors in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteConstructor() {
+  return !((PropertiesOfT<Prof>::move_constructible_support !=
+                move_constructible::maybe &&
+            std::is_same<T, Archetype<Prof>>::value) ||
+           (PropertiesOfT<Prof>::copy_constructible_support !=
+                copy_constructible::maybe &&
+            (std::is_same<T, const Archetype<Prof>&>::value ||
+             std::is_same<T, Archetype<Prof>&>::value ||
+             std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// This is used to conditionally delete "copy" and "move" assigns in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteAssign() {
+  return !(
+      (PropertiesOfT<Prof>::move_assignable_support != move_assignable::maybe &&
+       std::is_same<T, Archetype<Prof>>::value) ||
+      (PropertiesOfT<Prof>::copy_assignable_support != copy_assignable::maybe &&
+       (std::is_same<T, const Archetype<Prof>&>::value ||
+        std::is_same<T, Archetype<Prof>&>::value ||
+        std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// TODO(calabrese) Inherit from a chain of secondary bases to pull in the
+// associated functions of other concepts.
+template <class Prof, class Enabler>
+class Archetype : ArchetypeSpecialMembersBase<
+                      PropertiesOfT<Prof>::default_constructible_support,
+                      PropertiesOfT<Prof>::move_constructible_support,
+                      PropertiesOfT<Prof>::copy_constructible_support,
+                      PropertiesOfT<Prof>::move_assignable_support,
+                      PropertiesOfT<Prof>::copy_assignable_support,
+                      PropertiesOfT<Prof>::destructible_support> {
+  static_assert(std::is_same<Enabler, void>::value,
+                "An explicit type must not be passed as the second template "
+                "argument to 'Archetype`.");
+
+  // The cases mentioned in these static_asserts are expected to be handled in
+  // the partial template specializations of Archetype that follow this
+  // definition.
+  static_assert(PropertiesOfT<Prof>::destructible_support !=
+                    destructible::maybe,
+                "");
+  static_assert(PropertiesOfT<Prof>::move_constructible_support !=
+                        move_constructible::maybe ||
+                    PropertiesOfT<Prof>::copy_constructible_support ==
+                        copy_constructible::maybe,
+                "");
+  static_assert(PropertiesOfT<Prof>::move_assignable_support !=
+                        move_assignable::maybe ||
+                    PropertiesOfT<Prof>::copy_assignable_support ==
+                        copy_assignable::maybe,
+                "");
+
+ public:
+  Archetype() = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support !=
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = default;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support !=
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = default;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support !=
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = default;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support !=
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = default;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+// Explicitly deleted swap for Archetype if the profile does not require swap.
+// It is important to delete it rather than simply leave it out so that the
+// "using std::swap;" idiom will result in this deleted overload being picked.
+template <class Prof,
+          absl::enable_if_t<!PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>&, Archetype<Prof>&) = delete;  // NOLINT
+
+// A conditionally-noexcept swap implementation for Archetype when the profile
+// supports swap.
+template <class Prof,
+          absl::enable_if_t<PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>& lhs, Archetype<Prof>& rhs)  // NOLINT
+    noexcept(PropertiesOfT<Prof>::swappable_support != swappable::yes) {
+  std::swap(lhs.archetype_state, rhs.archetype_state);
+}
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+struct NothrowBool {
+  explicit NothrowBool() = delete;
+  ~NothrowBool() = default;
+
+  // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+  // elision makes it not required when returning from a function.
+  // NothrowBool(NothrowBool const&) = delete;
+
+  NothrowBool& operator=(NothrowBool const&) = delete;
+
+  explicit operator bool() const noexcept { return value; }
+
+  static NothrowBool make(bool const value) noexcept {
+    return NothrowBool(value);
+  }
+
+ private:
+  explicit NothrowBool(bool const value) noexcept : value(value) {}
+
+  bool value;
+};
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+// Note: ExceptionalBool has a conversion operator that is not noexcept, so
+// that even when a comparison operator is noexcept, that operation may still
+// potentially throw when converted to bool.
+struct ExceptionalBool {
+  explicit ExceptionalBool() = delete;
+  ~ExceptionalBool() = default;
+
+  // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+  // elision makes it not required when returning from a function.
+  // ExceptionalBool(ExceptionalBool const&) = delete;
+
+  ExceptionalBool& operator=(ExceptionalBool const&) = delete;
+
+  explicit operator bool() const { return value; }  // NOLINT
+
+  static ExceptionalBool make(bool const value) noexcept {
+    return ExceptionalBool(value);
+  }
+
+ private:
+  explicit ExceptionalBool(bool const value) noexcept : value(value) {}
+
+  bool value;
+};
+
+// The following macro is only used as a helper in this file to stamp out
+// comparison operator definitions. It is undefined after usage.
+//
+// NOTE: Non-nothrow operators throw via their result's conversion to bool even
+// though the operation itself is noexcept.
+#define ABSL_TYPES_INTERNAL_OP(enum_name, op)                                \
+  template <class Prof>                                                      \
+  absl::enable_if_t<!PropertiesOfT<Prof>::is_##enum_name, bool> operator op( \
+      const Archetype<Prof>&, const Archetype<Prof>&) = delete;              \
+                                                                             \
+  template <class Prof>                                                      \
+  typename absl::enable_if_t<                                                \
+      PropertiesOfT<Prof>::is_##enum_name,                                   \
+      std::conditional<PropertiesOfT<Prof>::enum_name##_support ==           \
+                           enum_name::nothrow,                               \
+                       NothrowBool, ExceptionalBool>>::type                  \
+  operator op(const Archetype<Prof>& lhs,                                    \
+              const Archetype<Prof>& rhs) noexcept {                         \
+    return absl::conditional_t<                                              \
+        PropertiesOfT<Prof>::enum_name##_support == enum_name::nothrow,      \
+        NothrowBool, ExceptionalBool>::make(lhs.archetype_state op           \
+                                                rhs.archetype_state);        \
+  }
+
+ABSL_TYPES_INTERNAL_OP(equality_comparable, ==);
+ABSL_TYPES_INTERNAL_OP(inequality_comparable, !=);
+ABSL_TYPES_INTERNAL_OP(less_than_comparable, <);
+ABSL_TYPES_INTERNAL_OP(less_equal_comparable, <=);
+ABSL_TYPES_INTERNAL_OP(greater_equal_comparable, >=);
+ABSL_TYPES_INTERNAL_OP(greater_than_comparable, >);
+
+#undef ABSL_TYPES_INTERNAL_OP
+
+// Base class for std::hash specializations when an Archetype doesn't support
+// hashing.
+struct PoisonedHash {
+  PoisonedHash() = delete;
+  PoisonedHash(const PoisonedHash&) = delete;
+  PoisonedHash& operator=(const PoisonedHash&) = delete;
+};
+
+// Base class for std::hash specializations when an Archetype supports hashing.
+template <class Prof>
+struct EnabledHash {
+  using argument_type = Archetype<Prof>;
+  using result_type = std::size_t;
+  result_type operator()(const argument_type& arg) const {
+    return std::hash<ArchetypeState>()(arg.archetype_state);
+  }
+};
+
+}  // namespace types_internal
+}  // namespace absl
+
+namespace std {
+
+template <class Prof>  // NOLINT
+struct hash<::absl::types_internal::Archetype<Prof>>
+    : conditional<::absl::types_internal::PropertiesOfT<Prof>::is_hashable,
+                  ::absl::types_internal::EnabledHash<Prof>,
+                  ::absl::types_internal::PoisonedHash>::type {};
+
+}  // namespace std
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
diff --git a/absl/types/internal/conformance_profile.h b/absl/types/internal/conformance_profile.h
new file mode 100644
index 000000000000..dce3bbee6908
--- /dev/null
+++ b/absl/types/internal/conformance_profile.h
@@ -0,0 +1,374 @@
+// Copyright 2019 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.
+//
+// -----------------------------------------------------------------------------
+// conformance_profiles.h
+// -----------------------------------------------------------------------------
+//
+// This file contains templates for representing "Regularity Profiles" and
+// concisely-named versions of commonly used Regularity Profiles.
+//
+// A Regularity Profile is a compile-time description of the types of operations
+// that a given type supports, along with properties of those operations when
+// they do exist. For instance, a Regularity Profile may describe a type that
+// has a move-constructor that is noexcept and a copy constructor that is not
+// noexcept. This description can then be examined and passed around to other
+// templates for the purposes of asserting expectations on user-defined types
+// via a series trait checks, or for determining what kinds of run-time tests
+// are able to be performed.
+//
+// Regularity Profiles are also used when creating "archetypes," which are
+// minimum-conforming types that meet all of the requirements of a given
+// Regularity Profile. For more information regarding archetypes, see
+// "conformance_archetypes.h".
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+
+// TODO(calabrese) Add support for extending profiles.
+
+namespace absl {
+namespace types_internal {
+
+template <class T, class /*Enabler*/ = void>
+struct PropertiesOfImpl {};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::properties>> {
+  using type = typename T::properties;
+};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::profile_alias_of>> {
+  using type = typename PropertiesOfImpl<typename T::profile_alias_of>::type;
+};
+
+template <class T>
+struct PropertiesOf : PropertiesOfImpl<T> {};
+
+template <class T>
+using PropertiesOfT = typename PropertiesOf<T>::type;
+
+// NOTE: These enums use this naming convention to be consistent with the
+// standard trait names, which is useful since it allows us to match up each
+// enum name with a corresponding trait name in macro definitions.
+
+enum class function_kind { maybe, yes, nothrow, trivial };
+
+#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(name) \
+  enum class name { maybe, yes, nothrow, trivial }
+
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(default_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(move_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(copy_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(destructible);
+
+#undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM
+
+#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(name) \
+  enum class name { maybe, yes, nothrow }
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(equality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(inequality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_than_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(less_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(greater_than_comparable);
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(swappable);
+
+#undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM
+
+enum class hashable { maybe, yes };
+
+constexpr const char* PropertyName(hashable v) {
+  return "support for std::hash";
+}
+
+template <
+    default_constructible DefaultConstructibleValue =
+        default_constructible::maybe,
+    move_constructible MoveConstructibleValue = move_constructible::maybe,
+    copy_constructible CopyConstructibleValue = copy_constructible::maybe,
+    move_assignable MoveAssignableValue = move_assignable::maybe,
+    copy_assignable CopyAssignableValue = copy_assignable::maybe,
+    destructible DestructibleValue = destructible::maybe,
+    equality_comparable EqualityComparableValue = equality_comparable::maybe,
+    inequality_comparable InequalityComparableValue =
+        inequality_comparable::maybe,
+    less_than_comparable LessThanComparableValue = less_than_comparable::maybe,
+    less_equal_comparable LessEqualComparableValue =
+        less_equal_comparable::maybe,
+    greater_equal_comparable GreaterEqualComparableValue =
+        greater_equal_comparable::maybe,
+    greater_than_comparable GreaterThanComparableValue =
+        greater_than_comparable::maybe,
+    swappable SwappableValue = swappable::maybe,
+    hashable HashableValue = hashable::maybe>
+struct ConformanceProfile {
+  using properties = ConformanceProfile;
+
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      DefaultConstructibleValue;
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      MoveConstructibleValue;
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      CopyConstructibleValue;
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      MoveAssignableValue;
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      CopyAssignableValue;
+
+  static constexpr destructible destructible_support =  // NOLINT
+      DestructibleValue;
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      EqualityComparableValue;
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      InequalityComparableValue;
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      LessThanComparableValue;
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      LessEqualComparableValue;
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      GreaterEqualComparableValue;
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      GreaterThanComparableValue;
+
+  static constexpr swappable swappable_support = SwappableValue;  // NOLINT
+
+  static constexpr hashable hashable_support = HashableValue;  // NOLINT
+
+  static constexpr bool is_default_constructible =  // NOLINT
+      DefaultConstructibleValue != default_constructible::maybe;
+
+  static constexpr bool is_move_constructible =  // NOLINT
+      MoveConstructibleValue != move_constructible::maybe;
+
+  static constexpr bool is_copy_constructible =  // NOLINT
+      CopyConstructibleValue != copy_constructible::maybe;
+
+  static constexpr bool is_move_assignable =  // NOLINT
+      MoveAssignableValue != move_assignable::maybe;
+
+  static constexpr bool is_copy_assignable =  // NOLINT
+      CopyAssignableValue != copy_assignable::maybe;
+
+  static constexpr bool is_destructible =  // NOLINT
+      DestructibleValue != destructible::maybe;
+
+  static constexpr bool is_equality_comparable =  // NOLINT
+      EqualityComparableValue != equality_comparable::maybe;
+
+  static constexpr bool is_inequality_comparable =  // NOLINT
+      InequalityComparableValue != inequality_comparable::maybe;
+
+  static constexpr bool is_less_than_comparable =  // NOLINT
+      LessThanComparableValue != less_than_comparable::maybe;
+
+  static constexpr bool is_less_equal_comparable =  // NOLINT
+      LessEqualComparableValue != less_equal_comparable::maybe;
+
+  static constexpr bool is_greater_equal_comparable =  // NOLINT
+      GreaterEqualComparableValue != greater_equal_comparable::maybe;
+
+  static constexpr bool is_greater_than_comparable =  // NOLINT
+      GreaterThanComparableValue != greater_than_comparable::maybe;
+
+  static constexpr bool is_swappable =  // NOLINT
+      SwappableValue != swappable::maybe;
+
+  static constexpr bool is_hashable =  // NOLINT
+      HashableValue != hashable::maybe;
+};
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name)     \
+  template <default_constructible DefaultConstructibleValue,                   \
+            move_constructible MoveConstructibleValue,                         \
+            copy_constructible CopyConstructibleValue,                         \
+            move_assignable MoveAssignableValue,                               \
+            copy_assignable CopyAssignableValue,                               \
+            destructible DestructibleValue,                                    \
+            equality_comparable EqualityComparableValue,                       \
+            inequality_comparable InequalityComparableValue,                   \
+            less_than_comparable LessThanComparableValue,                      \
+            less_equal_comparable LessEqualComparableValue,                    \
+            greater_equal_comparable GreaterEqualComparableValue,              \
+            greater_than_comparable GreaterThanComparableValue,                \
+            swappable SwappableValue, hashable HashableValue>                  \
+  constexpr type ConformanceProfile<                                           \
+      DefaultConstructibleValue, MoveConstructibleValue,                       \
+      CopyConstructibleValue, MoveAssignableValue, CopyAssignableValue,        \
+      DestructibleValue, EqualityComparableValue, InequalityComparableValue,   \
+      LessThanComparableValue, LessEqualComparableValue,                       \
+      GreaterEqualComparableValue, GreaterThanComparableValue, SwappableValue, \
+      HashableValue>::name
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(type)           \
+  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type,            \
+                                                         type##_support); \
+  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(bool, is_##type)
+
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(default_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(destructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(equality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(inequality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(swappable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(hashable);
+
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL
+
+// Converts an enum to its underlying integral value.
+template <class Enum>
+constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
+  return static_cast<absl::underlying_type_t<Enum>>(value);
+}
+
+// Retrieve the enum with the greatest underlying value.
+// Note: std::max is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MaxEnum(H head) {
+  return head;
+}
+
+template <class H, class N, class... T>
+constexpr H MaxEnum(H head, N next, T... tail) {
+  return (UnderlyingValue)(next) < (UnderlyingValue)(head)
+             ? (MaxEnum)(head, tail...)
+             : (MaxEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct CombineProfilesImpl {
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+  static constexpr destructible destructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+  static constexpr swappable swappable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+  static constexpr hashable hashable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+  using properties = ConformanceProfile<
+      default_constructible_support, move_constructible_support,
+      copy_constructible_support, move_assignable_support,
+      copy_assignable_support, destructible_support,
+      equality_comparable_support, inequality_comparable_support,
+      less_than_comparable_support, less_equal_comparable_support,
+      greater_equal_comparable_support, greater_than_comparable_support,
+      swappable_support, hashable_support>;
+};
+
+// NOTE: We use this as opposed to a direct alias of CombineProfilesImpl so that
+// when named aliases of CombineProfiles are created (such as in
+// conformance_aliases.h), we only pay for the combination algorithm on the
+// profiles that are actually used.
+template <class... Profs>
+struct CombineProfiles {
+  using profile_alias_of = CombineProfilesImpl<Profs...>;
+};
+
+template <>
+struct CombineProfiles<> {
+  using properties = ConformanceProfile<>;
+};
+
+template <class Profile, class Tag>
+struct StrongProfileTypedef {
+  using properties = PropertiesOfT<Profile>;
+};
+
+template <class T, class /*Enabler*/ = void>
+struct IsProfileImpl : std::false_type {};
+
+template <class T>
+struct IsProfileImpl<T, absl::void_t<PropertiesOfT<T>>> : std::true_type {};
+
+template <class T>
+struct IsProfile : IsProfileImpl<T>::type {};
+
+}  // namespace types_internal
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
diff --git a/absl/types/internal/conformance_testing_test.cc b/absl/types/internal/conformance_testing_test.cc
new file mode 100644
index 000000000000..3dcf53056703
--- /dev/null
+++ b/absl/types/internal/conformance_testing_test.cc
@@ -0,0 +1,1186 @@
+// Copyright 2019 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 <new>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/conformance_aliases.h"
+
+namespace {
+
+namespace ti = absl::types_internal;
+
+template <class T>
+using DefaultConstructibleWithNewImpl = decltype(::new (std::nothrow) T);
+
+template <class T>
+using DefaultConstructibleWithNew =
+    absl::type_traits_internal::is_detected<DefaultConstructibleWithNewImpl, T>;
+
+template <class T>
+using MoveConstructibleWithNewImpl =
+    decltype(::new (std::nothrow) T(std::declval<T>()));
+
+template <class T>
+using MoveConstructibleWithNew =
+    absl::type_traits_internal::is_detected<MoveConstructibleWithNewImpl, T>;
+
+template <class T>
+using CopyConstructibleWithNewImpl =
+    decltype(::new (std::nothrow) T(std::declval<const T&>()));
+
+template <class T>
+using CopyConstructibleWithNew =
+    absl::type_traits_internal::is_detected<CopyConstructibleWithNewImpl, T>;
+
+template <class T,
+          class Result =
+              std::integral_constant<bool, noexcept(::new (std::nothrow) T)>>
+using NothrowDefaultConstructibleWithNewImpl =
+    typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowDefaultConstructibleWithNew =
+    absl::type_traits_internal::is_detected<
+        NothrowDefaultConstructibleWithNewImpl, T>;
+
+template <class T,
+          class Result = std::integral_constant<
+              bool, noexcept(::new (std::nothrow) T(std::declval<T>()))>>
+using NothrowMoveConstructibleWithNewImpl =
+    typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowMoveConstructibleWithNew =
+    absl::type_traits_internal::is_detected<NothrowMoveConstructibleWithNewImpl,
+                                            T>;
+
+template <class T,
+          class Result = std::integral_constant<
+              bool, noexcept(::new (std::nothrow) T(std::declval<const T&>()))>>
+using NothrowCopyConstructibleWithNewImpl =
+    typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowCopyConstructibleWithNew =
+    absl::type_traits_internal::is_detected<NothrowCopyConstructibleWithNewImpl,
+                                            T>;
+
+// NOTE: ?: is used to verify contextually-convertible to bool and not simply
+//       implicit or explicit convertibility.
+#define ABSL_INTERNAL_COMPARISON_OP_EXPR(op) \
+  ((std::declval<const T&>() op std::declval<const T&>()) ? true : true)
+
+#define ABSL_INTERNAL_COMPARISON_OP_TRAIT(name, op)                         \
+  template <class T>                                                        \
+  using name##Impl = decltype(ABSL_INTERNAL_COMPARISON_OP_EXPR(op));        \
+                                                                            \
+  template <class T>                                                        \
+  using name = absl::type_traits_internal::is_detected<name##Impl, T>;      \
+                                                                            \
+  template <class T,                                                        \
+            class Result = std::integral_constant<                          \
+                bool, noexcept(ABSL_INTERNAL_COMPARISON_OP_EXPR(op))>>      \
+  using Nothrow##name##Impl = typename std::enable_if<Result::value>::type; \
+                                                                            \
+  template <class T>                                                        \
+  using Nothrow##name =                                                     \
+      absl::type_traits_internal::is_detected<Nothrow##name##Impl, T>
+
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(EqualityComparable, ==);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(InequalityComparable, !=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessThanComparable, <);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessEqualComparable, <=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterEqualComparable, >=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterThanComparable, >);
+
+#undef ABSL_INTERNAL_COMPARISON_OP_TRAIT
+
+template <class T>
+class ProfileTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(ProfileTest);
+
+TYPED_TEST_P(ProfileTest, HasAppropriateConstructionProperties) {
+  using profile = typename TypeParam::profile;
+  using arch = typename TypeParam::arch;
+  using expected_profile = typename TypeParam::expected_profile;
+
+  using props = ti::PropertiesOfT<profile>;
+  using arch_props = ti::PropertiesOfArchetypeT<arch>;
+  using expected_props = ti::PropertiesOfT<expected_profile>;
+
+  // Make sure all of the properties are as expected.
+  // There are seemingly redundant tests here to make it easier to diagnose
+  // the specifics of the failure if something were to go wrong.
+  EXPECT_TRUE((std::is_same<props, arch_props>::value));
+  EXPECT_TRUE((std::is_same<props, expected_props>::value));
+  EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+  EXPECT_EQ(props::default_constructible_support,
+            expected_props::default_constructible_support);
+
+  EXPECT_EQ(props::move_constructible_support,
+            expected_props::move_constructible_support);
+
+  EXPECT_EQ(props::copy_constructible_support,
+            expected_props::copy_constructible_support);
+
+  EXPECT_EQ(props::destructible_support, expected_props::destructible_support);
+
+  // Avoid additional error message noise when profile and archetype match with
+  // each other but were not what was expected.
+  if (!std::is_same<props, arch_props>::value) {
+    EXPECT_EQ(arch_props::default_constructible_support,
+              expected_props::default_constructible_support);
+
+    EXPECT_EQ(arch_props::move_constructible_support,
+              expected_props::move_constructible_support);
+
+    EXPECT_EQ(arch_props::copy_constructible_support,
+              expected_props::copy_constructible_support);
+
+    EXPECT_EQ(arch_props::destructible_support,
+              expected_props::destructible_support);
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                       Default constructor checks                         //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::default_constructible_support,
+            expected_props::default_constructible_support);
+
+  switch (expected_props::default_constructible_support) {
+    case ti::default_constructible::maybe:
+      EXPECT_FALSE(DefaultConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_FALSE(std::is_default_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+      }
+      break;
+    case ti::default_constructible::yes:
+      EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_default_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+      }
+      break;
+    case ti::default_constructible::nothrow:
+      EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_default_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+
+        // Constructor traits also check the destructor.
+        if (std::is_nothrow_destructible<arch>::value) {
+          EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+        }
+      }
+      break;
+    case ti::default_constructible::trivial:
+      EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_default_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+
+        // Constructor triviality traits require trivially destructible types.
+        if (absl::is_trivially_destructible<arch>::value) {
+          EXPECT_TRUE(absl::is_trivially_default_constructible<arch>::value);
+        }
+      }
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                         Move constructor checks                          //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::move_constructible_support,
+            expected_props::move_constructible_support);
+
+  switch (expected_props::move_constructible_support) {
+    case ti::move_constructible::maybe:
+      EXPECT_FALSE(MoveConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_FALSE(std::is_move_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+      }
+      break;
+    case ti::move_constructible::yes:
+      EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_move_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+      }
+      break;
+    case ti::move_constructible::nothrow:
+      EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_move_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+
+        // Constructor traits also check the destructor.
+        if (std::is_nothrow_destructible<arch>::value) {
+          EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+        }
+      }
+      break;
+    case ti::move_constructible::trivial:
+      EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_move_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+
+        // Constructor triviality traits require trivially destructible types.
+        if (absl::is_trivially_destructible<arch>::value) {
+          EXPECT_TRUE(absl::is_trivially_move_constructible<arch>::value);
+        }
+      }
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                         Copy constructor checks                          //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::copy_constructible_support,
+            expected_props::copy_constructible_support);
+
+  switch (expected_props::copy_constructible_support) {
+    case ti::copy_constructible::maybe:
+      EXPECT_FALSE(CopyConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_FALSE(std::is_copy_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+      }
+      break;
+    case ti::copy_constructible::yes:
+      EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+      EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+        EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+      }
+      break;
+    case ti::copy_constructible::nothrow:
+      EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+        EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+
+        // Constructor traits also check the destructor.
+        if (std::is_nothrow_destructible<arch>::value) {
+          EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+        }
+      }
+      break;
+    case ti::copy_constructible::trivial:
+      EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+      EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value);
+
+      // Standard constructible traits depend on the destructor.
+      if (std::is_destructible<arch>::value) {
+        EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+        EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+
+        // Constructor triviality traits require trivially destructible types.
+        if (absl::is_trivially_destructible<arch>::value) {
+          EXPECT_TRUE(absl::is_trivially_copy_constructible<arch>::value);
+        }
+      }
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                           Destructible checks                            //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::destructible_support, expected_props::destructible_support);
+
+  switch (expected_props::destructible_support) {
+    case ti::destructible::maybe:
+      EXPECT_FALSE(std::is_destructible<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_destructible<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+      break;
+    case ti::destructible::yes:
+      EXPECT_TRUE(std::is_destructible<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_destructible<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+      break;
+    case ti::destructible::nothrow:
+      EXPECT_TRUE(std::is_destructible<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_destructible<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+      break;
+    case ti::destructible::trivial:
+      EXPECT_TRUE(std::is_destructible<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_destructible<arch>::value);
+      EXPECT_TRUE(absl::is_trivially_destructible<arch>::value);
+      break;
+  }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateAssignmentProperties) {
+  using profile = typename TypeParam::profile;
+  using arch = typename TypeParam::arch;
+  using expected_profile = typename TypeParam::expected_profile;
+
+  using props = ti::PropertiesOfT<profile>;
+  using arch_props = ti::PropertiesOfArchetypeT<arch>;
+  using expected_props = ti::PropertiesOfT<expected_profile>;
+
+  // Make sure all of the properties are as expected.
+  // There are seemingly redundant tests here to make it easier to diagnose
+  // the specifics of the failure if something were to go wrong.
+  EXPECT_TRUE((std::is_same<props, arch_props>::value));
+  EXPECT_TRUE((std::is_same<props, expected_props>::value));
+  EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+  EXPECT_EQ(props::move_assignable_support,
+            expected_props::move_assignable_support);
+
+  EXPECT_EQ(props::copy_assignable_support,
+            expected_props::copy_assignable_support);
+
+  // Avoid additional error message noise when profile and archetype match with
+  // each other but were not what was expected.
+  if (!std::is_same<props, arch_props>::value) {
+    EXPECT_EQ(arch_props::move_assignable_support,
+              expected_props::move_assignable_support);
+
+    EXPECT_EQ(arch_props::copy_assignable_support,
+              expected_props::copy_assignable_support);
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                          Move assignment checks                          //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::move_assignable_support,
+            expected_props::move_assignable_support);
+
+  switch (expected_props::move_assignable_support) {
+    case ti::move_assignable::maybe:
+      EXPECT_FALSE(std::is_move_assignable<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+      break;
+    case ti::move_assignable::yes:
+      EXPECT_TRUE(std::is_move_assignable<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+      break;
+    case ti::move_assignable::nothrow:
+      EXPECT_TRUE(std::is_move_assignable<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+      break;
+    case ti::move_assignable::trivial:
+      EXPECT_TRUE(std::is_move_assignable<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value);
+      EXPECT_TRUE(absl::is_trivially_move_assignable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                          Copy assignment checks                          //
+  //////////////////////////////////////////////////////////////////////////////
+  EXPECT_EQ(props::copy_assignable_support,
+            expected_props::copy_assignable_support);
+
+  switch (expected_props::copy_assignable_support) {
+    case ti::copy_assignable::maybe:
+      EXPECT_FALSE(std::is_copy_assignable<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+      break;
+    case ti::copy_assignable::yes:
+      EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+      EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+      break;
+    case ti::copy_assignable::nothrow:
+      EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value);
+      EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+      break;
+    case ti::copy_assignable::trivial:
+      EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+      EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value);
+      EXPECT_TRUE(absl::is_trivially_copy_assignable<arch>::value);
+      break;
+  }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateComparisonProperties) {
+  using profile = typename TypeParam::profile;
+  using arch = typename TypeParam::arch;
+  using expected_profile = typename TypeParam::expected_profile;
+
+  using props = ti::PropertiesOfT<profile>;
+  using arch_props = ti::PropertiesOfArchetypeT<arch>;
+  using expected_props = ti::PropertiesOfT<expected_profile>;
+
+  // Make sure all of the properties are as expected.
+  // There are seemingly redundant tests here to make it easier to diagnose
+  // the specifics of the failure if something were to go wrong.
+  EXPECT_TRUE((std::is_same<props, arch_props>::value));
+  EXPECT_TRUE((std::is_same<props, expected_props>::value));
+  EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+  EXPECT_EQ(props::equality_comparable_support,
+            expected_props::equality_comparable_support);
+
+  EXPECT_EQ(props::inequality_comparable_support,
+            expected_props::inequality_comparable_support);
+
+  EXPECT_EQ(props::less_than_comparable_support,
+            expected_props::less_than_comparable_support);
+
+  EXPECT_EQ(props::less_equal_comparable_support,
+            expected_props::less_equal_comparable_support);
+
+  EXPECT_EQ(props::greater_equal_comparable_support,
+            expected_props::greater_equal_comparable_support);
+
+  EXPECT_EQ(props::greater_than_comparable_support,
+            expected_props::greater_than_comparable_support);
+
+  // Avoid additional error message noise when profile and archetype match with
+  // each other but were not what was expected.
+  if (!std::is_same<props, arch_props>::value) {
+    EXPECT_EQ(arch_props::equality_comparable_support,
+              expected_props::equality_comparable_support);
+
+    EXPECT_EQ(arch_props::inequality_comparable_support,
+              expected_props::inequality_comparable_support);
+
+    EXPECT_EQ(arch_props::less_than_comparable_support,
+              expected_props::less_than_comparable_support);
+
+    EXPECT_EQ(arch_props::less_equal_comparable_support,
+              expected_props::less_equal_comparable_support);
+
+    EXPECT_EQ(arch_props::greater_equal_comparable_support,
+              expected_props::greater_equal_comparable_support);
+
+    EXPECT_EQ(arch_props::greater_than_comparable_support,
+              expected_props::greater_than_comparable_support);
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                        Equality comparable checks                        //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::equality_comparable_support) {
+    case ti::equality_comparable::maybe:
+      EXPECT_FALSE(EqualityComparable<arch>::value);
+      EXPECT_FALSE(NothrowEqualityComparable<arch>::value);
+      break;
+    case ti::equality_comparable::yes:
+      EXPECT_TRUE(EqualityComparable<arch>::value);
+      EXPECT_FALSE(NothrowEqualityComparable<arch>::value);
+      break;
+    case ti::equality_comparable::nothrow:
+      EXPECT_TRUE(EqualityComparable<arch>::value);
+      EXPECT_TRUE(NothrowEqualityComparable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                       Inequality comparable checks                       //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::inequality_comparable_support) {
+    case ti::inequality_comparable::maybe:
+      EXPECT_FALSE(InequalityComparable<arch>::value);
+      EXPECT_FALSE(NothrowInequalityComparable<arch>::value);
+      break;
+    case ti::inequality_comparable::yes:
+      EXPECT_TRUE(InequalityComparable<arch>::value);
+      EXPECT_FALSE(NothrowInequalityComparable<arch>::value);
+      break;
+    case ti::inequality_comparable::nothrow:
+      EXPECT_TRUE(InequalityComparable<arch>::value);
+      EXPECT_TRUE(NothrowInequalityComparable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                       Less than comparable checks                        //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::less_than_comparable_support) {
+    case ti::less_than_comparable::maybe:
+      EXPECT_FALSE(LessThanComparable<arch>::value);
+      EXPECT_FALSE(NothrowLessThanComparable<arch>::value);
+      break;
+    case ti::less_than_comparable::yes:
+      EXPECT_TRUE(LessThanComparable<arch>::value);
+      EXPECT_FALSE(NothrowLessThanComparable<arch>::value);
+      break;
+    case ti::less_than_comparable::nothrow:
+      EXPECT_TRUE(LessThanComparable<arch>::value);
+      EXPECT_TRUE(NothrowLessThanComparable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                      Less equal comparable checks                        //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::less_equal_comparable_support) {
+    case ti::less_equal_comparable::maybe:
+      EXPECT_FALSE(LessEqualComparable<arch>::value);
+      EXPECT_FALSE(NothrowLessEqualComparable<arch>::value);
+      break;
+    case ti::less_equal_comparable::yes:
+      EXPECT_TRUE(LessEqualComparable<arch>::value);
+      EXPECT_FALSE(NothrowLessEqualComparable<arch>::value);
+      break;
+    case ti::less_equal_comparable::nothrow:
+      EXPECT_TRUE(LessEqualComparable<arch>::value);
+      EXPECT_TRUE(NothrowLessEqualComparable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                     Greater equal comparable checks                      //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::greater_equal_comparable_support) {
+    case ti::greater_equal_comparable::maybe:
+      EXPECT_FALSE(GreaterEqualComparable<arch>::value);
+      EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value);
+      break;
+    case ti::greater_equal_comparable::yes:
+      EXPECT_TRUE(GreaterEqualComparable<arch>::value);
+      EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value);
+      break;
+    case ti::greater_equal_comparable::nothrow:
+      EXPECT_TRUE(GreaterEqualComparable<arch>::value);
+      EXPECT_TRUE(NothrowGreaterEqualComparable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                     Greater than comparable checks                       //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::greater_than_comparable_support) {
+    case ti::greater_than_comparable::maybe:
+      EXPECT_FALSE(GreaterThanComparable<arch>::value);
+      EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value);
+      break;
+    case ti::greater_than_comparable::yes:
+      EXPECT_TRUE(GreaterThanComparable<arch>::value);
+      EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value);
+      break;
+    case ti::greater_than_comparable::nothrow:
+      EXPECT_TRUE(GreaterThanComparable<arch>::value);
+      EXPECT_TRUE(NothrowGreaterThanComparable<arch>::value);
+      break;
+  }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateAuxilliaryProperties) {
+  using profile = typename TypeParam::profile;
+  using arch = typename TypeParam::arch;
+  using expected_profile = typename TypeParam::expected_profile;
+
+  using props = ti::PropertiesOfT<profile>;
+  using arch_props = ti::PropertiesOfArchetypeT<arch>;
+  using expected_props = ti::PropertiesOfT<expected_profile>;
+
+  // Make sure all of the properties are as expected.
+  // There are seemingly redundant tests here to make it easier to diagnose
+  // the specifics of the failure if something were to go wrong.
+  EXPECT_TRUE((std::is_same<props, arch_props>::value));
+  EXPECT_TRUE((std::is_same<props, expected_props>::value));
+  EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+  EXPECT_EQ(props::swappable_support, expected_props::swappable_support);
+
+  EXPECT_EQ(props::hashable_support, expected_props::hashable_support);
+
+  // Avoid additional error message noise when profile and archetype match with
+  // each other but were not what was expected.
+  if (!std::is_same<props, arch_props>::value) {
+    EXPECT_EQ(arch_props::swappable_support, expected_props::swappable_support);
+
+    EXPECT_EQ(arch_props::hashable_support, expected_props::hashable_support);
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                            Swappable checks                              //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::swappable_support) {
+    case ti::swappable::maybe:
+      EXPECT_FALSE(absl::type_traits_internal::IsSwappable<arch>::value);
+      EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+      break;
+    case ti::swappable::yes:
+      EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value);
+      EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+      break;
+    case ti::swappable::nothrow:
+      EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value);
+      EXPECT_TRUE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+      break;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //                             Hashable checks                              //
+  //////////////////////////////////////////////////////////////////////////////
+  switch (expected_props::hashable_support) {
+    case ti::hashable::maybe:
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+      EXPECT_FALSE(absl::type_traits_internal::IsHashable<arch>::value);
+#endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+      break;
+    case ti::hashable::yes:
+      EXPECT_TRUE(absl::type_traits_internal::IsHashable<arch>::value);
+      break;
+  }
+}
+
+REGISTER_TYPED_TEST_SUITE_P(ProfileTest, HasAppropriateConstructionProperties,
+                            HasAppropriateAssignmentProperties,
+                            HasAppropriateComparisonProperties,
+                            HasAppropriateAuxilliaryProperties);
+
+template <class Profile, class Arch, class ExpectedProfile>
+struct ProfileAndExpectation {
+  using profile = Profile;
+  using arch = Arch;
+  using expected_profile = ExpectedProfile;
+};
+
+using CoreProfilesToTest = ::testing::Types<
+    // The terminating case of combine (all properties are "maybe").
+    ProfileAndExpectation<ti::CombineProfiles<>,
+                          ti::Archetype<ti::CombineProfiles<>>,
+                          ti::ConformanceProfile<>>,
+
+    // Core default constructor profiles
+    ProfileAndExpectation<
+        ti::HasDefaultConstructorProfile, ti::HasDefaultConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowDefaultConstructorProfile,
+        ti::HasNothrowDefaultConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialDefaultConstructorProfile,
+        ti::HasTrivialDefaultConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::trivial>>,
+
+    // Core move constructor profiles
+    ProfileAndExpectation<
+        ti::HasMoveConstructorProfile, ti::HasMoveConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowMoveConstructorProfile,
+        ti::HasNothrowMoveConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialMoveConstructorProfile,
+        ti::HasTrivialMoveConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::trivial>>,
+
+    // Core copy constructor profiles
+    ProfileAndExpectation<
+        ti::HasCopyConstructorProfile, ti::HasCopyConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::maybe,
+                               ti::copy_constructible::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowCopyConstructorProfile,
+        ti::HasNothrowCopyConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::maybe,
+                               ti::copy_constructible::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialCopyConstructorProfile,
+        ti::HasTrivialCopyConstructorArchetype,
+        ti::ConformanceProfile<ti::default_constructible::maybe,
+                               ti::move_constructible::maybe,
+                               ti::copy_constructible::trivial>>,
+
+    // Core move assignment profiles
+    ProfileAndExpectation<
+        ti::HasMoveAssignProfile, ti::HasMoveAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowMoveAssignProfile, ti::HasNothrowMoveAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialMoveAssignProfile, ti::HasTrivialMoveAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::trivial>>,
+
+    // Core copy assignment profiles
+    ProfileAndExpectation<
+        ti::HasCopyAssignProfile, ti::HasCopyAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowCopyAssignProfile, ti::HasNothrowCopyAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialCopyAssignProfile, ti::HasTrivialCopyAssignArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::trivial>>,
+
+    // Core destructor profiles
+    ProfileAndExpectation<
+        ti::HasDestructorProfile, ti::HasDestructorArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowDestructorProfile, ti::HasNothrowDestructorArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+    ProfileAndExpectation<
+        ti::HasTrivialDestructorProfile, ti::HasTrivialDestructorArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::trivial>>,
+
+    // Core equality comparable profiles
+    ProfileAndExpectation<
+        ti::HasEqualityProfile, ti::HasEqualityArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowEqualityProfile, ti::HasNothrowEqualityArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::nothrow>>,
+
+    // Core inequality comparable profiles
+    ProfileAndExpectation<
+        ti::HasInequalityProfile, ti::HasInequalityArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowInequalityProfile, ti::HasNothrowInequalityArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe,
+            ti::inequality_comparable::nothrow>>,
+
+    // Core less than comparable profiles
+    ProfileAndExpectation<
+        ti::HasLessThanProfile, ti::HasLessThanArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowLessThanProfile, ti::HasNothrowLessThanArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::nothrow>>,
+
+    // Core less equal comparable profiles
+    ProfileAndExpectation<
+        ti::HasLessEqualProfile, ti::HasLessEqualArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowLessEqualProfile, ti::HasNothrowLessEqualArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe,
+            ti::less_equal_comparable::nothrow>>,
+
+    // Core greater equal comparable profiles
+    ProfileAndExpectation<
+        ti::HasGreaterEqualProfile, ti::HasGreaterEqualArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowGreaterEqualProfile, ti::HasNothrowGreaterEqualArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::nothrow>>,
+
+    // Core greater than comparable profiles
+    ProfileAndExpectation<
+        ti::HasGreaterThanProfile, ti::HasGreaterThanArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowGreaterThanProfile, ti::HasNothrowGreaterThanArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::nothrow>>,
+
+    // Core swappable profiles
+    ProfileAndExpectation<
+        ti::HasSwapProfile, ti::HasSwapArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::yes>>,
+    ProfileAndExpectation<
+        ti::HasNothrowSwapProfile, ti::HasNothrowSwapArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+    // Core hashable profiles
+    ProfileAndExpectation<
+        ti::HasStdHashSpecializationProfile,
+        ti::HasStdHashSpecializationArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::maybe,
+            ti::hashable::yes>>>;
+
+using CommonProfilesToTest = ::testing::Types<
+    // NothrowMoveConstructible
+    ProfileAndExpectation<
+        ti::NothrowMoveConstructibleProfile,
+        ti::NothrowMoveConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+    // CopyConstructible
+    ProfileAndExpectation<
+        ti::CopyConstructibleProfile, ti::CopyConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+    // NothrowMovable
+    ProfileAndExpectation<
+        ti::NothrowMovableProfile, ti::NothrowMovableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+            ti::copy_assignable::maybe, ti::destructible::nothrow,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+    // Value
+    ProfileAndExpectation<
+        ti::ValueProfile, ti::ValueArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::nothrow,
+            ti::copy_assignable::yes, ti::destructible::nothrow,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+    ////////////////////////////////////////////////////////////////////////////
+    //                  Common but also DefaultConstructible                  //
+    ////////////////////////////////////////////////////////////////////////////
+
+    // DefaultConstructibleNothrowMoveConstructible
+    ProfileAndExpectation<
+        ti::DefaultConstructibleNothrowMoveConstructibleProfile,
+        ti::DefaultConstructibleNothrowMoveConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::yes, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+    // DefaultConstructibleCopyConstructible
+    ProfileAndExpectation<
+        ti::DefaultConstructibleCopyConstructibleProfile,
+        ti::DefaultConstructibleCopyConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::yes, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+    // DefaultConstructibleNothrowMovable
+    ProfileAndExpectation<
+        ti::DefaultConstructibleNothrowMovableProfile,
+        ti::DefaultConstructibleNothrowMovableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::yes, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+            ti::copy_assignable::maybe, ti::destructible::nothrow,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+    // DefaultConstructibleValue
+    ProfileAndExpectation<
+        ti::DefaultConstructibleValueProfile,
+        ti::DefaultConstructibleValueArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::yes, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::nothrow,
+            ti::copy_assignable::yes, ti::destructible::nothrow,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>>;
+
+using ComparableHelpersProfilesToTest = ::testing::Types<
+    // Equatable
+    ProfileAndExpectation<
+        ti::EquatableProfile, ti::EquatableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes>>,
+
+    // Comparable
+    ProfileAndExpectation<
+        ti::ComparableProfile, ti::ComparableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes,
+            ti::greater_than_comparable::yes>>,
+
+    // NothrowEquatable
+    ProfileAndExpectation<
+        ti::NothrowEquatableProfile, ti::NothrowEquatableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::nothrow,
+            ti::inequality_comparable::nothrow>>,
+
+    // NothrowComparable
+    ProfileAndExpectation<
+        ti::NothrowComparableProfile, ti::NothrowComparableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::maybe,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::maybe,
+            ti::equality_comparable::nothrow,
+            ti::inequality_comparable::nothrow,
+            ti::less_than_comparable::nothrow,
+            ti::less_equal_comparable::nothrow,
+            ti::greater_equal_comparable::nothrow,
+            ti::greater_than_comparable::nothrow>>>;
+
+using CommonComparableProfilesToTest = ::testing::Types<
+    // ComparableNothrowMoveConstructible
+    ProfileAndExpectation<
+        ti::ComparableNothrowMoveConstructibleProfile,
+        ti::ComparableNothrowMoveConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes,
+            ti::greater_than_comparable::yes>>,
+
+    // ComparableCopyConstructible
+    ProfileAndExpectation<
+        ti::ComparableCopyConstructibleProfile,
+        ti::ComparableCopyConstructibleArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::maybe,
+            ti::copy_assignable::maybe, ti::destructible::nothrow,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes,
+            ti::greater_than_comparable::yes>>,
+
+    // ComparableNothrowMovable
+    ProfileAndExpectation<
+        ti::ComparableNothrowMovableProfile,
+        ti::ComparableNothrowMovableArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+            ti::copy_assignable::maybe, ti::destructible::nothrow,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+            ti::swappable::nothrow>>,
+
+    // ComparableValue
+    ProfileAndExpectation<
+        ti::ComparableValueProfile, ti::ComparableValueArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::maybe, ti::move_constructible::nothrow,
+            ti::copy_constructible::yes, ti::move_assignable::nothrow,
+            ti::copy_assignable::yes, ti::destructible::nothrow,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+            ti::swappable::nothrow>>>;
+
+using TrivialProfilesToTest = ::testing::Types<
+    ProfileAndExpectation<
+        ti::TrivialSpecialMemberFunctionsProfile,
+        ti::TrivialSpecialMemberFunctionsArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::trivial, ti::move_constructible::trivial,
+            ti::copy_constructible::trivial, ti::move_assignable::trivial,
+            ti::copy_assignable::trivial, ti::destructible::trivial,
+            ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+            ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+            ti::greater_equal_comparable::maybe,
+            ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+    ProfileAndExpectation<
+        ti::TriviallyCompleteProfile, ti::TriviallyCompleteArchetype,
+        ti::ConformanceProfile<
+            ti::default_constructible::trivial, ti::move_constructible::trivial,
+            ti::copy_constructible::trivial, ti::move_assignable::trivial,
+            ti::copy_assignable::trivial, ti::destructible::trivial,
+            ti::equality_comparable::yes, ti::inequality_comparable::yes,
+            ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+            ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+            ti::swappable::nothrow, ti::hashable::yes>>>;
+
+INSTANTIATE_TYPED_TEST_SUITE_P(Core, ProfileTest, CoreProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(Common, ProfileTest, CommonProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(ComparableHelpers, ProfileTest,
+                               ComparableHelpersProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(CommonComparable, ProfileTest,
+                               CommonComparableProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(Trivial, ProfileTest, TrivialProfilesToTest);
+
+// TODO(calabrese) Test runtime results
+
+}  // namespace