+
+ return vmg_cb_call1(w->cb_clear, flags, sv, mg->mg_obj);
+}
+
+#define vmg_svt_clear_noop vmg_svt_default_noop
+
+/* ... free magic .......................................................... */
+
+#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
+
+static OP *vmg_pp_propagate_errsv(pTHX) {
+ SVOP *o = cSVOPx(PL_op);
+
+ if (o->op_sv) {
+ sv_setsv(ERRSV, o->op_sv);
+ SvREFCNT_dec(o->op_sv);
+ o->op_sv = NULL;
+ }
+
+ return NORMAL;
+}
+
+#endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
+
+static int vmg_propagate_errsv_free(pTHX_ SV *sv, MAGIC *mg) {
+ if (mg->mg_obj)
+ sv_setsv(ERRSV, mg->mg_obj);
+
+ return 0;
+}
+
+/* perl is already kind enough to handle the cloning of the mg_obj member,
+ hence we don't need to define a dup magic callback. */
+
+static MGVTBL vmg_propagate_errsv_vtbl = {
+ 0, /* get */
+ 0, /* set */
+ 0, /* len */
+ 0, /* clear */
+ vmg_propagate_errsv_free, /* free */
+ 0, /* copy */
+ 0, /* dup */
+#if MGf_LOCAL
+ 0, /* local */
+#endif /* MGf_LOCAL */
+};
+
+typedef struct {
+ SV *sv;
+ int in_eval;
+ I32 base;
+} vmg_svt_free_cleanup_ud;
+
+static int vmg_svt_free_cleanup(pTHX_ void *ud_) {
+ vmg_svt_free_cleanup_ud *ud = VOID2(vmg_svt_free_cleanup_ud *, ud_);
+
+ if (ud->in_eval) {
+ U32 optype = PL_op ? PL_op->op_type : OP_NULL;
+
+ if (optype == OP_LEAVETRY || optype == OP_LEAVEEVAL) {
+ SV *errsv = newSVsv(ERRSV);
+
+ FREETMPS;
+ LEAVE_SCOPE(ud->base);
+
+#if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
+ if (optype == OP_LEAVETRY) {
+ dXSH_CXT;
+ PL_op = vmg_trampoline_bump(&XSH_CXT.propagate_errsv, errsv, PL_op);
+ } else if (optype == OP_LEAVEEVAL) {
+ SV *guard = sv_newmortal();
+ vmg_sv_magicext(guard, errsv, &vmg_propagate_errsv_vtbl, NULL, 0);
+ }
+#else /* !VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
+# if !XSH_HAS_PERL(5, 8, 9)
+ {
+ SV *guard = sv_newmortal();
+ vmg_sv_magicext(guard, errsv, &vmg_propagate_errsv_vtbl, NULL, 0);
+ }
+# else
+ vmg_sv_magicext(ERRSV, errsv, &vmg_propagate_errsv_vtbl, NULL, 0);
+# endif
+#endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
+
+ SAVETMPS;
+ }
+
+ /* Don't propagate */
+ return 0;
+ } else {
+ SV *sv = ud->sv;
+ MAGIC *mg;
+
+ /* We are about to croak() while sv is being destroyed. Try to clean up
+ * things a bit. */
+ mg = SvMAGIC(sv);
+ if (mg) {
+ vmg_mg_del(sv, NULL, mg, mg->mg_moremagic);
+ mg_magical(sv);
+ }
+ SvREFCNT_dec(sv);
+
+ vmg_dispell_guard_oncroak(aTHX_ NULL);
+
+ /* After that, propagate the error upwards. */
+ return 1;
+ }
+}
+
+static int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
+ vmg_svt_free_cleanup_ud ud;
+ const vmg_wizard *w;