SF Patch #1463867: Improved generator finalization to allow generators
that are suspended outside of any try/except/finally blocks to be
garbage collected even if they are part of a cycle.  Generators that
suspend inside of an active try/except or try/finally block (including
those created by a ``with`` statement) are still not GC-able if they
are part of a cycle, however.
diff --git a/Include/genobject.h b/Include/genobject.h
index f4226ed..1ecd7ad 100644
--- a/Include/genobject.h
+++ b/Include/genobject.h
@@ -28,6 +28,7 @@
 #define PyGen_CheckExact(op) ((op)->ob_type == &PyGen_Type)
 
 PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
+PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
 
 #ifdef __cplusplus
 }
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index a8976b3..5bf95b9 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -413,8 +413,12 @@
 		assert(delstr != NULL);
 		return _PyInstance_Lookup(op, delstr) != NULL;
 	}
-	else
+	else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE))
 		return op->ob_type->tp_del != NULL;
+	else if (PyGen_CheckExact(op))
+		return PyGen_NeedsFinalizing((PyGenObject *)op);
+	else
+		return 0;
 }
 
 /* Move the objects in unreachable with __del__ methods into `finalizers`.
diff --git a/Objects/genobject.c b/Objects/genobject.c
index e7b8f87..a3eae6a 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -5,6 +5,7 @@
 #include "genobject.h"
 #include "ceval.h"
 #include "structmember.h"
+#include "opcode.h"
 
 static int
 gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
@@ -358,3 +359,22 @@
 	_PyObject_GC_TRACK(gen);
 	return (PyObject *)gen;
 }
+
+int
+PyGen_NeedsFinalizing(PyGenObject *gen)
+{
+	int i;
+	PyFrameObject *f = gen->gi_frame;
+
+	if ((PyObject *)f == Py_None || f->f_stacktop==NULL || f->f_iblock<=0)
+		return 0; /* no frame or no blockstack == no finalization */
+
+	for (i=f->f_iblock; i>=0; i--) {
+		if (f->f_blockstack[i].b_type != SETUP_LOOP)
+			/* any block type besides a loop requires cleanup */
+			return 1;
+	}
+
+	/* No blocks except loops, it's safe to skip finalization */
+	return 0;
+}
diff --git a/Python/ceval.c b/Python/ceval.c
index cc1eb97..6302ede 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2179,6 +2179,9 @@
 		case SETUP_LOOP:
 		case SETUP_EXCEPT:
 		case SETUP_FINALLY:
+			/* NOTE: If you add any new block-setup opcodes that are not try/except/finally
+			   handlers, you may need to update the PyGen_NeedsFinalizing() function. */
+
 			PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
 					   STACK_LEVEL());
 			continue;