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.
This commit is contained in:
Vadim Zeitlin 2021-12-07 16:56:56 +01:00
commit 57ba3a7245

View file

@ -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<Node*> 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<Node*> set(&cxx_wrappers_.node_func_, n);
if (cxx_class_wrapper_) {
cxx_class_wrapper_->emit_member_function(n);
}
}
Delete(name);