Fix/implement C++2020 compilation, tests, and CI (#1017)

* Fix C++20 bugs and tests
* Rework CI for C++2020 tests
* Update readme compiler versions
This commit is contained in:
dmitrykobets-msft 2021-12-09 14:54:06 -08:00 committed by GitHub
parent e0880931ae
commit bcf008ae55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 80 additions and 67 deletions

View File

@ -86,16 +86,14 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp
# Quick Start # Quick Start
## Supported Compilers ## Supported Compilers
The GSL officially supports the current and previous major release of MSVC, GCC, Clang, and XCode's Apple-Clang. The GSL officially supports the following versions of MSVC, GCC, Clang, and XCode's Apple-Clang.
See our latest test results for the most up-to-date list of supported configurations.
Compiler |Toolset Versions Currently Tested Compiler |Toolset Versions Currently Tested
:------- |--: :------- |--:
XCode |11.4 & 10.3 XCode | 12.4 & 11.3
GCC |9 & 8 GCC | 9.3.0 & 7.5.0
Clang |11 & 10 Clang | 11.0.0 & 9.0.0
Visual Studio with MSVC | VS2017 (15.9) & VS2019 (16.4) Visual Studio with MSVC | VS2017 (15.9.21) & VS2019 (16.11.2)
Visual Studio with LLVM | VS2017 (Clang 9) & VS2019 (Clang 10)
--- ---
If you successfully port GSL to another platform, we would love to hear from you! If you successfully port GSL to another platform, we would love to hear from you!

View File

@ -18,10 +18,12 @@ stages:
parameters: parameters:
jobName: 'Validate GCC latest' jobName: 'Validate GCC latest'
imageName: ubuntu-20.04 imageName: ubuntu-20.04
CXXVersions: [ 14, 17 ]
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate GCC Previous' jobName: 'Validate GCC Previous'
imageName: ubuntu-18.04 imageName: ubuntu-18.04
CXXVersions: [ 14, 17 ]
# Clang # Clang
- stage: Clang - stage: Clang
@ -40,6 +42,7 @@ stages:
parameters: parameters:
jobName: 'Validate Clang Previous' jobName: 'Validate Clang Previous'
imageName: ubuntu-18.04 imageName: ubuntu-18.04
CXXVersions: [ 14, 17 ]
# MSVC # MSVC
- stage: MSVC - stage: MSVC
@ -53,6 +56,7 @@ stages:
parameters: parameters:
jobName: 'Validate MSVC Previous' jobName: 'Validate MSVC Previous'
imageName: vs2017-win2016 imageName: vs2017-win2016
CXXVersions: [ 14, 17 ]
# Apple-Clang # Apple-Clang
- stage: Apple_Clang - stage: Apple_Clang
@ -62,7 +66,9 @@ stages:
parameters: parameters:
jobName: 'Validate Apple-Clang latest' jobName: 'Validate Apple-Clang latest'
imageName: macos-10.15 imageName: macos-10.15
CXXVersions: [ 14, 17 ]
- template: ./pipelines/jobs.yml - template: ./pipelines/jobs.yml
parameters: parameters:
jobName: 'Validate Apple-Clang Previous' jobName: 'Validate Apple-Clang Previous'
imageName: macos-10.14 imageName: macos-10.14
CXXVersions: [ 14, 17 ]

View File

@ -143,10 +143,10 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
template <class T, size_t extent = std::dynamic_extent> template <class T, size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i) constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()])
{ {
Expects(i >= 0 && i < narrow_cast<i>(sp.size())); Expects(i >= 0 && i < narrow_cast<index>(sp.size()));
return sp[i]; return sp[gsl::narrow_cast<size_t>(i)];
} }
#endif // __cpp_lib_span >= 202002L #endif // __cpp_lib_span >= 202002L
} // namespace gsl } // namespace gsl

View File

@ -1,26 +1,19 @@
parameters: parameters:
jobName: '' jobName: ''
imageName: '' imageName: ''
CXXVersions: [ 14, 17, 20 ]
buildTypes: [ 'Debug', 'Release' ]
jobs: jobs:
- job: - ${{ each CXXVersion in parameters.CXXVersions }}:
displayName: ${{ parameters.imageName }} - ${{ each buildType in parameters.buildTypes }}:
pool: - job:
vmImage: ${{ parameters.imageName }} displayName: ${{ format('{0} {1} C++{2}', parameters.imageName, buildType, CXXVersion) }}
strategy: pool:
matrix: vmImage: ${{ parameters.imageName }}
14_debug: continueOnError: false
GSL_CXX_STANDARD: '14' steps:
BUILD_TYPE: 'Debug' - template: ./steps.yml
14_release: parameters:
GSL_CXX_STANDARD: '14' buildType: ${{ buildType }}
BUILD_TYPE: 'Release' CXXVersion: ${{ CXXVersion }}
17_debug:
GSL_CXX_STANDARD: '17'
BUILD_TYPE: 'Debug'
17_release:
GSL_CXX_STANDARD: '17'
BUILD_TYPE: 'Release'
continueOnError: false
steps:
- template: ./steps.yml

