Browse Source

Merge branch 'release/1.10.x'

rdb 1 year ago
parent
commit
e04daec2fe

+ 331 - 228
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -1930,15 +1930,15 @@ write_module_class(ostream &out, Object *obj) {
             return_flags |= RF_preserve_null;
           }
           string expected_params;
-          write_function_forset(out, def._remaps, 0, 0, expected_params, 2, true, true,
-                                AT_no_args, return_flags, false);
-
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    return Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return nullptr;\n";
+          if (!write_function_forset(out, def._remaps, 0, 0, expected_params, 2, true, true,
+                                     AT_no_args, return_flags, false)) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    return Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return nullptr;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2087,40 +2087,42 @@ write_module_class(ostream &out, Object *obj) {
           if (!setattr_remaps.empty()) {
             out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
             string expected_params;
-            write_function_forset(out, setattr_remaps, 2, 2, expected_params, 4,
-                                  true, true, AT_varargs, RF_int | RF_decref_args, true);
-
-            out << "    Py_DECREF(args);\n";
-            out << "    if (!PyErr_Occurred()) {\n";
-            out << "      Dtool_Raise_BadArgumentsError(\n";
-            output_quoted(out, 8, expected_params);
-            out << ");\n";
-            out << "    }\n";
+            if (!write_function_forset(out, setattr_remaps, 2, 2, expected_params, 4,
+                                       true, true, AT_varargs, RF_int | RF_decref_args, true)) {
+              out << "    Py_DECREF(args);\n";
+              out << "    if (!PyErr_Occurred()) {\n";
+              out << "      Dtool_Raise_BadArgumentsError(\n";
+              output_quoted(out, 8, expected_params);
+              out << ");\n";
+              out << "    }\n";
+              out << "    return -1;\n\n";
+            }
           } else {
             out << "    PyErr_Format(PyExc_TypeError,\n";
             out << "      \"can't set attributes of built-in/extension type '%s'\",\n";
             out << "      Py_TYPE(self)->tp_name);\n";
+            out << "    return -1;\n\n";
           }
-          out << "    return -1;\n\n";
 
           out << "  } else { // __delattr__\n";
 
           if (!delattr_remaps.empty()) {
             string expected_params;
-            write_function_forset(out, delattr_remaps, 1, 1, expected_params, 4,
-                                  true, true, AT_single_arg, RF_int, true);
-
-            out << "    if (!PyErr_Occurred()) {\n";
-            out << "      Dtool_Raise_BadArgumentsError(\n";
-            output_quoted(out, 8, expected_params);
-            out << ");\n";
-            out << "    }\n";
+            if (!write_function_forset(out, delattr_remaps, 1, 1, expected_params, 4,
+                                       true, true, AT_single_arg, RF_int, true)) {
+              out << "    if (!PyErr_Occurred()) {\n";
+              out << "      Dtool_Raise_BadArgumentsError(\n";
+              output_quoted(out, 8, expected_params);
+              out << ");\n";
+              out << "    }\n";
+              out << "    return -1;\n";
+            }
           } else {
             out << "    PyErr_Format(PyExc_TypeError,\n";
             out << "      \"can't delete attributes of built-in/extension type '%s'\",\n";
             out << "      Py_TYPE(self)->tp_name);\n";
+            out << "    return -1;\n";
           }
-          out << "    return -1;\n";
           out << "  }\n";
 
           out << "}\n\n";
@@ -2153,12 +2155,12 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n\n";
 
           string expected_params;
-          write_function_forset(out, def._remaps, 1, 1, expected_params, 2,
-                                true, true, AT_single_arg,
-                                RF_pyobject | RF_err_null, true);
-
-          // out << "  PyErr_Clear();\n";
-          out << "  return nullptr;\n";
+          if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2,
+                                     true, true, AT_single_arg,
+                                     RF_pyobject | RF_err_null, true)) {
+            // out << "  PyErr_Clear();\n";
+            out << "  return nullptr;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2190,15 +2192,15 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n";
 
           string expected_params;
-          write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true,
-                                AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
-
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    return Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return nullptr;\n";
+          if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true,
+                                     AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    return Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return nullptr;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2240,20 +2242,27 @@ write_module_class(ostream &out, Object *obj) {
           }
 
           string expected_params;
+          bool always_returns = true;
           out << "  if (arg != nullptr) { // __setitem__\n";
-          write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4,
-                                true, true, AT_single_arg, RF_int, false, true, "index");
+          if (!write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4,
+                                     true, true, AT_single_arg, RF_int, false, true, "index")) {
+            always_returns = false;
+          }
           out << "  } else { // __delitem__\n";
