diff --git a/compiler2/SigParam.cc b/compiler2/SigParam.cc index 148920d04686e1a43c90e8fd361cfe169d83c40e..702e5a1f4e6e54d590e724fade302cb24d580464 100644 --- a/compiler2/SigParam.cc +++ b/compiler2/SigParam.cc @@ -14,6 +14,7 @@ #include "Type.hh" #include "CompilerError.hh" +#include "AST.hh" namespace Common { @@ -251,6 +252,47 @@ void SignatureExceptions::chk(Type *p_signature) } } +void SignatureExceptions::chk(Assignment* p_def) +{ + Error_Context cntxt(this, "In exception list"); + for (size_t i = 0; i < exc_v.size(); i++) { + Type* type = exc_v[i]; + type->set_genname(p_def->get_id().get_name(), string("_exception_") + Int2string(i + 1)); + type->chk(); + if (type->get_typetype() == Type::T_ERROR) continue; + Type* type_last = type->get_type_refd_last(); + bool type_error = false; + char* error_msg_start = NULL; + switch (type_last->get_typetype()) { + case Type::T_PORT: + type_error = true; + error_msg_start = mprintf("Port type `%s'", type_last->get_typename().c_str()); + break; + case Type::T_SIGNATURE: + type_error = true; + error_msg_start = mprintf("Signature `%s'", type_last->get_typename().c_str()); + break; + case Type::T_DEFAULT: + type_error = true; + error_msg_start = mcopystr("Default type"); + break; + default: + break; + } + if (type_error) { + type->error("%s cannot be on the exception list of a%s %s", + error_msg_start, p_def->get_asstype() == Assignment::A_FUNCTION ? "" : "n", p_def->get_assname()); + } + Free(error_msg_start); + const string& type_name = type->get_exception_name(); + if (exc_m.has_key(type_name)) { + type->error("Duplicate type in exception list"); + exc_m[type_name]->note("Type `%s' is already given here", + type_name.c_str()); + } else exc_m.add(type_name, type); + } +} + void SignatureExceptions::set_fullname(const string& p_fullname) { Node::set_fullname(p_fullname); diff --git a/compiler2/SigParam.hh b/compiler2/SigParam.hh index 91436af4de8daa944ba155d69e5eabea7f9a707a..e518f3c600f3670b41fcce7c6b1c86709d1957d5 100644 --- a/compiler2/SigParam.hh +++ b/compiler2/SigParam.hh @@ -83,7 +83,7 @@ public: }; /** - * Signature exception-list + * Signature or OOP exception-list */ class SignatureExceptions : public Node, public Location { vector<Type> exc_v; @@ -106,7 +106,10 @@ public: Type *get_type_byName(const string& p_typename) const { return exc_m[p_typename]; } + /** Semantic check for a signature exception list */ void chk(Type *p_signature); + /** Semantic check for a function, external function or altstep exception list (as part of the OOP features) */ + void chk(Assignment* p_def); virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope *p_scope); virtual void dump(unsigned level) const; diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index a37e008b8090d021fed183bf5d07a342d6c01275..8d140be73f16725285563e03bab9960ec5aa3dd3 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -47,6 +47,7 @@ #include "../CodeGenHelper.hh" #include "../../common/JSON_Tokenizer.hh" #include "../DebuggerStuff.hh" +#include "../SigParam.hh" #include <limits.h> // implemented in coding_attrib_p.y @@ -5367,21 +5368,27 @@ namespace Ttcn { void Def_Var::chk() { if(checked) return; - Error_Context cntxt(this, "In variable definition `%s'", - id->get_dispname().c_str()); + Error_Context cntxt(this, "In %s definition `%s'", + asstype == A_EXCEPTION ? "exception" : "variable", id->get_dispname().c_str()); type->set_genname(_T_, get_genname()); type->chk(); checked = true; Type *t = type->get_type_refd_last(); switch (t->get_typetype()) { case Type::T_PORT: - error("Variable cannot be defined for port type `%s'", - t->get_fullname().c_str()); + error("%s cannot be defined for port type `%s'", + asstype == A_EXCEPTION ? "Exception" : "Variable", t->get_fullname().c_str()); break; case Type::T_SIGNATURE: - error("Variable cannot be defined for signature `%s'", - t->get_fullname().c_str()); + error("%s cannot be defined for signature `%s'", + asstype == A_EXCEPTION ? "Exception" : "Variable", t->get_fullname().c_str()); break; + case Type::T_DEFAULT: + if (asstype == A_EXCEPTION) { + error("Exception cannot be defined for the default type"); + break; + } + // else fall through default: if (initial_value) { initial_value->set_my_governor(type); @@ -6609,7 +6616,7 @@ namespace Ttcn { Def_Function_Base::Def_Function_Base(const Def_Function_Base& p) : Definition(p), prototype(PROTOTYPE_NONE), input_type(0), output_type(0), - final(p.final) + final(p.final), exceptions(p.exceptions) { fp_list = p.fp_list->clone(); fp_list->set_my_def(this); @@ -6619,11 +6626,13 @@ namespace Ttcn { Def_Function_Base::Def_Function_Base(bool is_external, Identifier *p_id, FormalParList *p_fpl, Type *p_return_type, bool returns_template, - template_restriction_t p_template_restriction, bool p_final) + template_restriction_t p_template_restriction, bool p_final, + Common::SignatureExceptions* p_exceptions) : Definition(determine_asstype(is_external, p_return_type != 0, returns_template), p_id), fp_list(p_fpl), return_type(p_return_type), prototype(PROTOTYPE_NONE), input_type(0), output_type(0), - template_restriction(p_template_restriction), final(p_final) + template_restriction(p_template_restriction), final(p_final), + exceptions(p_exceptions) { if (!p_fpl) FATAL_ERROR("Def_Function_Base::Def_Function_Base()"); fp_list->set_my_def(this); @@ -6634,6 +6643,7 @@ namespace Ttcn { { delete fp_list; delete return_type; + delete exceptions; } void Def_Function_Base::set_fullname(const string& p_fullname) @@ -6641,6 +6651,9 @@ namespace Ttcn { Definition::set_fullname(p_fullname); fp_list->set_fullname(p_fullname + ".<formal_par_list>"); if (return_type) return_type->set_fullname(p_fullname + ".<return_type>"); + if (exceptions != NULL) { + exceptions->set_fullname(p_fullname + ".<exceptions>"); + } } void Def_Function_Base::set_my_scope(Scope *p_scope) @@ -6648,6 +6661,9 @@ namespace Ttcn { Definition::set_my_scope(p_scope); fp_list->set_my_scope(p_scope); if (return_type) return_type->set_my_scope(p_scope); + if (exceptions != NULL) { + exceptions->set_my_scope(p_scope); + } } Type *Def_Function_Base::get_Type() @@ -6837,6 +6853,20 @@ namespace Ttcn { return false; } } + if (exceptions != NULL || p_other->exceptions != NULL) { + if (exceptions == NULL || p_other->exceptions == NULL) { + // one of them has exceptions, the other doesn't + return false; + } + if (exceptions->get_nof_types() != p_other->exceptions->get_nof_types()) { + return false; + } + for (size_t i = 0; i < exceptions->get_nof_types(); ++i) { + if (!p_other->exceptions->has_type(exceptions->get_type_byIndex(i))) { + return false; + } + } + } return true; } @@ -6851,9 +6881,9 @@ namespace Ttcn { Type *p_return_type, bool returns_template, template_restriction_t p_template_restriction, - bool p_final, StatementBlock *p_block) + bool p_final, Common::SignatureExceptions* p_exceptions, StatementBlock *p_block) : Def_Function_Base(false, p_id, p_fpl, p_return_type, returns_template, - p_template_restriction, p_final), + p_template_restriction, p_final, p_exceptions), runs_on_ref(p_runs_on_ref), runs_on_type(0), mtc_ref(p_mtc_ref), mtc_type(0), system_ref(p_system_ref), system_type(0), @@ -7101,6 +7131,9 @@ namespace Ttcn { break; } } + if (exceptions != NULL) { + exceptions->chk(this); + } if (!semantic_check_only) { fp_list->set_genname(get_genname()); block->set_code_section(GovernedSimple::CS_INLINE); @@ -7345,6 +7378,10 @@ namespace Ttcn { DEBUG(level + 1, "Deterministic: %s", deterministic ? "true" : "false"); if (prototype != PROTOTYPE_NONE) DEBUG(level + 1, "Prototype: %s", get_prototype_name()); + if (exceptions != NULL) { + DEBUG(level + 1, "Exceptions:"); + exceptions->dump(level + 2); + } //DEBUG(level + 1, "Statement block:"); block->dump(level + 1); } @@ -7797,6 +7834,13 @@ namespace Ttcn { (Type::CT_JSON != encoding_type && Type::CT_XER != encoding_type))) { error("Attribute 'printing' is only allowed for JSON and XER encoding functions."); } + + if (exceptions != NULL) { + exceptions->chk(this); + if (function_type != EXTFUNC_MANUAL) { + error("Exception list is only allowed for manually written external functions"); + } + } } char *Def_ExtFunction::generate_code_encode(char *str) @@ -8157,6 +8201,10 @@ namespace Ttcn { DEBUG(level + 2, "Encoding options: %s", encoding_options->c_str()); } if (eb_list) eb_list->dump(level + 1); + if (exceptions != NULL) { + DEBUG(level + 1, "Exceptions:"); + exceptions->dump(level + 2); + } } void Def_ExtFunction::generate_json_schema_ref(map<Type*, JSON_Tokenizer>& json_refs) @@ -8312,6 +8360,9 @@ namespace Ttcn { return_type->chk_as_return_type(asstype == A_FUNCTION_RVAL, "n abstract function"); } + if (exceptions != NULL) { + exceptions->chk(this); + } if (!semantic_check_only) { fp_list->set_genname(get_genname()); } @@ -8355,10 +8406,10 @@ namespace Ttcn { Def_Altstep::Def_Altstep(Identifier *p_id, FormalParList *p_fpl, Reference *p_runs_on_ref, Reference *p_mtc_ref, Reference *p_system_ref, StatementBlock *p_sb, - AltGuards *p_ags) + AltGuards *p_ags, Common::SignatureExceptions* p_exceptions) : Definition(A_ALTSTEP, p_id), fp_list(p_fpl), runs_on_ref(p_runs_on_ref), runs_on_type(0), mtc_ref(p_mtc_ref), mtc_type(0), - system_ref(p_system_ref), system_type(0), sb(p_sb), ags(p_ags) + system_ref(p_system_ref), system_type(0), sb(p_sb), ags(p_ags), exceptions(p_exceptions) { if (!p_fpl || !p_sb || !p_ags) FATAL_ERROR("Def_Altstep::Def_Altstep()"); @@ -8376,6 +8427,7 @@ namespace Ttcn { delete system_ref; delete sb; delete ags; + delete exceptions; } Def_Altstep *Def_Altstep::clone() const @@ -8392,6 +8444,9 @@ namespace Ttcn { if (system_ref) system_ref->set_fullname(p_fullname + ".<system_type>"); sb->set_fullname(p_fullname+".<block>"); ags->set_fullname(p_fullname + ".<guards>"); + if (exceptions != NULL) { + exceptions->set_fullname(p_fullname + ".<exceptions>"); + } } void Def_Altstep::set_my_scope(Scope *p_scope) @@ -8406,6 +8461,9 @@ namespace Ttcn { if (system_ref) system_ref->set_my_scope(&bridgeScope); sb->set_my_scope(fp_list); ags->set_my_scope(sb); + if (exceptions != NULL) { + exceptions->set_my_scope(&bridgeScope); + } } Type *Def_Altstep::get_RunsOnType() @@ -8479,6 +8537,9 @@ namespace Ttcn { w_attrib_path->chk_global_attrib(); w_attrib_path->chk_no_qualif(); } + if (exceptions != NULL) { + exceptions->chk(this); + } } void Def_Altstep::generate_code(output_struct *target, bool) @@ -8635,6 +8696,10 @@ namespace Ttcn { DEBUG(level + 1, "System clause:"); system_ref->dump(level + 2); } + if (exceptions != NULL) { + DEBUG(level + 1, "Exceptions:"); + exceptions->dump(level + 2); + } /* DEBUG(level + 1, "Local definitions:"); sb->dump(level + 2); diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index 5f70a1b9337c967b472880eb4e7d5ab9e219db7c..5d6dd9aa371753a40471fd74749815aa2ac2b28b 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -1384,6 +1384,7 @@ namespace Ttcn { /** optional template restriction on return template value */ template_restriction_t template_restriction; bool final; + Common::SignatureExceptions* exceptions; static asstype_t determine_asstype(bool is_external, bool has_return_type, bool returns_template); @@ -1404,7 +1405,8 @@ namespace Ttcn { */ Def_Function_Base(bool is_external, Identifier *p_id, FormalParList *p_fpl, Type *p_return_type, bool returns_template, - template_restriction_t p_template_restriction, bool p_final); + template_restriction_t p_template_restriction, bool p_final, + Common::SignatureExceptions* p_exceptions); virtual ~Def_Function_Base(); virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope *p_scope); @@ -1502,7 +1504,7 @@ namespace Ttcn { Reference *p_system_ref, Reference *p_port_ref, Type *p_return_type, bool returns_template, template_restriction_t p_template_restriction, - bool p_final, StatementBlock *p_block); + bool p_final, Common::SignatureExceptions* p_exceptions, StatementBlock *p_block); virtual ~Def_Function(); virtual Def_Function *clone() const; virtual void set_fullname(const string& p_fullname); @@ -1598,9 +1600,10 @@ namespace Ttcn { */ Def_ExtFunction(bool p_deterministic, Identifier *p_id, FormalParList *p_fpl, Type *p_return_type, bool returns_template, - template_restriction_t p_template_restriction, bool p_final, bool p_ext_keyword) + template_restriction_t p_template_restriction, bool p_final, + Common::SignatureExceptions* p_exceptions, bool p_ext_keyword) : Def_Function_Base(true, p_id, p_fpl, p_return_type, returns_template, - p_template_restriction, p_final), + p_template_restriction, p_final, p_exceptions), function_type(EXTFUNC_MANUAL), encoding_type(Type::CT_UNDEF), encoding_options(0), eb_list(0), printing(0), deterministic(p_deterministic), ext_keyword(p_ext_keyword) { } @@ -1643,9 +1646,9 @@ namespace Ttcn { public: Def_AbsFunction(bool p_deterministic, Identifier* p_id, FormalParList* p_fpl, Type* p_return_type, bool returns_template, - template_restriction_t p_template_restriction) + template_restriction_t p_template_restriction, Common::SignatureExceptions* p_exceptions) : Def_Function_Base(false, p_id, p_fpl, p_return_type, returns_template, - p_template_restriction, false) { } + p_template_restriction, false, p_exceptions) { } virtual ~Def_AbsFunction(); virtual Definition* clone() const; virtual void chk(); @@ -1686,6 +1689,7 @@ namespace Ttcn { Type *system_type; StatementBlock *sb; /**< contains the local definitions */ AltGuards *ags; + Common::SignatureExceptions* exceptions; NameBridgingScope bridgeScope; @@ -1697,7 +1701,7 @@ namespace Ttcn { Def_Altstep(Identifier *p_id, FormalParList *p_fpl, Reference *p_runs_on_ref, Reference *p_mtc_ref, Reference *p_system_ref, StatementBlock *p_sb, - AltGuards *p_ags); + AltGuards *p_ags, Common::SignatureExceptions* p_exceptions); virtual ~Def_Altstep(); virtual Def_Altstep *clone() const; virtual void set_fullname(const string& p_fullname); diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index b606bc4926fd1542e1feca2ced775c4d3524de2a..19661463caa5e9fa8aad53591ec1bec28aa57089 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -283,12 +283,29 @@ namespace Ttcn { p_finally->exception_handling = EH_OOP_FINALLY; finally_block = p_finally; } + + boolean StatementBlock::is_in_finally_block() const + { + if (exception_handling == EH_OOP_FINALLY) { + return TRUE; + } + if (my_sb != NULL) { + return my_sb->is_in_finally_block(); + } + return FALSE; + } + + boolean StatementBlock::is_empty() const + { + return stmts.size() == 0 && exception_handling == StatementBlock::EH_NONE && + catch_blocks.size() == 0 && finally_block == NULL; + } StatementBlock::returnstatus_t StatementBlock::has_return() const { returnstatus_t ret_val = RS_NO; size_t nof_stmts = stmts.size(); - for (size_t i = 0; i < nof_stmts; i++) { + for (size_t i = 0; i < nof_stmts && ret_val != RS_YES; i++) { Statement *stmt = stmts[i]; if (stmt->get_statementtype() == Statement::S_GOTO) { if (stmt->goto_jumps_forward()) { @@ -300,7 +317,7 @@ namespace Ttcn { if (stmt->get_statementtype() == Statement::S_LABEL && stmt->label_is_used()) break; } - } else return RS_YES; + } else ret_val = RS_YES; } else if (stmt->get_statementtype()==Statement::S_BLOCK && stmt->get_block()->exception_handling!=EH_NONE) { switch (stmt->get_block()->exception_handling) { case EH_TRY: // the i-th statement is a try{} statement block, the (i+1)-th must be a catch{} block @@ -311,9 +328,11 @@ namespace Ttcn { if (try_block_rs==catch_block_rs) { switch (try_block_rs) { case RS_YES: - return RS_YES; + ret_val = RS_YES; + break; case RS_MAYBE: ret_val = RS_MAYBE; + break; default: break; } @@ -333,14 +352,28 @@ namespace Ttcn { } else { switch (stmt->has_return()) { case RS_YES: - return RS_YES; + ret_val = RS_YES; + break; case RS_MAYBE: ret_val = RS_MAYBE; + break; default: break; } } } + for (size_t i = 0; i < catch_blocks.size(); ++i) { + // all 'catch' blocks must also have return for the statement block to have return + switch(catch_blocks[i]->has_return()) { + case RS_YES: + break; // OK, keep checking + case RS_MAYBE: + return RS_MAYBE; + case RS_NO: + ret_val = (ret_val == RS_NO) ? RS_NO : RS_MAYBE; + break; + } + } return ret_val; } @@ -418,9 +451,25 @@ namespace Ttcn { } chk_trycatch_blocks(prev_stmt, 0); chk_unused_labels(); + map<string, Definition> catch_types; for (size_t i = 0; i < catch_blocks.size(); ++i) { - catch_blocks[i]->chk(); + if (oop_features) { + catch_blocks[i]->chk(); + Definition* def_exc = catch_blocks[i]->get_stmt_byIndex(0)->get_def(); + string catch_type_str = def_exc->get_Type()->get_exception_name(); + if (catch_types.has_key(catch_type_str)) { + def_exc->error("Duplicate catch block definition for exception type `%s'", catch_type_str.c_str()); + catch_types[catch_type_str]->note("Catch block for the same exception type already defined here"); + } + else { + catch_types.add(catch_type_str, def_exc); + } + } + else { + catch_blocks[i]->error("The compiler option `-k' must be activated to use object-oriented features such as catch clauses."); + } } + catch_types.clear(); if (finally_block != NULL) { finally_block->chk(); } @@ -531,9 +580,14 @@ namespace Ttcn { tmp_id.c_str()); } str = mputprintf(str, - "~%s_finally() {\n", tmp_id.c_str()); + "~%s_finally() {\n" + "try {\n", tmp_id.c_str()); str = finally_block->generate_code(str, def_glob_vars, src_glob_vars); str = mputprintf(str, + "} catch (...) {\n" + "fprintf(stderr, \"Unhandled exception or dynamic test case error in a finally block. Terminating application.\\n\");\n" + "exit(EXIT_FAILURE);\n" + "}\n" "}\n" "};\n" "%s_finally %s%s;\n", @@ -3819,6 +3873,10 @@ error: "It is allowed only in functions and altsteps"); goto error; } + if (my_sb->is_in_finally_block()) { + error("Return statement cannot be used inside a finally block or the destructor of a class."); + goto error; + } switch (my_def->get_asstype()) { case Definition::A_FUNCTION: if (returnexpr.t) { @@ -6353,38 +6411,60 @@ error: void Statement::chk_raise_oop() { Error_Context cntxt(this, "In raise statement"); + if (!oop_features) { + error("The compiler option `-k' must be activated to use object-oriented features such as raise statements."); + } + Definition *my_def = my_sb->get_my_def(); + if (!my_def) { + error("Raise statement cannot be used in the control part. " + "It is allowed only in functions, altsteps and testcases."); + } + if (my_sb->is_in_finally_block()) { + error("Raise statement cannot be used inside a finally block or the destructor of a class."); + } Common::Type* exc_type = raise_op.ti->get_expr_governor(Common::Type::EXPECTED_DYNAMIC_VALUE); if (exc_type == NULL) { raise_op.ti->get_Template()->set_lowerid_to_ref(); exc_type = raise_op.ti->get_expr_governor(Common::Type::EXPECTED_DYNAMIC_VALUE); } if (exc_type == NULL) { - // TODO - } - else { - if (raise_op.ti->get_Type() == exc_type) { - // don't use the type indicator of the TemplateInstance - // (i.e. the 'type:' part of the in-line template) - // as the exception's governor, because it will be deleted - if (exc_type->is_ref()) { - exc_type = exc_type->get_type_refd(); - } - else { - exc_type = Type::get_pooltype(exc_type->get_typetype()); - } + if (raise_op.ti->get_Template()->get_templatetype() != Template::TEMPLATE_ERROR && + (raise_op.ti->get_Template()->get_templatetype() != Template::SPECIFIC_VALUE || + raise_op.ti->get_Template()->get_specific_value()->get_valuetype() != Common::Value::V_ERROR)) { + error("Cannot determine the type of the raised exception."); } - raise_op.ti->chk(exc_type); - if (!raise_op.ti->get_Template()->is_Value()) { - // TODO: error - delete raise_op.ti; - raise_op.v = new Common::Value(Common::Value::V_ERROR); + exc_type = Type::get_pooltype(Type::T_ERROR); + } + switch (exc_type->get_type_refd_last()->get_typetype()) { + case Common::Type::T_DEFAULT: + case Common::Type::T_SIGNATURE: + //case Common::Type::T_PORT: // this case is handled by Template::get_expr_governor + error("Cannot raise an exception of type %s", exc_type->get_typename().c_str()); + break; + default: + break; + } + if (raise_op.ti->get_Type() == exc_type) { + // don't use the type indicator of the TemplateInstance + // (i.e. the 'type:' part of the in-line template) + // as the exception's governor, because it will be deleted + if (exc_type->is_ref()) { + exc_type = exc_type->get_type_refd(); } else { - Common::Value* val = raise_op.ti->get_Template()->get_Value(); - delete raise_op.ti; - raise_op.v = val; + exc_type = Type::get_pooltype(exc_type->get_typetype()); } - // TODO + } + raise_op.ti->chk(exc_type); + if (!raise_op.ti->get_Template()->is_Value()) { + error("A specific value without matching symbols or a reference to a value was expected for a raised exception."); + delete raise_op.ti; + raise_op.v = new Common::Value(Common::Value::V_ERROR); + } + else { + Common::Value* val = raise_op.ti->get_Template()->get_Value(); + delete raise_op.ti; + raise_op.v = val; } raise_op.checked = true; } @@ -7179,7 +7259,7 @@ error: default: FATAL_ERROR("Statement::generate_code_block()"); } - if (block->get_nof_stmts() > 0 || block->get_exception_handling()!=StatementBlock::EH_NONE) { + if (!block->is_empty()) { str = mputstr(str, "{\n"); if (debugger_active) { str = mputstr(str, "TTCN3_Debug_Scope debug_scope;\n"); diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh index 773ee00f3a23fe5127e769cde19f7562573ccefd..b90976b09758477909d620a3253e57f81c697d36 100644 --- a/compiler2/ttcn3/Statement.hh +++ b/compiler2/ttcn3/Statement.hh @@ -132,6 +132,8 @@ namespace Ttcn { void set_my_laic_stmt(AltGuards *p_ags, Statement *p_loop_stmt); void add_catch_block(StatementBlock* p_catch); void set_finally_block(StatementBlock* p_finally); + boolean is_in_finally_block() const; + boolean is_empty() const; returnstatus_t has_return() const; /** Used when generating code for interleaved statement. If has * not recv stmt, then the general code generation can be used diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 8934d5563e80af882d9230107c9276e89bcd901e..32c3d9255bcf156905cabc3220b3b2b62e631818 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3081,6 +3081,9 @@ namespace Ttcn { if (members == NULL) { FATAL_ERROR("ClassTypeBody::ClassTypeBody"); } + if (finally_block != NULL) { + finally_block->set_exception_handling(StatementBlock::EH_OOP_FINALLY); + } } ClassTypeBody::ClassTypeBody() @@ -3663,6 +3666,7 @@ namespace Ttcn { } if (finally_block != NULL) { + Error_Context cntxt(finally_block, "In class destructor"); finally_block->chk(); } @@ -3886,7 +3890,7 @@ namespace Ttcn { local_struct->source.methods = mputprintf(local_struct->source.methods, "} catch (...) {\n" "fprintf(stderr, \"Unhandled exception or dynamic test case error in " - "destructor of class `%s'\");\n" + "the destructor of class `%s'. Terminating application.\\n\");\n" "exit(EXIT_FAILURE);\n" "}\n" "}\n\n", class_id->get_name().c_str()); diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 8601873c1918ce61a81b941e664c800f65164bd2..42954a696f6cc14ff9b8733e55d55dbd4a302d73 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -3681,34 +3681,34 @@ ClassMember: ClassFunctionDef: FunctionKeyword optFinalModifier optDeterministicModifier IDentifier '(' optFunctionFormalParList ')' - optReturnType optError StatementBlock + optReturnType optExceptionSpec optError StatementBlock { $$ = new Def_Function($3, $4, $6, NULL, NULL, NULL, NULL, $8.type, - $8.returns_template, $8.template_restriction, $2, $10); + $8.returns_template, $8.template_restriction, $2, $9, $11); $$->set_location(infile, @$); } | FunctionKeyword optFinalModifier AbstractKeyword optDeterministicModifier IDentifier '(' optFunctionFormalParList ')' - optReturnType optError + optReturnType optExceptionSpec optError { $$ = new Def_AbsFunction($4, $5, $7, $9.type, $9.returns_template, - $9.template_restriction); + $9.template_restriction, $10); $$->set_location(infile, @$); } | ExtKeyword FunctionKeyword optFinalModifier optDeterministicModifier IDentifier '(' optFunctionFormalParList ')' - optReturnType + optReturnType optExceptionSpec { $$ = new Def_ExtFunction($4, $5, $7, $9.type, $9.returns_template, - $9.template_restriction, $3, true); + $9.template_restriction, $3, $10, true); $$->set_location(infile, @$); } | FunctionKeyword optFinalModifier optDeterministicModifier IDentifier '(' optFunctionFormalParList ')' - optReturnType + optReturnType optExceptionSpec { $$ = new Def_ExtFunction($3, $4, $6, $8.type, $8.returns_template, - $8.template_restriction, $2, false); + $8.template_restriction, $2, $9, false); $$->set_location(infile, @$); } ; @@ -4578,11 +4578,11 @@ ValueofOp: // 162 FunctionDef: // 164 FunctionKeyword optDeterministicModifier IDentifier '(' optFunctionFormalParList ')' - optRunsOnSpec AltOrTcConfigSpec optPortSpec optReturnType optError StatementBlock + optRunsOnSpec AltOrTcConfigSpec optPortSpec optReturnType optExceptionSpec optError StatementBlock { $5->set_location(infile, @4, @6); $$ = new Def_Function($2, $3, $5, $7, $8.mtcref, $8.systemref, $9, $10.type, $10.returns_template, - $10.template_restriction, false, $12); + $10.template_restriction, false, $11, $13); $$->set_location(infile, @$); } ; @@ -5232,25 +5232,25 @@ TestcaseActualPar: AltstepDef: // 211 AltstepKeyword IDentifier '(' optAltstepFormalParList ')' optRunsOnSpec - AltOrTcConfigSpec optError '{' AltstepLocalDefList AltGuardList optError '}' + AltOrTcConfigSpec optExceptionSpec optError '{' AltstepLocalDefList AltGuardList optError '}' optCatchBlockList optFinallyDef { StatementBlock *sb = new StatementBlock; - for (size_t i = 0; i < $10.nElements; i++) { - Statement *stmt = new Statement(Statement::S_DEF, $10.elements[i]); - stmt->set_location(*$10.elements[i]); + for (size_t i = 0; i < $11.nElements; i++) { + Statement *stmt = new Statement(Statement::S_DEF, $11.elements[i]); + stmt->set_location(*$11.elements[i]); sb->add_stmt(stmt); } - Free($10.elements); - for (size_t i = 0; i < $14.nElements; ++i) { - sb->add_catch_block($14.elements[i]); + Free($11.elements); + for (size_t i = 0; i < $15.nElements; ++i) { + sb->add_catch_block($15.elements[i]); } - Free($14.elements); - if ($15 != NULL) { - sb->set_finally_block($15); + Free($15.elements); + if ($16 != NULL) { + sb->set_finally_block($16); } $4->set_location(infile, @4); - $$ = new Def_Altstep($2, $4, $6, $7.mtcref, $7.systemref, sb, $11); + $$ = new Def_Altstep($2, $4, $6, $7.mtcref, $7.systemref, sb, $12, $8); $$->set_location(infile, @$); } ; @@ -5733,11 +5733,11 @@ GroupIdentifier: // 274 (followed by) 275. ExtFunctionDef: // 276 ExtKeyword FunctionKeyword optDeterministicModifier IDentifier - '(' optFunctionFormalParList ')' optReturnType + '(' optFunctionFormalParList ')' optReturnType optExceptionSpec { $6->set_location(infile, @5, @7); $$ = new Def_ExtFunction($3, $4, $6, $8.type, $8.returns_template, - $8.template_restriction, false, true); + $8.template_restriction, false, $9, true); $$->set_location(infile, @$); } ; diff --git a/core/OOP.hh b/core/OOP.hh index 2d11e25f86b6474bbdb918d078bf0139ef89291f..de12f7c8c49753cc2ca1452baf5ed9a8d6755e0b 100644 --- a/core/OOP.hh +++ b/core/OOP.hh @@ -292,7 +292,13 @@ public: FINALLY(const std::function<void(void)> &p_functor) : functor(p_functor) {} ~FINALLY() { - functor(); + try { + functor(); + } + catch (...) { + fprintf(stderr, "Unhandled exception or dynamic test case error in a finally block. Terminating application.\n"); + exit(EXIT_FAILURE); + } } }; #endif // C++11 diff --git a/function_test/Makefile b/function_test/Makefile index bef0203ef8bc77714eaae619e89e0cdaf3cc7d5b..af8d1b1f27d3923503e326fb731f85bb5f067423 100644 --- a/function_test/Makefile +++ b/function_test/Makefile @@ -17,7 +17,7 @@ # ############################################################################## # Makefile to run the non-interactive tests -DIRS := Semantic_Analyser Semantic_Analyser_Csaba Config_Parser +DIRS := Semantic_Analyser Semantic_Analyser_Csaba Config_Parser OOP SCRIPTFLAGS := @@ -93,6 +93,9 @@ Semantic_Analyser_Csaba: Config_Parser: cd $@; if [ ! -f perl ] ; then ln -s `which perl` perl; fi; ./run_test $(SCRIPTFLAGS) + +OOP: + cd $@; if [ ! -f perl ] ; then ln -s `which perl` perl; fi; ./run_test $(SCRIPTFLAGS) profile: $(DIRS) make all diff --git a/function_test/OOP/.gitignore b/function_test/OOP/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9be6a06c3f1ab53b46e99da8f5f44e0705ca9923 --- /dev/null +++ b/function_test/OOP/.gitignore @@ -0,0 +1,9 @@ +*.report +compile +core +Temp* +*.gcda +*.gcno +Makefile +perl +perl.lnk diff --git a/function_test/OOP/NonOOP_negtest.script b/function_test/OOP/NonOOP_negtest.script new file mode 100644 index 0000000000000000000000000000000000000000..86d233c282113200502eb5c747bf784f1e5fafee --- /dev/null +++ b/function_test/OOP/NonOOP_negtest.script @@ -0,0 +1,112 @@ +.****************************************************************************** +.* Copyright (c) 2000-2021 Ericsson Telecom AB +.* All rights reserved. This program and the accompanying materials +.* are made available under the terms of the Eclipse Public License v2.0 +.* which accompanies this distribution, and is available at +.* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +.* +.* Contributors: +.* Baranyi, Botond +.* +.******************************************************************************/ +:text. +:lang eng. +.*---------------------------------------------------------------------* +:h1.Test cases +.*---------------------------------------------------------------------* +.*---------------------------------------------------------------------* +:h3.Raise and catch without '-k' flag +.*---------------------------------------------------------------------* +:xmp tab=0. + +<TC - Raise and catch without '-k' flag> + +<COMPILE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +type component CT { + var integer counter := 0; + timer tmr; +} + +function f() runs on CT return integer { + counter := counter + 1; + return counter; +} + +altstep as() runs on CT { + var integer local := f(); + [] tmr.timeout { log(counter); raise 3; } +} + +testcase tc() runs on CT { + tmr.start(2.0); + alt { + [] as(); + } +} +catch (integer x) { + log(x); +} + +control { + execute(tc()); +} + +} +<END_MODULE> +<RESULT> +The compiler option `-k' must be activated to use object-oriented features such as raise statements. +<END_RESULT> +<RESULT> +The compiler option `-k' must be activated to use object-oriented features such as catch clauses. +<END_RESULT> +<END_TC> + +:exmp. + +.*---------------------------------------------------------------------* +:h3.Class and finally without '-k' flag +.*---------------------------------------------------------------------* +.Note: 'class' and 'finally' are treated as keywords by the parser and a warning +.is issued for both. The actual parsing error is caused by the parser interpreting +.a class definition as a type alias definition for a type called 'class'. +:xmp tab=0. + +<TC - Class and finally without '-k' flag> + +<COMPILE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +type class MyClass { + var integer m_int; + public function get_int() return integer { return m_int; } + public function set_int(integer p_int) { m_int := p_int; } +} + +type component CT { } + +function f() { } +finally { + log("finally"); +} + +} +<END_MODULE> +<RESULT> +Keyword 'class' is treated as an identifier. Activate compiler option '-k' to use object-oriented features. +<END_RESULT> +<RESULT> +at or before token `var': syntax error, unexpected VarKeyword, expecting '\{' +<END_RESULT> +<RESULT> +Keyword 'finally' is treated as an identifier. Activate compiler option '-k' to use object-oriented features. +<END_RESULT> +<END_TC> + +:exmp. + +:etext. + diff --git a/function_test/OOP/OOP_negtest.script b/function_test/OOP/OOP_negtest.script new file mode 100644 index 0000000000000000000000000000000000000000..ee18c91841fa5a53ced37837abd57b6b132951d3 --- /dev/null +++ b/function_test/OOP/OOP_negtest.script @@ -0,0 +1,230 @@ +.****************************************************************************** +.* Copyright (c) 2000-2021 Ericsson Telecom AB +.* All rights reserved. This program and the accompanying materials +.* are made available under the terms of the Eclipse Public License v2.0 +.* which accompanies this distribution, and is available at +.* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +.* +.* Contributors: +.* Baranyi, Botond +.* +.******************************************************************************/ +:text. +:lang eng. +.*---------------------------------------------------------------------* +:h1.Test cases +.*---------------------------------------------------------------------* +.*---------------------------------------------------------------------* +:h3.Unhandled exception +.*---------------------------------------------------------------------* +:xmp tab=0. + +<TC - Unhandled exception> + +<EXECUTE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +type component CT {} + +testcase tc() runs on CT { + raise 1; +} + +control { + execute (tc()); +} + +} +<END_MODULE> +<MODULE CFG Temp Temp.cfg> +[EXECUTE] +Temp +<END_MODULE> +<RESULT> +Unhandled exception: 1 +<END_RESULT> +<END_TC> + +:exmp. + +.*---------------------------------------------------------------------* +:h3.Exception in the destructor +.*---------------------------------------------------------------------* +.Note: This test causes memory leaks, because the test executor terminates prematurely. +:xmp tab=0. + +<TC - Exception in the destructor> + +<EXECUTE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +function f() { + raise 1; +} + +type class C { } +finally { + f(); +} + +type component CT {} + +testcase tc() runs on CT { + var C x := C.create; +} + +control { + execute(tc()); +} + +} +<END_MODULE> +<MODULE CFG Temp Temp.cfg> +[EXECUTE] +Temp +<END_MODULE> +<RESULT> +Unhandled exception or dynamic test case error in the destructor of class `C'. Terminating application. +<END_RESULT> +<END_TC> + +:exmp. + +.*---------------------------------------------------------------------* +:h3.DTE in the destructor +.*---------------------------------------------------------------------* +.Note: This test causes memory leaks, because the test executor terminates prematurely. +:xmp tab=0. + +<TC - DTE in the destructor> + +<EXECUTE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +function f() { + var integer x := 0; + var integer y := 1 / x; +} + +type class C { } +finally { + f(); +} + +type component CT {} + +testcase tc() runs on CT { + var C x := C.create; +} + +control { + execute(tc()); +} + +} +<END_MODULE> +<MODULE CFG Temp Temp.cfg> +[EXECUTE] +Temp +<END_MODULE> +<RESULT> +Unhandled exception or dynamic test case error in the destructor of class `C'. Terminating application. +<END_RESULT> +<END_TC> + +:exmp. + +.*---------------------------------------------------------------------* +:h3.Exception in the finally block +.*---------------------------------------------------------------------* +.Note: This test causes memory leaks, because the test executor terminates prematurely. +:xmp tab=0. + +<TC - Exception in the finally block> + +<EXECUTE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +function f() { + raise 1; +} + +type component CT {} + +testcase tc() runs on CT { + { + } + finally { + f(); + } +} + + +control { + execute(tc()); +} + +} +<END_MODULE> +<MODULE CFG Temp Temp.cfg> +[EXECUTE] +Temp +<END_MODULE> +<RESULT> +Unhandled exception or dynamic test case error in a finally block. Terminating application. +<END_RESULT> +<END_TC> + +:exmp. + +.*---------------------------------------------------------------------* +:h3.DTE in the finally block +.*---------------------------------------------------------------------* +.Note: This test causes memory leaks, because the test executor terminates prematurely. +:xmp tab=0. + +<TC - DTE in the finally block> + +<EXECUTE> +<MODULE TTCN Temp Temp.ttcn> +module Temp { + +function f() { + var integer x := 0; + var integer y := 1 / x; +} + +type component CT {} + +testcase tc() runs on CT { + { + } + finally { + f(); + } +} + + +control { + execute(tc()); +} + +} +<END_MODULE> +<MODULE CFG Temp Temp.cfg> +[EXECUTE] +Temp +<END_MODULE> +<RESULT> +Unhandled exception or dynamic test case error in a finally block. Terminating application. +<END_RESULT> +<END_TC> + +:exmp. + +:etext. + diff --git a/function_test/OOP/run_test b/function_test/OOP/run_test new file mode 100755 index 0000000000000000000000000000000000000000..7474b517f738242c395891d3ea2c3de2745ff0b6 --- /dev/null +++ b/function_test/OOP/run_test @@ -0,0 +1,24 @@ +#!/bin/bash + +SCRIPTFLAGS= +while [ $# -gt 0 ]; do +case $1 in +"-coverage") SCRIPTFLAGS+=" -coverage"; shift 1 ;; +"-rt2") SCRIPTFLAGS=" -rt2"; shift 1 ;; +*) echo "Usage: $0 [-rt2] [-coverage]"; exit 1 ;; +esac +done + +echo "Batch execution of OOP tests: creating 1 report for each script file" +echo "You must have a symlink in this directory named perl and pointing to perl 5.6.0 or higher" + +# OOP_negtest needs to be run with OOP enabled ('-k' flag) and memory leaks need to be ignored +echo "./perl ../Tools/SAtester.pl $SCRIPTFLAGS -oop -imemleaks -log OOP_negtest.report OOP_negtest.script" +./perl ../Tools/SAtester.pl $SCRIPTFLAGS -oop -imemleaks -log OOP_negtest.report OOP_negtest.script + +# NonOOP_negtest needs to be run with OOP disabled (no '-k' flag) +echo "./perl ../Tools/SAtester.pl $SCRIPTFLAGS -log NonOOP_negtest.report NonOOP_negtest.script" +./perl ../Tools/SAtester.pl $SCRIPTFLAGS -log NonOOP_negtest.report NonOOP_negtest.script + +echo "Finished. Reports are generated with .report extension." + diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index b5a49e641ad9697a8633d0b3d7b34accd6825637..02872e813e5366e06481b60de24699fa607b03e6 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -15,6 +15,7 @@ module oop_SE { //^In TTCN-3 module// type component Comp { var integer cv_comp; const integer cc_comp := -1; + timer c_timer; } type port Port message { @@ -29,8 +30,23 @@ type record Rec { charstring str } +type record of integer RoI; + +type union Uni { + integer i, + float f +} + +signature Sig(inout integer p); + +type integer SmallNumber (-100..100); + +type enumerated Enum { E1, E2, E3 }; + const integer c := 3; +template integer t := 4; + type class C0 { } type class C1 extends Nonexistent { } //^In type definition// //^In superclass definition// //There is no local or imported definition with name `Nonexistent'// @@ -550,8 +566,99 @@ function f_aliases() { } +function f_exception1(in integer p) return integer exception(integer, charstring, Rec, C0) { return p; } +function f_exception2() exception(boolean, verdicttype, integer, SmallNumber, RoI, Uni, anytype, Comp, RoI[-], Rec.num, Uni.i, Enum) { } +external function ef_exception1(in integer p) return integer exception(integer, charstring, Rec, C0); +altstep a_exception1(in integer p) runs on Comp exception(integer, charstring, Rec, C0) { + [] c_timer.timeout { } +} + +function f_exception3() //^In function definition// + exception (float, //^In exception list// + default, //Default type cannot be on the exception list of a function// + bitstring, + Port, //Port type `@oop_SE.Port' cannot be on the exception list of a function// + hexstring, + Sig, //Signature `@oop_SE.Sig' cannot be on the exception list of a function// + octetstring) { } +external function ef_exception2() //^In external function definition// + exception (universal charstring, //^In exception list// //Type `universal charstring' is already given here// + integer, + universal charstring); //Duplicate type in exception list// + + +function f_raise(in integer p, inout template integer p2) runs on CT_Mtc { //^In function definition// //Previous definition with identifier `p' in higher scope unit is here// + if (p == 0) { raise 3; } + if (p == 1) { raise Enum: E2; } + if (p == 2) { raise int2char(p + 1); } + if (p == 3) { raise omit; } //^In if statement// //^In raise statement// //Cannot determine the type of the raised exception.// + if (p == 4) { raise null; } //^In if statement// //^In raise statement// //Cannot determine the type of the raised exception.// + if (p == 5) { raise pattern "ab?c"; } //^In if statement// //^In raise statement// //A specific value without matching symbols or a reference to a value was expected for a raised exception.// + var default def := null; + if (p == 6) { raise def; } //^In if statement// //^In raise statement// //Cannot raise an exception of type default// + if (p == 7) { raise Sig: { p }; } //^In if statement// //^In raise statement// //Cannot raise an exception of type @oop_SE.Sig// + if (p == 8) { raise pt; } //^In if statement// //^In raise statement// //Reference to a value was expected instead of port `@oop_SE.CT_Mtc.pt'// + var template charstring vt := ? length (3); + if (p == 9) { raise vt; } //^In if statement// //^In raise statement// //A specific value without matching symbols or a reference to a value was expected for a raised exception.// + if (p == 10) { raise c; } + if (p == 11) { raise t; } //^In if statement// //^In raise statement// //A specific value without matching symbols or a reference to a value was expected for a raised exception.// + if (p == 12) { raise p2; } //^In if statement// //^In raise statement// //A specific value without matching symbols or a reference to a value was expected for a raised exception.// +} +catch (integer x) { } //Catch block for the same exception type already defined here// +catch (integer y) { } //Duplicate catch block definition for exception type `integer'// +catch (SmallNumber x) { } +catch (RoI[-] x) { } +catch (Rec.num x) { } +catch (charstring p) { } //Definition with identifier `p' is not unique in the scope hierarchy// +catch (default x) { } //^In exception definition// //Exception cannot be defined for the default type// +catch (Sig x) { } //^In exception definition// //Exception cannot be defined for signature `@oop_SE.Sig'// +catch (Port x) { } //^In exception definition// //Exception cannot be defined for port type `@oop_SE.Port'// +catch (octetstring x) { return; } +finally { + raise 3; //^In raise statement// //Raise statement cannot be used inside a finally block or the destructor of a class.// +} + +function f_return1(in integer p) return integer { //^In function definition// + if (p > 0) { + return 0; + } + else { + raise 0; + } +} +catch (integer x) { + return x; +} +finally { + return -1; //^In return statement// //Return statement cannot be used inside a finally block or the destructor of a class.// +} + +function f_return2(in integer p) return integer { //^In function definition// //The function has return type, but control might leave it without reaching a return statement// + if (p > 0) { + return f_return1(p); + } + catch (integer x) { + log(x); + } + else { + raise 0; + } +} + +type class C50 { } //^In type definition// +finally { //^In class destructor// + return; //^In return statement// //Return statement cannot be used inside a finally block or the destructor of a class.// +} + +type class C51 { } //^In type definition// +finally { //^In class destructor// + raise 1.0; //^In raise statement// //Raise statement cannot be used inside a finally block or the destructor of a class.// +} + + control { //^In control part// var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.// + raise "abc"; //^In raise statement// //Raise statement cannot be used in the control part. It is allowed only in functions, altsteps and testcases.// } } diff --git a/function_test/Tools/SAtester.pl b/function_test/Tools/SAtester.pl index 00c23c14c54f68df22f1573dc0d9a63827c8aeb9..de9e76a9b856d44c4e43d611acaf3d38a8c0a3bd 100755 --- a/function_test/Tools/SAtester.pl +++ b/function_test/Tools/SAtester.pl @@ -56,6 +56,10 @@ my $sa_printHelp_doc = 0; my $sa_titanRuntime2 = 0; # Enable coverage or not my $sa_coverageEnabled = 0; +# Enable object-oriented features +my $sa_titanOOP = 0; +# Ignore memory leaks +my $sa_ignoreMemLeaks = 0; # Files existed before a test case execution my %sa_existedFiles; # Store input TD files from which TCs are collected @@ -389,6 +393,8 @@ sub sa_processCommandLine() { 'help' => \$sa_printHelp_cmd, 'doc' => \$sa_printHelp_doc, 'rt2' => \$sa_titanRuntime2, + 'oop' => \$sa_titanOOP, + 'imemleaks' => \$sa_ignoreMemLeaks, 'coverage' => \$sa_coverageEnabled, 'log=s' => \$sa_logFile, 'timeout=s' => \$sa_timeout, @@ -683,10 +689,12 @@ sub sa_compileTC(\@) { sa_log( "Compiling sources...\n"); my $runtimeOption = ''; if ($sa_titanRuntime2) { $runtimeOption = '-R'; } + my $oopOption = ''; + if ($sa_titanOOP) { $oopOption = '-k'; } do { if ($cycles) { sleep(60 * 10); } $cycles++; - ($res, $subRes) = sa_executeCommand("$sa_compilerCmd $runtimeOption $modules2compile"); + ($res, $subRes) = sa_executeCommand("$sa_compilerCmd $runtimeOption $oopOption $modules2compile"); # Purify message, when no floating license available. Sleep for a while # and retry. # -continue-without-license=yes @@ -696,12 +704,12 @@ sub sa_compileTC(\@) { if ($root->[1] eq "COMPILE") { return (0, $resultBuffer); } sa_log( "Generating test port skeletons...\n"); - ($res, $subRes) = sa_executeCommand("$sa_compilerCmd $runtimeOption -t -f $modules2compile"); + ($res, $subRes) = sa_executeCommand("$sa_compilerCmd $runtimeOption $oopOption -t -f $modules2compile"); if ($res) { return (1, $subRes); } $resultBuffer .= $subRes; sa_log( "Generating Makefile...\n"); - ($res, $subRes) = sa_executeCommand("$sa_mfgenCmd $runtimeOption -s -f $modules2compile *.cc*"); + ($res, $subRes) = sa_executeCommand("$sa_mfgenCmd $runtimeOption $oopOption -s -f $modules2compile *.cc*"); if ($res) { return (1, $subRes); } $resultBuffer .= $subRes; if (not (-e 'Makefile')) { @@ -803,7 +811,7 @@ sub sa_checkTCResult(\@$) { } } # Check if there is any memory leak in compiler - if ($resultBuffer =~ /${sa_re_MemoryLeak}/mi) { + if (not $sa_ignoreMemLeaks and $resultBuffer =~ /${sa_re_MemoryLeak}/mi) { sa_log( "WARNING: Memory leak detected in compiler, setting verdict to 'FAIL'\n"); $root->[7] = 'memory leak detected'; $result = 'FAIL';