diff --git a/.clang-tidy b/.clang-tidy index 23018386c1..6a51acc8ba 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -74,4 +74,4 @@ CheckOptions: - key: readability-implicit-bool-conversion.AllowPointerConditions value: true -HeaderFilterRegex: 'pybind11/.*h' +HeaderFilterRegex: 'pybind11\/(?!.*vendor\/).*h' diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d93203881..de555bc522 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ endforeach() if(PYBIND11_VERSION_PATCH MATCHES [[\.([a-zA-Z0-9]+)$]]) set(pybind11_VERSION_TYPE "${CMAKE_MATCH_1}") endif() + string(REGEX MATCH "^[0-9]+" PYBIND11_VERSION_PATCH "${PYBIND11_VERSION_PATCH}") project( @@ -52,7 +53,7 @@ endif() # Check if pybind11 is being used directly or via add_subdirectory if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - ### Warn if not an out-of-source builds + # Warn if not an out-of-source builds if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) set(lines "You are building in-place. If that is not what you intended to " @@ -129,6 +130,10 @@ set(PYBIND11_HEADERS include/pybind11/eigen/matrix.h include/pybind11/eigen/tensor.h include/pybind11/embed.h + include/pybind11/detail/function_record.h + include/pybind11/detail/internal_pytypes.h + include/pybind11/detail/vendor/optional.h + include/pybind11/detail/python_compat.h include/pybind11/eval.h include/pybind11/gil.h include/pybind11/iostream.h @@ -152,9 +157,11 @@ if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12) set(_pybind11_disk_only ${_pybind11_header_check}) list(REMOVE_ITEM _pybind11_here_only ${_pybind11_header_check}) list(REMOVE_ITEM _pybind11_disk_only ${PYBIND11_HEADERS}) + if(_pybind11_here_only) message(AUTHOR_WARNING "PYBIND11_HEADERS has extra files:" ${_pybind11_here_only}) endif() + if(_pybind11_disk_only) message(AUTHOR_WARNING "PYBIND11_HEADERS is missing files:" ${_pybind11_disk_only}) endif() @@ -196,6 +203,7 @@ if(NOT TARGET pybind11_headers) target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals cxx_right_angle_brackets) + if(NOT "${PYBIND11_INTERNALS_VERSION}" STREQUAL "") target_compile_definitions( pybind11_headers INTERFACE "PYBIND11_INTERNALS_VERSION=${PYBIND11_INTERNALS_VERSION}") @@ -206,6 +214,7 @@ else() endif() include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake") + # https://github.com/jtojnar/cmake-snips/#concatenating-paths-when-building-pkg-config-files # TODO: cmake 3.20 adds the cmake_path() function, which obsoletes this snippet include("${CMAKE_CURRENT_SOURCE_DIR}/tools/JoinPaths.cmake") @@ -277,6 +286,7 @@ if(PYBIND11_INSTALL) if(NOT prefix_for_pc_file) set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}") endif() + join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc" @ONLY) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index db7cd8efff..fe0eb72d4b 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -14,6 +14,7 @@ #include "cast.h" #include +#include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -52,8 +53,8 @@ struct name { /// Annotation indicating that a function is an overload associated with a given "sibling" struct sibling { - handle value; - explicit sibling(const handle &value) : value(value.ptr()) {} + object value; + explicit sibling(const object &_value) : value(_value) {} }; /// Annotation indicating that a class derives from another given type @@ -65,6 +66,8 @@ struct base { base() = default; }; +struct has_no_temporary_casts {}; + /// Keep patient alive while nurse lives template struct keep_alive {}; @@ -163,104 +166,16 @@ struct call_guard { /// @} annotations PYBIND11_NAMESPACE_BEGIN(detail) + +template +using is_sibling = std::is_same, sibling>; + /* Forward declarations */ enum op_id : int; enum op_type : int; struct undefined_t; template struct op_; -void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); - -/// Internal data structure which holds metadata about a keyword argument -struct argument_record { - const char *name; ///< Argument name - const char *descr; ///< Human-readable version of the argument value - handle value; ///< Associated Python object - bool convert : 1; ///< True if the argument is allowed to convert when loading - bool none : 1; ///< True if None is allowed when loading - - argument_record(const char *name, const char *descr, handle value, bool convert, bool none) - : name(name), descr(descr), value(value), convert(convert), none(none) {} -}; - -/// Internal data structure which holds metadata about a bound function (signature, overloads, -/// etc.) -struct function_record { - function_record() - : is_constructor(false), is_new_style_constructor(false), is_stateless(false), - is_operator(false), is_method(false), has_args(false), has_kwargs(false), - prepend(false) {} - - /// Function name - char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ - - // User-specified documentation string - char *doc = nullptr; - - /// Human-readable version of the function signature - char *signature = nullptr; - - /// List of registered keyword arguments - std::vector args; - - /// Pointer to lambda function which converts arguments and performs the actual call - handle (*impl)(function_call &) = nullptr; - - /// Storage for the wrapped function pointer and captured data, if any - void *data[3] = {}; - - /// Pointer to custom destructor for 'data' (if needed) - void (*free_data)(function_record *ptr) = nullptr; - - /// Return value policy associated with this function - return_value_policy policy = return_value_policy::automatic; - - /// True if name == '__init__' - bool is_constructor : 1; - - /// True if this is a new-style `__init__` defined in `detail/init.h` - bool is_new_style_constructor : 1; - - /// True if this is a stateless function pointer - bool is_stateless : 1; - - /// True if this is an operator (__add__), etc. - bool is_operator : 1; - - /// True if this is a method - bool is_method : 1; - - /// True if the function has a '*args' argument - bool has_args : 1; - - /// True if the function has a '**kwargs' argument - bool has_kwargs : 1; - - /// True if this function is to be inserted at the beginning of the overload resolution chain - bool prepend : 1; - - /// Number of arguments (including py::args and/or py::kwargs, if present) - std::uint16_t nargs; - - /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs - /// argument or by a py::kw_only annotation. - std::uint16_t nargs_pos = 0; - - /// Number of leading arguments (counted in `nargs`) that are positional-only - std::uint16_t nargs_pos_only = 0; - - /// Python method object - PyMethodDef *def = nullptr; - - /// Python handle to the parent scope (a class or a module) - handle scope; - - /// Python handle to the sibling function representing an overload chain - handle sibling; - - /// Pointer to next overload - function_record *next = nullptr; -}; /// Special data structure which (temporarily) holds metadata about a bound class struct type_record { @@ -357,11 +272,6 @@ struct type_record { } }; -inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) { - args.reserve(f.nargs); - args_convert.reserve(f.nargs); -} - /// Tag for a new-style `__init__` defined in `detail/init.h` struct is_new_style_constructor {}; @@ -377,29 +287,41 @@ struct process_attribute; template struct process_attribute_default { /// Default implementation: do nothing - static void init(const T &, function_record *) {} - static void init(const T &, type_record *) {} - static void precall(function_call &) {} - static void postcall(function_call &, handle) {} + template + static void init(const T &, RecordType &) {} + + template + static void precall(CallArgs &, handle) {} + + template + static void postcall(CallArgs &, handle, handle) {} }; /// Process an attribute specifying the function's name template <> struct process_attribute : process_attribute_default { - static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } + template + static void init(const name &n, RecordType &r) { + r.name = n.value; + } }; /// Process an attribute specifying the function's docstring template <> struct process_attribute : process_attribute_default { - static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } + template + static void init(const doc &n, RecordType &r) { + r.doc = n.value; + } }; /// Process an attribute specifying the function's docstring (provided as a C-style string) template <> struct process_attribute : process_attribute_default { - static void init(const char *d, function_record *r) { r->doc = const_cast(d); } - static void init(const char *d, type_record *r) { r->doc = const_cast(d); } + template + static void init(const char *d, RecordType &r) { + r.doc = d; + } }; template <> struct process_attribute : process_attribute {}; @@ -407,78 +329,101 @@ struct process_attribute : process_attribute {}; /// Process an attribute indicating the function's return value policy template <> struct process_attribute : process_attribute_default { - static void init(const return_value_policy &p, function_record *r) { r->policy = p; } + template + static void init(const return_value_policy &p, RecordType &r) { + r.policy = p; + } }; /// Process an attribute which indicates that this is an overloaded function associated with a /// given sibling template <> -struct process_attribute : process_attribute_default { - static void init(const sibling &s, function_record *r) { r->sibling = s.value; } -}; +struct process_attribute : process_attribute_default {}; /// Process an attribute which indicates that this function is a method template <> struct process_attribute : process_attribute_default { - static void init(const is_method &s, function_record *r) { - r->is_method = true; - r->scope = s.class_; + template + static void init(const is_method &s, RecordType &r) { + if (RecordType::nargs > 0) { + if (r.arginfo_index != 0) { + pybind11_fail("is_method must come before any arguments when mapping"); + } + r.argument_info[0].name = "self"; + r.argument_info[0].convert = false; + r.arginfo_index++; + r.current_scope = s.class_; + r.argument_index["self"] = -1; + } } }; /// Process an attribute which indicates the parent scope of a method template <> struct process_attribute : process_attribute_default { - static void init(const scope &s, function_record *r) { r->scope = s.value; } + template + static void init(const scope &s, RecordType &r) { + r.current_scope = s.value; + } }; /// Process an attribute which indicates that this function is an operator template <> -struct process_attribute : process_attribute_default { - static void init(const is_operator &, function_record *r) { r->is_operator = true; } -}; +struct process_attribute : process_attribute_default {}; template <> -struct process_attribute - : process_attribute_default { - static void init(const is_new_style_constructor &, function_record *r) { - r->is_new_style_constructor = true; - } -}; - -inline void check_kw_only_arg(const arg &a, function_record *r) { - if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) { - pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or " - "args() argument"); - } -} +struct process_attribute + : process_attribute_default {}; -inline void append_self_arg_if_needed(function_record *r) { - if (r->is_method && r->args.empty()) { - r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false); - } -} +template <> +struct process_attribute + : process_attribute_default {}; /// Process a keyword argument attribute (*without* a default value) template <> struct process_attribute : process_attribute_default { - static void init(const arg &a, function_record *r) { - append_self_arg_if_needed(r); - r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + template + static void init(const arg &a, RecordType &r) { + PYBIND11_WARNING_PUSH + PYBIND11_WARNING_DISABLE_INTEL(186) // "Pointless" comparison with zero + + if (r.arginfo_index >= RecordType::nargs_pos && (!a.name || a.name[0] == '\0')) { + pybind11_fail( + "arg(): cannot specify an unnamed argument after a kw_only() annotation or " + "args() argument"); + } + + PYBIND11_WARNING_PUSH + + if (r.arginfo_index == RecordType::nargs_pos && RecordType::has_args) { + r.arginfo_index++; + } - check_kw_only_arg(a, r); + if (a.name != nullptr) { + r.argument_info[r.arginfo_index].name = a.name; + PYBIND11_WARNING_PUSH + PYBIND11_WARNING_DISABLE_INTEL(186) // "Pointless" comparison with zero + if (r.arginfo_index < RecordType::nargs_pos_only) { + r.argument_index[a.name] = -1; + } else { + r.argument_index[a.name] = static_cast(r.arginfo_index); + } + PYBIND11_WARNING_PUSH + } + + r.argument_info[r.arginfo_index].convert = !a.flag_noconvert; + r.argument_info[r.arginfo_index].none = a.flag_none; + + r.arginfo_index++; } }; /// Process a keyword argument attribute (*with* a default value) template <> struct process_attribute : process_attribute_default { - static void init(const arg_v &a, function_record *r) { - if (r->is_method && r->args.empty()) { - r->args.emplace_back( - "self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false); - } - + template + static void init(const arg_v &a, RecordType &r) { + process_attribute::init(a, r); if (!a.value) { #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string descr("'"); @@ -486,15 +431,15 @@ struct process_attribute : process_attribute_default { descr += std::string(a.name) + ": "; } descr += a.type + "'"; - if (r->is_method) { - if (r->name) { - descr += " in method '" + (std::string) str(r->scope) + "." - + (std::string) r->name + "'"; + if (RecordType::has_self) { + if (!r.name.empty()) { + descr += " in method '" + (std::string) str(r.current_scope) + "." + + (std::string) r.name + "'"; } else { - descr += " in method of '" + (std::string) str(r->scope) + "'"; + descr += " in method of '" + (std::string) str(r.current_scope) + "'"; } - } else if (r->name) { - descr += " in function '" + (std::string) r->name + "'"; + } else if (!r.name.empty()) { + descr += " in function '" + (std::string) r.name + "'"; } pybind11_fail("arg(): could not convert default argument " + descr + " into a Python object (type not registered yet?)"); @@ -505,97 +450,128 @@ struct process_attribute : process_attribute_default { "more information."); #endif } - r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); - - check_kw_only_arg(a, r); + if (a.descr != nullptr) { + r.argument_info[r.arginfo_index - 1].desc = a.descr; + } else { + r.argument_info[r.arginfo_index - 1].desc = repr(a.value).cast(); + } + r.argument_info[r.arginfo_index - 1].value = reinterpret_borrow(a.value); } }; /// Process a keyword-only-arguments-follow pseudo argument template <> struct process_attribute : process_attribute_default { - static void init(const kw_only &, function_record *r) { - append_self_arg_if_needed(r); - if (r->has_args && r->nargs_pos != static_cast(r->args.size())) { - pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative " - "argument location (or omit kw_only() entirely)"); + template + static void init(const kw_only &, RecordType &r) { + if (RecordType::nargs_pos != r.arginfo_index) { + throw std::runtime_error("Should never happen as defined at compile time " + + std::to_string(RecordType::nargs_pos) + " " + + std::to_string(r.arginfo_index) + " " + r.name + " " + + std::to_string(RecordType::has_kw_only_args) + " " + + std::to_string(RecordType::kw_only_pos) + " " + + std::to_string(RecordType::has_args)); + + // static constexpr size_t nargs_pos = has_kw_only_args ? kw_only_pos : (has_args ? + // args_pos : + // (has_kwargs ? nargs - 1 : nargs) } - r->nargs_pos = static_cast(r->args.size()); } }; /// Process a positional-only-argument maker template <> struct process_attribute : process_attribute_default { - static void init(const pos_only &, function_record *r) { - append_self_arg_if_needed(r); - r->nargs_pos_only = static_cast(r->args.size()); - if (r->nargs_pos_only > r->nargs_pos) { - pybind11_fail("pos_only(): cannot follow a py::args() argument"); + template + static void init(const pos_only &, RecordType &r) { + if (RecordType::nargs_pos_only != r.arginfo_index) { + throw std::runtime_error("Should never happen as defined at compile time pos only " + + std::to_string(r.arginfo_index) + " " + + std::to_string(RecordType::nargs_pos_only)); } - // It also can't follow a kw_only, but a static_assert in pybind11.h checks that } }; -/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees -/// that) +/// Process a parent class attribute. Single inheritance only (class_ itself already +/// guarantees that) template struct process_attribute::value>> : process_attribute_default { - static void init(const handle &h, type_record *r) { r->bases.append(h); } + template + static void init(const handle &h, RecordType &r) { + r.bases.append(h); + } }; /// Process a parent class attribute (deprecated, does not support multiple inheritance) template struct process_attribute> : process_attribute_default> { - static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } + template + static void init(const base &, RecordType &r) { + r.add_base(typeid(T), nullptr); + } }; /// Process a multiple inheritance attribute template <> struct process_attribute : process_attribute_default { - static void init(const multiple_inheritance &, type_record *r) { - r->multiple_inheritance = true; + template + static void init(const multiple_inheritance &, RecordType &r) { + r.multiple_inheritance = true; } }; template <> struct process_attribute : process_attribute_default { - static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } + template + static void init(const dynamic_attr &, RecordType &r) { + r.dynamic_attr = true; + } }; template <> struct process_attribute { - static void init(const custom_type_setup &value, type_record *r) { - r->custom_type_setup_callback = value.value; + template + static void init(const custom_type_setup &value, RecordType &r) { + r.custom_type_setup_callback = value.value; } }; template <> struct process_attribute : process_attribute_default { - static void init(const is_final &, type_record *r) { r->is_final = true; } + template + static void init(const is_final &, RecordType &r) { + r.is_final = true; + } }; template <> struct process_attribute : process_attribute_default { - static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } + template + static void init(const buffer_protocol &, RecordType &r) { + r.buffer_protocol = true; + } }; template <> struct process_attribute : process_attribute_default { - static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } + template + static void init(const metaclass &m, RecordType &r) { + r.metaclass = m.value; + } }; template <> struct process_attribute : process_attribute_default { - static void init(const module_local &l, type_record *r) { r->module_local = l.value; } + template + static void init(const module_local &l, RecordType &r) { + r.module_local = l.value; + } }; /// Process a 'prepend' attribute, putting this at the beginning of the overload chain template <> -struct process_attribute : process_attribute_default { - static void init(const prepend &, function_record *r) { r->prepend = true; } -}; +struct process_attribute : process_attribute_default {}; /// Process an 'arithmetic' attribute for enums (does nothing here) template <> @@ -604,6 +580,28 @@ struct process_attribute : process_attribute_default {}; template struct process_attribute> : process_attribute_default> {}; +template +void keep_alive_impl_for_call(const CallArgs &call_args, handle parent, handle ret) { + static_assert(Nurse <= std::tuple_size::value, + "Nurse must be within the range of call arguments"); + static_assert(Patient <= std::tuple_size::value, + "Patient must be within the range of call arguments"); + auto get_arg = [&](size_t n) { + if (n == 0) { + return ret; + } + if (n == 1) { + return parent; + } + if (n <= call_args.size()) { + return call_args[n - 1]; + } + pybind11_fail("This should never happen, internal pybind11 error"); + }; + + keep_alive_impl(get_arg(Nurse), get_arg(Patient)); +} + /** * Process a keep_alive call policy -- invokes keep_alive_impl during the * pre-call handler if both Nurse, Patient != 0 and use the post-call handler @@ -612,67 +610,68 @@ struct process_attribute> : process_attribute_default struct process_attribute> : public process_attribute_default> { - template = 0> - static void precall(function_call &call) { - keep_alive_impl(Nurse, Patient, call, handle()); + + template = 0> + static void precall(CallArgs &call_args, handle parent) { + keep_alive_impl_for_call(call_args, parent, handle()); } - template = 0> - static void postcall(function_call &, handle) {} - template = 0> - static void precall(function_call &) {} - template = 0> - static void postcall(function_call &call, handle ret) { - keep_alive_impl(Nurse, Patient, call, ret); + template = 0> + static void postcall(CallArgs &, handle, handle) {} + + template = 0> + static void precall(CallArgs &, handle) {} + + template = 0> + static void postcall(CallArgs &call_args, handle parent, handle ret) { + keep_alive_impl_for_call(call_args, parent, ret); } }; /// Recursively iterate over variadic template arguments template struct process_attributes { - static void init(const Args &...args, function_record *r) { + template + static void init(const Args &...args, RecordType &r) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); using expander = int[]; (void) expander{ 0, ((void) process_attribute::type>::init(args, r), 0)...}; } - static void init(const Args &...args, type_record *r) { - PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); - PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); - using expander = int[]; - (void) expander{0, - (process_attribute::type>::init(args, r), 0)...}; - } - static void precall(function_call &call) { - PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call); + template + static void precall(CallArgs &call_args, handle parent) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call_args); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(parent); using expander = int[]; - (void) expander{0, - (process_attribute::type>::precall(call), 0)...}; + (void) expander{ + 0, + (process_attribute::type>::precall(call_args, parent), + 0)...}; } - static void postcall(function_call &call, handle fn_ret) { - PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret); + template + static void postcall(CallArgs &call_args, handle parent, handle fn_ret) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call_args, fn_ret); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(parent); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret); using expander = int[]; - (void) expander{ - 0, (process_attribute::type>::postcall(call, fn_ret), 0)...}; + (void) expander{0, + (process_attribute::type>::postcall( + call_args, parent, fn_ret), + 0)...}; } }; -template -using is_call_guard = is_instantiation; - -/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) -template -using extract_guard_t = typename exactly_one_t, Extra...>::type; - -/// Check the number of named arguments at compile time -template ::value...), - size_t self = constexpr_sum(std::is_same::value...)> -constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { - PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs); - return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs; -} - PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3a40460276..2a095ddf34 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -34,6 +34,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_NAMESPACE_BEGIN(detail) +struct argument_record; + template class type_caster : public type_caster_base {}; template @@ -1350,33 +1352,6 @@ using is_kw_only = std::is_same, kw_only>; template using is_pos_only = std::is_same, pos_only>; -// forward declaration (definition in attr.h) -struct function_record; - -/// Internal data associated with a single function call -struct function_call { - function_call(const function_record &f, handle p); // Implementation in attr.h - - /// The function data: - const function_record &func; - - /// Arguments passed to the function: - std::vector args; - - /// The `convert` value the arguments should be loaded with - std::vector args_convert; - - /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if - /// present, are also in `args` but without a reference). - object args_ref, kwargs_ref; - - /// The parent, if any - handle parent; - - /// If this is a call to an initializer, this argument contains `self` - handle init_self; -}; - /// Helper class which loads arguments for C++ functions called from Python template class argument_loader { @@ -1397,13 +1372,18 @@ class argument_loader { // py::args argument position; -1 if not present. static constexpr int args_pos = constexpr_last(); + static constexpr bool has_args = args_pos != -1; static_assert(args_pos == -1 || args_pos == constexpr_first(), "py::args cannot be specified more than once"); static constexpr auto arg_names = concat(type_descr(make_caster::name)...); - bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); } + bool load_args(const std::array &args, + const std::array &infos, + bool force_noconvert) { + return load_impl_sequence(args, infos, force_noconvert, indices{}); + } template // NOLINTNEXTLINE(readability-const-return-type) @@ -1420,16 +1400,26 @@ class argument_loader { } private: - static bool load_impl_sequence(function_call &, index_sequence<>) { return true; } + static bool load_impl_sequence(const std::array &, + const std::array &, + bool, + index_sequence<>) { + return true; + } template - bool load_impl_sequence(function_call &call, index_sequence) { -#ifdef __cpp_fold_expressions - if ((... || !std::get(argcasters).load(call.args[Is], call.args_convert[Is]))) { + bool load_impl_sequence(const std::array &args, + const std::array &infos, + bool force_noconvert, + index_sequence) { +#ifdef __cpp_fold_expression + if ((... + || !std::get(argcasters).load(args[Is], infos[Is].convert && !force_noconvert))) { return false; } #else - for (bool r : {std::get(argcasters).load(call.args[Is], call.args_convert[Is])...}) { + for (bool r : + {std::get(argcasters).load(args[Is], infos[Is].convert && !force_noconvert)...}) { if (!r) { return false; } diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 528e716f78..550e98b2f7 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -165,21 +165,6 @@ extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyOb } } -/** - * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing - * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function, - * when called on a class, or a PyMethod, when called on an instance. Override that behaviour here - * to do a special case bypass for PyInstanceMethod_Types. - */ -extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) { - PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); - if (descr && PyInstanceMethod_Check(descr)) { - Py_INCREF(descr); - return descr; - } - return PyType_Type.tp_getattro(obj, name); -} - /// metaclass `__call__` function that is used to create all pybind11 objects. extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) { @@ -274,7 +259,6 @@ inline PyTypeObject *make_default_metaclass() { type->tp_call = pybind11_meta_call; type->tp_setattro = pybind11_meta_setattro; - type->tp_getattro = pybind11_meta_getattro; type->tp_dealloc = pybind11_meta_dealloc; diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 9acf104668..ac002c2b32 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -27,7 +27,12 @@ // possible using these macros. Please also be sure to push/pop with the pybind11 macros. Please // only use compiler specifics if you need to check specific versions, e.g. Apple Clang vs. vanilla // Clang. -#if defined(_MSC_VER) +#if defined(__clang__) +# define PYBIND11_COMPILER_CLANG +# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) +# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push) +# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push) +#elif defined(_MSC_VER) # define PYBIND11_COMPILER_MSVC # define PYBIND11_PRAGMA(...) __pragma(__VA_ARGS__) # define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning(push)) @@ -37,11 +42,6 @@ # define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) # define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push) # define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop) -#elif defined(__clang__) -# define PYBIND11_COMPILER_CLANG -# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) -# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push) -# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push) #elif defined(__GNUC__) # define PYBIND11_COMPILER_GCC # define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) @@ -69,6 +69,8 @@ #ifdef PYBIND11_COMPILER_INTEL # define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(warning disable name) +#elif defined(__CUDACC__) +# define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(nv_diag_suppress name) #else # define PYBIND11_WARNING_DISABLE_INTEL(name) #endif @@ -307,6 +309,7 @@ PYBIND11_WARNING_POP #include #include #include +#include #include #include #include @@ -346,9 +349,6 @@ PYBIND11_WARNING_POP // behavior. /// Compatibility macros for Python 2 / Python 3 versions TODO: remove -#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) -#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check -#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION #define PYBIND11_BYTES_CHECK PyBytes_Check #define PYBIND11_BYTES_FROM_STRING PyBytes_FromString #define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize @@ -830,12 +830,70 @@ constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate::value...); } +template