-          write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4,
-                                true, true, AT_single_arg, RF_int, false, true, "index");
+          if (!write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4,
+                                     true, true, AT_single_arg, RF_int, false, true, "index")) {
+            always_returns = false;
+          }
           out << "  }\n\n";
 
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return -1;\n";
+          if (!always_returns) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return -1;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2306,22 +2315,33 @@ write_module_class(ostream &out, Object *obj) {
           }
 
           string expected_params;
+          bool always_returns = true;
           out << "  if (arg2 != nullptr) { // __setitem__\n";
-          out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
-          write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4,
-                                true, true, AT_varargs, RF_int | RF_decref_args, false);
-          out << "    Py_DECREF(args);\n";
+          if (setitem_remaps.empty()) {
+            always_returns = false;
+          } else {
+            out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
+            if (!write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4,
+                                       true, true, AT_varargs, RF_int | RF_decref_args, false)) {
+              always_returns = false;
+            }
+            out << "    Py_DECREF(args);\n";
+          }
           out << "  } else { // __delitem__\n";
-          write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4,
-                                true, true, AT_single_arg, RF_int, false);
+          if (!write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4,
+                                     true, true, AT_single_arg, RF_int, false)) {
+            always_returns = false;
+          }
           out << "  }\n\n";
 
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return -1;\n";
+          if (!always_returns) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return -1;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2541,23 +2561,33 @@ write_module_class(ostream &out, Object *obj) {
           }
 
           string expected_params;
-
+          bool always_returns = true;
           out << "  if (arg2 != nullptr && arg2 != Py_None) {\n";
-          out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
-          write_function_forset(out, two_param_remaps, 2, 2, expected_params, 4,
-                                true, true, AT_varargs, return_flags | RF_decref_args, true);
-          out << "    Py_DECREF(args);\n";
+          if (two_param_remaps.empty()) {
+            always_returns = false;
+          } else {
+            out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
+            if (!write_function_forset(out, two_param_remaps, 2, 2, expected_params, 4,
+                                       true, true, AT_varargs, return_flags | RF_decref_args, true)) {
+              always_returns = false;
+            }
+            out << "    Py_DECREF(args);\n";
+          }
           out << "  } else {\n";
-          write_function_forset(out, one_param_remaps, 1, 1, expected_params, 4,
-                                true, true, AT_single_arg, return_flags, true);
+          if (!write_function_forset(out, one_param_remaps, 1, 1, expected_params, 4,
+                                     true, true, AT_single_arg, return_flags, true)) {
+            always_returns = false;
+          }
           out << "  }\n\n";
 
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    return Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return nullptr;\n";
+          if (!always_returns) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    return Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return nullptr;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2608,15 +2638,15 @@ write_module_class(ostream &out, Object *obj) {
           out << "  }\n\n";
 
           string expected_params;
-          write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true,
-                                AT_single_arg, RF_compare, false, true);
-
-          out << "  if (!PyErr_Occurred()) {\n";
-          out << "    Dtool_Raise_BadArgumentsError(\n";
-          output_quoted(out, 6, expected_params);
-          out << ");\n";
-          out << "  }\n";
-          out << "  return -1;\n";
+          if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true,
+                                     AT_single_arg, RF_compare, false, true)) {
+            out << "  if (!PyErr_Occurred()) {\n";
+            out << "    Dtool_Raise_BadArgumentsError(\n";
+            output_quoted(out, 6, expected_params);
+            out << ");\n";
+            out << "  }\n";
+            out << "  return -1;\n";
+          }
           out << "}\n\n";
         }
         break;
@@ -2782,10 +2812,10 @@ write_module_class(ostream &out, Object *obj) {
       out << "    {\n";
 
       string expected_params;
-      write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false,
-                            AT_single_arg, RF_pyobject | RF_err_null, false);
-
-      out << "      break;\n";
+      if (!write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false,
+                                 AT_single_arg, RF_pyobject | RF_err_null, false)) {
+        out << "      break;\n";
+      }
       out << "    }\n";
     }
 
