diff --git a/.appveyor.yml b/.appveyor.yml index 8429d5ec57..2faaa24e45 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,7 +39,7 @@ build_script: - cmake -G "%CMAKE_GENERATOR%" -A "%CMAKE_ARCH%" -DPython_ROOT_DIR="%PYTHON_ROOT%" -DCMAKE_MAP_IMPORTED_CONFIG_DEBUG=Release - -DCMAKE_CXX_STANDARD=14 + -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_SUPPRESS_REGENERATION=1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb2fcf2b67..d6ac1454eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: include: - runs-on: ubuntu-22.04 python-version: '3.9' - cmake-args: -DPYBIND11_FINDPYTHON=OFF -DPYBIND11_NUMPY_1_ONLY=ON + cmake-args: -DPYBIND11_FINDPYTHON=OFF - runs-on: ubuntu-latest python-version: '3.13' cmake-args: -DCMAKE_CXX_STANDARD=23 -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON @@ -58,7 +58,7 @@ jobs: cmake-args: -DCMAKE_CXX_STANDARD=20 - runs-on: macos-latest python-version: '3.14' - cmake-args: -DCMAKE_CXX_STANDARD=14 + cmake-args: -DCMAKE_CXX_STANDARD=17 - runs-on: windows-2022 python-version: '3.9' cmake-args: -DPYBIND11_FINDPYTHON=OFF @@ -88,7 +88,7 @@ jobs: cmake-args: -DPYBIND11_TEST_SMART_HOLDER=ON -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON - runs-on: ubuntu-latest python-version: '3.14' - cmake-args: -DCMAKE_CXX_STANDARD=14 + cmake-args: -DCMAKE_CXX_STANDARD=17 - runs-on: ubuntu-latest python-version: '3.15t' cmake-args: -DCMAKE_CXX_STANDARD=17 -DPYBIND11_TEST_SMART_HOLDER=ON @@ -96,10 +96,10 @@ jobs: # No SciPy for macOS ARM - runs-on: macos-15-intel python-version: '3.9' - cmake-args: -DCMAKE_CXX_STANDARD=14 + cmake-args: -DCMAKE_CXX_STANDARD=17 - runs-on: macos-15-intel python-version: '3.13' - cmake-args: -DCMAKE_CXX_STANDARD=11 + cmake-args: -DCMAKE_CXX_STANDARD=17 - runs-on: macos-latest python-version: '3.12' cmake-args: -DCMAKE_CXX_STANDARD=17 -DPYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION=ON @@ -119,7 +119,7 @@ jobs: cmake-args: -DPYBIND11_TEST_SMART_HOLDER=ON - runs-on: windows-2022 python-version: '3.9' - cmake-args: -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DPYBIND11_NUMPY_1_ONLY=ON + cmake-args: -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded # This needs a python built with MTd # - runs-on: windows-2022 # python-version: '3.11' @@ -152,7 +152,7 @@ jobs: python-version: ${{ matrix.python-version }} cmake-args: ${{ matrix.cmake-args }} - # This checks inplace builds with C++11 + # This checks inplace builds with C++17. inplace: if: github.event.pull_request.draft == false strategy: @@ -166,7 +166,7 @@ jobs: - runs-on: windows-latest python-version: '3.11' - name: "🐍 ${{ matrix.python-version }} • ${{ matrix.runs-on }} • x64 inplace C++14" + name: "🐍 ${{ matrix.python-version }} • ${{ matrix.runs-on }} • x64 inplace C++17" runs-on: ${{ matrix.runs-on }} timeout-minutes: 90 @@ -202,7 +202,7 @@ jobs: -DPYBIND11_PYTEST_ARGS=-v -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=14 + -DCMAKE_CXX_STANDARD=17 -DPYBIND11_INTERNALS_VERSION=10000000 # Checks to makes sure defining `_` is allowed @@ -254,12 +254,15 @@ jobs: run: uv tool install ninja - name: Configure via preset - run: cmake --preset venv -DPYBIND11_CREATE_WITH_UV="${{ matrix.python-version }}" + run: > + cmake --preset venv + -DPYBIND11_CREATE_WITH_UV="${{ matrix.python-version }}" + -DCMAKE_CXX_STANDARD=17 - - name: Build C++11 + - name: Build C++17 run: cmake --build --preset venv - - name: Python tests C++11 + - name: Python tests C++17 run: cmake --build --preset testsvenv -t pytest # Testing on clang using the excellent silkeh clang docker images @@ -270,10 +273,11 @@ jobs: fail-fast: false matrix: include: - - clang: 5 - std: 14 + # Clang 11 is the oldest LLVM toolchain available on a Debian base + # that meets pybind11's current Python and CMake requirements. - clang: 11 - std: 20 + std: 17 + container_suffix: "-bullseye" - clang: 16 std: 20 container_suffix: "-bullseye" @@ -333,7 +337,12 @@ jobs: run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy - name: Configure - run: cmake -S . -B build -DPYBIND11_CUDA_TESTS=ON -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON + run: > + cmake -S . -B build + -DPYBIND11_CUDA_TESTS=ON + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DCMAKE_CXX_STANDARD=17 - name: Build run: cmake --build build -j2 --verbose @@ -371,7 +380,7 @@ jobs: # run: | # source /etc/profile.d/modules.sh # module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/20.11 -# cmake -S . -B build -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=14 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") +# cmake -S . -B build -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") # # - name: Build # run: cmake --build build -j 2 --verbose @@ -536,44 +545,6 @@ jobs: set +e; source /opt/intel/oneapi/setvars.sh; set -e python3 -m pip install -r tests/requirements.txt - - name: Configure C++11 - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake -S . -B build-11 \ - -DPYBIND11_WERROR=ON \ - -DDOWNLOAD_CATCH=ON \ - -DDOWNLOAD_EIGEN=OFF \ - -DCMAKE_CXX_STANDARD=11 \ - -DCMAKE_CXX_COMPILER=$(which icpc) \ - -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - - - name: Build C++11 - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-11 -j 2 -v - - - name: Python tests C++11 - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - sudo service apport stop - cmake --build build-11 --target check - - - name: C++ tests C++11 - timeout-minutes: 3 - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-11 --target cpptest - - - name: Interface test C++11 - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-11 --target test_cmake_build - - - name: Visibility test - run: | - set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-11 --target test_cross_module_rtti - - name: Configure C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e @@ -659,7 +630,7 @@ jobs: -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=11 + -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build @@ -701,6 +672,7 @@ jobs: run: > cmake . -DPYBIND11_INSTALL=1 -DPYBIND11_TEST=0 + -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Make and install @@ -717,6 +689,7 @@ jobs: cmake ../pybind11-tests -DDOWNLOAD_CATCH=ON -DPYBIND11_WERROR=ON + -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") working-directory: /build-tests @@ -772,6 +745,7 @@ jobs: - python: '3.9' args: -DCMAKE_CXX_STANDARD=17 - python: '3.13' + args: -DCMAKE_CXX_STANDARD=17 name: "🐍 ${{ matrix.python }} • MSVC 2022 • x86 ${{ matrix.args }}" @@ -810,7 +784,7 @@ jobs: -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON ${{ matrix.args }} - - name: Build C++11 + - name: Build C++17 run: cmake --build build -j 2 - name: Python tests @@ -859,7 +833,7 @@ jobs: -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON ${{ matrix.args }} - - name: Build C++11 + - name: Build C++20 run: cmake --build build --config Debug -j 2 - name: Python tests @@ -969,80 +943,30 @@ jobs: - uses: actions/checkout@v7 - - name: Configure C++11 + - name: Configure C++17 # LTO leads to many undefined reference like # `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&) run: >- - cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON + cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") -S . -B build - - name: Build C++11 + - name: Build C++17 run: cmake --build build -j 2 - - name: Python tests C++11 + - name: Python tests C++17 run: cmake --build build --target pytest -j 2 - - name: C++11 tests + - name: C++17 tests timeout-minutes: 3 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target cpptest -j 2 - - name: Interface test C++11 + - name: Interface test C++17 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cmake_build - name: Visibility test run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cross_module_rtti - - name: Clean directory - run: git clean -fdx - - - name: Configure C++14 - run: >- - cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON - -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") - -S . -B build2 - - - name: Build C++14 - run: cmake --build build2 -j 2 - - - name: Python tests C++14 - run: cmake --build build2 --target pytest -j 2 - - - name: C++14 tests - timeout-minutes: 3 - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target cpptest -j 2 - - - name: Interface test C++14 - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cmake_build - - - name: Visibility test - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cross_module_rtti - - - name: Clean directory - run: git clean -fdx - - - name: Configure C++17 - run: >- - cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON - -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") - -S . -B build3 - - - name: Build C++17 - run: cmake --build build3 -j 2 - - - name: Python tests C++17 - run: cmake --build build3 --target pytest -j 2 - - - name: C++17 tests - timeout-minutes: 3 - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target cpptest -j 2 - - - name: Interface test C++17 - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build - - - name: Visibility test - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cross_module_rtti - windows_clang: if: github.event.pull_request.draft == false diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index b9c09566bd..19f77aae3a 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -71,7 +71,11 @@ jobs: # These steps use a directory with a space in it intentionally - name: Configure shell: bash - run: cmake -S. -B"build dir" -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON + run: > + cmake -S. -B"build dir" + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DCMAKE_CXX_STANDARD=17 # Only build and test if this was manually triggered in the GitHub UI - name: Build diff --git a/.github/workflows/reusable-standard.yml b/.github/workflows/reusable-standard.yml index 326c20170b..49b13950e6 100644 --- a/.github/workflows/reusable-standard.yml +++ b/.github/workflows/reusable-standard.yml @@ -78,6 +78,7 @@ jobs: -DPYBIND11_PYTEST_ARGS=-v -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 -DPYTHON_EXECUTABLE=${{ steps.python.outputs.python-path }} ${{ inputs.cmake-args }} diff --git a/.github/workflows/tests-cibw.yml b/.github/workflows/tests-cibw.yml index 83107b23da..dea67eb5ea 100644 --- a/.github/workflows/tests-cibw.yml +++ b/.github/workflows/tests-cibw.yml @@ -15,6 +15,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + CIBW_CONFIG_SETTINGS: "cmake.define.CMAKE_CXX_STANDARD=17" + jobs: build-wasm-emscripten: name: Pyodide wheel diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 7ad8c99014..76775516c0 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -49,47 +49,48 @@ jobs: cmake --version pip list - # First build - C++11 mode and inplace - - name: Configure C++11 + # First build - C++17 Debug mode + - name: Configure C++17 Debug run: > - cmake -S . -B build11 + cmake -S . -B build-debug -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=11 + -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=Debug - - name: Build C++11 - run: cmake --build build11 -j 2 + - name: Build C++17 Debug + run: cmake --build build-debug -j 2 - - name: Python tests C++11 - run: cmake --build build11 --target pytest -j 2 + - name: Python tests C++17 Debug + run: cmake --build build-debug --target pytest -j 2 - - name: C++11 tests + - name: C++17 Debug tests timeout-minutes: 3 - run: cmake --build build11 --target cpptest -j 2 + run: cmake --build build-debug --target cpptest -j 2 - - name: Interface test C++11 - run: cmake --build build11 --target test_cmake_build + - name: Interface test C++17 Debug + run: cmake --build build-debug --target test_cmake_build - # Second build - C++17 mode and in a build directory - - name: Configure C++17 + # Second build - C++17 MinSizeRel mode + - name: Configure C++17 MinSizeRel run: > - cmake -S . -B build17 + cmake -S . -B build-minsizerel -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 + -DCMAKE_BUILD_TYPE=MinSizeRel - - name: Build C++17 - run: cmake --build build17 -j 2 + - name: Build C++17 MinSizeRel + run: cmake --build build-minsizerel -j 2 - - name: Python tests C++17 - run: cmake --build build17 --target pytest + - name: Python tests C++17 MinSizeRel + run: cmake --build build-minsizerel --target pytest - - name: C++17 tests + - name: C++17 MinSizeRel tests timeout-minutes: 3 - run: cmake --build build17 --target cpptest + run: cmake --build build-minsizerel --target cpptest # Third build - C++17 mode with unstable ABI - name: Configure (unstable ABI) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f3f8beb2b..d4249ba839 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -301,8 +301,7 @@ if(NOT TARGET pybind11_headers) pybind11_headers ${pybind11_system} INTERFACE $ $) - target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals - cxx_right_angle_brackets) + target_compile_features(pybind11_headers INTERFACE cxx_std_17) if(NOT "${PYBIND11_INTERNALS_VERSION}" STREQUAL "") target_compile_definitions( pybind11_headers INTERFACE "PYBIND11_INTERNALS_VERSION=${PYBIND11_INTERNALS_VERSION}") diff --git a/CMakePresets.json b/CMakePresets.json index 42bf3ade9d..1ae47043fb 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,6 +12,7 @@ }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_STANDARD": "17", "CMAKE_EXPORT_COMPILE_COMMANDS": true, "DOWNLOAD_CATCH": true, "DOWNLOAD_EIGEN": true, @@ -35,8 +36,7 @@ "inherits": "default", "binaryDir": "build-tidy", "cacheVariables": { - "CMAKE_CXX_CLANG_TIDY": "clang-tidy;--use-color;--warnings-as-errors=*", - "CMAKE_CXX_STANDARD": "17" + "CMAKE_CXX_CLANG_TIDY": "clang-tidy;--use-color;--warnings-as-errors=*" } } ], diff --git a/include/pybind11/complex.h b/include/pybind11/complex.h index a6ec11a462..dbc3573814 100644 --- a/include/pybind11/complex.h +++ b/include/pybind11/complex.h @@ -27,15 +27,6 @@ struct format_descriptor, detail::enable_if_t -constexpr const char - format_descriptor, - detail::enable_if_t::value>>::value[3]; - -#endif - PYBIND11_NAMESPACE_BEGIN(detail) template diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 7f182afb2c..e4b33162f0 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -72,6 +72,10 @@ # endif #endif +#if !defined(PYBIND11_CPP17) +# error "pybind11 requires C++17 or newer" +#endif + // These PYBIND11_HAS_... macros are consolidated in pybind11/detail/common.h // to simplify backward compatibility handling for users (e.g., via #ifdef checks): #define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS 1 @@ -79,7 +83,7 @@ #define PYBIND11_HAS_CPP_CONDUIT 1 #define PYBIND11_HAS_NATIVE_ENUM 1 -#if defined(PYBIND11_CPP17) && defined(__has_include) +#if defined(__has_include) # if __has_include() # define PYBIND11_HAS_FILESYSTEM 1 # elif __has_include() @@ -109,10 +113,8 @@ // Compiler version assertions #if defined(__INTEL_COMPILER) -# if __INTEL_COMPILER < 1800 -# error pybind11 requires Intel C++ compiler v18 or newer -# elif __INTEL_COMPILER < 1900 && defined(PYBIND11_CPP14) -# error pybind11 supports only C++11 with Intel C++ compiler v18. Use v19 or newer for C++14. +# if __INTEL_COMPILER < 1900 +# error pybind11 requires Intel C++ compiler v19 or newer # endif /* The following pragma cannot be pop'ed: https://community.intel.com/t5/Intel-C-Compiler/Inline-and-no-inline-warning/td-p/1216764 */ @@ -179,19 +181,11 @@ // For unknown reasons all PYBIND11_DEPRECATED member trigger a warning when declared // whether it is used or not # define PYBIND11_DEPRECATED(reason) -#elif defined(PYBIND11_CPP14) -# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] #else -# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) +# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] #endif -#if defined(PYBIND11_CPP17) -# define PYBIND11_MAYBE_UNUSED [[maybe_unused]] -#elif defined(_MSC_VER) && !defined(__clang__) -# define PYBIND11_MAYBE_UNUSED -#else -# define PYBIND11_MAYBE_UNUSED __attribute__((__unused__)) -#endif +#define PYBIND11_MAYBE_UNUSED [[maybe_unused]] // https://en.cppreference.com/w/c/chrono/localtime #if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__) @@ -199,26 +193,24 @@ #endif #ifdef __has_include -// std::optional (but including it in c++14 mode isn't allowed) -# if defined(PYBIND11_CPP17) && __has_include() +// std::optional +# if __has_include() # define PYBIND11_HAS_OPTIONAL 1 # endif -// std::experimental::optional (but not allowed in c++11 mode) -# if defined(PYBIND11_CPP14) && (__has_include() && \ - !__has_include()) +// std::experimental::optional +# if __has_include() && !__has_include() # define PYBIND11_HAS_EXP_OPTIONAL 1 # endif // std::variant -# if defined(PYBIND11_CPP17) && __has_include() +# if __has_include() # define PYBIND11_HAS_VARIANT 1 # endif -#elif defined(_MSC_VER) && defined(PYBIND11_CPP17) +#elif defined(_MSC_VER) # define PYBIND11_HAS_OPTIONAL 1 # define PYBIND11_HAS_VARIANT 1 #endif -#if defined(PYBIND11_CPP17) \ - && ((defined(__has_include) && __has_include()) || defined(_MSC_VER)) +#if (defined(__has_include) && __has_include()) || defined(_MSC_VER) # define PYBIND11_HAS_STRING_VIEW 1 #endif @@ -706,22 +698,11 @@ static_assert(std::is_standard_layout::value, template struct always_false : std::false_type {}; -/// from __cpp_future__ import (convenient aliases from C++14/17) -#if defined(PYBIND11_CPP14) +/// Convenient aliases from newer C++ versions using std::conditional_t; using std::enable_if_t; using std::remove_cv_t; using std::remove_reference_t; -#else -template -using enable_if_t = typename std::enable_if::type; -template -using conditional_t = typename std::conditional::type; -template -using remove_cv_t = typename std::remove_cv::type; -template -using remove_reference_t = typename std::remove_reference::type; -#endif #if defined(PYBIND11_CPP20) && defined(__cpp_lib_remove_cvref) using std::remove_cvref; @@ -740,56 +721,8 @@ template using is_same_ignoring_cvref = std::is_same, U>; /// Index sequences -#if defined(PYBIND11_CPP14) using std::index_sequence; using std::make_index_sequence; -#else -template -struct index_sequence {}; -// Comments about the algorithm below. -// -// Credit: This is based on an algorithm by taocpp here: -// https://github.com/taocpp/sequences/blob/main/include/tao/seq/make_integer_sequence.hpp -// but significantly simplified. -// -// We build up a sequence S by repeatedly doubling its length and sometimes adding 1 to the end. -// E.g. if the current S is 0...3, then we either go to 0...7 or 0...8 on the next pass. -// The goal is to end with S = 0...N-1. -// The key insight is that the times we need to add an additional digit to S correspond -// exactly to the 1's in the binary representation of the number N. -// -// Invariants: -// - digit is a power of 2 -// - N_digit_is_1 is whether N's binary representation has a 1 in that digit's position. -// - end <= N -// - S is 0...end-1. -// - if digit > 0, end * digit * 2 <= N < (end+1) * digit * 2 -// -// The process starts with digit > N, end = 0, and S is empty. -// The process concludes with digit=0, in which case, end == N and S is 0...N-1. - -template // N_digit_is_1=false -struct make_index_sequence_impl - : make_index_sequence_impl { -}; -template -struct make_index_sequence_impl - : make_index_sequence_impl {}; -template -struct make_index_sequence_impl<0, false, N, end, S...> { - using type = index_sequence; -}; -constexpr size_t next_power_of_2(size_t N) { return N == 0 ? 1 : next_power_of_2(N >> 1) << 1; } -template -using make_index_sequence = - typename make_index_sequence_impl::type; -#endif /// Make an index sequence of the indices of true arguments template @@ -1202,14 +1135,6 @@ struct format_descriptor::value>> { static std::string format() { return std::string(1, c); } }; -#if !defined(PYBIND11_CPP17) - -template -constexpr const char - format_descriptor::value>>::value[2]; - -#endif - /// RAII wrapper that temporarily clears any Python error state struct error_scope { PyObject *type, *value, *trace; @@ -1277,29 +1202,18 @@ struct overload_cast_impl { }; PYBIND11_NAMESPACE_END(detail) -// overload_cast requires variable templates: C++14 -#if defined(PYBIND11_CPP14) -# define PYBIND11_OVERLOAD_CAST 1 +#define PYBIND11_OVERLOAD_CAST 1 /// Syntax sugar for resolving overloaded function pointers: /// - regular: static_cast(&Class::func) /// - sweet: overload_cast(&Class::func) template static constexpr detail::overload_cast_impl overload_cast{}; -#endif /// Const member function selector for overload_cast /// - regular: static_cast(&Class::func) /// - sweet: overload_cast(&Class::func, const_) static constexpr auto const_ = std::true_type{}; -#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails: -template -struct overload_cast { - static_assert(detail::deferred_t::value, - "pybind11::overload_cast<...> requires compiling in C++14 mode"); -}; -#endif // overload_cast - PYBIND11_NAMESPACE_BEGIN(detail) // Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index a1083f8457..ae2f66bd62 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -388,17 +388,9 @@ struct factory { // instance, or the alias needs to be constructible from a `Class &&` argument. template void execute(Class &cl, const Extra &...extra) && { -#if defined(PYBIND11_CPP14) cl.def( "__init__", - [func = std::move(class_factory)] -#else - auto &func = class_factory; - cl.def( - "__init__", - [func] -#endif - (value_and_holder &v_h, Args... args) { + [func = std::move(class_factory)](value_and_holder &v_h, Args... args) { construct( v_h, func(std::forward(args)...), Py_TYPE(v_h.inst) != v_h.type->type); }, @@ -435,18 +427,10 @@ struct factory { static_assert(Class::has_alias, "The two-argument version of `py::init()` can " "only be used if the class has an alias"); -#if defined(PYBIND11_CPP14) - cl.def( - "__init__", - [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] -#else - auto &class_func = class_factory; - auto &alias_func = alias_factory; cl.def( "__init__", - [class_func, alias_func] -#endif - (value_and_holder &v_h, CArgs... args) { + [class_func = std::move(class_factory), + alias_func = std::move(alias_factory)](value_and_holder &v_h, CArgs... args) { if (Py_TYPE(v_h.inst) == v_h.type->type) { // If the instance type equals the registered type we don't have inheritance, // so don't need the alias and can construct using the class function: @@ -524,17 +508,9 @@ struct pickle_factory { void execute(Class &cl, const Extra &...extra) && { cl.def("__getstate__", std::move(get), pos_only()); -#if defined(PYBIND11_CPP14) - cl.def( - "__setstate__", - [func = std::move(set)] -#else - auto &func = set; cl.def( "__setstate__", - [func] -#endif - (value_and_holder &v_h, ArgState state) { + [func = std::move(set)](value_and_holder &v_h, ArgState state) { setstate( v_h, func(std::forward(state)), Py_TYPE(v_h.inst) != v_h.type->type); }, diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index eebb130694..064a508438 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1,5 +1,5 @@ /* - pybind11/pybind11.h: Main header file of the C++11 python + pybind11/pybind11.h: Main header file of the C++17 python binding generator library Copyright (c) 2016 Wenzel Jakob @@ -44,12 +44,6 @@ PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") # include #endif -#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606 -# define PYBIND11_MAYBE_CONSTEXPR constexpr -#else -# define PYBIND11_MAYBE_CONSTEXPR -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning @@ -274,10 +268,7 @@ class ReadableFunctionSignature { using sig_type = decltype(PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR); private: - // We have to repeat PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR in decltype() - // because C++11 doesn't allow functions to return `auto`. (We don't - // know the type because it's some variant of detail::descr with - // unknown N.) + // The type is some variant of detail::descr, with an N dependent on the casters. static constexpr sig_type sig() { return PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR; } public: @@ -292,19 +283,6 @@ class ReadableFunctionSignature { }; #undef PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR -// Prior to C++17, we don't have inline variables, so we have to -// provide an out-of-line definition of the class member. -#if !defined(PYBIND11_CPP17) -template -constexpr typename ReadableFunctionSignature::sig_type - ReadableFunctionSignature::kSig; -# if !defined(_MSC_VER) -template -constexpr typename ReadableFunctionSignature::types_type - ReadableFunctionSignature::kTypes; -# endif -#endif - PYBIND11_NAMESPACE_END(detail) /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object @@ -2436,7 +2414,7 @@ class class_ : public detail::generic_type { // so the reinterpret_cast shortcut in load_impl Case 2a is invalid. // Force the MI path (implicit_casts) for correct pointer adjustment. // Detection: static_cast(Base*) is ill-formed for virtual bases. - if PYBIND11_MAYBE_CONSTEXPR (!detail::is_static_downcastable::value) { + if constexpr (!detail::is_static_downcastable::value) { rec.multiple_inheritance = true; } } @@ -3920,9 +3898,9 @@ function get_override(const T *this_ptr, const char *name) { auto o = override(__VA_ARGS__); \ PYBIND11_WARNING_PUSH \ PYBIND11_WARNING_DISABLE_MSVC(4127) \ - if PYBIND11_MAYBE_CONSTEXPR ( \ - pybind11::detail::cast_is_temporary_value_reference::value \ - && !pybind11::detail::is_same_ignoring_cvref::value) { \ + if constexpr (pybind11::detail::cast_is_temporary_value_reference::value \ + && !pybind11::detail::is_same_ignoring_cvref::value) { \ static pybind11::detail::override_caster_t caster; \ return pybind11::detail::cast_ref(std::move(o), caster); \ } else { \ diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 8f42605245..b93002ec73 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -1,5 +1,5 @@ """ -This module provides helpers for C++11+ projects using pybind11. +This module provides helpers for C++17+ projects using pybind11. LICENSE: @@ -85,7 +85,7 @@ class Pybind11Extension(_Extension): """ - Build a C++11+ Extension module with pybind11. This automatically adds the + Build a C++17+ Extension module with pybind11. This automatically adds the recommended flags when you init the extension and assumes C++ sources - you can further modify the options yourself. @@ -98,8 +98,8 @@ class Pybind11Extension(_Extension): Finally, you can set ``cxx_std`` via constructor or afterwards to enable flags for C++ std, and a few extra helper flags related to the C++ standard level. It is _highly_ recommended you either set this, or use the provided - ``build_ext``, which will search for the highest supported extension for - you if the ``cxx_std`` property is not set. Do not set the ``cxx_std`` + ``build_ext``, which will check for C++17 support if the ``cxx_std`` + property is not set. Do not set the ``cxx_std`` property more than once, as flags are added when you set it. Set the property to None to disable the addition of C++ standard flags. @@ -117,7 +117,7 @@ def _add_ldflags(self, flags: list[str]) -> None: self.extra_link_args[:0] = flags def __init__(self, *args: Any, **kwargs: Any) -> None: - self._cxx_level = 0 + self._cxx_level: str | int | None = 0 cxx_std = kwargs.pop("cxx_std", 0) if "language" not in kwargs: @@ -155,27 +155,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self._add_cflags(cflags) @property - def cxx_std(self) -> int: + def cxx_std(self) -> str | int | None: """ The CXX standard level. If set, will add the required flags. If left at 0, it will trigger an automatic search when pybind11's build_ext is used. If None, will have no effect. Besides just the flags, this may - add a macos-min 10.9 or 10.14 flag if MACOSX_DEPLOYMENT_TARGET is - unset. + add a macos-min 10.14 flag if MACOSX_DEPLOYMENT_TARGET is unset. """ return self._cxx_level @cxx_std.setter - def cxx_std(self, level: int) -> None: + def cxx_std(self, level: str | int | None) -> None: + if isinstance(level, int) and level != 0 and level < 17: + msg = "pybind11 requires C++17 or newer" + raise ValueError(msg) + if self._cxx_level: warnings.warn( "You cannot safely change the cxx_level after setting it!", stacklevel=2 ) - # MSVC only has 14 and later modes, so force a valid flag here. - if WIN and level == 11: - level = 14 - self._cxx_level = level if not level: @@ -191,7 +190,7 @@ def cxx_std(self, level: int) -> None: # setting for general use. However, never set higher than the # current macOS version! current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2]) - desired_macos = (10, 9) if level < 17 else (10, 14) + desired_macos = (10, 14) macos_string = ".".join(str(x) for x in min(current_macos, desired_macos)) macosx_min = f"-mmacosx-version-min={macos_string}" cflags += [macosx_min] @@ -244,27 +243,24 @@ def has_flag(compiler: Any, flag: str) -> bool: @lru_cache def auto_cpp_level(compiler: Any) -> str | int: """ - Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows. + Return the minimum supported C++ std level (17). Returns latest on Windows. """ if WIN: return "latest" - levels = [17, 14, 11] - - for level in levels: - if has_flag(compiler, STD_TMPL.format(level)): - return level + if has_flag(compiler, STD_TMPL.format(17)): + return 17 - msg = "Unsupported compiler -- at least C++11 support is needed!" + msg = "Unsupported compiler -- at least C++17 support is needed!" raise RuntimeError(msg) class build_ext(_build_ext): # noqa: N801 """ - Customized build_ext that allows an auto-search for the highest supported - C++ level for Pybind11Extension. This is only needed for the auto-search - for now, and is completely optional otherwise. + Customized build_ext that checks for C++17 support for Pybind11Extension. + This is only needed for the automatic check and is completely optional + otherwise. """ def build_extensions(self) -> None: diff --git a/tests/extra_setuptools/test_setuphelper.py b/tests/extra_setuptools/test_setuphelper.py index 22c0c76f5d..9040b0af10 100644 --- a/tests/extra_setuptools/test_setuphelper.py +++ b/tests/extra_setuptools/test_setuphelper.py @@ -13,7 +13,7 @@ @pytest.mark.parametrize("parallel", [False, True]) -@pytest.mark.parametrize("std", [11, 0]) +@pytest.mark.parametrize("std", [17, 0]) def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): monkeypatch.chdir(tmpdir) monkeypatch.syspath_prepend(MAIN_DIR) @@ -110,6 +110,15 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): ) +@pytest.mark.parametrize("std", [11, 14]) +def test_cxx_std_too_old(monkeypatch, std): + monkeypatch.syspath_prepend(MAIN_DIR) + from pybind11.setup_helpers import Pybind11Extension + + with pytest.raises(ValueError, match=r"pybind11 requires C\+\+17 or newer"): + Pybind11Extension("example", ["example.cpp"], cxx_std=std) + + def test_intree_extensions(monkeypatch, tmpdir): monkeypatch.syspath_prepend(MAIN_DIR) diff --git a/tests/test_cmake_build/installed_target/CMakeLists.txt b/tests/test_cmake_build/installed_target/CMakeLists.txt index 6ee01693df..0659f1a808 100644 --- a/tests/test_cmake_build/installed_target/CMakeLists.txt +++ b/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -7,6 +7,8 @@ message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") add_library(test_installed_target MODULE ../main.cpp) +# Verify that the installed interface promotes a consumer that initially requests C++14. +set_target_properties(test_installed_target PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON) target_link_libraries(test_installed_target PRIVATE pybind11::module) set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build) diff --git a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt index 88d73f6045..ac5296b2d1 100644 --- a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -13,6 +13,8 @@ add_subdirectory("${pybind11_SOURCE_DIR}" pybind11) add_library(test_subdirectory_target MODULE ../main.cpp) set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake_build) +# Verify that pybind11's interface requirement promotes a consumer that initially requests C++14. +set_target_properties(test_subdirectory_target PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON) target_link_libraries(test_subdirectory_target PRIVATE pybind11::module) # Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib diff --git a/tests/test_cross_module_rtti/CMakeLists.txt b/tests/test_cross_module_rtti/CMakeLists.txt index c9b95bfba1..2b9f0b0549 100644 --- a/tests/test_cross_module_rtti/CMakeLists.txt +++ b/tests/test_cross_module_rtti/CMakeLists.txt @@ -36,7 +36,7 @@ add_library(test_cross_module_rtti_lib::test_cross_module_rtti_lib ALIAS test_cross_module_rtti_lib) target_include_directories(test_cross_module_rtti_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(test_cross_module_rtti_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_compile_features(test_cross_module_rtti_lib PUBLIC cxx_std_11) +target_compile_features(test_cross_module_rtti_lib PUBLIC cxx_std_17) generate_export_header(test_cross_module_rtti_lib) diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake index d75fb67520..227e737923 100644 --- a/tools/pybind11Common.cmake +++ b/tools/pybind11Common.cmake @@ -169,23 +169,21 @@ set_property( # Warn or error if old variable name used if(PYBIND11_CPP_STANDARD) string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}") - if(CMAKE_CXX_STANDARD) + set(supported_standards 17 20) + if(NOT "${VAL}" IN_LIST supported_standards) + message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD " + "(${VAL} is below pybind11's C++17 minimum or is not supported)") + elseif(CMAKE_CXX_STANDARD) if(NOT CMAKE_CXX_STANDARD STREQUAL VAL) message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match " "PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, " "please remove PYBIND11_CPP_STANDARD from your cache") endif() else() - set(supported_standards 11 14 17 20) - if("${VAL}" IN_LIST supported_standards) - message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD") - set(CMAKE_CXX_STANDARD - ${VAL} - CACHE STRING "From PYBIND11_CPP_STANDARD") - else() - message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD " - "(last two chars: ${VAL} not understood as a valid CXX std)") - endif() + message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD") + set(CMAKE_CXX_STANDARD + ${VAL} + CACHE STRING "From PYBIND11_CPP_STANDARD") endif() endif()