ruby-changes:57603
From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Fri, 6 Sep 2019 16:12:45 +0900 (JST)
Subject: [ruby-changes:57603] a569bc09e2 (master): add include/ruby/backward/cxxanyargs.hpp
https://git.ruby-lang.org/ruby.git/commit/?id=a569bc09e2 From a569bc09e25a2ba813d0bec1228d9ff65330a3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= <shyouhei@r...> Date: Thu, 5 Sep 2019 23:50:45 +0900 Subject: add include/ruby/backward/cxxanyargs.hpp Compilation of extension libraries written in C++ are reportedly broken due to https://github.com/ruby/ruby/pull/2404 The root cause of this issue was that the definition of ANYARGS differ between C and C++, and that of C++ is incompatible with the updated ones. We are using the incompatibility against itself. In C++ two distinct function prototypes can be overloaded. We provide the old, ANYARGSed prototypes in addition to the current granular ones; and let the older ones warn about types. diff --git a/eval.c b/eval.c index eb34c35..1b62498 100644 --- a/eval.c +++ b/eval.c @@ -948,12 +948,26 @@ VALUE https://github.com/ruby/ruby/blob/trunk/eval.c#L948 rb_rescue2(VALUE (* b_proc) (VALUE), VALUE data1, VALUE (* r_proc) (VALUE, VALUE), VALUE data2, ...) { + va_list ap; + va_start(ap, data2); + return rb_vrescue2(b_proc, data1, r_proc, data2, ap); + va_end(ap); +} + +/*! + * \copydoc rb_rescue2 + * \param[in] args exception classes, terminated by 0. + */ +VALUE +rb_vrescue2(VALUE (* b_proc) (VALUE), VALUE data1, + VALUE (* r_proc) (VALUE, VALUE), VALUE data2, + va_list args) +{ enum ruby_tag_type state; rb_execution_context_t * volatile ec = GET_EC(); rb_control_frame_t *volatile cfp = ec->cfp; volatile VALUE result = Qfalse; volatile VALUE e_info = ec->errinfo; - va_list args; EC_PUSH_TAG(ec); if ((state = EC_EXEC_TAG()) == TAG_NONE) { @@ -976,14 +990,12 @@ rb_rescue2(VALUE (* b_proc) (VALUE), VALUE data1, https://github.com/ruby/ruby/blob/trunk/eval.c#L990 int handle = FALSE; VALUE eclass; - va_init_list(args, data2); while ((eclass = va_arg(args, VALUE)) != 0) { if (rb_obj_is_kind_of(ec->errinfo, eclass)) { handle = TRUE; break; } } - va_end(args); if (handle) { result = Qnil; diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp new file mode 100644 index 0000000..70191a9 --- /dev/null +++ b/include/ruby/backward/cxxanyargs.hpp @@ -0,0 +1,376 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/backward/cxxanyargs.hpp#L1 +#ifndef RUBY_BACKWARD_CXXANYARGS_HPP // -*- C++ -*- +#define RUBY_BACKWARD_CXXANYARGS_HPP +/// @file +/// @brief Provides old prototypes for C++ programs. +/// @author \@shyouhei +/// @copyright This file is a part of the programming language Ruby. +/// Permission is hereby granted, to either redistribute and/or +/// modify this file, provided that the conditions mentioned in the +/// file COPYING are met. Consult the file for details. +/// @note DO NOT MODERNIZE THIS FILE! As the file name implies it is +/// meant to be a backwards compatibility shim. Please stick to +/// C++ 98 and never use newer features, like `constexpr`. + +/// @brief The main namespace. +/// @note The name "ruby" might already be taken, but that must not be a +/// problem because namespaces are allowed to reopen. +namespace ruby { + +/// @brief Backwards compatibility layer. +namespace backward { + +/// @brief Provides ANYARGS deprecation warnings. +/// +/// In C, ANYARGS means there is no function prototype. Literally anything, +/// even including nothing, can be a valid ANYARGS. So passing a correctly +/// prototyped function pointer to an ANYARGS-ed function parameter is valid, +/// at the same time passing an ANYARGS-ed function pointer to a granular typed +/// function parameter is also valid. However on the other hand in C++, +/// ANYARGS doesn't actually mean any number of arguments. C++'s ANYARGS means +/// _variadic_ number of arguments. This is incompatible with ordinal, correct +/// function prototypes. +/// +/// Luckily, function prototypes being distinct each other means they can be +/// overloaded. We can provide a compatibility layer for older Ruby APIs which +/// used to have ANYARGS. This namespace includes such attempts. +namespace cxxanyargs { + +/// @brief ANYARGS-ed function type. +typedef VALUE type(ANYARGS); + +/// @brief ANYARGS-ed function type, void variant. +typedef void void_type(ANYARGS); + +/// @brief ANYARGS-ed function type, int variant. +typedef int int_type(ANYARGS); + +/// @name Hooking global variables +/// @{ + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief Define a function-backended global variable. +/// @param[in] q Name of the variable. +/// @param[in] w Getter function. +/// @param[in] e Setter function. +/// @note Both functions can be nullptr. +/// @see rb_define_hooked_variable() +/// @deprecated Use glanular typed overload instead. +inline void +rb_define_virtual_variable(const char *q, type *w, void_type *e) +{ + rb_gvar_getter_t *r = reinterpret_cast<rb_gvar_getter_t*>(w); + rb_gvar_setter_t *t = reinterpret_cast<rb_gvar_setter_t*>(e); + ::rb_define_virtual_variable(q, r, t); +} + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief Define a function-backended global variable. +/// @param[in] q Name of the variable. +/// @param[in] w Variable storage. +/// @param[in] e Getter function. +/// @param[in] r Setter function. +/// @note Both functions can be nullptr. +/// @see rb_define_virtual_variable() +/// @deprecated Use glanular typed overload instead. +inline void +rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r) +{ + rb_gvar_getter_t *t = reinterpret_cast<rb_gvar_getter_t*>(e); + rb_gvar_setter_t *y = reinterpret_cast<rb_gvar_setter_t*>(r); + ::rb_define_hooked_variable(q, w, t, y); +} + +/// @} +/// @name Exceptions and tag jumps +/// @{ + +DEPRECATED_BY(::rb_block_call,) +/// @brief Old way to implement iterators. +/// @param[in] q A function that can yield. +/// @param[in] w Passed to `q`. +/// @param[in] e What is to be yielded. +/// @param[in] r Passed to `e`. +/// @return The return value of `q`. +/// @note `e` can be nullptr. +/// @deprecated This function is obsolated since long before 2.x era. Do not +/// use it any longer. rb_block_call() is provided instead. +inline VALUE +rb_iterate(VALUE(*q)(VALUE), VALUE w, type *e, VALUE r) +{ + rb_block_call_func_t t = reinterpret_cast<rb_block_call_func_t>(e); + return ::rb_iterate(q, w, t, r); +} + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief Call a method with a block. +/// @param[in] q The self. +/// @param[in] w The method. +/// @param[in] e The 3 of elems of `r` +/// @param[in] r The arguments. +/// @param[in] t What is to be yielded. +/// @param[in] y Passed to `t` +/// @return Return value of `q#w(*r,&t)` +/// @note 't' can be nullptr. +/// @deprecated Use glanular typed overload instead. +inline VALUE +rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y) +{ + rb_block_call_func_t u = reinterpret_cast<rb_block_call_func_t>(t); + return ::rb_block_call(q, w, e, r, u, y); +} + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief An equivalent of `rescue` clause. +/// @param[in] q A function that can raise. +/// @param[in] w Passed to `q`. +/// @param[in] e A function that cleans-up. +/// @param[in] r Passed to `e`. +/// @return The return value of `q` if no exception occurs, or the return +/// value of `e` if otherwise. +/// @note `e` can be nullptr. +/// @see rb_ensure() +/// @see rb_rescue2() +/// @see rb_protect() +/// @deprecated Use glanular typed overload instead. +inline VALUE +rb_rescue(type *q, VALUE w, type *e, VALUE r) +{ + typedef VALUE func1_t(VALUE); + typedef VALUE func2_t(VALUE, VALUE); + func1_t *t = reinterpret_cast<func1_t*>(q); + func2_t *y = reinterpret_cast<func2_t*>(e); + return ::rb_rescue(t, w, y, r); +} + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief An equivalent of `rescue` clause. +/// @param[in] q A function that can raise. +/// @param[in] w Passed to `q`. +/// @param[in] e A function that cleans-up. +/// @param[in] r Passed to `e`. +/// @param[in] ... 0-terminated list of subclass of @ref rb_eException. +/// @return The return value of `q` if no exception occurs, or the return +/// value of `e` if otherwise. +/// @note `e` can be nullptr. +/// @see rb_ensure() +/// @see rb_rescue() +/// @see rb_protect() +/// @deprecated Use glanular typed overload instead. +inline VALUE +rb_rescue2(type *q, VALUE w, type *e, VALUE r, ...) +{ + typedef VALUE func1_t(VALUE); + typedef VALUE func2_t(VALUE, VALUE); + func1_t *t = reinterpret_cast<func1_t*>(q); + func2_t *y = reinterpret_cast<func2_t*>(e); + va_list ap; + va_start(ap, r); + return ::rb_vrescue2(t, w, y, r, ap); + va_end(ap); +} + +DEPRECATED_TYPE(("Use of ANYARGS in this function is deprected"),) +/// @brief An equivalent of `ensure` clause. +/// @param[in] q A function that can raise. +/// @param[in] w Passed to `q`. +/// @param[in] e A function that ensures. +/// @param[in] r Passed to `e`. +/// @return The return value of `q`. +/// @note It makes no sense to pass nullptr to `e`. +/// @see rb_rescue() +/// @see rb_rescue2() +/// @see rb_protect() +/// @deprecated Use glanular typed overload instead. +inline VALUE +rb_ensure(type *q, VALUE w, type *e, VALUE r) +{ + typedef VALUE func1_t(VALUE); + func1_t *t = reinterpret_cast<func1_t*>(q); + func1_t * (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/