View File

@ -1,9 +1,13 @@
parameters:
buildType: ''
CXXVersion: ''
steps: steps:
- task: CMake@1 - task: CMake@1
name: Configure name: Configure
inputs: inputs:
workingDirectory: build workingDirectory: build
cmakeArgs: '-DCMAKE_CXX_STANDARD=$(GSL_CXX_STANDARD) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -Werror=dev .. ' cmakeArgs: '-DGSL_CXX_STANDARD=${{ parameters.CXXVersion }} -DCMAKE_BUILD_TYPE=${{ parameters.buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev .. '
- task: CMake@1 - task: CMake@1
name: Build name: Build

View File

@ -9,6 +9,10 @@ include(ExternalProject)
# will make visual studio generated project group files # will make visual studio generated project group files
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20)
add_compile_definitions(FORCE_STD_SPAN_TESTS=1)
endif()
if(IOS) if(IOS)
add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1) add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1)
endif() endif()
@ -54,7 +58,7 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
find_package(Microsoft.GSL REQUIRED) find_package(Microsoft.GSL REQUIRED)
endif() endif()
if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17))
set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-)
endif() endif()
@ -135,6 +139,11 @@ else()
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>: $<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,4.99>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
$<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template> $<$<EQUAL:${GSL_CXX_STANDARD},17>:-Wno-undefined-func-template>
> >
$<$<AND:$<EQUAL:${GSL_CXX_STANDARD},20>,$<CXX_COMPILER_VERSION:11.0.0>>:
-Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 11.0.0
# (operator< is being re-written by the compiler as operator<=> and
# raising the warning)
>
> >
$<$<CXX_COMPILER_ID:AppleClang>: $<$<CXX_COMPILER_ID:AppleClang>:
$<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>: $<$<AND:$<VERSION_GREATER:$<CXX_COMPILER_VERSION>,9.1>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,10>>:

View File

@ -27,7 +27,6 @@ namespace gsl
struct fail_fast; struct fail_fast;
} // namespace gsl } // namespace gsl
using namespace std;
using namespace gsl; using namespace gsl;
TEST(algorithm_tests, same_type) TEST(algorithm_tests, same_type)
@ -73,8 +72,8 @@ TEST(algorithm_tests, same_type)
std::array<int, 5> src{1, 2, 3, 4, 5}; std::array<int, 5> src{1, 2, 3, 4, 5};
std::array<int, 10> dst{}; std::array<int, 10> dst{};
const span<int> src_span(src); const gsl::span<int> src_span(src);
const span<int, 10> dst_span(dst); const gsl::span<int, 10> dst_span(dst);
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));

View File

@ -119,7 +119,7 @@ TEST(at_tests, InitializerList)
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
} }
#if defined(__cplusplus) && __cplusplus >= 202002L #if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
TEST(at_tests, std_span) TEST(at_tests, std_span)
{ {
std::vector<int> vec{1, 2, 3, 4, 5}; std::vector<int> vec{1, 2, 3, 4, 5};
@ -128,18 +128,24 @@ TEST(at_tests, std_span)
std::vector<int> cvec{1, 2, 3, 4, 5}; std::vector<int> cvec{1, 2, 3, 4, 5};
std::span csp{cvec}; std::span csp{cvec};
for (size_t i = 0, i < vec.size(); ++i) for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vec.size()); ++i)
{ {
EXPECT_TRUE(&gsl::at(sp, i) == &vec[i]); EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast<size_t>(i)]);
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[i]); EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast<size_t>(i)]);
} }
const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. std_span";
std::abort();
});
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(sp, -1), expected); EXPECT_DEATH(gsl::at(sp, -1), expected);
EXPECT_DEATH(gsl::at(sp, sp.size()), expected); EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
EXPECT_DEATH(gsl::at(csp, -1), expected); EXPECT_DEATH(gsl::at(csp, -1), expected);
EXPECT_DEATH(gsl::at(csp, sp.size()), expected); EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast<gsl::index>(sp.size())), expected);
} }
#endif // __cplusplus >= 202002L #endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
static constexpr bool test_constexpr() static constexpr bool test_constexpr()

View File

@ -55,14 +55,14 @@ void ArrayConvertibilityCheck()
EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data());
EXPECT_TRUE(sp_const_nullptr_1.size() == 3); EXPECT_TRUE(sp_const_nullptr_1.size() == 3);
span<const T* const> sp_const_nullptr_2{std::as_const(stl_nullptr)}; gsl::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.data() == stl_nullptr.data());
EXPECT_TRUE(sp_const_nullptr_2.size() == 3); EXPECT_TRUE(sp_const_nullptr_2.size() == 3);
static_assert(std::is_same<decltype(span{stl_nullptr}), span<T*, 3>>::value, static_assert(std::is_same<decltype(gsl::span{stl_nullptr}), gsl::span<T*, 3>>::value,
"std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value"); "std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
static_assert( static_assert(
std::is_same<decltype(span{std::as_const(stl_nullptr)}), span<T* const, 3>>::value, std::is_same<decltype(gsl::span{std::as_const(stl_nullptr)}), gsl::span<T* const, 3>>::value,
"std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, " "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
"3>>::value"); "3>>::value");
} }

