Workaround for gcc bug, fix for static global variable and function in header, fix of c++20 warning

This commit is contained in:
Hans Dembinski 2020-11-01 17:10:11 +01:00 committed by GitHub
parent 2f91f037b9
commit 0840102bfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 152 additions and 79 deletions

View File

@ -4,12 +4,9 @@
shallow_clone: true
max_jobs: 2
matrix:
fast_finish: true
image:
- Visual Studio 2017
- Ubuntu
branches:
only:
@ -20,23 +17,17 @@ build: off
environment:
B2_OPTS: -j2 -q warnings-as-errors=on
UBSAN_OPTIONS: print_stacktrace=1
LSAN_OPTIONS: verbosity=1:log_threads=1
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
install:
# clone minimal set of Boost libraries
- cd ..
- cmd: git clone -b %APPVEYOR_REPO_BRANCH% --depth 5 https://github.com/boostorg/boost.git
- sh: git clone -b $APPVEYOR_REPO_BRANCH --depth 5 https://github.com/boostorg/boost.git
- git clone -b %APPVEYOR_REPO_BRANCH% --depth 5 https://github.com/boostorg/boost.git
- cd boost
- git submodule update --init --depth 5 tools/build tools/boostdep
# replace Boost library with this project and install dependencies
- cmd: xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\histogram\
- cmd: python tools\boostdep\depinst\depinst.py -N units -N range -N accumulators --git_args "--depth 5 --jobs 2" histogram
- sh: rm -rf libs/histogram ; mv $APPVEYOR_BUILD_FOLDER libs/histogram
- sh: python3 tools/boostdep/depinst/depinst.py --git_args "--depth 5 --jobs 2" histogram
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\histogram\
- python tools\boostdep\depinst\depinst.py -N units -N range -N accumulators --git_args "--depth 5 --jobs 2" histogram
# use hdembinski/serialization due to frequent errors in boostorg/serialization
- cd libs/serialization
@ -46,18 +37,11 @@ install:
- cd ../..
# prepare Boost build
- cmd: cmd /c bootstrap & b2 headers & cd libs\histogram
- sh: ./bootstrap.sh; ./b2 headers; cd libs/histogram
- cmd /c bootstrap & b2 headers & cd libs\histogram
test_script:
# on windows
- cmd: ..\..\b2 %B2_OPTS% cxxstd=latest test//minimal test//serialization
# on linux
- sh:
B2="../../b2 ${B2_OPTS}";
$B2 toolset=gcc-7 cxxstd=14 exception-handling=off rtti=off test//minimal &&
$B2 toolset=gcc-9 cxxstd=latest cxxflags="-O3 -funsafe-math-optimizations" examples test//all &&
$B2 toolset=clang-6 cxxstd=latest variant=histogram_ubasan test//all
- ..\..\b2 %B2_OPTS% cxxstd=latest test//minimal test//serialization
## Uncomment the following to stop VM and enable interactive login.
## Instructions how to log into the Appveyor VM are automatically printed.

View File

