From 57ba3a72453a436e6ae08446de45e4a9f1db63c6 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 7 Dec 2021 16:56:56 +0100 Subject: [PATCH] Factor out C++ function generation into cxx_function_wrapper No real changes, just factor out the code for (non-special) functions generation from emit_member_function() into a separate cxx_function_wrapper class, so that it could be reused for the global functions generation too. --- Source/Modules/c.cxx | 256 ++++++++++++++++++++++++++----------------- 1 file changed, 154 insertions(+), 102 deletions(-) diff --git a/Source/Modules/c.cxx b/Source/Modules/c.cxx index 4dfdeb92a..b4d6d6ee3 100644 --- a/Source/Modules/c.cxx +++ b/Source/Modules/c.cxx @@ -813,6 +813,135 @@ public: Node* node_func_; }; +/* + cxx_function_wrapper + + Outputs the C++ wrapper function. It's different from the C function because it is declared inside the namespace and so doesn't need the usual prefix and may + also have different parameter and return types when objects and/or cxx{in,out}type typemaps are involved. + */ +class cxx_function_wrapper +{ +public: + // Call can_wrap() to check if this wrapper can be emitted later. + explicit cxx_function_wrapper(cxx_wrappers& cxx_wrappers, Node* n, Parm* p) : cxx_wrappers_(cxx_wrappers) { + func_node = NULL; + + except_check_start = + except_check_end = ""; + + // Usually generating wrappers for overloaded methods is fine, but sometimes their types can clash after applying typemaps and in this case we have no + // choice but to avoid generating them, as otherwise we'd just generate uncompilable code. + if (Getattr(n, "sym:overloaded")) { + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) + return; + } + + if (!cxx_wrappers_.lookup_cxx_ret_type(rtype_desc, n)) + return; + + parms_cxx = NewStringEmpty(); + parms_call = NewStringEmpty(); + + if (p) { + // We want to use readable parameter names in our wrappers instead of the autogenerated arg$N if possible, so do it, and do it before calling + // Swig_typemap_attach_parms(), as this uses the parameter names for typemap expansion. + for (Parm* p2 = p; p2; p2 = nextSibling(p2)) { + String* name = Getattr(p, "name"); + if (!name) { + // Can't do anything for unnamed parameters. + continue; + } + + // Static variables use fully qualified names, so we need to strip the scope from them. + scoped_dohptr name_ptr; + if (Strstr(name, "::")) { + name_ptr = Swig_scopename_last(name); + name = name_ptr.get(); + } + + Setattr(p, "lname", name); + } + + Swig_typemap_attach_parms("cxxin", p, NULL); + + for (; p; p = nextSibling(p)) { + String* const name = Getattr(p, "lname"); + + cxx_ptype_desc ptype_desc; + if (!cxx_wrappers_.lookup_cxx_parm_type(ptype_desc, n, p)) + return; + + if (Len(parms_cxx)) + Append(parms_cxx, ", "); + Printv(parms_cxx, ptype_desc.type(), " ", name, NIL); + + if (Len(parms_call)) + Append(parms_call, ", "); + Append(parms_call, ptype_desc.get_param_code(name)); + } + } + + + // Avoid checking for exceptions unnecessarily. Note that this is more than an optimization: we'd get into infinite recursion if we checked for exceptions + // thrown by members of SWIG_CException itself if we didn't do it. + if (cxx_wrappers_.is_exception_support_enabled() && + !Checkattr(n, "noexcept", "true") && + (!Checkattr(n, "throw", "1") || Getattr(n, "throws"))) { + except_check_start = cxx_wrappers_.except_check_start; + except_check_end = cxx_wrappers_.except_check_end; + } + + // Everything is fine, so set func_node to indicate success. + func_node = n; + } + + bool can_wrap() const { return func_node != NULL; } + + // Emit just the function body, including the braces around it. + void emit_body(String* wparms) { + String* const wname = Getattr(func_node, "wrap:name"); + + Append(cxx_wrappers_.sect_impls, "{"); + + if (rtype_desc.is_void()) { + Printv(cxx_wrappers_.sect_impls, + " ", wname, "(", wparms, "); ", + NIL + ); + + if (*except_check_start != '\0') { + Printv(cxx_wrappers_.sect_impls, + except_check_start, + except_check_end, + "; ", + NIL + ); + } + } else { + rtype_desc.set_return_value(NewStringf("%s%s(%s)%s", except_check_start, wname, wparms, except_check_end)); + Append(cxx_wrappers_.sect_impls, rtype_desc.get_return_code()); + } + + Append(cxx_wrappers_.sect_impls, "}\n"); + } + + + cxx_wrappers& cxx_wrappers_; + Node* func_node; + cxx_rtype_desc rtype_desc; + scoped_dohptr parms_cxx; + scoped_dohptr parms_call; + const char* except_check_start; + const char* except_check_end; + +private: + // Non copyable. + cxx_function_wrapper(const cxx_function_wrapper&); + cxx_function_wrapper& operator=(const cxx_function_wrapper&); +}; + + /* cxx_class_wrapper @@ -911,32 +1040,12 @@ public: if (Checkattr(n, "storage", "friend")) return; - // Usually generating wrappers for overloaded methods is fine, but sometimes their types can clash after applying typemaps and in this case we have no - // choice but to avoid generating them, as otherwise we'd just generate uncompilable code. - if (Getattr(n, "sym:overloaded")) { - Swig_overload_check(n); - if (Getattr(n, "overload:ignore")) - return; - } - - temp_ptr_setter set(&cxx_wrappers_.node_func_, n); - // As mentioned elsewhere, we can't use Swig_storage_isstatic() here because the "storage" attribute is temporarily saved in another view when this // function is being executed, so rely on another attribute to determine if it's a static function instead. const bool is_member = Checkattr(n, "ismember", "1"); const bool is_static = is_member && Getattr(n, "cplus:staticbase"); const bool is_ctor = Checkattr(n, "nodeType", "constructor"); - // Deal with the return type: it may be different from the type of the C wrapper function if it involves objects, and so we may need to add a cast. - - cxx_rtype_desc rtype_desc; - if (!cxx_wrappers_.lookup_cxx_ret_type(rtype_desc, n)) - return; - - // We also need the list of parameters to take in the C++ function being generated and the list of them to pass to the C wrapper. - scoped_dohptr parms_cxx(NewStringEmpty()); - scoped_dohptr parms_call(NewStringEmpty()); - Parm* p = Getattr(n, "parms"); if (p && is_member && !is_ctor && !is_static) { // We should have "this" as the first parameter and we need to just skip it, as we handle it specially in C++ wrappers. @@ -951,59 +1060,18 @@ public: } } - if (p) { - // We want to use readable parameter names in our wrappers instead of the autogenerated arg$N if possible, so do it, and do it before calling - // Swig_typemap_attach_parms(), as this uses the parameter names for typemap expansion. - for (Parm* p2 = p; p2; p2 = nextSibling(p2)) { - String* name = Getattr(p, "name"); - if (!name) { - // Can't do anything for unnamed parameters. - continue; - } + cxx_function_wrapper func_wrapper(cxx_wrappers_, n, p); + if (!func_wrapper.can_wrap()) + return; - // Static variables use fully qualified names, so we need to strip the scope from them. - scoped_dohptr name_ptr; - if (Strstr(name, "::")) { - name_ptr = Swig_scopename_last(name); - name = name_ptr.get(); - } - - Setattr(p, "lname", name); - } - - Swig_typemap_attach_parms("cxxin", p, NULL); - - for (; p; p = nextSibling(p)) { - String* const name = Getattr(p, "lname"); - - cxx_ptype_desc ptype_desc; - if (!cxx_wrappers_.lookup_cxx_parm_type(ptype_desc, n, p)) - return; - - if (Len(parms_cxx)) - Append(parms_cxx, ", "); - Printv(parms_cxx, ptype_desc.type(), " ", name, NIL); - - if (Len(parms_call)) - Append(parms_call, ", "); - Append(parms_call, ptype_desc.get_param_code(name)); - } - } - - // Avoid checking for exceptions unnecessarily. Note that this is more than an optimization: we'd get into infinite recursion if we checked for exceptions - // thrown by members of SWIG_CException itself if we didn't do it. - const char* except_check_start = cxx_wrappers_.except_check_start; - const char* except_check_end = cxx_wrappers_.except_check_end; - if (cxx_wrappers_.is_exception_support_enabled()) { - if (Checkattr(n, "noexcept", "true") || (Checkattr(n, "throw", "1") && !Getattr(n, "throws"))) { - except_check_start = - except_check_end = ""; - } - } + // Define aliases for the stuff actually stored in the function wrapper object. + cxx_rtype_desc& rtype_desc = func_wrapper.rtype_desc; + String* const parms_cxx = func_wrapper.parms_cxx; + String* const parms_call = func_wrapper.parms_call; // For some reason overloaded functions use fully-qualified name, so we can't just use the name directly. scoped_dohptr name_ptr(Swig_scopename_last(Getattr(n, "name"))); - String* const name = name_ptr.get(); + String* const name = name_ptr; String* const wname = Getattr(n, "wrap:name"); String* const classname = Getattr(class_node_, "sym:name"); @@ -1018,8 +1086,8 @@ public: ); } else if (Checkattr(n, "memberset", "1")) { Printv(cxx_wrappers_.sect_decls, - cindent, "void ", name, "(", parms_cxx.get(), ") " - "{ ", Getattr(n, "sym:name"), "(swig_self(), ", parms_call.get(), "); }\n", + cindent, "void ", name, "(", parms_cxx, ") " + "{ ", Getattr(n, "sym:name"), "(swig_self(), ", parms_call, "); }\n", NIL ); } else if (Checkattr(n, "varget", "1")) { @@ -1031,8 +1099,8 @@ public: ); } else if (Checkattr(n, "varset", "1")) { Printv(cxx_wrappers_.sect_decls, - cindent, "static void ", name, "(", parms_cxx.get(), ") " - "{ ", Getattr(n, "sym:name"), "(", parms_call.get(), "); }\n", + cindent, "static void ", name, "(", parms_cxx, ") " + "{ ", Getattr(n, "sym:name"), "(", parms_call, "); }\n", NIL ); } else { @@ -1044,16 +1112,16 @@ public: } else if (is_ctor) { // Delegate to the ctor from opaque C pointer taking ownership of the object. Printv(cxx_wrappers_.sect_decls, - cindent, classname, "(", parms_cxx.get(), ");\n", + cindent, classname, "(", parms_cxx, ");\n", NIL ); Printv(cxx_wrappers_.sect_impls, - "inline ", classname, "::", classname, "(", parms_cxx.get(), ") : ", + "inline ", classname, "::", classname, "(", parms_cxx, ") : ", classname, "{", - except_check_start, - wname, "(", parms_call.get(), ")", - except_check_end, + func_wrapper.except_check_start, + wname, "(", parms_call, ")", + func_wrapper.except_check_end, "} {}\n", NIL ); @@ -1100,39 +1168,20 @@ public: Printv(cxx_wrappers_.sect_decls, cindent, is_static ? "static " : get_virtual_prefix(n), rtype_desc.type(), " ", - name, "(", parms_cxx.get(), ")", + name, "(", parms_cxx, ")", get_const_suffix(n), ";\n", NIL ); Printv(cxx_wrappers_.sect_impls, "inline ", rtype_desc.type(), " ", - classname, "::", name, "(", parms_cxx.get(), ")", + classname, "::", name, "(", parms_cxx, ")", get_const_suffix(n), - " {", + " ", NIL ); - if (rtype_desc.is_void()) { - Printv(cxx_wrappers_.sect_impls, - " ", wname, "(", wparms.get(), "); ", - NIL - ); - - if (*except_check_start) { - Printv(cxx_wrappers_.sect_impls, - except_check_start, - except_check_end, - "; ", - NIL - ); - } - } else { - rtype_desc.set_return_value(NewStringf("%s%s(%s)%s", except_check_start, wname, wparms.get(), except_check_end)); - Append(cxx_wrappers_.sect_impls, rtype_desc.get_return_code()); - } - - Append(cxx_wrappers_.sect_impls, "}\n"); + func_wrapper.emit_body(wparms); } else { // This is something we don't know about Swig_warning(WARN_C_UNSUPPORTTED, Getfile(n), Getline(n), @@ -2401,8 +2450,11 @@ public: emit_wrapper_func_decl(n, wname); if (cxx_wrappers_.is_initialized()) { - if (cxx_class_wrapper_) + temp_ptr_setter set(&cxx_wrappers_.node_func_, n); + + if (cxx_class_wrapper_) { cxx_class_wrapper_->emit_member_function(n); + } } Delete(name);