@@ -2818,10 +2848,10 @@ write_module_class(ostream &out, Object *obj) {
           out << "    {\n";
 
           string expected_params;
-          write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false,
-                                AT_single_arg, RF_pyobject | RF_invert_bool | RF_err_null, false);
-
-          out << "      break;\n";
+          if (!write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false,
+                                     AT_single_arg, RF_pyobject | RF_invert_bool | RF_err_null, false)) {
+            out << "      break;\n";
+          }
           out << "    }\n";
         }
       }
@@ -3932,17 +3962,24 @@ write_function_for_name(ostream &out, Object *obj,
         }
       }
 
+      bool always_returns;
       if (strip_keyword_args) {
         // None of the remaps take any keyword arguments, so let's check that
         // we take none.  This saves some checks later on.
         indent(out, 4) << "if (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0) {\n";
         if (min_args == 1 && min_args == 1) {
           indent(out, 4) << "  PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
-          write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
-                coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
+          always_returns = write_function_forset(out, mii->second, min_args,
+                                                 max_args, expected_params, 6,
+                                                 coercion_allowed, true,
+                                                 AT_single_arg, return_flags,
+                                                 true, !all_nonconst);
         } else {
-          write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
-                coercion_allowed, true, AT_varargs, return_flags, true, !all_nonconst);
+          always_returns = write_function_forset(out, mii->second, min_args,
+                                                 max_args, expected_params, 6,
+                                                 coercion_allowed, true,
+                                                 AT_varargs, return_flags,
+                                                 true, !all_nonconst);
         }
       } else if (min_args == 1 && max_args == 1 && args_type == AT_varargs) {
         // We already checked that the args tuple has only one argument, so
@@ -3950,16 +3987,23 @@ write_function_for_name(ostream &out, Object *obj,
         indent(out, 4) << "{\n";
         indent(out, 4) << "  PyObject *arg = PyTuple_GET_ITEM(args, 0);\n";
 
-        write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
-                      coercion_allowed, true, AT_single_arg, return_flags, true, !all_nonconst);
+        always_returns = write_function_forset(out, mii->second, min_args,
+                                               max_args, expected_params, 6,
+                                               coercion_allowed, true,
+                                               AT_single_arg, return_flags,
+                                               true, !all_nonconst);
       } else {
         indent(out, 4) << "{\n";
-        write_function_forset(out, mii->second, min_args, max_args, expected_params, 6,
-                      coercion_allowed, true, args_type, return_flags, true, !all_nonconst);
+        always_returns = write_function_forset(out, mii->second, min_args,
+                                               max_args, expected_params, 6,
+                                               coercion_allowed, true, args_type,
+                                               return_flags, true, !all_nonconst);
       }
 
       indent(out, 4) << "}\n";
-      indent(out, 4) << "break;\n";
+      if (!always_returns) {
+        indent(out, 4) << "break;\n";
+      }
     }
 
     // In NDEBUG case, fall through to the error at end of function.
@@ -4070,24 +4114,22 @@ write_function_for_name(ostream &out, Object *obj,
     }
 
     int min_args = min(max_required_args, mii->first);
-    write_function_forset(out, mii->second, min_args, mii->first, expected_params, 2,
-                          coercion_allowed, true, args_type, return_flags, true, !all_nonconst);
-
-    // This block is often unreachable for many functions... maybe we can
-    // figure out a way in the future to better determine when it will be and
-    // won't be necessary to write this out.
-    if (args_type != AT_no_args) {
-      out << "  if (!PyErr_Occurred()) {\n"
-          << "    ";
-      if ((return_flags & ~RF_pyobject) == RF_err_null) {
-        out << "return ";
-      }
-      out << "Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n"
-          << "  }\n";
+    if (!write_function_forset(out, mii->second, min_args, mii->first,
+                               expected_params, 2, coercion_allowed, true,
+                               args_type, return_flags, true, !all_nonconst)) {
+      if (args_type != AT_no_args) {
+        out << "  if (!PyErr_Occurred()) {\n"
+            << "    ";
+        if ((return_flags & ~RF_pyobject) == RF_err_null) {
+          out << "return ";
+        }
+        out << "Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n"
+            << "  }\n";
 
-      error_return(out, 2, return_flags);
+        error_return(out, 2, return_flags);
+      }
     }
   }
 
