// Tests for providing new default operations. #include #include exception log_message { char * msg; }; // Manually define the virtual table and helper functions. void copy(log_message * this, log_message * that) { *this = *that; } const char * msg(log_message * this) { return this->msg; } const struct log_message_vtable log_vt @= { .__cfavir_typeid = &__cfatid_log_message, .size = sizeof(struct log_message), .copy = copy, .^?{} = ^?{}, .msg = msg, }; // Logging messages don't have to be handled. void defaultResumptionHandler(log_message &) {} // And should never be used to terminate computation. void defaultTerminationHandler(log_message &) = void; void log_test(void) { // We can catch log: try { throwResume (log_message){&log_vt, "Should be printed.\n"}; } catchResume (log_message * this) { sout | this->virtual_table->msg(this) | nonl; } // But we don't have to: throwResume (log_message){&log_vt, "Should not be printed.\n"}; } // I don't have a good use case for doing the same with termination. exception jump {}; void defaultTerminationHandler(jump &) { sout | "jump default handler."; } vtable(jump) jump_vt; void jump_test(void) { try { throw (jump){&jump_vt}; } catch (jump * this) { sout | "jump catch handler."; } throw (jump){&jump_vt}; } exception first {}; vtable(first) first_vt; exception unhandled_exception {}; vtable(unhandled_exception) unhandled_vt; void unhandled_test(void) { forall(T &, V & | is_exception(T, V)) void defaultTerminationHandler(T &) { throw (unhandled_exception){&unhandled_vt}; } void defaultTerminationHandler(unhandled_exception &) { abort(); } try { throw (first){&first_vt}; } catch (unhandled_exception * t) { sout | "Catch unhandled_exception."; } } exception second {}; vtable(second) second_vt; void cross_test(void) { void defaultTerminationHandler(first &) { sout | "cross terminate default"; throw (second){&second_vt}; } void defaultResumptionHandler(first &) { sout | "cross resume default"; throwResume (second){&second_vt}; } try { sout | "cross terminate throw"; throw (first){&first_vt}; } catch (second *) { sout | "cross terminate catch"; } try { sout | "cross resume throw"; throwResume (first){&first_vt}; } catchResume (second *) { sout | "cross resume catch"; } } int main(int argc, char * argv[]) { log_test(); jump_test(); unhandled_test(); cross_test(); }