Skip to content

Commit 4853408

Browse files
mkuronax3lhenryiii
authored
fix: Intel ICC C++17 compatibility (#2729)
* CI: Intel icc/icpc via oneAPI Add testing for Intel icc/icpc via the oneAPI images. Intel oneAPI is in a late beta stage, currently shipping oneAPI beta09 with ICC 20.2. CI: Skip Interpreter Tests for Intel Cannot find how to add this, neiter the package `libc6-dev` nor `intel-oneapi-mkl-devel` help when installed to solve this: ``` -- Looking for C++ include pthread.h -- Looking for C++ include pthread.h - not found CMake Error at /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message): Could NOT find Threads (missing: Threads_FOUND) Call Stack (most recent call first): /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE) /__t/cmake/3.18.4/x64/cmake-3.18.4-Linux-x86_64/share/cmake-3.18/Modules/FindThreads.cmake:234 (FIND_PACKAGE_HANDLE_STANDARD_ARGS) tests/test_embed/CMakeLists.txt:17 (find_package) ``` CI: libc6-dev from GCC for ICC CI: Run bare metal for oneAPI CI: Ubuntu 18.04 for oneAPI CI: Intel +Catch -Eigen CI: CMake from Apt (ICC tests) CI: Replace Intel Py with GCC Py CI: Intel w/o GCC's Eigen CI: ICC with verbose make [Debug] Find core dump tests: use arg{} instead of arg() for Intel tests: adding a few more missing {} fix: sync with @tobiasleibner's branch fix: try ubuntu 20-04 fix: drop exit 1 docs: Apply suggestions from code review Co-authored-by: Tobias Leibner <[email protected]> Workaround for ICC enable_if issues Another workaround for ICC's enable_if issues fix error in previous commit Disable one test for the Intel compiler in C++17 mode Add back one instance of py::arg().noconvert() Add NOLINT to fix clang-tidy check Work around for ICC internal error in PYBIND11_EXPAND_SIDE_EFFECTS in C++17 mode CI: Intel ICC with C++17 docs: pybind11/numpy.h does not require numpy at build time. (#2720) This is nice enough to be mentioned explicitly in the docs. docs: Update warning about Python 3.9.0 UB, now that 3.9.1 has been released (#2719) Adjusting `type_caster<std::reference_wrapper<T>>` to support const/non-const propagation in `cast_op`. (#2705) * Allow type_caster of std::reference_wrapper<T> to be the same as a native reference. Before, both std::reference_wrapper<T> and std::reference_wrapper<const T> would invoke cast_op<type>. This doesn't allow the type_caster<> specialization for T to distinguish reference_wrapper types from value types. After, the type_caster<> specialization invokes cast_op<type&>, which allows reference_wrapper to behave in the same way as a native reference type. * Add tests/examples for std::reference_wrapper<const T> * Add tests which use mutable/immutable variants This test is a chimera; it blends the pybind11 casters with a custom pytype implementation that supports immutable and mutable calls. In order to detect the immutable/mutable state, the cast_op needs to propagate it, even through e.g. std::reference<const T> Note: This is still a work in progress; some things are crashing, which likely means that I have a refcounting bug or something else missing. * Add/finish tests that distinguish const& from & Fixes the bugs in my custom python type implementation, demonstrate test that requires const& and reference_wrapper<const T> being treated differently from Non-const. * Add passing a const to non-const method. * Demonstrate non-const conversion of reference_wrapper in tests. Apply formatting presubmit check. * Fix build errors from presubmit checks. * Try and fix a few more CI errors * More CI fixes. * More CI fixups. * Try and get PyPy to work. * Additional minor fixups. Getting close to CI green. * More ci fixes? * fix clang-tidy warnings from presubmit * fix more clang-tidy warnings * minor comment and consistency cleanups * PyDECREF -> Py_DECREF * copy/move constructors * Resolve codereview comments * more review comment fixes * review comments: remove spurious & * Make the test fail even when the static_assert is commented out. This expands the test_freezable_type_caster a bit by: 1/ adding accessors .is_immutable and .addr to compare identity from python. 2/ Changing the default cast_op of the type_caster<> specialization to return a non-const value. In normal codepaths this is a reasonable default. 3/ adding roundtrip variants to exercise the by reference, by pointer and by reference_wrapper in all call paths. In conjunction with 2/, this demonstrates the failure case of the existing std::reference_wrpper conversion, which now loses const in a similar way that happens when using the default cast_op_type<>. * apply presubmit formatting * Revert inclusion of test_freezable_type_caster There's some concern that this test is a bit unwieldly because of the use of the raw <Python.h> functions. Removing for now. * Add a test that validates const references propagation. This test verifies that cast_op may be used to correctly detect const reference types when used with std::reference_wrapper. * mend * Review comments based changes. 1. std::add_lvalue_reference<type> -> type& 2. Simplify the test a little more; we're never returning the ConstRefCaster type so the class_ definition can be removed. * formatted files again. * Move const_ref_caster test to builtin_casters * Review comments: use cast_op and adjust some comments. * Simplify ConstRefCasted test I like this version better as it moves the assertion that matters back into python. ci: drop pypy2 linux, PGI 20.7, add Python 10 dev (#2724) * ci: drop pypy2 linux, add Python 10 dev * ci: fix mistake * ci: commented-out PGI 20.11, drop 20.7 fix: regression with installed pybind11 overriding local one (#2716) * fix: regression with installed pybind11 overriding discovered one Closes #2709 * docs: wording incorrect style: remove redundant instance->owned = true (#2723) which was just before set to True in instance->allocate_layout() fix: also throw in the move-constructor added by the PYBIND11_OBJECT macro, after the argument has been moved-out (if necessary) (#2701) Make args_are_all_* ICC workarounds unconditional Disable test_aligned on Intel ICC Fix test_aligned on Intel ICC Skip test_python_alreadyset_in_destructor on Intel ICC Fix test_aligned again ICC CI: Downgrade pytest pytest 6 does not capture the `discard_as_unraisable` stderr and just writes a warning with its content instead. * refactor: simpler Intel workaround, suggested by @laramiel * fix: try version with impl to see if it is easier to compile * docs: update README for ICC Co-authored-by: Axel Huebl <[email protected]> Co-authored-by: Henry Schreiner <[email protected]>
1 parent 8449a80 commit 4853408

File tree

10 files changed

+120
-29
lines changed

10 files changed

+120
-29
lines changed

.github/workflows/ci.yml

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ jobs:
474474
name: "🐍 3 • ICC latest • x64"
475475

476476
steps:
477-
- uses: actions/checkout@v1
477+
- uses: actions/checkout@v2
478478

479479
- name: Add apt repo
480480
run: |
@@ -488,7 +488,6 @@ jobs:
488488
run: sudo apt-get update; sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic cmake python3-dev python3-numpy python3-pytest python3-pip
489489

490490
- name: Update pip
491-
shell: bash
492491
run: |
493492
set +e; source /opt/intel/oneapi/setvars.sh; set -e
494493
python3 -m pip install --upgrade pip
@@ -498,43 +497,69 @@ jobs:
498497
set +e; source /opt/intel/oneapi/setvars.sh; set -e
499498
python3 -m pip install -r tests/requirements.txt --prefer-binary
500499
501-
- name: Configure
502-
shell: bash
500+
- name: Configure C++11
503501
run: |
504502
set +e; source /opt/intel/oneapi/setvars.sh; set -e
505-
cmake -S . -B build \
503+
cmake -S . -B build-11 \
506504
-DPYBIND11_WERROR=ON \
507505
-DDOWNLOAD_CATCH=ON \
508506
-DDOWNLOAD_EIGEN=OFF \
509507
-DCMAKE_CXX_STANDARD=11 \
510508
-DCMAKE_CXX_COMPILER=$(which icpc) \
511-
-DCMAKE_VERBOSE_MAKEFILE=ON \
512509
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
513510
514-
- name: Build
515-
shell: bash
511+
- name: Build C++11
516512
run: |
517513
set +e; source /opt/intel/oneapi/setvars.sh; set -e
518-
cmake --build build -j 2
514+
cmake --build build-11 -j 2 -v
519515
520-
- name: Python tests
521-
shell: bash
516+
- name: Python tests C++11
522517
run: |
523518
set +e; source /opt/intel/oneapi/setvars.sh; set -e
524519
sudo service apport stop
525-
cmake --build build --target check
520+
cmake --build build-11 --target check
526521
527-
- name: C++ tests
528-
shell: bash
522+
- name: C++ tests C++11
529523
run: |
530524
set +e; source /opt/intel/oneapi/setvars.sh; set -e
531-
cmake --build build --target cpptest
525+
cmake --build build-11 --target cpptest
532526
533-
- name: Interface test
534-
shell: bash
527+
- name: Interface test C++11
528+
run: |
529+
set +e; source /opt/intel/oneapi/setvars.sh; set -e
530+
cmake --build build-11 --target test_cmake_build
531+
532+
- name: Configure C++17
533+
run: |
534+
set +e; source /opt/intel/oneapi/setvars.sh; set -e
535+
cmake -S . -B build-17 \
536+
-DPYBIND11_WERROR=ON \
537+
-DDOWNLOAD_CATCH=ON \
538+
-DDOWNLOAD_EIGEN=OFF \
539+
-DCMAKE_CXX_STANDARD=17 \
540+
-DCMAKE_CXX_COMPILER=$(which icpc) \
541+
-DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
542+
543+
- name: Build C++17
544+
run: |
545+
set +e; source /opt/intel/oneapi/setvars.sh; set -e
546+
cmake --build build-17 -j 2 -v
547+
548+
- name: Python tests C++17
549+
run: |
550+
set +e; source /opt/intel/oneapi/setvars.sh; set -e
551+
sudo service apport stop
552+
cmake --build build-17 --target check
553+
554+
- name: C++ tests C++17
555+
run: |
556+
set +e; source /opt/intel/oneapi/setvars.sh; set -e
557+
cmake --build build-17 --target cpptest
558+
559+
- name: Interface test C++17
535560
run: |
536561
set +e; source /opt/intel/oneapi/setvars.sh; set -e
537-
cmake --build build --target test_cmake_build
562+
cmake --build build-17 --target test_cmake_build
538563
539564
540565
# Testing on CentOS (manylinux uses a centos base, and this is an easy way

README.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,10 @@ Supported compilers
136136
newer)
137137
2. GCC 4.8 or newer
138138
3. Microsoft Visual Studio 2015 Update 3 or newer
139-
4. Intel C++ compiler 18 or newer
140-
(`possible issue <https://github.com/pybind/pybind11/pull/2573>`_ on 20.2)
139+
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
141140
5. Cygwin/GCC (previously tested on 2.5.1)
142-
6. NVCC (CUDA 11.0 tested)
143-
7. NVIDIA PGI (20.9 tested)
141+
6. NVCC (CUDA 11.0 tested in CI)
142+
7. NVIDIA PGI (20.9 tested in CI)
144143

145144
About
146145
-----

include/pybind11/cast.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,16 +2182,26 @@ class unpacking_collector {
21822182
dict m_kwargs;
21832183
};
21842184

2185+
// [workaround(intel)] Separate function required here
2186+
// We need to put this into a separate function because the Intel compiler
2187+
// fails to compile enable_if_t<!all_of<is_positional<Args>...>::value>
2188+
// (tested with ICC 2021.1 Beta 20200827).
2189+
template <typename... Args>
2190+
constexpr bool args_are_all_positional()
2191+
{
2192+
return all_of<is_positional<Args>...>::value;
2193+
}
2194+
21852195
/// Collect only positional arguments for a Python function call
21862196
template <return_value_policy policy, typename... Args,
2187-
typename = enable_if_t<all_of<is_positional<Args>...>::value>>
2197+
typename = enable_if_t<args_are_all_positional<Args...>()>>
21882198
simple_collector<policy> collect_arguments(Args &&...args) {
21892199
return simple_collector<policy>(std::forward<Args>(args)...);
21902200
}
21912201

21922202
/// Collect all arguments, including keywords and unpacking (only instantiated when needed)
21932203
template <return_value_policy policy, typename... Args,
2194-
typename = enable_if_t<!all_of<is_positional<Args>...>::value>>
2204+
typename = enable_if_t<!args_are_all_positional<Args...>()>>
21952205
unpacking_collector<policy> collect_arguments(Args &&...args) {
21962206
// Following argument order rules for generalized unpacking according to PEP 448
21972207
static_assert(

include/pybind11/detail/common.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,10 @@ template <typename T> using is_function_pointer = bool_constant<
665665
std::is_pointer<T>::value && std::is_function<typename std::remove_pointer<T>::type>::value>;
666666

667667
template <typename F> struct strip_function_object {
668+
// If you are encountering an
669+
// 'error: name followed by "::" must be a class or namespace name'
670+
// with the Intel compiler and a noexcept function here,
671+
// try to use noexcept(true) instead of plain noexcept.
668672
using type = typename remove_class<decltype(&F::operator())>::type;
669673
};
670674

@@ -689,8 +693,10 @@ template <typename T> using is_lambda = satisfies_none_of<remove_reference_t<T>,
689693
/// Ignore that a variable is unused in compiler warnings
690694
inline void ignore_unused(const int *) { }
691695

696+
// [workaround(intel)] Internal error on fold expression
692697
/// Apply a function over each element of a parameter pack
693-
#ifdef __cpp_fold_expressions
698+
#if defined(__cpp_fold_expressions) && !defined(__INTEL_COMPILER)
699+
// Intel compiler produces an internal error on this fold expression (tested with ICC 19.0.2)
694700
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
695701
#else
696702
using expand_side_effects = bool[];

include/pybind11/pytypes.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,14 +1271,23 @@ class tuple : public object {
12711271
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
12721272
};
12731273

1274+
// We need to put this into a separate function because the Intel compiler
1275+
// fails to compile enable_if_t<all_of<is_keyword_or_ds<Args>...>::value> part below
1276+
// (tested with ICC 2021.1 Beta 20200827).
1277+
template <typename... Args>
1278+
constexpr bool args_are_all_keyword_or_ds()
1279+
{
1280+
return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;
1281+
}
1282+
12741283
class dict : public object {
12751284
public:
12761285
PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)
12771286
dict() : object(PyDict_New(), stolen_t{}) {
12781287
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
12791288
}
12801289
template <typename... Args,
1281-
typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>,
1290+
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,
12821291
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
12831292
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
12841293
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }

include/pybind11/stl_bind.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,10 +375,20 @@ struct vector_has_data_and_format : std::false_type {};
375375
template <typename Vector>
376376
struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
377377

378+
// [workaround(intel)] Separate function required here
379+
// Workaround as the Intel compiler does not compile the enable_if_t part below
380+
// (tested with icc (ICC) 2021.1 Beta 20200827)
381+
template <typename... Args>
382+
constexpr bool args_any_are_buffer() {
383+
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
384+
}
385+
386+
// [workaround(intel)] Separate function required here
387+
// [workaround(msvc)] Can't use constexpr bool in return type
388+
378389
// Add the buffer interface to a vector
379390
template <typename Vector, typename Class_, typename... Args>
380-
enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
381-
vector_buffer(Class_& cl) {
391+
void vector_buffer_impl(Class_& cl, std::true_type) {
382392
using T = typename Vector::value_type;
383393

384394
static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
@@ -416,7 +426,12 @@ vector_buffer(Class_& cl) {
416426
}
417427

418428
template <typename Vector, typename Class_, typename... Args>
419-
enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
429+
void vector_buffer_impl(Class_&, std::false_type) {}
430+
431+
template <typename Vector, typename Class_, typename... Args>
432+
void vector_buffer(Class_& cl) {
433+
vector_buffer_impl<Vector, Class_, Args...>(cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
434+
}
420435

421436
PYBIND11_NAMESPACE_END(detail)
422437

tests/test_builtin_casters.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ TEST_SUBMODULE(builtin_casters, m) {
193193
m.def("bool_passthrough", [](bool arg) { return arg; });
194194
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
195195

196+
// TODO: This should be disabled and fixed in future Intel compilers
197+
#if !defined(__INTEL_COMPILER)
198+
// Test "bool_passthrough_noconvert" again, but using () instead of {} to construct py::arg
199+
// When compiled with the Intel compiler, this results in segmentation faults when importing
200+
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
201+
// a newer version of icc is available.
202+
m.def("bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
203+
#endif
204+
196205
// test_reference_wrapper
197206
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
198207
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });

tests/test_callbacks.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ TEST_SUBMODULE(callbacks, m) {
120120
class AbstractBase {
121121
public:
122122
// [workaround(intel)] = default does not work here
123+
// Defaulting this destructor results in linking errors with the Intel compiler
124+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
123125
virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default)
124126
virtual unsigned int func() = 0;
125127
};

tests/test_class.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
BSD-style license that can be found in the LICENSE file.
88
*/
99

10+
#if defined(__INTEL_COMPILER) && __cplusplus >= 201703L
11+
// Intel compiler requires a separate header file to support aligned new operators
12+
// and does not set the __cpp_aligned_new feature macro.
13+
// This header needs to be included before pybind11.
14+
#include <aligned_new>
15+
#endif
16+
1017
#include "pybind11_tests.h"
1118
#include "constructor_stats.h"
1219
#include "local_bindings.h"
@@ -324,6 +331,8 @@ TEST_SUBMODULE(class_, m) {
324331
class PublicistB : public ProtectedB {
325332
public:
326333
// [workaround(intel)] = default does not work here
334+
// Removing or defaulting this destructor results in linking errors with the Intel compiler
335+
// (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
327336
~PublicistB() override {}; // NOLINT(modernize-use-equals-default)
328337
using ProtectedB::foo;
329338
};

tests/test_constants_and_functions.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,14 @@ std::string print_bytes(py::bytes bytes) {
4646
// Test that we properly handle C++17 exception specifiers (which are part of the function signature
4747
// in C++17). These should all still work before C++17, but don't affect the function signature.
4848
namespace test_exc_sp {
49+
// [workaround(intel)] Unable to use noexcept instead of noexcept(true)
50+
// Make the f1 test basically the same as the f2 test in C++17 mode for the Intel compiler as
51+
// it fails to compile with a plain noexcept (tested with icc (ICC) 2021.1 Beta 20200827).
52+
#if defined(__INTEL_COMPILER) && defined(PYBIND11_CPP17)
53+
int f1(int x) noexcept(true) { return x+1; }
54+
#else
4955
int f1(int x) noexcept { return x+1; }
56+
#endif
5057
int f2(int x) noexcept(true) { return x+2; }
5158
int f3(int x) noexcept(false) { return x+3; }
5259
#if defined(__GNUG__)

0 commit comments

Comments
 (0)