Commit c1e639a5 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

OOP: improved the non-C++11 code generated for finally blocks to allow...


OOP: improved the non-C++11 code generated for finally blocks to allow references to local variables and parameters (bug 568899)
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
Change-Id: Ia857c7cc56317ded9a1b548572698e3533a07ac7
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 23d0aba8
......@@ -910,6 +910,27 @@ namespace Ttcn {
}
}
}
if (ass != NULL) {
ref_usage_found(ass);
StatementBlock* sb = my_scope->get_statementblock_scope();
if (sb != NULL && sb->is_in_finally_block()) {
switch (ass->get_asstype()) {
default:
if (!ass->is_local()) {
break;
}
// else fall through
case Common::Assignment::A_PAR_VAL:
case Common::Assignment::A_PAR_VAL_IN:
case Common::Assignment::A_PAR_VAL_OUT:
case Common::Assignment::A_PAR_VAL_INOUT:
case Common::Assignment::A_PAR_TEMPL_IN:
case Common::Assignment::A_PAR_TEMPL_OUT:
case Common::Assignment::A_PAR_TEMPL_INOUT:
sb->get_finally_block()->add_refd_local_def(ass);
}
}
}
return ass;
}
......@@ -1115,9 +1136,8 @@ namespace Ttcn {
return true;
}
void Reference::ref_usage_found()
void Reference::ref_usage_found(Common::Assignment *ass)
{
Common::Assignment *ass = get_refd_assignment();
if (!ass) FATAL_ERROR("Reference::ref_usage_found()");
switch (ass->get_asstype()) {
case Common::Assignment::A_PAR_VAL_OUT:
......@@ -1142,6 +1162,13 @@ namespace Ttcn {
}
def->set_usage_found();
break; }
case Common::Assignment::A_EXCEPTION: {
Def_Exception* def = dynamic_cast<Def_Exception*>(ass);
if (def == NULL) {
FATAL_ERROR("Reference::ref_usage_found()");
}
def->set_usage_found();
break; }
default:
break;
}
......@@ -1170,7 +1197,6 @@ namespace Ttcn {
void Reference::generate_code(expression_struct_t *expr)
{
ref_usage_found();
Common::Assignment *ass = get_refd_assignment();
if (!ass) FATAL_ERROR("Reference::generate_code()");
if (reftype == REF_THIS) {
......@@ -1228,7 +1254,6 @@ namespace Ttcn {
return;
}
ref_usage_found();
Common::Assignment *ass = get_refd_assignment();
if (!ass) FATAL_ERROR("Reference::generate_code_const_ref()");
......@@ -1341,7 +1366,6 @@ namespace Ttcn {
void Reference::generate_code_portref(expression_struct_t *expr,
Scope *p_scope)
{
ref_usage_found();
Common::Assignment *ass = get_refd_assignment();
if (!ass) FATAL_ERROR("Reference::generate_code_portref()");
expr->expr = mputstr(expr->expr,
......@@ -1353,7 +1377,6 @@ namespace Ttcn {
void Reference::generate_code_ispresentboundchosen(expression_struct_t *expr,
bool is_template, const Value::operationtype_t optype, const char* field)
{
ref_usage_found();
Common::Assignment *ass = get_refd_assignment();
const string& ass_id = ass->get_genname_from_scope(my_scope);
const char *ass_id_str = ass_id.c_str();
......@@ -5548,15 +5571,16 @@ namespace Ttcn {
// ===== Def_Exception
// =================================
Def_Exception::Def_Exception(Identifier* p_id, Type* p_type): Def_Var(p_id, p_type, NULL)
Def_Exception::Def_Exception(Identifier* p_id, Type* p_type): Def_Var(p_id, p_type, NULL), usage_found(false)
{
asstype = Common::Assignment::A_EXCEPTION;
}
char* Def_Exception::generate_code_str(char *str)
{
return 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());
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;
}
// =================================
......@@ -11235,13 +11259,6 @@ namespace Ttcn {
LazyFuzzyParamData::init(used_as_lvalue);
LazyFuzzyParamData::generate_code(expr, val, my_scope, param_eval == LAZY_EVAL);
LazyFuzzyParamData::clean();
if (val->get_valuetype() == Value::V_REFD) {
// check if the reference is a parameter, mark it as used if it is
Reference* r = dynamic_cast<Reference*>(val->get_reference());
if (r != NULL) {
r->ref_usage_found();
}
}
} else {
char* expr_expr = NULL;
if (use_runtime_2 && TypeConv::needs_conv_refd(val)) {
......@@ -11292,15 +11309,6 @@ namespace Ttcn {
LazyFuzzyParamData::generate_code(expr, temp, gen_restriction_check, my_scope,
param_eval == LAZY_EVAL);
LazyFuzzyParamData::clean();
if (temp->get_DerivedRef() != NULL ||
temp->get_Template()->get_templatetype() == Template::TEMPLATE_REFD) {
// check if the reference is a parameter, mark it as used if it is
Reference* r = dynamic_cast<Reference*>(temp->get_DerivedRef() != NULL ?
temp->get_DerivedRef() : temp->get_Template()->get_reference());
if (r != NULL) {
r->ref_usage_found();
}
}
} else {
char* expr_expr = NULL;
if (use_runtime_2 && TypeConv::needs_conv_refd(temp->get_Template())) {
......
......@@ -416,8 +416,8 @@ namespace Ttcn {
* On further runs the cached expression is returned.*/
virtual void generate_code_cached (expression_struct_t *expr);
/** Lets the referenced assignment object know, that the reference is used
* at least once (only relevant for formal parameters and external constants). */
void ref_usage_found();
* at least once (only relevant for formal parameters, external constants and exceptions). */
static void ref_usage_found(Common::Assignment *ass);
/** Appends a new field subref for the union type's @default alternative at the end of the reference.
* Used when the reference points to a union value or template in a context where a union is not allowed.
* This attempts to use the union's default alternative instead. */
......@@ -1196,6 +1196,9 @@ namespace Ttcn {
class Def_Exception : public Def_Var {
private:
/** Indicates whether the exception is used in the catch block. */
bool usage_found;
/// Copy constructor disabled
Def_Exception(const Def_Exception& p);
/// %Assignment disabled
......@@ -1203,6 +1206,7 @@ namespace Ttcn {
public:
Def_Exception(Identifier* p_id, Type* p_type);
void set_usage_found() { usage_found = true; }
virtual char* generate_code_str(char *str);
};
......
......@@ -60,6 +60,7 @@ namespace Ttcn {
}
catch_blocks.clear();
delete finally_block;
refd_local_defs.clear();
}
StatementBlock *StatementBlock::clone() const
......@@ -284,6 +285,16 @@ namespace Ttcn {
finally_block = p_finally;
}
void StatementBlock::add_refd_local_def(Common::Assignment* p_def)
{
if (exception_handling != EH_OOP_FINALLY || p_def == NULL) {
FATAL_ERROR("StatementBlock::add_refd_local_defs");
}
if (!refd_local_defs.has_key(p_def)) {
refd_local_defs.add(p_def, NULL);
}
}
boolean StatementBlock::is_in_finally_block() const
{
if (exception_handling == EH_OOP_FINALLY) {
......@@ -295,6 +306,17 @@ namespace Ttcn {
return FALSE;
}
StatementBlock* StatementBlock::get_finally_block()
{
if (exception_handling == EH_OOP_FINALLY) {
return this;
}
if (my_sb != NULL) {
return my_sb->get_finally_block();
}
FATAL_ERROR("StatementBlock::get_finally_block()");
}
boolean StatementBlock::is_empty() const
{
return stmts.size() == 0 && exception_handling == StatementBlock::EH_NONE &&
......@@ -568,16 +590,85 @@ namespace Ttcn {
if (finally_block != NULL) {
string tmp_id = get_scope_mod_gen()->get_temporary_id();
#if __cplusplus < 201103L
// the finally block's code is generated into the destructor of a newly created class;
// all local definitions, parameters and the TTCN_Location object are added to the class as members,
// so the destructor can reach them
str = mputprintf(str,
"class %s_finally {\n"
"public:\n", tmp_id.c_str());
// TODO: all local declarations (or those referenced in the 'finally' block) need to
// be added as members of this class, so the destructor can reach them
if (include_location_info) {
str = mputprintf(str,
"TTCN_Location& current_location;\n"
"%s_finally(TTCN_Location& p_loc):current_location(p_loc) { }\n",
tmp_id.c_str());
str = mputstr(str, "TTCN_Location& current_location;\n");
}
for (size_t i = 0; i < finally_block->refd_local_defs.size(); ++i) {
bool is_const = false;
bool is_template = false;
Common::Assignment* def = finally_block->refd_local_defs.get_nth_key(i);
switch (def->get_asstype()) {
case Common::Assignment::A_PAR_TEMPL_IN:
case Common::Assignment::A_TEMPLATE:
is_template = true;
// fall through
case Common::Assignment::A_PAR_VAL:
case Common::Assignment::A_PAR_VAL_IN:
case Common::Assignment::A_CONST:
is_const = true;
break;
case Common::Assignment::A_VAR_TEMPLATE:
case Common::Assignment::A_PAR_TEMPL_INOUT:
case Common::Assignment::A_PAR_TEMPL_OUT:
is_template = true;
break;
default:
break;
}
str = mputprintf(str, "%s%s& %s;\n",
is_const ? "const " : "",
is_template ? def->get_Type()->get_genname_template(my_sb).c_str() : def->get_Type()->get_genname_value(my_sb).c_str(),
def->get_id().get_name().c_str());
}
if (include_location_info || finally_block->refd_local_defs.size() > 0) {
str = mputprintf(str, "%s_finally(", tmp_id.c_str());
if (include_location_info) {
str = mputstr(str, "TTCN_Location& p_loc");
}
for (size_t i = 0; i < finally_block->refd_local_defs.size(); ++i) {
bool is_const = false;
bool is_template = false;
Common::Assignment* def = finally_block->refd_local_defs.get_nth_key(i);
switch (def->get_asstype()) {
case Common::Assignment::A_PAR_TEMPL_IN:
case Common::Assignment::A_TEMPLATE:
is_template = true;
// fall through
case Common::Assignment::A_PAR_VAL:
case Common::Assignment::A_PAR_VAL_IN:
case Common::Assignment::A_CONST:
is_const = true;
break;
case Common::Assignment::A_VAR_TEMPLATE:
case Common::Assignment::A_PAR_TEMPL_INOUT:
case Common::Assignment::A_PAR_TEMPL_OUT:
is_template = true;
break;
default:
break;
}
str = mputprintf(str, "%s%s%s& p_%s",
include_location_info || i > 0 ? ", " : "", is_const ? "const " : "",
is_template ? def->get_Type()->get_genname_template(my_sb).c_str() : def->get_Type()->get_genname_value(my_sb).c_str(),
def->get_id().get_name().c_str());
}
str = mputstr(str, "): ");
if (include_location_info) {
str = mputstr(str, "current_location(p_loc)");
}
for (size_t i = 0; i < finally_block->refd_local_defs.size(); ++i) {
Common::Assignment* def = finally_block->refd_local_defs.get_nth_key(i);
str = mputprintf(str, "%s%s(p_%s)", include_location_info || i > 0 ? ", " : "",
def->get_id().get_name().c_str(), def->get_id().get_name().c_str());
}
str = mputstr(str, " { }\n");
}
str = mputprintf(str,
"~%s_finally() {\n"
......@@ -590,9 +681,20 @@ namespace Ttcn {
"}\n"
"}\n"
"};\n"
"%s_finally %s%s;\n",
tmp_id.c_str(), tmp_id.c_str(),
include_location_info ? "(current_location)" : "");
"%s_finally %s",
tmp_id.c_str(), tmp_id.c_str());
if (include_location_info || finally_block->refd_local_defs.size() > 0) {
str = mputc(str, '(');
if (include_location_info) {
str = mputstr(str, "current_location");
}
for (size_t i = 0; i < finally_block->refd_local_defs.size(); ++i) {
str = mputprintf(str, "%s%s", include_location_info || i > 0 ? ", " : "",
finally_block->refd_local_defs.get_nth_key(i)->get_id().get_name().c_str());
}
str = mputc(str, ')');
}
str = mputstr(str, ";\n");
#else
// C++11 version:
str = mputprintf(str,
......@@ -9701,8 +9803,6 @@ error:
char *Assignment::generate_code(char *str)
{
// check if the LHS reference is a parameter, mark it as used if it is
ref->ref_usage_found();
FieldOrArrayRefs *t_subrefs = ref->get_subrefs();
const bool rhs_copied = self_ref;
switch (asstype) {
......
......@@ -100,8 +100,13 @@ namespace Ttcn {
Definition *my_def;
/** */
exception_handling_t exception_handling;
/** List of catch blocks at the end of this statement block (OOP feature) */
vector<StatementBlock> catch_blocks;
/** Optional finally block at the end of this statement block (OOP feature) */
StatementBlock* finally_block;
/** List of local definitions referenced inside this block
* (only for the finally block of a normal statement block) */
map<Common::Assignment*, void> refd_local_defs; // elements not owned
StatementBlock(const StatementBlock& p);
StatementBlock& operator=(const StatementBlock& p);
......@@ -132,7 +137,9 @@ 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);
void add_refd_local_def(Common::Assignment* p_def);
boolean is_in_finally_block() const;
StatementBlock* get_finally_block();
boolean is_empty() const;
returnstatus_t has_return() const;
/** Used when generating code for interleaved statement. If has
......
......@@ -46,7 +46,7 @@ type integer SmallNumber (-100..100);
function test_block(in integer p_exception_type) runs on CT {
//var integer v_finally_increment := 1;
var integer v_finally_increment := 1;
{
select (p_exception_type) {
case (1) {
......@@ -118,7 +118,10 @@ function test_block(in integer p_exception_type) runs on CT {
}
}
finally {
cv_finally_counter := cv_finally_counter + 1;
cv_finally_counter := cv_finally_counter + v_finally_increment; // test referencing a local variable (in the main block)
if (cv_finally_counter > 0) {
log(p_exception_type); // test referencing a function parameter (in a sub-block)
}
setverdict(pass);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment