From 1dd1320c8b29099fe5bba591d1b0dba367fa68d7 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Tue, 17 Mar 2020 13:53:13 -0700
Subject: [PATCH 01/14] test commit to get extra eyes on the problem

---
 include/gsl/span                   | 18 ++++++++++++++++++
 tests/span_compatibility_tests.cpp | 16 ++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/include/gsl/span b/include/gsl/span
index 23c58c9..7c15eb4 100644
--- a/include/gsl/span
+++ b/include/gsl/span
@@ -441,6 +441,8 @@ public:
         : storage_(KnownNotNull{arr + 0}, details::extent_type<N>())
     {}
 
+// #define useold
+#if defined(useold)
     template <std::size_t N,
               std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
     constexpr span(std::array<element_type, N>& arr) noexcept
@@ -455,7 +457,23 @@ public:
     constexpr span(const std::array<value_type, N>& arr) noexcept
         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
     {}
+#else
+    template <class T, std::size_t N,
+              std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
+                                details::is_allowed_element_type_conversion<T, element_type>::value), int> = 0>
+    constexpr span(std::array<T, N>& arr) noexcept
+        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
+    {}
 
+    template <class T, std::size_t N,
+              std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
+                                details::is_allowed_element_type_conversion<const T,
+                                                                            element_type>::value),
+                               int> = 0>
+    constexpr span(const std::array<T, N>& arr) noexcept
+        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
+    {}
+#endif
     // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement
     // on Container to be a contiguous sequence container.
     template <class Container,
diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index 8733e72..1985f6f 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -46,6 +46,22 @@ TEST(span_compatibility_tests, assertion_tests)
 {
     int arr[3]{10, 20, 30};
     std::array<int, 3> stl{{100, 200, 300}};
+    std::array<int*, 3> stl_nullptr{{nullptr,nullptr,nullptr}};
+
+    {
+        gsl::span<const int* const> sp_const_nullptr_1{stl_nullptr};
+        EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
+        EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
+
+#if __cplusplus >= 201703l
+        span<const int* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
+        EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
+        EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
+
+        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>);
+        static_assert(std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>);
+#endif
+    }
 
     {
         gsl::span<int> sp_dyn;

From 9b3ac8d681222a082231de712a4bd4299b658f11 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Tue, 17 Mar 2020 15:02:00 -0700
Subject: [PATCH 02/14] discussed the issue with Casey Carter, the span ctor
 changes are accurate but the tests are not. The test require work that was
 done in C++17 regarding qualifier conversions to work correctly. Scoping
 tests for 17.

---
 include/gsl/span                   | 19 +------------------
 tests/span_compatibility_tests.cpp |  6 ++++--
 2 files changed, 5 insertions(+), 20 deletions(-)

diff --git a/include/gsl/span b/include/gsl/span
index 7c15eb4..469a2db 100644
--- a/include/gsl/span
+++ b/include/gsl/span
@@ -441,23 +441,6 @@ public:
         : storage_(KnownNotNull{arr + 0}, details::extent_type<N>())
     {}
 
-// #define useold
-#if defined(useold)
-    template <std::size_t N,
-              std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
-    constexpr span(std::array<element_type, N>& arr) noexcept
-        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
-    {}
-
-    template <std::size_t N,
-              std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
-                                details::is_allowed_element_type_conversion<const value_type,
-                                                                            element_type>::value),
-                               int> = 0>
-    constexpr span(const std::array<value_type, N>& arr) noexcept
-        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
-    {}
-#else
     template <class T, std::size_t N,
               std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
                                 details::is_allowed_element_type_conversion<T, element_type>::value), int> = 0>
@@ -473,7 +456,7 @@ public:
     constexpr span(const std::array<T, N>& arr) noexcept
         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
     {}
-#endif
+
     // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement
     // on Container to be a contiguous sequence container.
     template <class Container,
diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index 1985f6f..acd85c5 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -48,20 +48,22 @@ TEST(span_compatibility_tests, assertion_tests)
     std::array<int, 3> stl{{100, 200, 300}};
     std::array<int*, 3> stl_nullptr{{nullptr,nullptr,nullptr}};
 
+#if __cplusplus >= 201703l
+    // This std::is_convertible_v<int*(*)[], int const* const(*)[]> fails for C++14
+    // so these conversions aren't valid in C++14
     {
         gsl::span<const int* const> sp_const_nullptr_1{stl_nullptr};
         EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
 
-#if __cplusplus >= 201703l
         span<const int* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
         static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>);
         static_assert(std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>);
-#endif
     }
+#endif
 
     {
         gsl::span<int> sp_dyn;

From f8bcb7d9eb44be91a04882eb972fbef328c24cae Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Tue, 17 Mar 2020 15:04:58 -0700
Subject: [PATCH 03/14] applied clang-format

---
 include/gsl/span                   | 43 +++++++++++++++++-------------
 tests/span_compatibility_tests.cpp | 22 +++++++--------
 2 files changed, 36 insertions(+), 29 deletions(-)

diff --git a/include/gsl/span b/include/gsl/span
index 469a2db..566f731 100644
--- a/include/gsl/span
+++ b/include/gsl/span
@@ -21,9 +21,9 @@
 #include <gsl/gsl_byte>   // for byte
 #include <gsl/gsl_util>   // for narrow_cast, narrow
 
-#include <array>     // for array
-#include <cstddef>   // for ptrdiff_t, size_t, nullptr_t
-#include <iterator>  // for reverse_iterator, distance, random_access_...
+#include <array>       // for array
+#include <cstddef>     // for ptrdiff_t, size_t, nullptr_t
+#include <iterator>    // for reverse_iterator, distance, random_access_...
 #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
 
 #if defined(_MSC_VER) && !defined(__clang__)
@@ -441,18 +441,20 @@ public:
         : storage_(KnownNotNull{arr + 0}, details::extent_type<N>())
     {}
 
-    template <class T, std::size_t N,
-              std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
-                                details::is_allowed_element_type_conversion<T, element_type>::value), int> = 0>
+    template <
+        class T, std::size_t N,
+        std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
+                          details::is_allowed_element_type_conversion<T, element_type>::value),
+                         int> = 0>
     constexpr span(std::array<T, N>& arr) noexcept
         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
     {}
 
     template <class T, std::size_t N,
-              std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
-                                details::is_allowed_element_type_conversion<const T,
-                                                                            element_type>::value),
-                               int> = 0>
+              std::enable_if_t<
+                  (details::is_allowed_extent_conversion<N, Extent>::value &&
+                   details::is_allowed_element_type_conversion<const T, element_type>::value),
+                  int> = 0>
     constexpr span(const std::array<T, N>& arr) noexcept
         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
     {}
@@ -463,7 +465,9 @@ public:
               class = std::enable_if_t<
                   !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
                   std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
-                  std::is_convertible<std::remove_pointer_t<decltype(std::declval<Container&>().data())>(*)[], element_type(*)[]>::value>>
+                  std::is_convertible<
+                      std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
+                      element_type (*)[]>::value>>
     constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
     {}
 
@@ -472,7 +476,9 @@ public:
                   std::is_const<element_type>::value && !details::is_span<Container>::value &&
                   !details::is_std_array<Container>::value &&
                   std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
-                  std::is_convertible<std::remove_pointer_t<decltype(std::declval<const Container&>().data())>(*)[], element_type(*)[]>::value>>
+                  std::is_convertible<std::remove_pointer_t<
+                                          decltype(std::declval<const Container&>().data())> (*)[],
+                                      element_type (*)[]>::value>>
     constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
     {}
 
@@ -501,8 +507,8 @@ public:
     template <std::size_t Count>
     // clang-format off
     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
-    // clang-format on
-    constexpr span<element_type, Count> last() const noexcept
+        // clang-format on
+        constexpr span<element_type, Count> last() const noexcept
     {
         Expects(Count <= size());
         return {data() + (size() - Count), Count};
@@ -511,9 +517,9 @@ public:
     template <std::size_t Offset, std::size_t Count = dynamic_extent>
     // clang-format off
     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
-    // clang-format on
-    constexpr auto subspan() const noexcept ->
-    typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
+        // clang-format on
+        constexpr auto subspan() const noexcept ->
+        typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
     {
         Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
 
@@ -674,7 +680,8 @@ private:
 
     template <std::size_t CallerExtent>
     constexpr span<element_type, dynamic_extent> make_subspan(size_type offset, size_type count,
-                                                              subspan_selector<CallerExtent>) const noexcept
+                                                              subspan_selector<CallerExtent>) const
+        noexcept
     {
         const span<element_type, dynamic_extent> tmp(*this);
         return tmp.subspan(offset, count);
diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index acd85c5..d8226ec 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -24,7 +24,7 @@
 #include <iterator>    // for reverse_iterator, operator-, operator==
 #include <type_traits> // for integral_constant<>::value, is_default_co...
 #include <utility>
-#include <vector>      // for vector
+#include <vector> // for vector
 
 using namespace std;
 using namespace gsl;
@@ -46,7 +46,7 @@ TEST(span_compatibility_tests, assertion_tests)
 {
     int arr[3]{10, 20, 30};
     std::array<int, 3> stl{{100, 200, 300}};
-    std::array<int*, 3> stl_nullptr{{nullptr,nullptr,nullptr}};
+    std::array<int*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
 
 #if __cplusplus >= 201703l
     // This std::is_convertible_v<int*(*)[], int const* const(*)[]> fails for C++14
@@ -60,8 +60,9 @@ TEST(span_compatibility_tests, assertion_tests)
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
-        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>);
-        static_assert(std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>);
+        static_assert(std::is_same < decltype(span{stl_nullptr}), span<int*, 3>);
+        static_assert(std::is_same < decltype(span{std::as_const(stl_nullptr)}),
+                      span<int* const, 3>);
     }
 #endif
 
@@ -1070,21 +1071,20 @@ static_assert(std::is_convertible<std::array<int, 3>&, gsl::span<const int>>::va
 static_assert(std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>::value,
               "std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>");
 
-
 #if __cplusplus >= 201703l
 template <typename U, typename = void>
 static constexpr bool AsWritableBytesCompilesFor = false;
 
 template <typename U>
-static constexpr bool AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> =
-    true;
+static constexpr bool
+    AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
 
 static_assert(AsWritableBytesCompilesFor<gsl::span<int>>,
-                "AsWritableBytesCompilesFor<gsl::span<int>>");
+              "AsWritableBytesCompilesFor<gsl::span<int>>");
 static_assert(AsWritableBytesCompilesFor<gsl::span<int, 9>>,
-                "AsWritableBytesCompilesFor<gsl::span<int, 9>>");
+              "AsWritableBytesCompilesFor<gsl::span<int, 9>>");
 static_assert(!AsWritableBytesCompilesFor<gsl::span<const int>>,
-                "!AsWritableBytesCompilesFor<gsl::span<const int>>");
+              "!AsWritableBytesCompilesFor<gsl::span<const int>>");
 static_assert(!AsWritableBytesCompilesFor<gsl::span<const int, 9>>,
-                "!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
+              "!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
 #endif // __cplusplus >= 201703l

From 6eab19d3c145911cd34f00644e041512cda6e717 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Tue, 17 Mar 2020 15:13:26 -0700
Subject: [PATCH 04/14] moving decl so we dont get the stl_nullptr is not used
 warning

---
 tests/span_compatibility_tests.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index d8226ec..4be3c4d 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -46,12 +46,12 @@ TEST(span_compatibility_tests, assertion_tests)
 {
     int arr[3]{10, 20, 30};
     std::array<int, 3> stl{{100, 200, 300}};
-    std::array<int*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
 
 #if __cplusplus >= 201703l
     // This std::is_convertible_v<int*(*)[], int const* const(*)[]> fails for C++14
     // so these conversions aren't valid in C++14
     {
+        std::array<int*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
         gsl::span<const int* const> sp_const_nullptr_1{stl_nullptr};
         EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_1.size() == 3);

From ddde9e153d150ba5b635825898a2bde45512b635 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 19 Mar 2020 14:08:04 -0700
Subject: [PATCH 05/14] update convertibility test

---
 tests/span_compatibility_tests.cpp | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index 4be3c4d..e344e88 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -42,14 +42,11 @@ static_assert(std::is_convertible<Derived*, Base*>::value, "std::is_convertible<
 static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
               "!std::is_convertible<Derived(*)[], Base(*)[]>");
 
-TEST(span_compatibility_tests, assertion_tests)
+template <class = void>
+void ArrayConvertibilityCheck()
 {
-    int arr[3]{10, 20, 30};
-    std::array<int, 3> stl{{100, 200, 300}};
-
 #if __cplusplus >= 201703l
-    // This std::is_convertible_v<int*(*)[], int const* const(*)[]> fails for C++14
-    // so these conversions aren't valid in C++14
+    if constexpr (std::is_convertible<int*(*) [], int const* const(*)[]>::value)
     {
         std::array<int*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
         gsl::span<const int* const> sp_const_nullptr_1{stl_nullptr};
@@ -60,11 +57,22 @@ TEST(span_compatibility_tests, assertion_tests)
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
-        static_assert(std::is_same < decltype(span{stl_nullptr}), span<int*, 3>);
-        static_assert(std::is_same < decltype(span{std::as_const(stl_nullptr)}),
-                      span<int* const, 3>);
+        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
+                      "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
+        static_assert(
+            std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
+            "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
+            "3>>::value");
     }
 #endif
+}
+
+TEST(span_compatibility_tests, assertion_tests)
+{
+    int arr[3]{10, 20, 30};
+    std::array<int, 3> stl{{100, 200, 300}};
+
+    ArrayConvertibilityCheck();
 
     {
         gsl::span<int> sp_dyn;

From 01d206f4d8997a01741ffe8f6ba719a747b7e014 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Wed, 8 Apr 2020 14:38:01 -0700
Subject: [PATCH 06/14] adding additional filtering

---
 tests/span_compatibility_tests.cpp | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index e344e88..fa327f7 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -42,6 +42,7 @@ static_assert(std::is_convertible<Derived*, Base*>::value, "std::is_convertible<
 static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
               "!std::is_convertible<Derived(*)[], Base(*)[]>");
 
+#if (defined(_MSC_VER)) || (defined(__GNUC__) && __GNUC__ > 7) || (defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()
 {
@@ -57,15 +58,19 @@ void ArrayConvertibilityCheck()
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
-        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
-                      "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
-        static_assert(
-            std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
-            "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
-            "3>>::value");
+         static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
+                       "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
+         static_assert(
+             std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
+             "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
+             "3>>::value");
     }
 #endif
 }
+#else
+template <class = void>
+void ArrayConvertibilityCheck(){}
+#endif
 
 TEST(span_compatibility_tests, assertion_tests)
 {

From 2f9d8730439ba0cc1998c6f3239498af79e352fe Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 10:34:58 -0700
Subject: [PATCH 07/14] added additional filtering to Apple clang versions 9.4
 and 10.1 for the ArrayConvertibilityCheck

---
 tests/span_compatibility_tests.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index fa327f7..db9efba 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -42,7 +42,14 @@ static_assert(std::is_convertible<Derived*, Base*>::value, "std::is_convertible<
 static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
               "!std::is_convertible<Derived(*)[], Base(*)[]>");
 
-#if (defined(_MSC_VER)) || (defined(__GNUC__) && __GNUC__ > 7) || (defined(__clang__) && __clang_major__ > 6)
+// int*(*) [], int const* const(*)[] was identified as an issue in CWG330 and the resolution was provided with N4261
+// The changes were not backported to all versions of the compilers that GSL supports.
+// The `if constexpr` should prevent codegen from happening if it is not supported however a few compilers continue to complain about the logic within.
+// Filtering g++ version < 8, clang version < 7, and Apple clang versions 9.4 and 10.1.
+#if (defined(_MSC_VER)) || \
+(defined(__GNUC__) && __GNUC__ > 7) || \
+(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor == 4) && !(__clang_major__ == 10 && __clang_minro__ == 1))) || \
+(defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()
 {

From 6ef56d73daae558bde2f02a436474c26b35587d7 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 10:35:44 -0700
Subject: [PATCH 08/14] fixed a couple typos

---
 tests/span_compatibility_tests.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index db9efba..e32a507 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -48,7 +48,7 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
 // Filtering g++ version < 8, clang version < 7, and Apple clang versions 9.4 and 10.1.
 #if (defined(_MSC_VER)) || \
 (defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor == 4) && !(__clang_major__ == 10 && __clang_minro__ == 1))) || \
+(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor__ == 4) && !(__clang_major__ == 10 && __clang_minor__ == 1))) || \
 (defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()

From 809aee231519d939c151fc355ded2b4e1b1085c2 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 11:51:59 -0700
Subject: [PATCH 09/14] testing different major/minor for Apple suppression

---
 tests/span_compatibility_tests.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index e32a507..4012839 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -45,10 +45,10 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
 // int*(*) [], int const* const(*)[] was identified as an issue in CWG330 and the resolution was provided with N4261
 // The changes were not backported to all versions of the compilers that GSL supports.
 // The `if constexpr` should prevent codegen from happening if it is not supported however a few compilers continue to complain about the logic within.
-// Filtering g++ version < 8, clang version < 7, and Apple clang versions 9.4 and 10.1.
+// Filtering g++ version < 8, clang version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
 #if (defined(_MSC_VER)) || \
 (defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor__ == 4) && !(__clang_major__ == 10 && __clang_minor__ == 1))) || \
+(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor__ == 1) && !(__clang_major__ == 10 && __clang_minor__ == 0))) || \
 (defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()

From b7d9d754aca05d248ef17688c94186d9016e551a Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 14:17:52 -0700
Subject: [PATCH 10/14] another attempt at apple clang version filtering

---
 tests/span_compatibility_tests.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index 4012839..ef9e50c 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -48,7 +48,7 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
 // Filtering g++ version < 8, clang version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
 #if (defined(_MSC_VER)) || \
 (defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__APPLE__) && defined(__clang__) && (!(__clang_major__ == 9 && __clang_minor__ == 1) && !(__clang_major__ == 10 && __clang_minor__ == 0))) || \
+(defined(__apple_build_version__) && __apple_build_version__ != 10001145 && __apple_build_version__ != 9020039 ) || \
 (defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()

From 8d907dadfbe9d605185b968bc8a9aa73fd196f5b Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 14:35:44 -0700
Subject: [PATCH 11/14] prevent comparison for apple clang versions older than
 11

---
 tests/span_compatibility_tests.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index ef9e50c..d8e9e99 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -48,7 +48,7 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
 // Filtering g++ version < 8, clang version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
 #if (defined(_MSC_VER)) || \
 (defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__apple_build_version__) && __apple_build_version__ != 10001145 && __apple_build_version__ != 9020039 ) || \
+(defined(__apple_build_version__) && defined(__clang__) && __clang_major__ > 10 ) || \
 (defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()

From 5ca02327c4ca3d67f66094c7b5c92f3eb86d4d11 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 15:56:26 -0700
Subject: [PATCH 12/14] another test

---
 tests/span_compatibility_tests.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index d8e9e99..b1be4cb 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -48,8 +48,8 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
 // Filtering g++ version < 8, clang version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
 #if (defined(_MSC_VER)) || \
 (defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__apple_build_version__) && defined(__clang__) && __clang_major__ > 10 ) || \
-(defined(__clang__) && __clang_major__ > 6)
+(defined(__APPLE__) && defined(__clang_major__) && __clang_major__ > 10 ) || \
+(!defined(__APPLE__) && defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()
 {

From ffbfcc0a9fecd7740440bfc8ab3dec7a0108ed87 Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 16:15:08 -0700
Subject: [PATCH 13/14] apply clang-format to the span_compatibility_tests.

---
 tests/span_compatibility_tests.cpp | 31 +++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index b1be4cb..e8981d1 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -42,14 +42,14 @@ static_assert(std::is_convertible<Derived*, Base*>::value, "std::is_convertible<
 static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
               "!std::is_convertible<Derived(*)[], Base(*)[]>");
 
-// int*(*) [], int const* const(*)[] was identified as an issue in CWG330 and the resolution was provided with N4261
-// The changes were not backported to all versions of the compilers that GSL supports.
-// The `if constexpr` should prevent codegen from happening if it is not supported however a few compilers continue to complain about the logic within.
-// Filtering g++ version < 8, clang version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
-#if (defined(_MSC_VER)) || \
-(defined(__GNUC__) && __GNUC__ > 7) || \
-(defined(__APPLE__) && defined(__clang_major__) && __clang_major__ > 10 ) || \
-(!defined(__APPLE__) && defined(__clang__) && __clang_major__ > 6)
+// int*(*) [], int const* const(*)[] was identified as an issue in CWG330 and the resolution was
+// provided with N4261. The changes were not backported to all versions of the compilers that GSL
+// supports. The `if constexpr` should prevent codegen from happening if it is not supported however
+// a few compilers continue to complain about the logic within. Filtering g++ version < 8, clang
+// version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
+#if (defined(_MSC_VER)) || (defined(__GNUC__) && __GNUC__ > 7) ||                                  \
+    (defined(__APPLE__) && defined(__clang_major__) && __clang_major__ > 10) ||                    \
+    (!defined(__APPLE__) && defined(__clang__) && __clang_major__ > 6)
 template <class = void>
 void ArrayConvertibilityCheck()
 {
@@ -65,18 +65,19 @@ void ArrayConvertibilityCheck()
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
-         static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
-                       "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
-         static_assert(
-             std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
-             "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
-             "3>>::value");
+        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
+                      "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
+        static_assert(
+            std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
+            "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
+            "3>>::value");
     }
 #endif
 }
 #else
 template <class = void>
-void ArrayConvertibilityCheck(){}
+void ArrayConvertibilityCheck()
+{}
 #endif
 
 TEST(span_compatibility_tests, assertion_tests)

From efbce17ca498bbdf7bb1694f6323ecfa126b74cc Mon Sep 17 00:00:00 2001
From: Jordan Maples <jomaples@microsoft.com>
Date: Thu, 9 Apr 2020 17:33:33 -0700
Subject: [PATCH 14/14] testing one of CaseyCarter's comments

---
 tests/span_compatibility_tests.cpp | 31 ++++++++++--------------------
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp
index e8981d1..ab29748 100644
--- a/tests/span_compatibility_tests.cpp
+++ b/tests/span_compatibility_tests.cpp
@@ -43,42 +43,31 @@ static_assert(!std::is_convertible<Derived (*)[], Base (*)[]>::value,
               "!std::is_convertible<Derived(*)[], Base(*)[]>");
 
 // int*(*) [], int const* const(*)[] was identified as an issue in CWG330 and the resolution was
-// provided with N4261. The changes were not backported to all versions of the compilers that GSL
-// supports. The `if constexpr` should prevent codegen from happening if it is not supported however
-// a few compilers continue to complain about the logic within. Filtering g++ version < 8, clang
-// version < 7, and XCode 9.4 and 10.1 which looks to be Apple clang versions 9.1 and 10.0.
-#if (defined(_MSC_VER)) || (defined(__GNUC__) && __GNUC__ > 7) ||                                  \
-    (defined(__APPLE__) && defined(__clang_major__) && __clang_major__ > 10) ||                    \
-    (!defined(__APPLE__) && defined(__clang__) && __clang_major__ > 6)
-template <class = void>
+// provided with N4261.
+template <class T = int>
 void ArrayConvertibilityCheck()
 {
 #if __cplusplus >= 201703l
-    if constexpr (std::is_convertible<int*(*) [], int const* const(*)[]>::value)
+    if constexpr (std::is_convertible<T*(*) [], T const* const(*)[]>::value)
     {
-        std::array<int*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
-        gsl::span<const int* const> sp_const_nullptr_1{stl_nullptr};
+        std::array<T*, 3> stl_nullptr{{nullptr, nullptr, nullptr}};
+        gsl::span<const T* const> sp_const_nullptr_1{stl_nullptr};
         EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
 
-        span<const int* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
+        span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)};
         EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data());
         EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
 
-        static_assert(std::is_same<decltype(span{stl_nullptr}), span<int*, 3>>::value,
-                      "std::is_same< decltype(span{stl_nullptr}), span<int*, 3>>::value");
+        static_assert(std::is_same<decltype(span{stl_nullptr}), span<T*, 3>>::value,
+                      "std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
         static_assert(
-            std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<int* const, 3>>::value,
-            "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<int* const, "
+            std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<T* const, 3>>::value,
+            "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
             "3>>::value");
     }
 #endif
 }
-#else
-template <class = void>
-void ArrayConvertibilityCheck()
-{}
-#endif
 
 TEST(span_compatibility_tests, assertion_tests)
 {