View File

@ -48,7 +48,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
int* p = nullptr; int* p = nullptr;
auto s = make_span(p, narrow_cast<span<int>::size_type>(0)); auto s = make_span(p, narrow_cast<gsl::span<int>::size_type>(0));
EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == nullptr); EXPECT_TRUE(s.data() == nullptr);
} }
@ -136,9 +136,9 @@ TEST(span_ext_test, make_span_from_std_array_constructor)
// This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
{ {
span<int> s1 = make_span(arr); gsl::span<int> s1 = make_span(arr);
static span<int> s2; static gsl::span<int> s2;
s2 = s1; s2 = s1;
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
@ -194,7 +194,7 @@ TEST(span_ext_test, make_span_from_container_constructor)
TEST(span_test, interop_with_gsl_at) TEST(span_test, interop_with_gsl_at)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
span<int> s{arr}; gsl::span<int> s{arr};
EXPECT_TRUE(at(s, 0) == 1); EXPECT_TRUE(at(s, 0) == 1);
EXPECT_TRUE(at(s, 1) == 2); EXPECT_TRUE(at(s, 1) == 2);
} }
@ -202,7 +202,7 @@ TEST(span_test, interop_with_gsl_at)
TEST(span_ext_test, iterator_free_functions) TEST(span_ext_test, iterator_free_functions)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; gsl::span<int> s{a};
EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
@ -232,7 +232,7 @@ TEST(span_ext_test, iterator_free_functions)
TEST(span_ext_test, ssize_free_function) TEST(span_ext_test, ssize_free_function)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; gsl::span<int> s{a};
EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value)); EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s))); EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
@ -242,8 +242,8 @@ TEST(span_ext_test, ssize_free_function)
TEST(span_ext_test, comparison_operators) TEST(span_ext_test, comparison_operators)
{ {
{ {
span<int> s1; gsl::span<int> s1;
span<int> s2; gsl::span<int> s2;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
EXPECT_FALSE(s1 < s2); EXPECT_FALSE(s1 < s2);
@ -260,8 +260,8 @@ TEST(span_ext_test, comparison_operators)
{ {
int arr[] = {2, 1}; int arr[] = {2, 1};
span<int> s1 = arr; gsl::span<int> s1 = arr;
span<int> s2 = arr; gsl::span<int> s2 = arr;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
@ -280,8 +280,8 @@ TEST(span_ext_test, comparison_operators)
{ {
int arr[] = {2, 1}; // bigger int arr[] = {2, 1}; // bigger
span<int> s1; gsl::span<int> s1;
span<int> s2 = arr; gsl::span<int> s2 = arr;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
@ -300,8 +300,8 @@ TEST(span_ext_test, comparison_operators)
{ {
int arr1[] = {1, 2}; int arr1[] = {1, 2};
int arr2[] = {1, 2}; int arr2[] = {1, 2};
span<int> s1 = arr1; gsl::span<int> s1 = arr1;
span<int> s2 = arr2; gsl::span<int> s2 = arr2;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
@ -320,8 +320,8 @@ TEST(span_ext_test, comparison_operators)
{ {
int arr[] = {1, 2, 3}; int arr[] = {1, 2, 3};
span<int> s1 = {&arr[0], 2}; // shorter gsl::span<int> s1 = {&arr[0], 2}; // shorter
span<int> s2 = arr; // longer gsl::span<int> s2 = arr; // longer
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
@ -341,8 +341,8 @@ TEST(span_ext_test, comparison_operators)
int arr1[] = {1, 2}; // smaller int arr1[] = {1, 2}; // smaller
int arr2[] = {2, 1}; // bigger int arr2[] = {2, 1}; // bigger
span<int> s1 = arr1; gsl::span<int> s1 = arr1;
span<int> s2 = arr2; gsl::span<int> s2 = arr2;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);

View File

@ -43,7 +43,6 @@
#include "deathTestCommon.h" #include "deathTestCommon.h"
using namespace std;
using namespace gsl; using namespace gsl;
namespace namespace
@ -1085,7 +1084,7 @@ TEST(span_test, as_bytes)
int b[5] = {1, 2, 3, 4, 5}; int b[5] = {1, 2, 3, 4, 5};
{ {
span<int> sp(begin(b), static_cast<size_t>(-2)); span<int> sp(std::begin(b), static_cast<size_t>(-2));
EXPECT_DEATH((void) sp.size_bytes(), expected); EXPECT_DEATH((void) sp.size_bytes(), expected);
} }
} }

View File

@ -30,7 +30,6 @@
#include "deathTestCommon.h" #include "deathTestCommon.h"
using namespace std;
using namespace gsl; using namespace gsl;
// Generic string functions // Generic string functions