From 755065ad38df0daca7bad2d4ce88adb1684fc025 Mon Sep 17 00:00:00 2001 From: Botond Baranyi <botond.baranyi@ericsson.com> Date: Thu, 29 Apr 2021 17:27:32 +0200 Subject: [PATCH] OOP: catching exceptions of class type is now determined by the dynamic class type, instead of the static type raised (issue #533) Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com> --- compiler2/ttcn3/AST_ttcn3.cc | 15 ++++- compiler2/ttcn3/Statement.cc | 53 +++++++-------- core/OOP.hh | 101 +++++++++++++++++++--------- regression_test/oop/exceptions.ttcn | 8 ++- 4 files changed, 113 insertions(+), 64 deletions(-) diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 647b8cb2a..346949a69 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -5578,9 +5578,18 @@ namespace Ttcn { char* Def_Exception::generate_code_str(char *str) { - return usage_found ? mputprintf(str, "EXCEPTION< %s >& %s = static_cast<EXCEPTION< %s >&>(exc_base);\n", - type->get_genname_value(my_scope).c_str(), id->get_name().c_str(), type->get_genname_value(my_scope).c_str()) : - str; + if (!usage_found) { + return str; + } + Common::Type* type_last = type->get_type_refd_last(); + if (type_last->get_typetype() == Common::Type::T_CLASS) { + ClassTypeBody* class_ = type_last->get_class_type_body(); + string class_name = class_->is_built_in() ? string("OBJECT") : type_last->get_genname_own(my_scope); + return mputprintf(str, "CLASS_EXCEPTION<%s> %s(exc_base.get_object_ref().cast_to_dyn<%s>());\n", + class_name.c_str(), id->get_name().c_str(), class_name.c_str()); + } + return mputprintf(str, "NON_CLASS_EXCEPTION<%s>& %s = static_cast<NON_CLASS_EXCEPTION<%s>&>(exc_base);\n", + type->get_genname_value(my_scope).c_str(), id->get_name().c_str(), type->get_genname_value(my_scope).c_str()); } // ================================= diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 5622e8b44..dec16d6ce 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -594,7 +594,7 @@ namespace Ttcn { // C++11 version: string tmp_id = get_scope_mod_gen()->get_temporary_id(); str = mputprintf(str, - "FINALLY %s([&] {\n", tmp_id.c_str()); + "FINALLY_CPP11 %s([&] {\n", tmp_id.c_str()); str = finally_block->generate_code(str, def_glob_vars, src_glob_vars); str = mputstr(str, "});\n"); #endif @@ -630,9 +630,18 @@ namespace Ttcn { "catch (EXCEPTION_BASE& exc_base) {\n"); for (size_t i = 0; i < catch_blocks.size(); ++i) { Type* exc_type = catch_blocks[i]->get_stmt_byIndex(0)->get_def()->get_Type(); - str = mputprintf(str, - "%sif (exc_base.has_type(\"%s\")) {\n", - i > 0 ? "else " : "", exc_type->get_exception_name().c_str()); + Type* exc_type_last = exc_type->get_type_refd_last(); + if (exc_type_last->get_typetype() == Common::Type::T_CLASS) { + ClassTypeBody* class_ = exc_type_last->get_class_type_body(); + str = mputprintf(str, + "%sif (exc_base.is_class() && dynamic_cast<%s*>(exc_base.get_object()) != NULL) {\n", + i > 0 ? "else " : "", class_->is_built_in() ? "OBJECT" : exc_type_last->get_genname_own(this).c_str()); + } + else { + str = mputprintf(str, + "%sif (exc_base.is_type(\"%s\")) {\n", + i > 0 ? "else " : "", exc_type->get_exception_name().c_str()); + } str = catch_blocks[i]->generate_code(str, def_glob_vars, src_glob_vars, alt_guards); str = mputstr(str, "}\n"); } @@ -8742,32 +8751,18 @@ error: str = mputstr(str, expr.preamble); } Common::Type* exc_type = raise_op.v->get_expr_governor(Common::Type::EXPECTED_DYNAMIC_VALUE); + Common::Type* exc_type_last = exc_type->get_type_refd_last(); string exc_type_str = exc_type->get_genname_value(my_sb); - string id_str = my_sb->get_scope_mod_gen()->get_temporary_id(); - bool is_class = exc_type->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS; - // the EXCEPTION class stores all the superclasses of the class type, too, since those - // can also catch this type of exception - int nof_exc_types = 1; - Type* t; - if (is_class) { - t = exc_type; - while (t != NULL) { - ++nof_exc_types; - t = t->get_type_refd_last()->get_class_type_body()->get_base_type(); - } - } - str = mputprintf(str, "const char** %s = new const char*[%i];\n", - id_str.c_str(), nof_exc_types); - t = exc_type; - for (int i = 0; i < nof_exc_types; ++i) { - if (i > 0) { - t = t->get_type_refd_last()->get_class_type_body()->get_base_type(); - } - str = mputprintf(str, "%s[%i] = \"%s\";\n", - id_str.c_str(), i, t != NULL ? t->get_exception_name().c_str() : "object"); - } - str = mputprintf(str, "throw EXCEPTION< %s >(new %s(%s), %s, %i);\n", - exc_type_str.c_str(), exc_type_str.c_str(), expr.expr, id_str.c_str(), nof_exc_types); + if (exc_type_last->get_typetype() == Common::Type::T_CLASS) { + ClassTypeBody* class_ = exc_type_last->get_class_type_body(); + str = mputprintf(str, "throw CLASS_EXCEPTION<%s>(new %s(%s));\n", + class_->is_built_in() ? "OBJECT" : exc_type_last->get_genname_own(my_sb).c_str(), + exc_type_str.c_str(), expr.expr); + } + else { + str = mputprintf(str, "throw NON_CLASS_EXCEPTION< %s >(new %s(%s), \"%s\");\n", + exc_type_str.c_str(), exc_type_str.c_str(), expr.expr, exc_type->get_exception_name().c_str()); + } if (expr.postamble != NULL) { str = mputstr(str, expr.postamble); } diff --git a/core/OOP.hh b/core/OOP.hh index de12f7c8c..607d4098f 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -208,6 +208,18 @@ public: } return OBJECT_REF<T2>(new_ptr); } + + template<typename T2> + OBJECT_REF<T2>* cast_to_dyn() const { + if (ptr == NULL) { + TTCN_error("Internal error: Casting a null reference"); + } + T2* new_ptr = dynamic_cast<T2*>(ptr); + if (new_ptr == NULL) { + TTCN_error("Internal error: Invalid casting to class type `%s'", T2::class_name()); + } + return new OBJECT_REF<T2>(new_ptr); + } }; template<typename T> @@ -224,73 +236,102 @@ boolean operator!=(null_type, const OBJECT_REF<T>& right_val) { // inequality op // --------- class EXCEPTION_BASE { -private: - const char** exc_types; - size_t nof_types; protected: CHARSTRING exception_log; // this is set by the EXCEPTION class public: - EXCEPTION_BASE(const char** p_exc_types, size_t p_nof_types) - : exc_types(p_exc_types), nof_types(p_nof_types) { } - EXCEPTION_BASE(const EXCEPTION_BASE& p) - : exc_types(new const char*[p.nof_types]), nof_types(p.nof_types), exception_log(p.exception_log) { - for (size_t i = 0; i < nof_types; ++i) { - exc_types[i] = p.exc_types[i]; - } + EXCEPTION_BASE() { } + EXCEPTION_BASE(const EXCEPTION_BASE& p): exception_log(p.exception_log) { } + virtual ~EXCEPTION_BASE() { } + CHARSTRING get_log() const { return exception_log; } + virtual boolean is_class() const { return FALSE; } + virtual boolean is_type(const char* p_type_name) const { return FALSE; } + virtual OBJECT* get_object() const { return NULL; } + virtual OBJECT_REF<OBJECT> get_object_ref() { return OBJECT_REF<OBJECT>(); } +}; + +template<typename T> +class NON_CLASS_EXCEPTION : public EXCEPTION_BASE { +public: + struct exception_struct { + T* val_ptr; + size_t ref_count; + }; +private: + exception_struct* exc_ptr; + const char* type_name; + NON_CLASS_EXCEPTION operator=(const NON_CLASS_EXCEPTION&); // assignment disabled +public: + NON_CLASS_EXCEPTION(T* p_value, const char* p_type_name) + : EXCEPTION_BASE(), exc_ptr(new exception_struct), type_name(p_type_name) { + exc_ptr->val_ptr = p_value; + exc_ptr->ref_count = 1; + exception_log = (TTCN_Logger::begin_event_log2str(), + p_value->log(), TTCN_Logger::end_event_log2str()); } - ~EXCEPTION_BASE() { - delete exc_types; + NON_CLASS_EXCEPTION(const NON_CLASS_EXCEPTION& p) + : EXCEPTION_BASE(p), exc_ptr(p.exc_ptr), type_name(p.type_name) { + ++exc_ptr->ref_count; } - CHARSTRING get_log() const { return exception_log; } - boolean has_type(const char* type_name) const { - for (size_t i = 0; i < nof_types; ++i) { - if (strcmp(exc_types[i], type_name) == 0) { - return TRUE; - } + virtual ~NON_CLASS_EXCEPTION() { + --exc_ptr->ref_count; + if (exc_ptr->ref_count == 0) { + delete exc_ptr->val_ptr; + delete exc_ptr; } - return FALSE; + } + T& operator()() { return *exc_ptr->val_ptr; } + virtual boolean is_type(const char* p_type_name) const { + return strcmp(p_type_name, type_name) == 0; } }; template<typename T> -class EXCEPTION : public EXCEPTION_BASE { +class CLASS_EXCEPTION : public EXCEPTION_BASE { public: struct exception_struct { - T* val_ptr; + OBJECT_REF<T>* val_ptr; size_t ref_count; }; private: exception_struct* exc_ptr; - EXCEPTION operator=(const EXCEPTION&); // assignment disabled + CLASS_EXCEPTION operator=(const CLASS_EXCEPTION&); // assignment disabled public: - EXCEPTION(T* p_value, const char** p_exc_types, size_t p_nof_types) - : EXCEPTION_BASE(p_exc_types, p_nof_types), exc_ptr(new exception_struct) { + CLASS_EXCEPTION(OBJECT_REF<T>* p_value) + : EXCEPTION_BASE(), exc_ptr(new exception_struct) { exc_ptr->val_ptr = p_value; exc_ptr->ref_count = 1; exception_log = (TTCN_Logger::begin_event_log2str(), p_value->log(), TTCN_Logger::end_event_log2str()); } - EXCEPTION(const EXCEPTION& p) + CLASS_EXCEPTION(const CLASS_EXCEPTION& p) : EXCEPTION_BASE(p), exc_ptr(p.exc_ptr) { ++exc_ptr->ref_count; } - ~EXCEPTION() { + virtual ~CLASS_EXCEPTION() { --exc_ptr->ref_count; if (exc_ptr->ref_count == 0) { delete exc_ptr->val_ptr; delete exc_ptr; } } - T& operator()() { return *exc_ptr->val_ptr; } + OBJECT_REF<T>& operator()() { return *exc_ptr->val_ptr; } + virtual boolean is_class() const { return TRUE; } + virtual OBJECT* get_object() const { + return **exc_ptr->val_ptr; + } + virtual OBJECT_REF<OBJECT> get_object_ref() { + return exc_ptr->val_ptr->template cast_to<OBJECT>(); + } }; + #if __cplusplus >= 201103L -class FINALLY +class FINALLY_CPP11 { std::function<void(void)> functor; public: - FINALLY(const std::function<void(void)> &p_functor) : functor(p_functor) {} - ~FINALLY() + FINALLY_CPP11(const std::function<void(void)> &p_functor) : functor(p_functor) {} + ~FINALLY_CPP11() { try { functor(); diff --git a/regression_test/oop/exceptions.ttcn b/regression_test/oop/exceptions.ttcn index 2a6319a4c..61ef81d7e 100644 --- a/regression_test/oop/exceptions.ttcn +++ b/regression_test/oop/exceptions.ttcn @@ -76,6 +76,10 @@ function test_block(in integer p_exception_type, in charstring p_dummy := "a") r case (8) { raise Class2.create; } + case (9) { + var object x := Class.create(); + raise x; + } } // otherwise don't raise anything } @@ -129,12 +133,12 @@ function test_block(in integer p_exception_type, in charstring p_dummy := "a") r } testcase tc_exceptions_block() runs on CT { - for (var integer i := 1; i <= 8; i := i + 1) { + for (var integer i := 1; i <= 9; i := i + 1) { test_block(i); } test_block(200); - if (cv_finally_counter != 9) { + if (cv_finally_counter != 10) { setverdict(fail, "Invalid 'finally' execution count: ", cv_finally_counter); } } -- GitLab