@ -9,8 +9,14 @@ on:
- 'doc/**'
- 'tools/**'
jobs:
env:
B2_OPTS: -q -j2 warnings-as-errors=on
UBSAN_OPTIONS: print_stacktrace=1
LSAN_OPTIONS: verbosity=1:log_threads=1
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
jobs:
superproject_cmake_and_b2:
runs-on: macos-latest
steps:
@ -27,15 +33,19 @@ jobs:
cd ..
cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 boost
ctest -j2 --output-on-failure -R boost_histogram
- name: b2 cxxstd=14,17 exception-handling=on/off rtti=on/off
- name: prepare b2
run: |
cd $GITHUB_WORKSPACE/../boost
cd ../boost
./bootstrap.sh
./b2 headers
cd libs/histogram
B2="../../b2 -q -j2 warnings-as-errors=on"
$B2 cxxstd=14,17 test//all examples
$B2 cxxstd=14 exception-handling=off rtti=off test//minimal
- name: b2 cxxstd=14 exception-handling=off rtti=off
run: |
cd ../boost/libs/histogram
../../b2 $B2_OPTS cxxstd=14 exception-handling=off rtti=off test//minimal
- name: b2 cxxstd=17
run: |
cd ../boost/libs/histogram
../../b2 $B2_OPTS cxxstd=17 test//all
cov:
runs-on: ubuntu-latest
@ -48,9 +58,7 @@ jobs:
run: |
python --version
pip install cpp-coveralls
- name: b2 toolset=gcc-8 cxxstd=latest coverage=on test//all
env:
COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
- name: prepare
run: |
cd ..
git clone -b $GITHUB_BASE_REF --depth 5 https://github.com/boostorg/boost.git
@ -74,11 +82,43 @@ jobs:
# simulate bundled boost by moving the headers instead of symlinking
rm -rf boost/histogram.pp boost/histogram
mv -f libs/histogram/include/boost/* boost
cd libs/histogram
B2="../../b2 -q -j2 warnings-as-errors=on"
- name: test gcc-8 cxxstd=latest coverage=on test//all
run: |
cd ../boost/libs/histogram
# don't compile examples in coverage build, coverage must come from tests alone
$B2 toolset=gcc-8 cxxstd=latest coverage=on test//all
../../b2 $B2_OPTS toolset=gcc-8 cxxstd=latest coverage=on test//all
# process and send coverage data
GCOV=gcov-8 tools/cov.sh $COVERALLS_TOKEN
stress:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: prepare b2
run: |
cd ..
git clone -b $GITHUB_BASE_REF --depth 5 https://github.com/boostorg/boost.git
cd boost
git submodule update --init --depth 5 tools/build tools/boostdep
mv -f $GITHUB_WORKSPACE/* libs/histogram
python tools/boostdep/depinst/depinst.py --git_args "--depth 5 --jobs 3" histogram
# prepare build
./bootstrap.sh
./b2 headers
- name: test gcc-7 cxxstd=14
run: |
cd ../boost/libs/histogram
../../b2 $B2_OPTS toolset=gcc-7 cxxstd=14 test//all examples
- name: test gcc-10 cxxstd=20 -O3 -funsafe-math-optimizations
run: |
cd ../boost/libs/histogram
../../b2 $B2_OPTS toolset=gcc-10 cxxstd=20 cxxflags="-O3 -funsafe-math-optimizations" test//all examples
- name: test clang-6 cxxstd=17 ubsan asan
run: |
cd ../boost/libs/histogram
../../b2 $B2_OPTS toolset=clang-6 cxxstd=17 variant=histogram_ubasan test//all

View File

@ -17,7 +17,7 @@ project
: requirements
<implicit-dependency>/boost//headers
<include>$(BOOST_ROOT)
<toolset>clang:<cxxflags>"-pedantic -Wextra -Wsign-compare -Wstrict-aliasing -fstrict-aliasing"
<toolset>clang:<cxxflags>"-pedantic -Wextra -Wsign-compare -Wstrict-aliasing -fstrict-aliasing -Wvexing-parse"
<toolset>gcc:<cxxflags>"-pedantic -Wextra -Wsign-compare -Wstrict-aliasing -fstrict-aliasing"
<toolset>msvc:<cxxflags>"/bigobj"
<toolset>intel-win:<cxxflags>"/bigobj"

View File

@ -28,8 +28,6 @@ namespace boost {
namespace histogram {
namespace detail {
static axis::null_type null_value;
template <class Axis>
struct value_type_deducer {
using type =
@ -115,7 +113,8 @@ decltype(auto) metadata_impl(A&& a, decltype(a.metadata(), 0)) {
template <class A>
axis::null_type& metadata_impl(A&&, float) {
return detail::null_value;
static axis::null_type null_value;
return null_value;
}
} // namespace detail
@ -381,7 +380,7 @@ decltype(auto) value(const Axis& axis, real_index_type index) {
template <class Result, class Axis>
Result value_as(const Axis& axis, real_index_type index) {
return detail::try_cast<Result, std::runtime_error>(
value(axis, index)); // avoid conversion warning
axis::traits::value(axis, index)); // avoid conversion warning
}
/** Returns axis index for value.
@ -407,8 +406,9 @@ axis::index_type index(const variant<Ts...>& axis, const U& value) {
@param axis any axis instance
*/
// gcc workaround: must use unsigned int not unsigned as return type
template <class Axis>
constexpr unsigned rank(const Axis& axis) {
constexpr unsigned int rank(const Axis& axis) {
(void)axis;
using T = value_type<Axis>;
// cannot use mp_eval_or since T could be a fixed-sized sequence
@ -417,9 +417,11 @@ constexpr unsigned rank(const Axis& axis) {
}
// specialization for variant
// gcc workaround: must use unsigned int not unsigned as return type
template <class... Ts>
unsigned rank(const axis::variant<Ts...>& axis) {
return detail::variant_access::visit([](const auto& a) { return rank(a); }, axis);
unsigned int rank(const axis::variant<Ts...>& axis) {
return detail::variant_access::visit(
[](const auto& a) { return axis::traits::rank(a); }, axis);
}
/** Returns pair of axis index and shift for the value argument.
@ -441,7 +443,7 @@ std::pair<index_type, index_type> update(Axis& axis, const U& value) noexcept(
return a.update(detail::try_cast<value_type<Axis>, std::invalid_argument>(value));
},
[&value](auto& a) -> std::pair<index_type, index_type> {
return {index(a, value), 0};
return {axis::traits::index(a, value), 0};
},
axis);
}

View File

@ -30,9 +30,9 @@ using common_axes = mp11::mp_cond<
// Non-PODs rank highest, then floats, than integers; types with more capacity are higher
template <class Storage>
static constexpr std::size_t type_rank() {
constexpr std::size_t type_rank() {
using T = typename Storage::value_type;
return !std::is_pod<T>::value * 10000 + std::is_floating_point<T>::value * 100 +
return !std::is_arithmetic<T>::value * 10000 + std::is_floating_point<T>::value * 100 +
10 * sizeof(T) + 2 * is_array_like<Storage>::value +
is_vector_like<Storage>::value;
;

View File

@ -91,7 +91,7 @@ BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t
BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() ==
std::declval<const U>()));
std::declval<const U&>()));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd,
(std::declval<T&>() += std::declval<U>()));
@ -106,7 +106,7 @@ BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv,
(std::declval<T&>() /= std::declval<U>()));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
has_method_eq, (std::declval<const T>().operator==(std::declval<const U>())));
has_method_eq, (std::declval<const T&>().operator==(std::declval<const U&>())));
BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));

View File

@ -165,40 +165,63 @@ struct large_int : totally_ordered<large_int<Allocator>, large_int<Allocator>>,
}
template <class U>
std::enable_if_t<std::is_integral<U>::value, bool> operator<(const U& o) const
noexcept {
std::enable_if_t<std::is_integral<U>::value, bool> operator<(
const U& o) const noexcept {
assert(data.size() > 0u);
return data.size() == 1 && safe_less()(data[0], o);
}
template <class U>
std::enable_if_t<std::is_integral<U>::value, bool> operator>(const U& o) const
noexcept {
std::enable_if_t<std::is_integral<U>::value, bool> operator>(
const U& o) const noexcept {
assert(data.size() > 0u);
assert(data.size() == 1 || data.back() > 0u); // no leading zeros allowed
return data.size() > 1 || safe_less()(o, data[0]);
}
template <class U>
std::enable_if_t<std::is_integral<U>::value, bool> operator==(const U& o) const
noexcept {
std::enable_if_t<std::is_integral<U>::value, bool> operator==(
const U& o) const noexcept {
assert(data.size() > 0u);
return data.size() == 1 && safe_equal()(data[0], o);
}
template <class U>
std::enable_if_t<std::is_floating_point<U>::value, bool> operator<(const U& o) const
noexcept {
std::enable_if_t<std::is_floating_point<U>::value, bool> operator<(
const U& o) const noexcept {
return operator double() < o;
}
template <class U>
std::enable_if_t<std::is_floating_point<U>::value, bool> operator>(const U& o) const
noexcept {
std::enable_if_t<std::is_floating_point<U>::value, bool> operator>(
const U& o) const noexcept {
return operator double() > o;
}
template <class U>
std::enable_if_t<std::is_floating_point<U>::value, bool> operator==(const U& o) const
noexcept {
std::enable_if_t<std::is_floating_point<U>::value, bool> operator==(
const U& o) const noexcept {
return operator double() == o;
}
template <class U>
std::enable_if_t<
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
operator<(const U& o) const noexcept {
return operator double() < o;
}
template <class U>
std::enable_if_t<
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
operator>(const U& o) const noexcept {
return operator double() > o;
}
template <class U>
std::enable_if_t<
(!std::is_arithmetic<U>::value && std::is_convertible<U, double>::value), bool>
operator==(const U& o) const noexcept {
return operator double() == o;
}

View File

@ -11,20 +11,25 @@
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
#include <type_traits>
namespace boost {
namespace histogram {
namespace detail {
template <class T, class U>
using if_not_same_and_has_eq =
std::enable_if_t<(!std::is_same<T, U>::value && has_method_eq<T, U>::value), bool>;
using if_not_same = std::enable_if_t<(!std::is_same<T, U>::value), bool>;
// template <class T, class U>
// using if_not_same_and_has_eq =
// std::enable_if_t<(!std::is_same<T, U>::value && !has_method_eq<T, U>::value),
// bool>;
// totally_ordered is for types with a <= b == !(a > b) [floats with NaN violate this]
// Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
// partially_ordered is for types with a <= b == a < b || a == b [for floats with NaN]
// Derived must implement <,== for the symmetric form and <,>,== for non-symmetric.
// Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
template <class T, class U>
struct mirrored {
@ -34,32 +39,33 @@ struct mirrored {
friend bool operator<=(const U& a, const T& b) noexcept { return b >= a; }
friend bool operator>=(const U& a, const T& b) noexcept { return b <= a; }
friend bool operator!=(const U& a, const T& b) noexcept { return b != a; }
};
}; // namespace histogram
template <class T>
struct mirrored<T, void> {
template <class U>
friend if_not_same_and_has_eq<T, U> operator<(const U& a, const T& b) noexcept {
friend if_not_same<T, U> operator<(const U& a, const T& b) noexcept {
return b > a;
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator>(const U& a, const T& b) noexcept {
friend if_not_same<T, U> operator>(const U& a, const T& b) noexcept {
return b < a;
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator==(const U& a, const T& b) noexcept {
return b == a;
friend std::enable_if_t<(!has_method_eq<U, T>::value), bool> operator==(
const U& a, const T& b) noexcept {
return b.operator==(a);
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator<=(const U& a, const T& b) noexcept {
friend if_not_same<T, U> operator<=(const U& a, const T& b) noexcept {
return b >= a;
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator>=(const U& a, const T& b) noexcept {
friend if_not_same<T, U> operator>=(const U& a, const T& b) noexcept {
return b <= a;
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator!=(const U& a, const T& b) noexcept {
friend if_not_same<T, U> operator!=(const U& a, const T& b) noexcept {
return b != a;
}
};
@ -77,7 +83,7 @@ struct equality {
template <class T>
struct equality<T, void> {
template <class U>
friend if_not_same_and_has_eq<T, U> operator!=(const T& a, const U& b) noexcept {
friend if_not_same<T, U> operator!=(const T& a, const U& b) noexcept {
return !(a == b);
}
};
@ -91,11 +97,11 @@ struct totally_ordered_impl : equality<T, U>, mirrored<T, U> {
template <class T>
struct totally_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
template <class U>
friend if_not_same_and_has_eq<T, U> operator<=(const T& a, const U& b) noexcept {
friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
return !(a > b);
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator>=(const T& a, const U& b) noexcept {
friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
return !(a < b);
}
};
@ -114,11 +120,11 @@ struct partially_ordered_impl : equality<T, U>, mirrored<T, U> {
template <class T>
struct partially_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
template <class U>
friend if_not_same_and_has_eq<T, U> operator<=(const T& a, const U& b) noexcept {
friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
return a < b || a == b;
}
template <class U>
friend if_not_same_and_has_eq<T, U> operator>=(const T& a, const U& b) noexcept {
friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
return a > b || a == b;
}
};

View File

@ -120,3 +120,4 @@ endif()
# LINK_LIBRARIES Boost::serialization)
boost_test(TYPE run SOURCES deduction_guides_test.cpp COMPILE_FEATURES cxx_std_17)
boost_test(TYPE run SOURCES issue_290_test.cpp COMPILE_FEATURES cxx_std_17)

View File

@ -92,8 +92,9 @@ alias cxx14 :
;
alias cxx17 :
[ run deduction_guides_test.cpp ] :
[ requires cpp_deduction_guides ]
[ run deduction_guides_test.cpp ]
[ compile issue_290_test.cpp ]
: [ requires cpp_deduction_guides ]
;
# check that useful error messages are produced when library is used incorrectly

View File

@ -24,8 +24,6 @@ namespace tr = axis::transform;
// tests requires a C++17 compatible compiler
#define TEST BOOST_TEST_TRAIT_SAME
int main() {
using axis::null_type;

18
test/issue_290_test.cpp Normal file
View File

@ -0,0 +1,18 @@
// Copyright 2020 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// - bug only appears on cxxstd=17 or higher and only in gcc
// - reported in issue: https://github.com/boostorg/histogram/issues/290
// - originally caused by rank struct in boost/type_traits/rank.hpp,
// which we emulate here to avoid the dependency on boost.type_traits
// Original: #include <boost/type_traits/rank.hpp>
template <class T>
struct rank;
#include <boost/histogram/axis/traits.hpp>
int main() { return 0; }