@@ -4290,10 +4332,11 @@ write_coerce_constructor(ostream &out, Object *obj, bool is_const) {
       }
       indent(out, 6) << "case " << max_args << ": {\n";
 
-      write_function_forset(out, mii->second, min_args, max_args, expected_params, 8, false, false,
-                            AT_varargs, return_flags, true, false);
-
-      indent(out, 8) << "break;\n";
+      if (!write_function_forset(out, mii->second, min_args, max_args,
+                                 expected_params, 8, false, false,
+                                 AT_varargs, return_flags, true, false)) {
+        indent(out, 8) << "break;\n";
+      }
       indent(out, 6) << "}\n";
     }
     indent(out, 4) << "}\n";
@@ -4540,7 +4583,7 @@ bool RemapCompareLess(FunctionRemap *in1, FunctionRemap *in2) {
  * first parameter.  This is a special-case hack for one of the slot
  * functions.
  */
-void InterfaceMakerPythonNative::
+bool InterfaceMakerPythonNative::
 write_function_forset(ostream &out,
                       const std::set<FunctionRemap *> &remapsin,
                       int min_num_args, int max_num_args,
@@ -4551,13 +4594,14 @@ write_function_forset(ostream &out,
                       const string &first_pexpr) {
 
   if (remapsin.empty()) {
-    return;
+    return false;
   }
 
   FunctionRemap *remap = nullptr;
   std::set<FunctionRemap *>::iterator sii;
 
   bool all_nonconst = false;
+  bool always_returns = true;
 
   if (verify_const) {
     // Check if all of the remaps are non-const.  If so, we only have to check
@@ -4613,6 +4657,7 @@ write_function_forset(ostream &out,
     indent(out, indent_level) << "if (Dtool_ExtractArg(&arg, args, kwds, \"" << first_param_name << "\")) {\n";
     indent_level += 2;
     args_type = AT_single_arg;
+    always_returns = false;
   }
 
   if (remapsin.size() > 1) {
@@ -4624,6 +4669,7 @@ write_function_forset(ostream &out,
     std::vector<FunctionRemap *>::const_iterator sii;
 
     int num_coercion_possible = 0;
+    bool caught_all = false;
     sii = remaps.begin();
     while (sii != remaps.end()) {
       remap = *(sii++);
@@ -4638,7 +4684,16 @@ write_function_forset(ostream &out,
         }
       }
 
-      if (verify_const && (remap->_has_this && !remap->_const_method)) {
+      if (caught_all) {
+        indent(out, indent_level)
+          << "  // [DCE] -2 \n";
+        remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args));
+        out << "\n";
+        continue;
+      }
+
+      bool remap_verify_const = verify_const && (remap->_has_this && !remap->_const_method);
+      if (remap_verify_const) {
         // If it's a non-const method, we only allow a non-const this.
         indent(out, indent_level)
           << "if (!DtoolInstance_IS_CONST(self)) {\n";
@@ -4654,17 +4709,23 @@ write_function_forset(ostream &out,
       // NB.  We don't pass on report_errors here because we want it to
       // silently drop down to the next overload.
 
-      write_function_instance(out, remap, min_num_args, max_num_args,
-                              expected_params, indent_level + 2,
-                              false, false, args_type, return_flags,
-                              check_exceptions, first_pexpr);
+      if (write_function_instance(out, remap, min_num_args, max_num_args,
+                                  expected_params, indent_level + 2,
+                                  false, false, args_type, return_flags,
+                                  check_exceptions, first_pexpr)) {
+        // The rest of the overloads are dead code.
+        if (!remap_verify_const) {
+          caught_all = true;
+          //indent(out, indent_level) << "  // caught all cases here\n";
+        }
+      }
 
       indent(out, indent_level) << "}\n\n";
     }
 
     // Go through one more time, but allow coercion this time.
-    if (coercion_allowed) {
-      for (sii = remaps.begin(); sii != remaps.end(); sii ++) {
+    if (coercion_allowed && !caught_all) {
+      for (sii = remaps.begin(); sii != remaps.end(); ++sii) {
         remap = (*sii);
         if (!is_remap_coercion_possible(remap)) {
           indent(out, indent_level)
@@ -4674,7 +4735,16 @@ write_function_forset(ostream &out,
           continue;
         }
 
-        if (verify_const && (remap->_has_this && !remap->_const_method)) {
+        if (caught_all) {
+          indent(out, indent_level)
+            << "  // [DCE] -2 \n";
+          remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args));
+          out << "\n";
+          continue;
+        }
+
+        bool remap_verify_const = verify_const && (remap->_has_this && !remap->_const_method);
+        if (remap_verify_const) {
           indent(out, indent_level)
             << "if (!DtoolInstance_IS_CONST(self)) {\n";
         } else {
@@ -4687,14 +4757,24 @@ write_function_forset(ostream &out,
         out << "\n";
 
         string ignore_expected_params;
-        write_function_instance(out, remap, min_num_args, max_num_args,
-                                ignore_expected_params, indent_level + 2,
-                                true, false, args_type, return_flags,
-                                check_exceptions, first_pexpr);
+        if (write_function_instance(out, remap, min_num_args, max_num_args,
+                                     ignore_expected_params, indent_level + 2,
+                                     true, false, args_type, return_flags,
+                                     check_exceptions, first_pexpr)) {
+          // The rest of the overloads are dead code.
+          if (!remap_verify_const) {
+            caught_all = true;
+            //indent(out, indent_level) << "  // caught all cases here\n";
+          }
+        }
 
         indent(out, indent_level) << "}\n\n";
       }
     }
+
+    if (!caught_all) {
+      always_returns = false;
+    }
   } else {
     // There is only one possible overload with this number of parameters.
     // Just call it.
@@ -4706,11 +4786,13 @@ write_function_forset(ostream &out,
     remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args));
     out << "\n";
 
-    write_function_instance(out, remap, min_num_args, max_num_args,
-                            expected_params, indent_level,
-                            coercion_allowed, report_errors,
-                            args_type, return_flags,
-                            check_exceptions, first_pexpr);
+    if (!write_function_instance(out, remap, min_num_args, max_num_args,
+                                 expected_params, indent_level,
+                                 coercion_allowed, report_errors,
+                                 args_type, return_flags,
+                                 check_exceptions, first_pexpr)) {
+      always_returns = false;
+    }
   }
 
   // Close the brace we opened earlier.
@@ -4739,10 +4821,14 @@ write_function_forset(ostream &out,
       out << "#else\n";
       error_raise_return(out, indent_level, return_flags, "TypeError", msg.str());
       out << "#endif\n";
+    } else {
+      always_returns = false;
     }
     indent_level -= 2;
     indent(out, indent_level) << "}\n";
   }
+
+  return always_returns;
 }
 
 /**
@@ -4769,8 +4855,11 @@ write_function_forset(ostream &out,
  * If first_pexpr is not empty, it represents the preconverted value of the
  * first parameter.  This is a special-case hack for one of the slot
  * functions.
+ *
+ * Returns true if the function returns unconditionally, false if it may fall
+ * through and additional error handling code is needed.
  */
-void InterfaceMakerPythonNative::
+bool InterfaceMakerPythonNative::
 write_function_instance(ostream &out, FunctionRemap *remap,
                         int min_num_args, int max_num_args,
                         string &expected_params, int indent_level,
@@ -4827,7 +4916,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
         --max_num_args;
       }
     }
-    nassertv(num_params <= (int)remap->_parameters.size());
+    nassertr(num_params <= (int)remap->_parameters.size(), false);
   }
 
   bool only_pyobjects = true;
@@ -4938,7 +5027,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
 
       // We should only ever have to consider optional arguments for functions
       // taking a variable number of arguments.
-      nassertv(args_type == AT_varargs || args_type == AT_keyword_args);
+      nassertr(args_type == AT_varargs || args_type == AT_keyword_args, false);
     }
 
     string reported_name = remap->_parameters[pn]._name;
@@ -6220,9 +6309,15 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     // The general case; an ordinary constructor or function.
     return_expr = remap->call_function(out, indent_level, true, container, pexprs);
 
-    if (return_flags & RF_self) {
-      // We won't be using the return value, anyway.
-      return_expr.clear();
+    if ((return_flags & RF_self) != 0) {
+      if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) {
+        // If the function returns a PyObject *, let it override the default
+        // behavior of returning self.
+        return_flags = (return_flags & ~RF_self) | RF_pyobject;
+      } else {
+        // We won't be using the return value, anyway.
+        return_expr.clear();
+      }
     }
 
     if (!return_expr.empty()) {
@@ -6546,12 +6641,18 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     indent(out, indent_level) << "}\n";
   }
 
-  // Close the extra braces opened earlier.
-  while (open_scopes > 0) {
-    indent_level -= 2;
-    indent(out, indent_level) << "}\n";
+  // If we were in a scope
+  bool always_returns = true;
+  if (open_scopes > 0) {
+    always_returns = false;
 
-    --open_scopes;
+    // Close the extra braces opened earlier.
+    while (open_scopes > 0) {
+      indent_level -= 2;
+      indent(out, indent_level) << "}\n";
+
+      --open_scopes;
+    }
   }
 
   if (clear_error && !report_errors) {
@@ -6563,7 +6664,10 @@ write_function_instance(ostream &out, FunctionRemap *remap,
   if (min_version > 0) {
     // Close the #if PY_VERSION_HEX check.
     out << "#endif\n";
+    always_returns = false;
   }
+
+  return always_returns;
 }
 
 /**
@@ -6924,15 +7028,15 @@ write_getset(ostream &out, Object *obj, Property *property) {
     }
 
     string expected_params;
-    write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
-                          AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
-
-    out << "  if (!PyErr_Occurred()) {\n";
-    out << "    return Dtool_Raise_BadArgumentsError(\n";
-    output_quoted(out, 6, expected_params);
-    out << ");\n"
-            "  }\n"
-            "}\n\n";
+    if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
+                               AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) {
+      out << "  if (!PyErr_Occurred()) {\n";
+      out << "    return Dtool_Raise_BadArgumentsError(\n";
+      output_quoted(out, 6, expected_params);
+      out << ");\n";
+      out << "  }\n";
+    }
+    out << "}\n\n";
 
     // Write out a setitem if this is not a read-only property.
     if (!property->_setter_remaps.empty()) {
@@ -6997,16 +7101,15 @@ write_getset(ostream &out, Object *obj, Property *property) {
       }
 
       string expected_params;
-      write_function_forset(out, remaps, 2, 2,
-                            expected_params, 2, true, true, AT_single_arg,
-                            RF_int, false, false, "index");
-
-      out << "  if (!PyErr_Occurred()) {\n";
-      out << "    Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n";
-      out << "  }\n";
-      out << "  return -1;\n";
+      if (!write_function_forset(out, remaps, 2, 2, expected_params, 2, true,
+                                 true, AT_single_arg, RF_int, false, false, "index")) {
+        out << "  if (!PyErr_Occurred()) {\n";
+        out << "    Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n";
+        out << "  }\n";
+        out << "  return -1;\n";
+      }
       out << "}\n\n";
     }
 
@@ -7026,16 +7129,16 @@ write_getset(ostream &out, Object *obj, Property *property) {
                     property->_inserter->_remaps.end());
 
       string expected_params;
-      write_function_forset(out, remaps, 2, 2,
-                            expected_params, 2, true, true, AT_single_arg,
-                            RF_pyobject | RF_err_null, false, false, "index");
-
-      out << "  if (!PyErr_Occurred()) {\n";
-      out << "    Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n";
-      out << "  }\n";
-      out << "  return nullptr;\n";
+      if (!write_function_forset(out, remaps, 2, 2, expected_params, 2, true,
+                                 true, AT_single_arg, RF_pyobject | RF_err_null,
+                                 false, false, "index")) {
+        out << "  if (!PyErr_Occurred()) {\n";
+        out << "    Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n";
+        out << "  }\n";
+        out << "  return nullptr;\n";
+      }
       out << "}\n\n";
     }
   }
@@ -7095,16 +7198,16 @@ write_getset(ostream &out, Object *obj, Property *property) {
     }
 
     string expected_params;
-    write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
-                          AT_single_arg, RF_pyobject | RF_err_null, false, true);
-
-    out << "  if (!PyErr_Occurred()) {\n";
-    out << "    return Dtool_Raise_BadArgumentsError(\n";
-    output_quoted(out, 6, expected_params);
-    out << ");\n"
-            "  }\n"
-            "  return nullptr;\n"
-            "}\n\n";
+    if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
+                               AT_single_arg, RF_pyobject | RF_err_null, false, true)) {
+      out << "  if (!PyErr_Occurred()) {\n";
+      out << "    return Dtool_Raise_BadArgumentsError(\n";
+      output_quoted(out, 6, expected_params);
+      out << ");\n"
+              "  }\n"
+              "  return nullptr;\n";
+    }
+    out << "}\n\n";
 
     // Write out a setitem if this is not a read-only property.
     if (!property->_setter_remaps.empty()) {
@@ -7144,10 +7247,11 @@ write_getset(ostream &out, Object *obj, Property *property) {
                       property->_deleter->_remaps.end());
 
         string expected_params;
-        write_function_forset(out, remaps, 1, 1,
-                              expected_params, 4, true, true, AT_single_arg,
-                              RF_int, false, false);
-        out << "    return -1;\n";
+        if (!write_function_forset(out, remaps, 1, 1,
+                                   expected_params, 4, true, true, AT_single_arg,
+                                   RF_int, false, false)) {
+          out << "    return -1;\n";
+        }
       } else {
         out << "#ifdef NDEBUG\n"
                "    Dtool_Raise_TypeError(\"can't delete attribute\");\n"
@@ -7177,17 +7281,17 @@ write_getset(ostream &out, Object *obj, Property *property) {
           << "  Py_INCREF(value);\n";
 
       string expected_params;
-      write_function_forset(out, remaps, 2, 2,
-                            expected_params, 2, true, true, AT_varargs,
-                            RF_int | RF_decref_args, false, false);
-
-      out << "  if (!PyErr_Occurred()) {\n";
-      out << "    Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n";
-      out << "  }\n";
-      out << "  Py_DECREF(args);\n";
-      out << "  return -1;\n";
+      if (!write_function_forset(out, remaps, 2, 2,
+                                 expected_params, 2, true, true, AT_varargs,
+                                 RF_int | RF_decref_args, false, false)) {
+        out << "  if (!PyErr_Occurred()) {\n";
+        out << "    Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n";
+        out << "  }\n";
+        out << "  Py_DECREF(args);\n";
+        out << "  return -1;\n";
+      }
       out << "}\n\n";
     }
 
@@ -7232,15 +7336,15 @@ write_getset(ostream &out, Object *obj, Property *property) {
       }
 
       string expected_params;
-      write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
-                            AT_no_args, RF_pyobject | RF_err_null, false, true, "index");
-
-      out << "  if (!PyErr_Occurred()) {\n";
-      out << "    return Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n"
-              "  }\n"
-              "}\n\n";
+      if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true,
+                                 AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) {
+        out << "  if (!PyErr_Occurred()) {\n";
+        out << "    return Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n"
+                "  }\n";
+      }
+      out << "}\n\n";
     }
   }
 
@@ -7432,16 +7536,15 @@ write_getset(ostream &out, Object *obj, Property *property) {
       }
 
       string expected_params;
-      write_function_forset(out, remaps, 1, 1,
-                            expected_params, 2, true, true, AT_single_arg,
-                            RF_int, false, false);
-
-      out << "  if (!PyErr_Occurred()) {\n";
-      out << "    Dtool_Raise_BadArgumentsError(\n";
-      output_quoted(out, 6, expected_params);
-      out << ");\n";
-      out << "  }\n";
-      out << "  return -1;\n";
+      if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true,
+                                 true, AT_single_arg, RF_int, false, false)) {
+        out << "  if (!PyErr_Occurred()) {\n";
+        out << "    Dtool_Raise_BadArgumentsError(\n";
+        output_quoted(out, 6, expected_params);
+        out << ");\n";
+        out << "  }\n";
+        out << "  return -1;\n";
+      }
       out << "}\n\n";
     }
   }

+ 2 - 2
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -155,7 +155,7 @@ private:
   int collapse_default_remaps(std::map<int, std::set<FunctionRemap *> > &map_sets,
                               int max_required_args);
 
-  void write_function_forset(std::ostream &out,
+  bool write_function_forset(std::ostream &out,
                              const std::set<FunctionRemap*> &remaps,
                              int min_num_args, int max_num_args,
                              std::string &expected_params, int indent_level,
@@ -165,7 +165,7 @@ private:
                              bool verify_const = true,
                              const std::string &first_expr = std::string());
 
-  void write_function_instance(std::ostream &out, FunctionRemap *remap,
+  bool write_function_instance(std::ostream &out, FunctionRemap *remap,
                                int min_num_args, int max_num_args,
                                std::string &expected_params, int indent_level,
                                bool coercion_allowed, bool report_errors,