diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh index e59ce8cb8fe9e7cc444b704cea2c6dc706535c7a..5eb2da254089d87d7b6b862d0d00a2b500d26fe3 100644 --- a/compiler2/Setting.hh +++ b/compiler2/Setting.hh @@ -448,9 +448,11 @@ public: CS_INIT_COMP, /**< Initialized with the component entities (i.e. when * the component type is known). Example: initial value * for component variables, default duration for timers. */ - CS_INLINE /**< Initialized immediately at the place of definition. - * Applicable to local definitions only. Example: initial - * value for a local variable. */ + CS_INLINE, /**< Initialized immediately at the place of definition. + * Applicable to local definitions only. Example: initial + * value for a local variable. */ + CS_INIT_CLASS /**< Initialized at the beginning of a class's constructor. + * Example: class members */ }; private: /** A prefix that shall be inserted before the genname when initializing diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 37f2e3cac3a54b780e1a1a8fad082b69a0a3edaf..49acabed9d9ef092e0398371f71169c5a5eeefd4 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -48,7 +48,8 @@ enum namedbool { INCOMPLETE_NOT_ALLOWED = 0, INCOMPLETE_ALLOWED = 1, WARNING_FOR ANY_OR_OMIT_NOT_ALLOWED = 0, ANY_OR_OMIT_ALLOWED = 5, NOT_IMPLICIT_OMIT = 0, IMPLICIT_OMIT = 6, NOT_STR_ELEM = 0, IS_STR_ELEM = 7, - ISBOUND = 8, ISPRESENT = 9, ISCHOSEN = 10, ISVALUE = 11 + ISBOUND = 8, ISPRESENT = 9, ISCHOSEN = 10, ISVALUE = 11, + NOT_CLASS_MEMBER_INIT = 0, CLASS_MEMBER_INIT = 12 }; namespace Asn { @@ -952,11 +953,13 @@ namespace Common { expected_value_t expected_value, namedbool incomplete_allowed, namedbool omit_allowed, namedbool sub_chk, namedbool implicit_omit = NOT_IMPLICIT_OMIT, - namedbool str_elem = NOT_STR_ELEM); + namedbool str_elem = NOT_STR_ELEM, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); /** Checks the given referenced value */ bool chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_value_t expected_value, ReferenceChain *refch=0, - namedbool str_elem = NOT_STR_ELEM); + namedbool str_elem = NOT_STR_ELEM, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); /** Checks the given invocation */ void chk_this_invoked_value(Value *value, Common::Assignment *lhs, expected_value_t expected_value); @@ -980,19 +983,24 @@ namespace Common { expected_value_t expected_value, namedbool incomplete_allowed, namedbool omit_allowed, namedbool sub_chk, namedbool implicit_omit = NOT_IMPLICIT_OMIT, - namedbool str_elem = NOT_STR_ELEM); + namedbool str_elem = NOT_STR_ELEM, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Se(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Se_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Seq_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Set_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Se_A(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool implicit_omit); bool chk_this_value_Seq_A(Value *value, Common::Assignment *lhs, @@ -1001,14 +1009,16 @@ namespace Common { expected_value_t expected_value, namedbool implicit_omit); bool chk_this_value_SeOf(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit = NOT_IMPLICIT_OMIT); + namedbool implicit_omit = NOT_IMPLICIT_OMIT, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); void chk_this_value_Verdict(Value *value); void chk_this_value_Default(Value *value); bool chk_this_value_Array(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, - namedbool implicit_omit); + namedbool implicit_omit, namedbool class_member_init = NOT_CLASS_MEMBER_INIT); bool chk_this_value_Signature(Value *value, Common::Assignment *lhs, - expected_value_t expected_value, namedbool incomplete_allowed); + expected_value_t expected_value, namedbool incomplete_allowed, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); void chk_this_value_Component(Value *value); void chk_this_value_FAT(Value *value); void chk_this_value_class(Value* value); @@ -1025,19 +1035,19 @@ namespace Common { bool chk_this_template_ref_pard(Ttcn::Reference* ref_pard, Common::Assignment* lhs); bool chk_this_template_generic(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); /** Checks if a template's type contains default or port field somehow.*/ void chk_this_template_incorrect_field(); private: - bool chk_this_refd_template(Template *t, Common::Assignment *lhs); + bool chk_this_refd_template(Template *t, namedbool class_member_init, Common::Assignment *lhs); void chk_this_template_length_restriction(Template *t); bool chk_this_template_concat_operand(Template* t, namedbool implicit_omit, - Common::Assignment *lhs); + namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_Str(Template *t, namedbool implicit_omit, - Common::Assignment *lhs); + namedbool class_member_init, Common::Assignment *lhs); /** Checks whether \a v is a correct range boundary for this type. * Applicable to the following types: integer, float, charstring, * universal charstring. @@ -1054,19 +1064,19 @@ namespace Common { void chk_this_template_Enum(Template *t); bool chk_this_template_Choice(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_Seq(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_Set(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); bool chk_this_template_array(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs); + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs); void chk_this_template_Fat(Template *t); - void chk_this_template_Signature(Template *t, namedbool incomplete_allowed); + void chk_this_template_Signature(Template *t, namedbool incomplete_allowed, namedbool class_member_init); public: /** Check whether there is an enum item with the given name. * diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 740a12a0c58cc9744008d128dd9f049052262222..ce9393795d38a0dc0954fb0f0110013902b4abf0 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -3998,7 +3998,8 @@ void Type::chk_this_value_ref(Value *value) bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool incomplete_allowed, namedbool omit_allowed, - namedbool sub_chk, namedbool implicit_omit, namedbool is_str_elem) + namedbool sub_chk, namedbool implicit_omit, namedbool is_str_elem, + namedbool class_member_init) { bool self_ref = false; chk(); @@ -4015,12 +4016,12 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ case Value::V_ERROR: return false; case Value::V_REFD: - return chk_this_refd_value(value, lhs, expected_value, 0, is_str_elem); + return chk_this_refd_value(value, lhs, expected_value, 0, is_str_elem, class_member_init); case Value::V_INVOKE: chk_this_invoked_value(value, lhs, expected_value); return false; // assumes no self-reference in invoke case Value::V_EXPR: - if (lhs) self_ref = value->chk_expr_self_ref(lhs); + self_ref = value->chk_expr_self_ref(lhs, class_member_init); // no break case Value::V_MACRO: if (value->is_unfoldable(0, expected_value)) { @@ -4031,7 +4032,7 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, sub_chk, implicit_omit, is_str_elem); + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, is_str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -4118,23 +4119,23 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ case T_OPENTYPE: case T_ANYTYPE: self_ref = chk_this_value_Choice(value, lhs, expected_value, omit_allowed, - sub_chk, incomplete_allowed, implicit_omit, is_str_elem); + sub_chk, incomplete_allowed, implicit_omit, is_str_elem, class_member_init); break; case T_SEQ_T: case T_SET_T: case T_SEQ_A: case T_SET_A: self_ref = chk_this_value_Se(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); break; case T_SEQOF: case T_SETOF: self_ref = chk_this_value_SeOf(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); break; case T_REFD: self_ref = get_type_refd()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, NO_SUB_CHK, implicit_omit, is_str_elem); + incomplete_allowed, omit_allowed, NO_SUB_CHK, implicit_omit, is_str_elem, class_member_init); break; case T_UNRESTRICTEDSTRING: case T_OCFT: @@ -4144,7 +4145,7 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ case T_SELTYPE: case T_ADDRESS: self_ref = get_type_refd()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, NO_SUB_CHK, NOT_IMPLICIT_OMIT, is_str_elem); + incomplete_allowed, omit_allowed, NO_SUB_CHK, NOT_IMPLICIT_OMIT, is_str_elem, class_member_init); break; case T_VERDICT: chk_this_value_Verdict(value); @@ -4153,14 +4154,14 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ chk_this_value_Default(value); break; case T_ARRAY: - self_ref = chk_this_value_Array(value, lhs, expected_value, incomplete_allowed, implicit_omit); + self_ref = chk_this_value_Array(value, lhs, expected_value, incomplete_allowed, implicit_omit, class_member_init); break; case T_PORT: // Remain silent. The error has already been reported in the definition // that the value belongs to. break; case T_SIGNATURE: - self_ref = chk_this_value_Signature(value, lhs, expected_value, incomplete_allowed); + self_ref = chk_this_value_Signature(value, lhs, expected_value, incomplete_allowed, class_member_init); break; case T_COMPONENT: chk_this_value_Component(value); @@ -4184,7 +4185,7 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_ } bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - ReferenceChain* refch, namedbool str_elem) + ReferenceChain* refch, namedbool str_elem, namedbool class_member_init) { Reference *ref = value->get_reference(); Assignment *ass = ref->get_refd_assignment(); @@ -4206,10 +4207,15 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v return self_ref; case Assignment::A_CONST: if (expected_value == EXPECTED_CONSTANT && - ass->get_Value()->is_unfoldable(NULL, expected_value)) { + (ass->get_Value() == NULL || ass->get_Value()->is_unfoldable(NULL, expected_value))) { value->error("Referenced constant value cannot be evaluated at compile-time"); error_flag = true; } + else if (class_member_init && ass->get_Value() == NULL) { + value->error("Reference to uninitialized constant `%s' in class member initialization", + ass->get_id().get_dispname().c_str()); + error_flag = true; + } else { is_const = true; } @@ -4253,6 +4259,13 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v } // else fall through case Assignment::A_VAR: + if (ass->get_asstype() == Assignment::A_VAR && + class_member_init && ass->get_Value() == NULL) { + value->error("Reference to uninitialized variable `%s' in class member initialization", + ass->get_id().get_dispname().c_str()); + error_flag = true; + } + // else fall through case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL: case Assignment::A_PAR_VAL_IN: @@ -4388,7 +4401,7 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v "value of union type `%s'", def_alt_ref->get_name().get_dispname().c_str(), governor->get_typename().c_str()); ttcn_ref->use_default_alternative(def_alt_ref->get_name()); - return chk_this_refd_value(value, lhs, expected_value, refch, str_elem); + return chk_this_refd_value(value, lhs, expected_value, refch, str_elem, class_member_init); } CompField* def_alt = get_default_alternative(); if (def_alt != NULL) { @@ -4396,7 +4409,7 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_refd_value(value, lhs, - expected_value, refch, str_elem); + expected_value, refch, str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -4995,7 +5008,8 @@ static string actual_fields(Type& t) // alas, not even get_nof_comps() is const bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, expected_value_t expected_value, namedbool omit_allowed, namedbool sub_chk, - namedbool incomplete_allowed, namedbool implicit_omit, namedbool str_elem) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool str_elem, + namedbool class_member_init) { bool self_ref = false; CompField* def_alt = get_default_alternative(); @@ -5006,7 +5020,7 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -5022,7 +5036,7 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -5042,7 +5056,7 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -5071,7 +5085,7 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, alt_value->set_my_governor(alt_type); alt_type->chk_this_value_ref(alt_value); self_ref |= alt_type->chk_this_value(alt_value, lhs, expected_value, - incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit); + incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, class_member_init); if (alt_value->get_valuetype() == Value::V_NOTUSED) { value->set_valuetype(Value::V_NOTUSED); } @@ -5081,7 +5095,7 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, Error_Context cntxt(value, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_value(value, lhs, expected_value, - incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem); + incomplete_allowed, omit_allowed, sub_chk, implicit_omit, str_elem, class_member_init); value->use_default_alternative(this); return self_ref; } @@ -5096,27 +5110,27 @@ bool Type::chk_this_value_Choice(Value *value, Common::Assignment *lhs, } bool Type::chk_this_value_Se(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { if (value->is_asn1()) return chk_this_value_Se_A(value, lhs, expected_value, implicit_omit); else return chk_this_value_Se_T(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); } bool Type::chk_this_value_Se_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { switch (value->get_valuetype()) { case Value::V_SEQ: if (typetype == T_SET_A || typetype == T_SET_T) { value->set_valuetype(Value::V_SET); return chk_this_value_Set_T(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); } else { return chk_this_value_Seq_T(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); } break; case Value::V_SEQOF: @@ -5146,7 +5160,7 @@ bool Type::chk_this_value_Se_T(Value *value, Common::Assignment *lhs, expected_v } else { value->set_valuetype(Value::V_SEQ); return chk_this_value_Seq_T(value, lhs, expected_value, incomplete_allowed, - implicit_omit); + implicit_omit, class_member_init); } } break; @@ -5161,7 +5175,7 @@ bool Type::chk_this_value_Se_T(Value *value, Common::Assignment *lhs, expected_v } bool Type::chk_this_value_Seq_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { bool self_ref = false; map<string, NamedValue> comp_map; @@ -5240,7 +5254,8 @@ bool Type::chk_this_value_Seq_T(Value *value, Common::Assignment *lhs, expected_ value_dispname_str); type->chk_this_value_ref(comp_value); self_ref |= type->chk_this_value(comp_value, lhs, expected_value, incomplete_allowed, - cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit); + cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, + NOT_STR_ELEM, class_member_init); if (comp_value->get_valuetype() != Value::V_NOTUSED) { is_empty = false; } @@ -5274,7 +5289,7 @@ bool Type::chk_this_value_Seq_T(Value *value, Common::Assignment *lhs, expected_ } bool Type::chk_this_value_Set_T(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { bool self_ref = false; map<string, NamedValue> comp_map; @@ -5311,7 +5326,8 @@ bool Type::chk_this_value_Set_T(Value *value, Common::Assignment *lhs, expected_ value_dispname_str); type->chk_this_value_ref(comp_value); self_ref |= type->chk_this_value(comp_value, lhs, expected_value, incomplete_allowed, - cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit); + cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, + NOT_STR_ELEM, class_member_init); if (comp_value->get_valuetype() != Value::V_NOTUSED) { is_empty = false; } @@ -5487,7 +5503,7 @@ bool Type::chk_this_value_Set_A(Value *value, Common::Assignment *lhs, expected_ } bool Type::chk_this_value_SeOf(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { bool self_ref = false; const char *valuetypename; @@ -5523,7 +5539,8 @@ bool Type::chk_this_value_SeOf(Value *value, Common::Assignment *lhs, expected_v } else { u.seof.ofType->chk_this_value_ref(v_comp); self_ref |= u.seof.ofType->chk_this_value(v_comp, lhs, expected_value, - incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit); + incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, + NOT_STR_ELEM, class_member_init); } } } else { @@ -5579,7 +5596,7 @@ bool Type::chk_this_value_SeOf(Value *value, Common::Assignment *lhs, expected_v val->set_my_governor(u.seof.ofType); u.seof.ofType->chk_this_value_ref(val); self_ref |= u.seof.ofType->chk_this_value(val, lhs, expected_value, - incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK); + incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, NOT_STR_ELEM, class_member_init); } if (check_holes) { if ((size_t)max_index != index_map.size() - 1) { @@ -5631,7 +5648,7 @@ void Type::chk_this_value_Default(Value *value) } bool Type::chk_this_value_Array(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed, namedbool implicit_omit) + namedbool incomplete_allowed, namedbool implicit_omit, namedbool class_member_init) { bool self_ref = false; switch (value->get_valuetype()) { @@ -5668,7 +5685,7 @@ bool Type::chk_this_value_Array(Value *value, Common::Assignment *lhs, expected_ u.array.element_type->chk_this_value_ref(v_comp); self_ref |= u.array.element_type->chk_this_value(v_comp, lhs, expected_value, incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, - implicit_omit); + implicit_omit, NOT_STR_ELEM, class_member_init); } } } else { @@ -5718,7 +5735,8 @@ bool Type::chk_this_value_Array(Value *value, Common::Assignment *lhs, expected_ val->set_my_governor(u.array.element_type); u.array.element_type->chk_this_value_ref(val); self_ref |= u.array.element_type->chk_this_value(val, lhs, expected_value, - incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit); + incomplete_allowed, OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, NOT_STR_ELEM, + class_member_init); } if (check_holes) { if (index_map.size() < array_size) { @@ -5745,7 +5763,7 @@ bool Type::chk_this_value_Array(Value *value, Common::Assignment *lhs, expected_ bool Type::chk_this_value_Signature(Value *value, Common::Assignment *lhs, expected_value_t expected_value, - namedbool incomplete_allowed) + namedbool incomplete_allowed, namedbool class_member_init) { bool self_ref = false; switch(value->get_valuetype()) { @@ -5816,7 +5834,8 @@ bool Type::chk_this_value_Signature(Value *value, Common::Assignment *lhs, type->chk_this_value_ref(comp_value); self_ref |= type->chk_this_value(comp_value, lhs, expected_value, INCOMPLETE_NOT_ALLOWED, - cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK); + cf->get_is_optional() ? OMIT_ALLOWED : OMIT_NOT_ALLOWED, SUB_CHK, + NOT_IMPLICIT_OMIT, NOT_STR_ELEM, class_member_init); } if (INCOMPLETE_NOT_ALLOWED == incomplete_allowed) { for (size_t i = 0; i < u.signature.parameters->get_nof_in_params(); i++) { @@ -6496,7 +6515,7 @@ void Type::chk_this_template_incorrect_field() { bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; t->chk_concat_double_length_res(); @@ -6534,7 +6553,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, if (!ass) break; // probably erroneous //warning("asstype %d", ass->get_asstype()); - switch (ass->get_asstype()) { + switch (ass->get_asstype()) { // todo class_member_init case Assignment::A_VAR: case Assignment::A_EXCEPTION: case Assignment::A_PAR_VAL_IN: @@ -6587,7 +6606,8 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, chk_this_template_ref(t_comp); self_ref |= chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, (omit_in_value_list && temptype != Ttcn::Template::CONJUNCTION_MATCH) ? - allow_omit : OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, sub_chk, implicit_omit, lhs); + allow_omit : OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, sub_chk, implicit_omit, + class_member_init, lhs); if(temptype==Ttcn::Template::COMPLEMENTED_LIST && t_comp->get_template_refd_last()->get_templatetype() == Ttcn::Template::ANY_OR_OMIT) @@ -6599,7 +6619,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, Value *v = t->get_specific_value(); v->set_my_governor(this); self_ref |= chk_this_value(v, lhs, EXPECTED_TEMPLATE, incomplete_allowed, - allow_omit, SUB_CHK); + allow_omit, SUB_CHK, NOT_IMPLICIT_OMIT, NOT_STR_ELEM, class_member_init); break; } case Ttcn::Template::TEMPLATE_INVOKE: { t->chk_invoke(); @@ -6614,7 +6634,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, } break; } case Ttcn::Template::TEMPLATE_REFD: - self_ref = chk_this_refd_template(t, lhs); + self_ref = chk_this_refd_template(t, class_member_init, lhs); break; case Ttcn::Template::TEMPLATE_CONCAT: { @@ -6626,11 +6646,11 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, Template* t_right = t->get_concat_operand(false); { Error_Context cntxt2(t, "In first operand"); - self_ref |= chk_this_template_concat_operand(t_left, implicit_omit, lhs); + self_ref |= chk_this_template_concat_operand(t_left, implicit_omit, class_member_init, lhs); } { Error_Context cntxt2(t, "In second operand"); - self_ref |= chk_this_template_concat_operand(t_right, implicit_omit, lhs); + self_ref |= chk_this_template_concat_operand(t_right, implicit_omit, class_member_init, lhs); } if (t_left->get_templatetype() == Ttcn::Template::TEMPLATE_ERROR || t_right->get_templatetype() == Ttcn::Template::TEMPLATE_ERROR) { @@ -6639,8 +6659,8 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, } break; case Ttcn::Template::IMPLICATION_MATCH: - t->get_precondition()->chk(this); - t->get_implied_template()->chk(this); + t->get_precondition()->chk(this, class_member_init); + t->get_implied_template()->chk(this, class_member_init); break; case Ttcn::Template::DYNAMIC_MATCH: { Ttcn::FormalPar* matching_fp = new Ttcn::FormalPar(Assignment::A_PAR_VAL_IN, clone(), @@ -6667,7 +6687,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, break; } default: self_ref = chk_this_template(t, incomplete_allowed, allow_omit, allow_any_or_omit, - sub_chk, implicit_omit, lhs); + sub_chk, implicit_omit, class_member_init, lhs); break; } if (t->get_length_restriction()) chk_this_template_length_restriction(t); @@ -6681,7 +6701,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, return self_ref; } -bool Type::chk_this_refd_template(Template *t, Common::Assignment *lhs) +bool Type::chk_this_refd_template(Template *t, namedbool class_member_init, Common::Assignment *lhs) { if (t->get_templatetype() != Template::TEMPLATE_REFD) return false; Reference *ref = t->get_reference(); @@ -6730,11 +6750,26 @@ bool Type::chk_this_refd_template(Template *t, Common::Assignment *lhs) if (info.needs_conversion()) t->set_needs_conversion(); } } + if (class_member_init) { + switch (ass->get_asstype()) { + case Assignment::A_TEMPLATE: + case Assignment::A_VAR_TEMPLATE: + if (ass->get_Template() == NULL) { + t->error("Reference to uninitialized template%s `%s' in class member initialization", + ass->get_asstype() == Assignment::A_VAR_TEMPLATE ? " variable" : "", + ass->get_id().get_dispname().c_str()); + t->set_templatetype(Ttcn::Template::TEMPLATE_ERROR); + } + break; + default: + break; + } + } return (lhs == ass); } bool Type::chk_this_template_concat_operand(Template* t, namedbool implicit_omit, - Common::Assignment *lhs) + namedbool class_member_init, Common::Assignment *lhs) { Type* governor = t->get_expr_governor(EXPECTED_TEMPLATE); if (governor == NULL) { @@ -6748,7 +6783,7 @@ bool Type::chk_this_template_concat_operand(Template* t, namedbool implicit_omit } t->set_my_governor(governor); bool self_ref = governor->chk_this_template_generic(t, INCOMPLETE_NOT_ALLOWED, - OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, NO_SUB_CHK, implicit_omit, lhs); + OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, NO_SUB_CHK, implicit_omit, class_member_init, lhs); Template* t_last = t->get_template_refd_last(); if (t->get_templatetype() == Ttcn::Template::TEMPLATE_ERROR || t_last->get_templatetype() == Ttcn::Template::TEMPLATE_ERROR) { @@ -6819,7 +6854,7 @@ bool Type::chk_this_template_concat_operand(Template* t, namedbool implicit_omit bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; Type *t_last = get_type_refd_last(); @@ -6858,7 +6893,7 @@ bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, case T_UTCTIME: case T_GENERALIZEDTIME: case T_OBJECTDESCRIPTOR: - self_ref = t_last->chk_this_template_Str(t, implicit_omit, lhs); + self_ref = t_last->chk_this_template_Str(t, implicit_omit, class_member_init, lhs); break; case T_INT: case T_INT_A: @@ -6874,31 +6909,36 @@ bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, case T_OPENTYPE: case T_ANYTYPE: self_ref = t_last->chk_this_template_Choice(t, incomplete_allowed, allow_omit, - allow_any_or_omit, sub_chk, implicit_omit, lhs); + allow_any_or_omit, sub_chk, implicit_omit, class_member_init, lhs); break; case T_SEQ_A: case T_SEQ_T: - self_ref = t_last->chk_this_template_Seq(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_Seq(t, incomplete_allowed, implicit_omit, + class_member_init, lhs); break; case T_SET_A: case T_SET_T: - self_ref = t_last->chk_this_template_Set(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_Set(t, incomplete_allowed, implicit_omit, + class_member_init, lhs); break; case T_SEQOF: - self_ref = t_last->chk_this_template_SeqOf(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_SeqOf(t, incomplete_allowed, implicit_omit, + class_member_init, lhs); break; case T_SETOF: - self_ref = t_last->chk_this_template_SetOf(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_SetOf(t, incomplete_allowed, implicit_omit, + class_member_init, lhs); break; case T_ARRAY: - self_ref = t_last->chk_this_template_array(t, incomplete_allowed, implicit_omit, lhs); + self_ref = t_last->chk_this_template_array(t, incomplete_allowed, implicit_omit, + class_member_init, lhs); break; case T_PORT: t->error("Template cannot be defined for port type `%s'", get_fullname().c_str()); break; case T_SIGNATURE: - t_last->chk_this_template_Signature(t, incomplete_allowed); + t_last->chk_this_template_Signature(t, incomplete_allowed, class_member_init); break; case T_FUNCTION: case T_ALTSTEP: @@ -6912,7 +6952,7 @@ bool Type::chk_this_template(Template *t, namedbool incomplete_allowed, } bool Type::chk_this_template_Str(Template *t, namedbool implicit_omit, - Common::Assignment *lhs) + namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; typetype_t tt = get_typetype_ttcn3(typetype); @@ -6952,7 +6992,7 @@ bool Type::chk_this_template_Str(Template *t, namedbool implicit_omit, if (tt == T_CSTR) { Ttcn::PatternString *pstr = t->get_cstr_pattern(); Error_Context cntxt(t, "In character string pattern"); - pstr->chk_refs(); + pstr->chk_refs(EXPECTED_DYNAMIC_VALUE, class_member_init); pstr->join_strings(); if (!pstr->has_refs()) pstr->chk_pattern(); break; @@ -6970,7 +7010,7 @@ bool Type::chk_this_template_Str(Template *t, namedbool implicit_omit, if (tt == T_USTR) { Ttcn::PatternString *pstr = t->get_ustr_pattern(); Error_Context cntxt(t, "In universal string pattern"); - pstr->chk_refs(); + pstr->chk_refs(EXPECTED_DYNAMIC_VALUE, class_member_init); pstr->join_strings(); if (!pstr->has_refs()) pstr->chk_pattern(); } else report_error = true; @@ -6991,7 +7031,7 @@ bool Type::chk_this_template_Str(Template *t, namedbool implicit_omit, self_ref = target_type->chk_this_template_generic( target->get_Template(), (target->get_DerivedRef() != NULL) ? INCOMPLETE_ALLOWED : INCOMPLETE_NOT_ALLOWED, - OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs); + OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, class_member_init, lhs); Type* coding_type = legacy_codec_handling ? target_type->get_type_refd_last() : target_type; coding_type->chk_coding(false, t->get_my_scope()->get_scope_mod()); @@ -7163,7 +7203,7 @@ void Type::chk_this_template_Enum(Template *t) bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, namedbool allow_omit, namedbool allow_any_or_omit, namedbool sub_chk, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; CompField* def_alt = get_default_alternative(); @@ -7175,7 +7215,7 @@ bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, Error_Context cntxt(t, "Using default alternative `%s' in template of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_template_generic(t, incomplete_allowed, allow_omit, - allow_any_or_omit, sub_chk, implicit_omit, lhs); + allow_any_or_omit, sub_chk, implicit_omit, class_member_init, lhs); t->use_default_alternative(this); return self_ref; } @@ -7211,7 +7251,7 @@ bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, Ttcn::Template::C_MAY_INCOMPLETE; self_ref |= field_type->chk_this_template_generic(nt_templ, (incompl_ok ? incomplete_allowed : INCOMPLETE_NOT_ALLOWED), - OMIT_NOT_ALLOWED, ANY_OR_OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, lhs); + OMIT_NOT_ALLOWED, ANY_OR_OMIT_NOT_ALLOWED, SUB_CHK, implicit_omit, class_member_init, lhs); } break;} default: @@ -7219,7 +7259,7 @@ bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, Error_Context cntxt(t, "Using default alternative `%s' in value of union type `%s'", def_alt->get_name().get_dispname().c_str(), get_typename().c_str()); self_ref = def_alt->get_type()->chk_this_template_generic(t, incomplete_allowed, allow_omit, - allow_any_or_omit, sub_chk, implicit_omit, lhs); + allow_any_or_omit, sub_chk, implicit_omit, class_member_init, lhs); t->use_default_alternative(this); return self_ref; } @@ -7234,7 +7274,7 @@ bool Type::chk_this_template_Choice(Template *t, namedbool incomplete_allowed, } bool Type::chk_this_template_Seq(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; size_t n_type_comps = get_nof_comps(); @@ -7315,7 +7355,7 @@ bool Type::chk_this_template_Seq(Template *t, namedbool incomplete_allowed, self_ref |= type->chk_this_template_generic(comp_t, incomplete_allowed, (is_optional ? OMIT_ALLOWED : OMIT_NOT_ALLOWED), (is_optional ? ANY_OR_OMIT_ALLOWED : ANY_OR_OMIT_NOT_ALLOWED), - SUB_CHK, implicit_omit, lhs); + SUB_CHK, implicit_omit, class_member_init, lhs); } if (INCOMPLETE_ALLOWED != incomplete_allowed || IMPLICIT_OMIT == implicit_omit) { // check missing fields @@ -7351,7 +7391,8 @@ bool Type::chk_this_template_Seq(Template *t, namedbool incomplete_allowed, } bool Type::chk_this_template_Set(Template *t, - namedbool incomplete_allowed, namedbool implicit_omit, Common::Assignment *lhs) + namedbool incomplete_allowed, namedbool implicit_omit, + namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; size_t n_type_comps = get_nof_comps(); @@ -7399,7 +7440,7 @@ bool Type::chk_this_template_Set(Template *t, self_ref |= type->chk_this_template_generic(comp_t, incomplete_allowed, (is_optional ? OMIT_ALLOWED : OMIT_NOT_ALLOWED), (is_optional ? ANY_OR_OMIT_ALLOWED : ANY_OR_OMIT_NOT_ALLOWED), - SUB_CHK, implicit_omit, lhs); + SUB_CHK, implicit_omit, class_member_init, lhs); } if (INCOMPLETE_ALLOWED != incomplete_allowed || IMPLICIT_OMIT == implicit_omit) { // check missing fields @@ -7435,7 +7476,7 @@ bool Type::chk_this_template_Set(Template *t, } bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; switch(t->get_templatetype()) { @@ -7454,7 +7495,7 @@ bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, // the elements of permutation must be always complete self_ref |= u.seof.ofType->chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, - NOT_IMPLICIT_OMIT, lhs); + NOT_IMPLICIT_OMIT, class_member_init, lhs); } break; } case Ttcn::Template::TEMPLATE_LIST: { @@ -7484,7 +7525,7 @@ bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, // the templates within the permutation always have to be complete self_ref |= chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, - implicit_omit, lhs); + implicit_omit, class_member_init, lhs); break; case Ttcn::Template::TEMPLATE_NOTUSED: if (c == Ttcn::Template::C_MUST_COMPLETE) { @@ -7502,7 +7543,7 @@ bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, (c == Ttcn::Template::C_PARTIAL && i < nof_base_comps); self_ref |= u.seof.ofType->chk_this_template_generic(t_comp, (embedded_modified ? incomplete_allowed : INCOMPLETE_NOT_ALLOWED), - OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs); + OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, class_member_init, lhs); break; } } @@ -7548,7 +7589,7 @@ bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, u.seof.ofType->chk_this_template_ref(it_comp); self_ref |= u.seof.ofType->chk_this_template_generic(it_comp, INCOMPLETE_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, - SUB_CHK, implicit_omit, lhs); + SUB_CHK, implicit_omit, class_member_init, lhs); } for (size_t i = 0; i < index_map.size(); i++) delete index_map.get_nth_elem(i); @@ -7563,7 +7604,7 @@ bool Type::chk_this_template_SeqOf(Template *t, namedbool incomplete_allowed, } bool Type::chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, Common::Assignment *lhs) { bool self_ref = false; Ttcn::Template::templatetype_t temptype = t->get_templatetype(); @@ -7586,7 +7627,7 @@ bool Type::chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, // the elements of sets must be always complete self_ref |= u.seof.ofType->chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, - SUB_CHK, implicit_omit, lhs); + SUB_CHK, implicit_omit, class_member_init, lhs); if (t_comp->get_template_refd_last()->get_templatetype() == Ttcn::Template::ANY_OR_OMIT) { if (temptype == Ttcn::Template::SUPERSET_MATCH) @@ -7638,7 +7679,7 @@ bool Type::chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, (c == Ttcn::Template::C_PARTIAL && i < nof_base_comps); self_ref |= u.seof.ofType->chk_this_template_generic(t_comp, (embedded_modified ? incomplete_allowed : INCOMPLETE_NOT_ALLOWED), - OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs); + OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, class_member_init, lhs); break; } } @@ -7682,7 +7723,7 @@ bool Type::chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, u.seof.ofType->chk_this_template_ref(it_comp); self_ref |= u.seof.ofType->chk_this_template_generic(it_comp, INCOMPLETE_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, - SUB_CHK, implicit_omit, lhs); + SUB_CHK, implicit_omit, class_member_init, lhs); } for (size_t i = 0; i < index_map.size(); i++) delete index_map.get_nth_elem(i); @@ -7697,7 +7738,8 @@ bool Type::chk_this_template_SetOf(Template *t, namedbool incomplete_allowed, } bool Type::chk_this_template_array(Template *t, namedbool incomplete_allowed, - namedbool implicit_omit, Common::Assignment *lhs) + namedbool implicit_omit, namedbool class_member_init, + Common::Assignment *lhs) { bool self_ref = false; switch (t->get_templatetype()) { @@ -7716,7 +7758,7 @@ bool Type::chk_this_template_array(Template *t, namedbool incomplete_allowed, // the elements of permutation must be always complete self_ref |= u.array.element_type->chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, - NOT_IMPLICIT_OMIT, lhs); + NOT_IMPLICIT_OMIT, class_member_init, lhs); } break; } case Ttcn::Template::TEMPLATE_LIST: { @@ -7759,7 +7801,7 @@ bool Type::chk_this_template_array(Template *t, namedbool incomplete_allowed, // the templates within the permutation always have to be complete self_ref |= chk_this_template_generic(t_comp, INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, - implicit_omit, lhs); + implicit_omit, class_member_init, lhs); break; case Ttcn::Template::TEMPLATE_NOTUSED: if (INCOMPLETE_NOT_ALLOWED == incomplete_allowed) @@ -7771,7 +7813,8 @@ bool Type::chk_this_template_array(Template *t, namedbool incomplete_allowed, break; default: self_ref |= u.array.element_type->chk_this_template_generic(t_comp, - incomplete_allowed, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs); + incomplete_allowed, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, + implicit_omit, class_member_init, lhs); break; } } @@ -7812,7 +7855,8 @@ bool Type::chk_this_template_array(Template *t, namedbool incomplete_allowed, it_comp->set_my_governor(u.array.element_type); u.array.element_type->chk_this_template_ref(it_comp); self_ref |= u.array.element_type->chk_this_template_generic(it_comp, - incomplete_allowed, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, implicit_omit, lhs); + incomplete_allowed, OMIT_NOT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, + implicit_omit, class_member_init, lhs); } for (size_t i = 0; i < index_map.size(); i++) delete index_map.get_nth_elem(i); @@ -7834,7 +7878,8 @@ void Type::chk_this_template_Fat(Template *t) "allowed for type `%s'", get_typename().c_str()); } -void Type::chk_this_template_Signature(Template *t, namedbool incomplete_allowed) +void Type::chk_this_template_Signature(Template *t, namedbool incomplete_allowed, + namedbool class_member_init) { bool self_ref = false; size_t n_type_params = get_nof_comps(); @@ -7888,7 +7933,7 @@ void Type::chk_this_template_Signature(Template *t, namedbool incomplete_allowed type->chk_this_template_ref(comp_t); self_ref |= type->chk_this_template_generic(comp_t, incomplete_allowed, OMIT_NOT_ALLOWED, ANY_OR_OMIT_NOT_ALLOWED, - SUB_CHK, NOT_IMPLICIT_OMIT, NULL); + SUB_CHK, NOT_IMPLICIT_OMIT, class_member_init, NULL); } if(incomplete_allowed != INCOMPLETE_ALLOWED) { SignatureParam *first_undef_in = NULL, diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 54af76a944f7aa0fa052626c6679db7804490a04..f15cf586ab0bcee1701171025ea42e83cb05be83 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -10307,6 +10307,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } if (refch->add(get_fullname())) { if (ass->get_my_scope()->get_parent_scope()->is_class_scope()) { + // class members are considered unfoldable, because their initial + // values can be changed in the constructor u.ref.refd_last = this; } else { @@ -12059,7 +12061,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } // switch } - bool Value::chk_expr_self_ref_templ(Ttcn::Template *t, Common::Assignment *lhs) + bool Value::chk_expr_self_ref_templ(Ttcn::Template *t, Common::Assignment *lhs, namedbool class_member_init) { bool self_ref = false; switch (t->get_templatetype()) { @@ -12067,15 +12069,17 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Value *v = t->get_specific_value(); self_ref |= v->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE) ->chk_this_value(v, lhs, Type::EXPECTED_DYNAMIC_VALUE, - INCOMPLETE_NOT_ALLOWED, OMIT_ALLOWED, NO_SUB_CHK, NOT_IMPLICIT_OMIT, NOT_STR_ELEM); + INCOMPLETE_NOT_ALLOWED, OMIT_ALLOWED, NO_SUB_CHK, NOT_IMPLICIT_OMIT, NOT_STR_ELEM, class_member_init); break; } case Ttcn::Template::TEMPLATE_REFD: { - Ttcn::Reference *refb = t->get_reference(); - Common::Assignment *ass = refb->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Ttcn::Reference *refb = t->get_reference(); + Common::Assignment *ass = refb->get_refd_assignment(); + self_ref |= (ass == lhs); + } break; } case Ttcn::Template::ALL_FROM: - self_ref |= chk_expr_self_ref_templ(t->get_all_from(), lhs); + self_ref |= chk_expr_self_ref_templ(t->get_all_from(), lhs, class_member_init); break; case Ttcn::Template::TEMPLATE_LIST: case Ttcn::Template::SUPERSET_MATCH: @@ -12085,7 +12089,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Ttcn::Template::VALUE_LIST: { size_t num = t->get_nof_comps(); for (size_t i = 0; i < num; ++i) { - self_ref |= chk_expr_self_ref_templ(t->get_temp_byIndex(i), lhs); + self_ref |= chk_expr_self_ref_templ(t->get_temp_byIndex(i), lhs, class_member_init); } break; } // not yet clear whether we should use this or the above for TEMPLATE_LIST @@ -12099,22 +12103,22 @@ void Value::chk_expr_operand_execute_refd(Value *v1, size_t nnt = t->get_nof_comps(); for (size_t i=0; i < nnt; ++i) { Ttcn::NamedTemplate *nt = t->get_namedtemp_byIndex(i); - self_ref |= chk_expr_self_ref_templ(nt->get_template(), lhs); + self_ref |= chk_expr_self_ref_templ(nt->get_template(), lhs, class_member_init); } break; } case Ttcn::Template::INDEXED_TEMPLATE_LIST: { size_t nnt = t->get_nof_comps(); for (size_t i=0; i < nnt; ++i) { Ttcn::IndexedTemplate *it = t->get_indexedtemp_byIndex(i); - self_ref |= chk_expr_self_ref_templ(it->get_template(), lhs); + self_ref |= chk_expr_self_ref_templ(it->get_template(), lhs, class_member_init); } break; } case Ttcn::Template::VALUE_RANGE: { Ttcn::ValueRange *vr = t->get_value_range(); Common::Value *v = vr->get_min_v(); - if (v) self_ref |= chk_expr_self_ref_val(v, lhs); + if (v) self_ref |= chk_expr_self_ref_val(v, lhs, class_member_init); v = vr->get_max_v(); - if (v) self_ref |= chk_expr_self_ref_val(v, lhs); + if (v) self_ref |= chk_expr_self_ref_val(v, lhs, class_member_init); break; } case Ttcn::Template::CSTR_PATTERN: case Ttcn::Template::USTR_PATTERN: { @@ -12134,14 +12138,14 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Ttcn::Template::TEMPLATE_INVOKE: break; // assume self-ref can't happen case Ttcn::Template::DECODE_MATCH: - self_ref |= chk_expr_self_ref_templ(t->get_decode_target()->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(t->get_decode_target()->get_Template(), lhs, class_member_init); break; case Ttcn::Template::TEMPLATE_ERROR: //FATAL_ERROR("Value::chk_expr_self_ref_templ()"); break; case Ttcn::Template::TEMPLATE_CONCAT: - self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(true), lhs); - self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(false), lhs); + self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(true), lhs, class_member_init); + self_ref |= chk_expr_self_ref_templ(t->get_concat_operand(false), lhs, class_member_init); break; // default: // FATAL_ERROR("todo ttype %d", t->get_templatetype()); @@ -12150,7 +12154,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, return self_ref; } - bool Value::chk_expr_self_ref_val(Common::Value *v, Common::Assignment *lhs) + bool Value::chk_expr_self_ref_val(Common::Value *v, Common::Assignment *lhs, namedbool class_member_init) { Common::Type *gov = v->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE); namedbool is_str_elem = NOT_STR_ELEM; @@ -12163,13 +12167,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1, } return gov->chk_this_value(v, lhs, Type::EXPECTED_DYNAMIC_VALUE, INCOMPLETE_NOT_ALLOWED, OMIT_ALLOWED, NO_SUB_CHK, NOT_IMPLICIT_OMIT, - is_str_elem); + is_str_elem, class_member_init); } - bool Value::chk_expr_self_ref(Common::Assignment *lhs) + bool Value::chk_expr_self_ref(Common::Assignment *lhs, namedbool class_member_init) { if (valuetype != V_EXPR) FATAL_ERROR("Value::chk_expr_self_ref"); - if (!lhs) FATAL_ERROR("no lhs!"); bool self_ref = false; switch (u.expr.v_optype) { case OPTYPE_RND: // - @@ -12192,7 +12195,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1, break; // nothing to do case OPTYPE_MATCH: // v1 t2 - self_ref |= chk_expr_self_ref_templ(u.expr.t2->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.t2->get_Template(), lhs, class_member_init); // no break case OPTYPE_UNARYPLUS: // v1 case OPTYPE_UNARYMINUS: // v1 @@ -12236,18 +12239,18 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_GET_STRINGENCODING: case OPTYPE_DECODE_BASE64: case OPTYPE_REMOVE_BOM: - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); break; case OPTYPE_COMP_RUNNING: // v1 [r2] b4 case OPTYPE_COMP_ALIVE: // v1 [r2] b4 - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); - if (u.expr.r2 != NULL) { + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); + if (u.expr.r2 != NULL && lhs != NULL) { Common::Assignment *ass = u.expr.r2->get_refd_assignment(); self_ref |= (ass == lhs); } break; case OPTYPE_HOSTID: // [v1] - if (u.expr.v1) self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); + if (u.expr.v1) self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); break; case OPTYPE_ADD: // v1 v2 case OPTYPE_SUBTRACT: // v1 v2 @@ -12275,45 +12278,45 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_INT2BIT: // v1 v2 case OPTYPE_INT2HEX: // v1 v2 case OPTYPE_INT2OCT: // v1 v2 - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); - self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); + self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_UNICHAR2OCT: // v1 [v2] case OPTYPE_OCT2UNICHAR: case OPTYPE_ENCODE_BASE64: - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); - if (u.expr.v2) self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); + if (u.expr.v2) self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_DECOMP: // v1 v2 v3 - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); - self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); - self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); + self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); + self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); break; case OPTYPE_REPLACE: // ti1 v2 v3 ti4 - self_ref |= chk_expr_self_ref_templ(u.expr.ti4->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti4->get_Template(), lhs, class_member_init); // no break case OPTYPE_SUBSTR: // ti1 v2 v3 case OPTYPE_ENCODE: // ti1 [v2] [v3] - self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); if (u.expr.v2 != NULL) { - self_ref |= chk_expr_self_ref_val (u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_val (u.expr.v2, lhs, class_member_init); } if (u.expr.v3 != NULL) { - self_ref |= chk_expr_self_ref_val (u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val (u.expr.v3, lhs, class_member_init); } break; case OPTYPE_REGEXP: // ti1 t2 v3 - self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs); - self_ref |= chk_expr_self_ref_templ(u.expr.t2 ->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); + self_ref |= chk_expr_self_ref_templ(u.expr.t2 ->get_Template(), lhs, class_member_init); break; case OPTYPE_VALUEOF: // ti1 [subrefs2] if (u.expr.subrefs2 != NULL) { for (size_t i = 0; i < u.expr.subrefs2->get_nof_refs(); ++i) { Ttcn::FieldOrArrayRef* subref = u.expr.subrefs2->get_ref(i); if (subref->get_type() == Ttcn::FieldOrArrayRef::ARRAY_REF) { - self_ref |= chk_expr_self_ref_val(subref->get_val(), lhs); + self_ref |= chk_expr_self_ref_val(subref->get_val(), lhs, class_member_init); } } } @@ -12321,31 +12324,33 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case OPTYPE_LENGTHOF: // ti1 case OPTYPE_SIZEOF: // ti1 case OPTYPE_TTCN2STRING: - self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); break; case OPTYPE_ENCVALUE_UNICHAR: // ti1 [v2] [v3] [v4] - self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); if (u.expr.v2 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); } if (u.expr.v3 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } break; case OPTYPE_DECVALUE_UNICHAR: { // r1 r2 [v3] [v4] [v5] - Common::Assignment *ass = u.expr.r2->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Common::Assignment *ass = u.expr.r2->get_refd_assignment(); + self_ref |= (ass == lhs); + } if (u.expr.v3 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } if (u.expr.v5 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v5, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v5, lhs, class_member_init); } goto label_r1; break; } @@ -12373,19 +12378,21 @@ void Value::chk_expr_operand_execute_refd(Value *v1, case Ttcn::LogArgument::L_VAL: case Ttcn::LogArgument::L_MATCH: - self_ref |= chk_expr_self_ref_val(la->get_val(), lhs); + self_ref |= chk_expr_self_ref_val(la->get_val(), lhs, class_member_init); break; case Ttcn::LogArgument::L_REF: { - Ttcn::Reference *ref = la->get_ref(); - Common::Assignment *ass = ref->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Ttcn::Reference *ref = la->get_ref(); + Common::Assignment *ass = ref->get_refd_assignment(); + self_ref |= (ass == lhs); + } break; } case Ttcn::LogArgument::L_TI: { Ttcn::TemplateInstance *ti = la->get_ti(); Ttcn::Template *t = ti->get_Template(); - self_ref |= chk_expr_self_ref_templ(t, lhs); + self_ref |= chk_expr_self_ref_templ(t, lhs, class_member_init); break; } // no default please @@ -12394,32 +12401,38 @@ void Value::chk_expr_operand_execute_refd(Value *v1, break; } case OPTYPE_DECODE: { // r1 r2 - Common::Assignment *ass = u.expr.r2->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Common::Assignment *ass = u.expr.r2->get_refd_assignment(); + self_ref |= (ass == lhs); + } if (u.expr.v3 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } if (u.expr.v4 != NULL) { - self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v4, lhs, class_member_init); } goto label_r1; } case OPTYPE_EXECUTE: // r1 [v2] if (u.expr.v2) { - self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); } label_r1: // no break case OPTYPE_TMR_READ: { // r1 - Common::Assignment *ass = u.expr.r1->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Common::Assignment *ass = u.expr.r1->get_refd_assignment(); + self_ref |= (ass == lhs); + } break; } case OPTYPE_UNDEF_RUNNING: { // r1 [r2] b4 - if (u.expr.r2 != NULL) { - Common::Assignment *ass2 = u.expr.r2->get_refd_assignment(); - self_ref |= (ass2 == lhs); + if (lhs != NULL) { + if (u.expr.r2 != NULL) { + Common::Assignment *ass2 = u.expr.r2->get_refd_assignment(); + self_ref |= (ass2 == lhs); + } + Common::Assignment *ass = u.expr.r1->get_refd_assignment(); + self_ref |= (ass == lhs); } - Common::Assignment *ass = u.expr.r1->get_refd_assignment(); - self_ref |= (ass == lhs); break; } case OPTYPE_ISCHOSEN_T: // t1 i2 @@ -12429,25 +12442,27 @@ void Value::chk_expr_operand_execute_refd(Value *v1, Ttcn::Template *t; if (u.expr.v_optype == OPTYPE_ISCHOSEN_T) t = u.expr.t1; else t = u.expr.ti1->get_Template(); - self_ref |= chk_expr_self_ref_templ(t, lhs); + self_ref |= chk_expr_self_ref_templ(t, lhs, class_member_init); break; } case OPTYPE_ISTEMPLATEKIND: // ti1 v2 - self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs); - self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs); + self_ref |= chk_expr_self_ref_templ(u.expr.ti1->get_Template(), lhs, class_member_init); + self_ref |= chk_expr_self_ref_val(u.expr.v2, lhs, class_member_init); break; case OPTYPE_EXECUTE_REFD: // v1 t_list2 [v3] if (u.expr.v3) { - self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v3, lhs, class_member_init); } // no break case OPTYPE_ACTIVATE_REFD: // v1 t_list2 - self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs); + self_ref |= chk_expr_self_ref_val(u.expr.v1, lhs, class_member_init); // TODO t_list2 break; case OPTYPE_OF_CLASS: case OPTYPE_CLASS_CASTING: { - Common::Assignment *ass = u.expr.r2->get_refd_assignment(); - self_ref |= (ass == lhs); + if (lhs != NULL) { + Common::Assignment *ass = u.expr.r2->get_refd_assignment(); + self_ref |= (ass == lhs); + } break; } case NUMBER_OF_OPTYPES: // can never happen @@ -15969,6 +15984,15 @@ void Value::chk_expr_operand_execute_refd(Value *v1, { Value *v = get_value_refd_last(); if (v == this) { + Assignment* refd_ass = u.ref.ref->get_refd_assignment(); + if ((refd_ass->get_asstype() == Assignment::A_CONST || + refd_ass->get_asstype() == Assignment::A_VAR) && + refd_ass->get_my_scope()->get_parent_scope()->is_class_scope()) { + Value* v2 = refd_ass->get_Value(); + if (v2 != NULL && needs_init_precede(v2)) { + str = v2->generate_code_init(str, v2->get_lhs_name().c_str()); + } + } // the referred value is not available at compile time // the code generation is based on the reference if (use_runtime_2 && TypeConv::needs_conv_refd(v)) { diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 3698d4c1c4bdcd91f76112bd84e1afa74fb68309..1a920e9d6d81b3c374006137577b91c5f2f16519 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -849,12 +849,12 @@ namespace Common { /** Check that the value (a V_EXPR) - being used as the RHS - refers to * the LHS of the assignment. * @return true if self-assignment*/ - bool chk_expr_self_ref(Common::Assignment *lhs); + bool chk_expr_self_ref(Common::Assignment *lhs, namedbool class_member_init); virtual string create_stringRepr(); private: - static bool chk_expr_self_ref_templ(Ttcn::Template *t, Common::Assignment *lhs); - static bool chk_expr_self_ref_val (Common::Value *v, Common::Assignment *lhs); + static bool chk_expr_self_ref_templ(Ttcn::Template *t, Common::Assignment *lhs, namedbool class_member_init); + static bool chk_expr_self_ref_val (Common::Value *v, Common::Assignment *lhs, namedbool class_member_init); string create_stringRepr_unary(const char *operator_str); string create_stringRepr_infix(const char *operator_str); string create_stringRepr_predef1(const char *function_name); diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc index 723cba45e9394879bef0de188ffec925501122c7..1fa5e499c47e5e915fb34dbaa803d0eac5a40ed9 100644 --- a/compiler2/ttcn3/AST_ttcn3.cc +++ b/compiler2/ttcn3/AST_ttcn3.cc @@ -4037,7 +4037,7 @@ namespace Ttcn { Def_Const::Def_Const(Identifier *p_id, Type *p_type, Value *p_value) : Definition(A_CONST, p_id) { - if (!p_type || !p_value) FATAL_ERROR("Ttcn::Def_Const::Def_Const()"); + if (!p_type) FATAL_ERROR("Ttcn::Def_Const::Def_Const()"); type=p_type; type->set_ownertype(Type::OT_CONST_DEF, this); value=p_value; @@ -4059,14 +4059,18 @@ namespace Ttcn { { Definition::set_fullname(p_fullname); type->set_fullname(p_fullname + ".<type>"); - value->set_fullname(p_fullname); + if (value != NULL) { + value->set_fullname(p_fullname); + } } void Def_Const::set_my_scope(Scope *p_scope) { Definition::set_my_scope(p_scope); type->set_my_scope(p_scope); - value->set_my_scope(p_scope); + if (value != NULL) { + value->set_my_scope(p_scope); + } } Setting *Def_Const::get_Setting() @@ -4101,8 +4105,14 @@ namespace Ttcn { id->get_dispname().c_str()); type->set_genname(_T_, get_genname()); type->chk(); - value->set_my_governor(type); - type->chk_this_value_ref(value); + + if (value != NULL) { + value->set_my_governor(type); + type->chk_this_value_ref(value); + } + else if (!my_scope->is_class_scope()) { + error("Missing initial value"); + } checked=true; if (w_attrib_path) { w_attrib_path->chk_global_attrib(true); @@ -4134,23 +4144,26 @@ namespace Ttcn { t->get_typename().c_str()); break; default: - value_under_check = true; + if (value != NULL) { + value_under_check = true; + namedbool class_member_init = my_scope->is_class_scope() ? + CLASS_MEMBER_INIT : NOT_CLASS_MEMBER_INIT; type->chk_this_value(value, 0, Type::EXPECTED_STATIC_VALUE, WARNING_FOR_INCOMPLETE, - OMIT_NOT_ALLOWED, SUB_CHK, has_implicit_omit_attr()); - value_under_check = false; - erroneous_attrs = chk_erroneous_attr(w_attrib_path, type, get_my_scope(), - get_fullname(), false); - if (erroneous_attrs) value->add_err_descr(NULL, erroneous_attrs->get_err_descr()); - { - ReferenceChain refch(type, "While checking embedded recursions"); - value->chk_recursions(refch); - } + OMIT_NOT_ALLOWED, SUB_CHK, has_implicit_omit_attr(), NOT_STR_ELEM, class_member_init); + value_under_check = false; + erroneous_attrs = chk_erroneous_attr(w_attrib_path, type, get_my_scope(), + get_fullname(), false); + if (erroneous_attrs) value->add_err_descr(NULL, erroneous_attrs->get_err_descr()); + ReferenceChain refch(type, "While checking embedded recursions"); + value->chk_recursions(refch); + } break; } - if (!semantic_check_only) { + if (!semantic_check_only && value != NULL) { value->set_genname_prefix("const_"); value->set_genname_recursive(get_genname()); - value->set_code_section(GovernedSimple::CS_PRE_INIT); + value->set_code_section(my_scope->is_class_scope() ? + GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_PRE_INIT); } } @@ -4167,7 +4180,9 @@ namespace Ttcn { return false; } Def_Const *p_def_const = dynamic_cast<Def_Const*>(p_def); - if (!p_def_const) FATAL_ERROR("Def_Const::chk_identical()"); + if (p_def_const == NULL || value == NULL || p_def_const->value == NULL) { + FATAL_ERROR("Def_Const::chk_identical()"); + } if (!type->is_identical(p_def_const->type)) { const char *dispname_str = id->get_dispname().c_str(); type->error("Local constant `%s' has type `%s', but the constant " @@ -4193,15 +4208,20 @@ namespace Ttcn { const_def cdef; Code::init_cdef(&cdef); bool in_class = my_scope->is_class_scope(); - type->generate_code_object(&cdef, value, in_class); - if (value->is_unfoldable()) { - cdef.post = update_location_object(cdef.post); - cdef.post = value->generate_code_init(cdef.post, - value->get_lhs_name().c_str()); - } else { - cdef.init = update_location_object(cdef.init); - cdef.init = value->generate_code_init(cdef.init, - value->get_lhs_name().c_str()); + if (value != NULL) { + type->generate_code_object(&cdef, value, in_class); + if (value->is_unfoldable()) { + cdef.post = update_location_object(cdef.post); + cdef.post = value->generate_code_init(cdef.post, + value->get_lhs_name().c_str()); + } else { + cdef.init = update_location_object(cdef.init); + cdef.init = value->generate_code_init(cdef.init, + value->get_lhs_name().c_str()); + } + } + else { + type->generate_code_object(&cdef, my_scope, get_genname(), "const_", false, false, true); } Code::merge_cdef(target, &cdef, in_class); Code::free_cdef(&cdef); @@ -4214,6 +4234,9 @@ namespace Ttcn { char *Def_Const::generate_code_str(char *str) { + if (value == NULL) { + FATAL_ERROR("Def_Const::generate_code_str"); + } const string& t_genname = get_genname(); const char *genname_str = t_genname.c_str(); if (value->has_single_expr()) { @@ -4237,6 +4260,9 @@ namespace Ttcn { void Def_Const::ilt_generate_code(ILT *ilt) { + if (value == NULL) { + FATAL_ERROR("Def_Const::ilt_generate_code"); + } const string& t_genname = get_genname(); const char *genname_str = t_genname.c_str(); char*& def=ilt->get_out_def(); @@ -4257,7 +4283,9 @@ namespace Ttcn { { DEBUG(level, "Constant: %s @%p", id->get_dispname().c_str(), static_cast<const void*>(this)); type->dump(level + 1); - value->dump(level + 1); + if (value != NULL) { + value->dump(level + 1); + } } // ================================= @@ -4649,7 +4677,9 @@ namespace Ttcn { type->chk_this_template_ref(def_template); checked = true; type->chk_this_template_generic(def_template, INCOMPLETE_ALLOWED, - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, IMPLICIT_OMIT == has_implicit_omit_attr() ? IMPLICIT_OMIT : NOT_IMPLICIT_OMIT, 0); + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, + IMPLICIT_OMIT == has_implicit_omit_attr() ? IMPLICIT_OMIT : NOT_IMPLICIT_OMIT, + NOT_CLASS_MEMBER_INIT, 0); type->chk_this_template_incorrect_field(); if (!semantic_check_only) { def_template->set_genname_prefix("modulepar_"); @@ -4733,7 +4763,7 @@ namespace Ttcn { body(p_body), template_restriction(p_template_restriction), gen_restriction_check(false) { - if (!p_type || !p_body) FATAL_ERROR("Ttcn::Def_Template::Def_Template()"); + if (!p_type) FATAL_ERROR("Ttcn::Def_Template::Def_Template()"); type->set_ownertype(Type::OT_TEMPLATE_DEF, this); if (fp_list) fp_list->set_my_def(this); } @@ -4758,7 +4788,9 @@ namespace Ttcn { if (fp_list) fp_list->set_fullname(p_fullname + ".<formal_par_list>"); if (derived_ref) derived_ref->set_fullname(p_fullname + ".<derived_reference>"); - body->set_fullname(p_fullname); + if (body != NULL) { + body->set_fullname(p_fullname); + } } void Def_Template::set_my_scope(Scope *p_scope) @@ -4771,8 +4803,12 @@ namespace Ttcn { if (derived_ref) derived_ref->set_my_scope(&bridgeScope); if (fp_list) { fp_list->set_my_scope(&bridgeScope); - body->set_my_scope(fp_list); - } else body->set_my_scope(&bridgeScope); + if (body != NULL) { + body->set_my_scope(fp_list); + } + } else if (body != NULL) { + body->set_my_scope(&bridgeScope); + } } Setting *Def_Template::get_Setting() @@ -4827,21 +4863,29 @@ namespace Ttcn { fp_list->chk(asstype); if (local_scope) error("Parameterized local template `%s' not supported", id->get_dispname().c_str()); - body->set_formalparlist(fp_list); + if (body != NULL) { + body->set_formalparlist(fp_list); + } } // Merge the elements of "all from" into the list - body->flatten(false); + if (body != NULL) { + body->flatten(false); - body->set_my_governor(type); + body->set_my_governor(type); + + if (body->get_templatetype() == Template::CSTR_PATTERN && + type->get_type_refd_last()->get_typetype() == Type::T_USTR) { + body->set_templatetype(Template::USTR_PATTERN); + body->get_ustr_pattern()->set_pattern_type(PatternString::USTR_PATTERN); + } - if (body->get_templatetype() == Template::CSTR_PATTERN && - type->get_type_refd_last()->get_typetype() == Type::T_USTR) { - body->set_templatetype(Template::USTR_PATTERN); - body->get_ustr_pattern()->set_pattern_type(PatternString::USTR_PATTERN); + type->chk_this_template_ref(body); + } + else if (!my_scope->is_class_scope()) { + error("Missing template body"); } - type->chk_this_template_ref(body); Type *t = type->get_type_refd_last(); if (t->get_typetype() == Type::T_PORT) { error("Template cannot be defined for port type `%s'", @@ -4851,66 +4895,74 @@ namespace Ttcn { error("Template cannot be defined for class type `%s'", t->get_typename().c_str()); } + type->chk_this_template_incorrect_field(); chk_modified(); chk_recursive_derivation(); - type->chk_this_template_generic(body, - derived_ref != NULL ? INCOMPLETE_ALLOWED : WARNING_FOR_INCOMPLETE, - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, - IMPLICIT_OMIT == has_implicit_omit_attr() ? IMPLICIT_OMIT : NOT_IMPLICIT_OMIT, 0); - type->chk_this_template_incorrect_field(); - erroneous_attrs = chk_erroneous_attr(w_attrib_path, type, get_my_scope(), - get_fullname(), false); - if (erroneous_attrs) body->add_err_descr(NULL, erroneous_attrs->get_err_descr()); - { - ReferenceChain refch(type, "While checking embedded recursions"); - body->chk_recursions(refch); - } - if (template_restriction!=TR_NONE) { - Error_Context ec(this, "While checking template restriction `%s'", - Template::get_restriction_name(template_restriction)); - gen_restriction_check = - body->chk_restriction("template definition", template_restriction, body); - if (fp_list && template_restriction!=TR_PRESENT) { - size_t nof_fps = fp_list->get_nof_fps(); - for (size_t i=0; i<nof_fps; i++) { - FormalPar* fp = fp_list->get_fp_byIndex(i); - // if formal par is not template then skip restriction checking, - // templates can have only `in' parameters - if (fp->get_asstype()!=A_PAR_TEMPL_IN) continue; - template_restriction_t fp_tr = fp->get_template_restriction(); - switch (template_restriction) { - case TR_VALUE: - case TR_OMIT: - switch (fp_tr) { + if (body != NULL) { + namedbool class_member_init = my_scope->is_class_scope() ? + CLASS_MEMBER_INIT : NOT_CLASS_MEMBER_INIT; + type->chk_this_template_generic(body, + derived_ref != NULL ? INCOMPLETE_ALLOWED : WARNING_FOR_INCOMPLETE, + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, + IMPLICIT_OMIT == has_implicit_omit_attr() ? IMPLICIT_OMIT : NOT_IMPLICIT_OMIT, + class_member_init, 0); + erroneous_attrs = chk_erroneous_attr(w_attrib_path, type, get_my_scope(), + get_fullname(), false); + if (erroneous_attrs) body->add_err_descr(NULL, erroneous_attrs->get_err_descr()); + { + ReferenceChain refch(type, "While checking embedded recursions"); + body->chk_recursions(refch); + } + + if (template_restriction!=TR_NONE) { + Error_Context ec(this, "While checking template restriction `%s'", + Template::get_restriction_name(template_restriction)); + gen_restriction_check = + body->chk_restriction("template definition", template_restriction, body); + if (fp_list && template_restriction!=TR_PRESENT) { + size_t nof_fps = fp_list->get_nof_fps(); + for (size_t i=0; i<nof_fps; i++) { + FormalPar* fp = fp_list->get_fp_byIndex(i); + // if formal par is not template then skip restriction checking, + // templates can have only `in' parameters + if (fp->get_asstype()!=A_PAR_TEMPL_IN) continue; + template_restriction_t fp_tr = fp->get_template_restriction(); + switch (template_restriction) { case TR_VALUE: case TR_OMIT: - // allowed - break; - case TR_PRESENT: - fp->error("Formal parameter with template restriction `%s' " - "not allowed here", Template::get_restriction_name(fp_tr)); - break; - case TR_NONE: - fp->error("Formal parameter without template restriction " - "not allowed here"); + switch (fp_tr) { + case TR_VALUE: + case TR_OMIT: + // allowed + break; + case TR_PRESENT: + fp->error("Formal parameter with template restriction `%s' " + "not allowed here", Template::get_restriction_name(fp_tr)); + break; + case TR_NONE: + fp->error("Formal parameter without template restriction " + "not allowed here"); + break; + default: + FATAL_ERROR("Ttcn::Def_Template::chk()"); + } break; default: FATAL_ERROR("Ttcn::Def_Template::chk()"); } - break; - default: - FATAL_ERROR("Ttcn::Def_Template::chk()"); } } } - } - if (!semantic_check_only) { - if (fp_list) fp_list->set_genname(t_genname); - body->set_genname_prefix("template_"); - body->set_genname_recursive(t_genname); - body->set_code_section(fp_list ? GovernedSimple::CS_INLINE : - GovernedSimple::CS_POST_INIT); + + if (!semantic_check_only) { + if (fp_list) fp_list->set_genname(t_genname); + body->set_genname_prefix("template_"); + body->set_genname_recursive(t_genname); + body->set_code_section(fp_list ? GovernedSimple::CS_INLINE : + (my_scope->is_class_scope() ? + GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_POST_INIT)); + } } } @@ -4974,7 +5026,9 @@ namespace Ttcn { return; } base_template = dynamic_cast<Def_Template*>(ass); - if (!base_template) FATAL_ERROR("Def_Template::chk_modified()"); + if (base_template == NULL || body == NULL) { + FATAL_ERROR("Def_Template::chk_modified()"); + } Type *base_type = base_template->get_Type(); TypeCompatInfo info_base(my_scope->get_scope_mod(), type, base_type, true, false, true); @@ -5091,7 +5145,7 @@ namespace Ttcn { void Def_Template::generate_code(output_struct *target, bool) { type->generate_code(target); - if (body->get_err_descr() != NULL && body->get_err_descr()->has_descr(NULL)) { + if (body != NULL && body->get_err_descr() != NULL && body->get_err_descr()->has_descr(NULL)) { target->functions.post_init = body->get_err_descr()->generate_code_init_str( NULL, target->functions.post_init, body->get_lhs_name()); } @@ -5188,56 +5242,61 @@ namespace Ttcn { const_def cdef; Code::init_cdef(&cdef); bool in_class = my_scope->is_class_scope(); - type->generate_code_object(&cdef, body, in_class); - cdef.init = update_location_object(cdef.init); - if (base_template) { - // modified template - if (base_template->my_scope->get_scope_mod_gen() == - my_scope->get_scope_mod_gen()) { - // if the base template is in the same module its body has to be - // initialized first - cdef.init = base_template->body->generate_code_init(cdef.init, - base_template->body->get_lhs_name().c_str()); + if (body != NULL) { + type->generate_code_object(&cdef, body, in_class); + cdef.init = update_location_object(cdef.init); + if (base_template) { + // modified template + if (base_template->my_scope->get_scope_mod_gen() == + my_scope->get_scope_mod_gen()) { + // if the base template is in the same module its body has to be + // initialized first + cdef.init = base_template->body->generate_code_init(cdef.init, + base_template->body->get_lhs_name().c_str()); + } + if (use_runtime_2 && body->get_needs_conversion()) { + Type *body_type = body->get_my_governor()->get_type_refd_last(); + Type *base_type = base_template->body->get_my_governor() + ->get_type_refd_last(); + if (!body_type || !base_type) + FATAL_ERROR("Def_Template::generate_code()"); + const string& tmp_id = body->get_temporary_id(); + const char *tmp_id_str = tmp_id.c_str(); + // base template initialization + cdef.init = mputprintf(cdef.init, + "%s %s;\n" + "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' " + "and `%s' are not compatible at run-time\");\n" + "%s = %s;\n", + body_type->get_genname_template(my_scope).c_str(), tmp_id_str, + TypeConv::get_conv_func(base_type, body_type, my_scope + ->get_scope_mod()).c_str(), tmp_id_str, base_template + ->get_genname_from_scope(my_scope).c_str(), base_type + ->get_typename().c_str(), body_type->get_typename().c_str(), + body->get_lhs_name().c_str(), tmp_id_str); + } else { + cdef.init = mputprintf(cdef.init, "%s = %s;\n", + body->get_lhs_name().c_str(), + base_template->get_genname_from_scope(my_scope).c_str()); + } } - if (use_runtime_2 && body->get_needs_conversion()) { - Type *body_type = body->get_my_governor()->get_type_refd_last(); - Type *base_type = base_template->body->get_my_governor() - ->get_type_refd_last(); - if (!body_type || !base_type) - FATAL_ERROR("Def_Template::generate_code()"); - const string& tmp_id = body->get_temporary_id(); - const char *tmp_id_str = tmp_id.c_str(); - // base template initialization - cdef.init = mputprintf(cdef.init, - "%s %s;\n" - "if (!%s(%s, %s)) TTCN_error(\"Values or templates of types `%s' " - "and `%s' are not compatible at run-time\");\n" - "%s = %s;\n", - body_type->get_genname_template(my_scope).c_str(), tmp_id_str, - TypeConv::get_conv_func(base_type, body_type, my_scope - ->get_scope_mod()).c_str(), tmp_id_str, base_template - ->get_genname_from_scope(my_scope).c_str(), base_type - ->get_typename().c_str(), body_type->get_typename().c_str(), - body->get_lhs_name().c_str(), tmp_id_str); - } else { - cdef.init = mputprintf(cdef.init, "%s = %s;\n", - body->get_lhs_name().c_str(), - base_template->get_genname_from_scope(my_scope).c_str()); + if (use_runtime_2 && TypeConv::needs_conv_refd(body)) + cdef.init = TypeConv::gen_conv_code_refd(cdef.init, + body->get_lhs_name().c_str(), body); + else + cdef.init = body->generate_code_init(cdef.init, + body->get_lhs_name().c_str()); + if (template_restriction != TR_NONE && gen_restriction_check) + cdef.init = Template::generate_restriction_check_code(cdef.init, + body->get_lhs_name().c_str(), template_restriction); + if (body->get_err_descr() != NULL && body->get_err_descr()->has_descr(NULL)) { + cdef.init = mputprintf(cdef.init, "%s.set_err_descr(&%s_%lu_err_descr);\n", + body->get_lhs_name().c_str(), body->get_lhs_name().c_str(), + static_cast<unsigned long>( body->get_err_descr()->get_descr_index(NULL) )); } } - if (use_runtime_2 && TypeConv::needs_conv_refd(body)) - cdef.init = TypeConv::gen_conv_code_refd(cdef.init, - body->get_lhs_name().c_str(), body); - else - cdef.init = body->generate_code_init(cdef.init, - body->get_lhs_name().c_str()); - if (template_restriction != TR_NONE && gen_restriction_check) - cdef.init = Template::generate_restriction_check_code(cdef.init, - body->get_lhs_name().c_str(), template_restriction); - if (body->get_err_descr() != NULL && body->get_err_descr()->has_descr(NULL)) { - cdef.init = mputprintf(cdef.init, "%s.set_err_descr(&%s_%lu_err_descr);\n", - body->get_lhs_name().c_str(), body->get_lhs_name().c_str(), - static_cast<unsigned long>( body->get_err_descr()->get_descr_index(NULL) )); + else { // no template body + type->generate_code_object(&cdef, my_scope, get_genname(), "template_", true, false, true); } char*& header = in_class ? target->header.class_defs : target->header.global_vars; header = mputstr(header, cdef.decl); @@ -5255,6 +5314,9 @@ namespace Ttcn { char *Def_Template::generate_code_str(char *str) { + if (body == NULL) { + FATAL_ERROR("Def_Template::generate_code_str"); + } if (fp_list) { const char *dispname_str = id->get_dispname().c_str(); NOTSUPP("Code generation for parameterized local template `%s'", @@ -5322,6 +5384,9 @@ namespace Ttcn { void Def_Template::ilt_generate_code(ILT *ilt) { + if (body == NULL) { + FATAL_ERROR("Def_Template::ilt_generate_code"); + } char*& def=ilt->get_out_def(); char*& init=ilt->get_out_branches(); if (fp_list) { @@ -5361,7 +5426,9 @@ namespace Ttcn { DEBUG(level + 1, "restriction: %s", Template::get_restriction_name(template_restriction)); type->dump(level + 1); - body->dump(level + 1); + if (body != NULL) { + body->dump(level + 1); + } } // ================================= @@ -5407,6 +5474,22 @@ namespace Ttcn { return type; } + Value* Def_Var::get_Value() + { + chk(); + return initial_value; + } + + Value* Def_Var::steal_Value() + { + if (!checked) { + FATAL_ERROR("Def_Var::steal_Value"); + } + Value* ret_val = initial_value; + initial_value = NULL; + return ret_val; + } + void Def_Var::chk() { if(checked) return; @@ -5435,12 +5518,16 @@ namespace Ttcn { if (initial_value) { initial_value->set_my_governor(type); type->chk_this_value_ref(initial_value); + namedbool class_member_init = my_scope->is_class_scope() ? + CLASS_MEMBER_INIT : NOT_CLASS_MEMBER_INIT; type->chk_this_value(initial_value, this, is_local() ? Type::EXPECTED_DYNAMIC_VALUE : Type::EXPECTED_STATIC_VALUE, - INCOMPLETE_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); + INCOMPLETE_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, + NOT_STR_ELEM, class_member_init); if (!semantic_check_only) { initial_value->set_genname_recursive(get_genname()); - initial_value->set_code_section(GovernedSimple::CS_INLINE); + initial_value->set_code_section(my_scope->is_class_scope() ? + GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_INLINE); } } break; @@ -5656,6 +5743,22 @@ namespace Ttcn { return type; } + Template* Def_Var_Template::get_Template() + { + chk(); + return initial_value; + } + + Template* Def_Var_Template::steal_Template() + { + if (!checked) { + FATAL_ERROR("Def_Var_Template::steal_Template"); + } + Template* ret_val = initial_value; + initial_value = NULL; + return ret_val; + } + void Def_Var_Template::chk() { if(checked) return; @@ -5686,15 +5789,18 @@ namespace Ttcn { } type->chk_this_template_ref(initial_value); + namedbool class_member_init = my_scope->is_class_scope() ? + CLASS_MEMBER_INIT : NOT_CLASS_MEMBER_INIT; type->chk_this_template_generic(initial_value, INCOMPLETE_ALLOWED, - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, IMPLICIT_OMIT, 0); + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, IMPLICIT_OMIT, class_member_init, 0); gen_restriction_check = initial_value->chk_restriction("template variable definition", template_restriction, initial_value); type->chk_this_template_incorrect_field(); if (!semantic_check_only) { initial_value->set_genname_recursive(get_genname()); - initial_value->set_code_section(GovernedSimple::CS_INLINE); + initial_value->set_code_section(my_scope->is_class_scope() ? + GovernedSimple::CS_INIT_CLASS : GovernedSimple::CS_INLINE); } } if (w_attrib_path) { @@ -7032,7 +7138,6 @@ namespace Ttcn { " in clause 16.1.4 of the TTCN-3 core language standard (ES 201 873-1)", id->get_dispname().c_str()); } - ClassTypeBody* my_class = my_scope->get_scope_class(); // `runs on' clause and `port' clause are mutually exclusive if (runs_on_ref && port_ref) { @@ -9116,6 +9221,10 @@ namespace Ttcn { delete fp_list; delete base_call; delete block; + for (size_t i = 0; i < uninit_members.size(); ++i) { + delete uninit_members.get_nth_elem(i); + } + uninit_members.clear(); } Def_Constructor* Def_Constructor::clone() const @@ -9157,6 +9266,11 @@ namespace Ttcn { return fp_list; } + void Def_Constructor::add_uninit_member(const Identifier* p_member_id, bool p_is_template) + { + uninit_members.add(p_member_id, new bool(p_is_template)); + } + void Def_Constructor::chk() { if (checked) { @@ -9238,6 +9352,16 @@ namespace Ttcn { target->temp.constructor_block = fp_list->generate_shadow_objects( target->temp.constructor_block); target->temp.constructor_block = mputstr(target->temp.constructor_block, block_gen_str); + + for (size_t i = 0; i < uninit_members.size(); ++i) { + const Identifier* member_id = uninit_members.get_nth_key(i); + bool is_template = *uninit_members.get_nth_elem(i); + target->temp.constructor_block = mputprintf(target->temp.constructor_block, + "if (!%s.is_bound()) TTCN_error(\"%s member `%s' is not initialized " + "by the end of the constructor's execution.\");\n", + member_id->get_name().c_str(), is_template ? "Template" : "Constant", + member_id->get_dispname().c_str()); + } } Free(block_gen_str); } diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh index f74b68f6ee91d734d0f4968211b8a2f0f74c0a0a..820da52e48f82cbdc773360bd8d1582ed5ff6a9d 100644 --- a/compiler2/ttcn3/AST_ttcn3.hh +++ b/compiler2/ttcn3/AST_ttcn3.hh @@ -1184,6 +1184,8 @@ namespace Ttcn { virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope *p_scope); virtual Type *get_Type(); + virtual Value* get_Value(); + virtual Value* steal_Value(); virtual void chk(); virtual bool chk_identical(Definition *p_def); virtual void generate_code(output_struct *target, bool clean_up = false); @@ -1237,6 +1239,8 @@ namespace Ttcn { virtual void set_fullname(const string& p_fullname); virtual void set_my_scope(Scope *p_scope); virtual Type *get_Type(); + virtual Template* get_Template(); + virtual Template* steal_Template(); virtual void chk(); virtual bool chk_identical(Definition *p_def); virtual void generate_code(output_struct *target, bool clean_up = false); @@ -1791,6 +1795,9 @@ namespace Ttcn { NameBridgingScope bridgeScope; + /** IDs of members that need to be initialized by the end of the constructor's execution */ + map<const Identifier*, bool> uninit_members; + /// Copy constructor disabled Def_Constructor(const Def_Constructor& p); /// %Assignment disabled @@ -1804,6 +1811,7 @@ namespace Ttcn { virtual void set_my_scope(Scope* p_scope); virtual FormalParList* get_FormalParList(); virtual Reference* get_base_call() const { return base_call; } + virtual void add_uninit_member(const Identifier* p_member_id, bool p_is_template); virtual void chk(); virtual void generate_code(output_struct *target, bool clean_up = false); virtual void set_parent_path(WithAttribPath* p_path); diff --git a/compiler2/ttcn3/PatternString.cc b/compiler2/ttcn3/PatternString.cc index bf5ce0590cab52fa5a921b876dae830f44985a27..032919cbe4a9560eae3da1f845eb277078e8b1a6 100644 --- a/compiler2/ttcn3/PatternString.cc +++ b/compiler2/ttcn3/PatternString.cc @@ -50,7 +50,8 @@ namespace Ttcn { ps_elem_t* clone() const; void set_fullname(const string& p_fullname); void set_my_scope(Scope *p_scope); - void chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value); + void chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value, + namedbool class_member_init); void set_code_section(GovernedSimple::code_section_t p_code_section); }; @@ -128,7 +129,8 @@ namespace Ttcn { } // switch kind } - void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value) + void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value, + namedbool class_member_init) { if (kind != PSE_REF) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()"); Value* v = 0; @@ -181,7 +183,7 @@ namespace Ttcn { Template* templ = ass->get_Template(); refcheckertype->chk_this_template_ref(templ); refcheckertype->chk_this_template_generic(templ, INCOMPLETE_ALLOWED, - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, 0); + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, class_member_init, 0); switch (templ->get_templatetype()) { case Template::SPECIFIC_VALUE: v_last = templ->get_specific_value(); @@ -234,7 +236,8 @@ namespace Ttcn { v->set_my_scope(ref->get_my_scope()); v->set_location(*ref); refcheckertype->chk_this_value(v, 0, expected_value, - INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK); + INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK, + NOT_IMPLICIT_OMIT, NOT_STR_ELEM, class_member_init); v_last = v->get_value_refd_last(); } } @@ -403,7 +406,7 @@ namespace Ttcn { return false; } - void PatternString::chk_refs(Type::expected_value_t expected_value) + void PatternString::chk_refs(Type::expected_value_t expected_value, namedbool class_member_init) { for(size_t i=0; i<elems.size(); i++) { ps_elem_t *pse=elems[i]; @@ -414,7 +417,7 @@ namespace Ttcn { /* actually, not supported */ break; case ps_elem_t::PSE_REF: - pse->chk_ref(pattern_type, expected_value); + pse->chk_ref(pattern_type, expected_value, class_member_init); break; } // switch kind } // for diff --git a/compiler2/ttcn3/PatternString.hh b/compiler2/ttcn3/PatternString.hh index 7ac9dda0bc76794e93939a6e5c5ec007c8579f61..ba1903f9252bd7ff0160ec0118800549c0d84bfb 100644 --- a/compiler2/ttcn3/PatternString.hh +++ b/compiler2/ttcn3/PatternString.hh @@ -78,7 +78,8 @@ namespace Ttcn { /** Returns whether the pattern contains embedded references */ bool has_refs() const; /** Checks the embedded referenced values */ - void chk_refs(Type::expected_value_t expected_value=Type::EXPECTED_DYNAMIC_VALUE); + void chk_refs(Type::expected_value_t expected_value=Type::EXPECTED_DYNAMIC_VALUE, + namedbool class_member_init = NOT_CLASS_MEMBER_INIT); void chk_recursions(ReferenceChain& refch); /** Checks the pattern by translating it to POSIX regexp */ void chk_pattern(); diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc index 830c41368161e44ab066692be99d5d8f5f24bbb4..5e097921cf750f12de6468f8ac9e6afc49fa3d67 100644 --- a/compiler2/ttcn3/Statement.cc +++ b/compiler2/ttcn3/Statement.cc @@ -4088,7 +4088,7 @@ error: returnexpr.t->set_my_governor(return_type); return_type->chk_this_template_ref(returnexpr.t); return_type->chk_this_template_generic(returnexpr.t, INCOMPLETE_NOT_ALLOWED, - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, 0); + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, NOT_CLASS_MEMBER_INIT, 0); Def_Function_Base* dfb = dynamic_cast<Def_Function_Base*>(my_def); if (!dfb) FATAL_ERROR("Statement::chk_return()"); returnexpr.gen_restriction_check = @@ -9784,7 +9784,7 @@ error: self_ref |= type->chk_this_template_generic(templ, INCOMPLETE_ALLOWED, (type->get_parent_type() != NULL && !type->is_optional_field()) ? OMIT_NOT_ALLOWED : OMIT_ALLOWED, - ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, lhs); + ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, NOT_CLASS_MEMBER_INIT, lhs); chk_template_restriction(); return; error: diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index d56c2a1dd394301943f8c10dfd18b53552e270d4..01ffcefd04c2c8d031c97168a6af9b337af2af9c 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -1613,8 +1613,11 @@ namespace Ttcn { // escape from invalid recursion loops if (templatetype != TEMPLATE_REFD) return this; if (!t_ass) FATAL_ERROR("Template::get_template_refd_last()"); - if (t_ass->get_asstype() != Common::Assignment::A_TEMPLATE) { + if (t_ass->get_asstype() != Common::Assignment::A_TEMPLATE || + t_ass->get_my_scope()->get_parent_scope()->is_class_scope()) { // return this if the reference does not point to a template + // (also, class members are considered unfoldable, because their initial + // values can be changed in the constructor) u.ref.refd_last = this; return u.ref.refd_last; } @@ -1961,7 +1964,8 @@ namespace Ttcn { if (u.ref.refd) return u.ref.refd; Common::Assignment *ass = u.ref.ref->get_refd_assignment(); if (!ass) FATAL_ERROR("Template::get_template_refd()"); - if(ass->get_asstype() == Common::Assignment::A_TEMPLATE) { + if (ass->get_asstype() == Common::Assignment::A_TEMPLATE && + ass->get_Template() != NULL) { FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs(); Template *asst = ass->get_Template(); Template *t = asst->get_refd_sub_template( @@ -3896,7 +3900,7 @@ end: str = mputprintf(str, "%s%s = %s;\n", preamble.c_str(), name, expr.c_str()); break; } case SPECIFIC_VALUE: - if (get_code_section() == CS_POST_INIT) + if (get_code_section() == CS_POST_INIT || get_code_section() == CS_INIT_CLASS) str = u.specific_value->rearrange_init_code(str, my_scope->get_scope_mod_gen()); str = u.specific_value->generate_code_init(str, name); break; @@ -4063,10 +4067,12 @@ end: expression_struct expr; Code::init_expr(&expr); bool use_ref_for_codegen = true; - if (get_code_section() == CS_POST_INIT) { + if (get_code_section() == CS_POST_INIT || get_code_section() == CS_INIT_CLASS) { // the referencing template is a part of a non-parameterized template Common::Assignment *ass = u.ref.ref->get_refd_assignment(); - if (ass->get_asstype() == Common::Assignment::A_TEMPLATE) { + if (ass->get_asstype() == Common::Assignment::A_TEMPLATE || + (get_code_section() == CS_INIT_CLASS && + ass->get_asstype() == Common::Assignment::A_VAR_TEMPLATE)) { // the reference points to (a field of) a template if (ass->get_FormalParList()) { // the referred template is parameterized @@ -4166,7 +4172,9 @@ end: * - the referenced definition is not a template * - the referenced template is parameterized or * - the referenced template is in different module */ - if (ass->get_asstype() == Common::Assignment::A_TEMPLATE && + if ((ass->get_asstype() == Common::Assignment::A_TEMPLATE || + (ass->get_asstype() == Common::Assignment::A_VAR_TEMPLATE && + ass->get_my_scope()->is_class_scope())) && ass->get_FormalParList() == 0 && ass->get_my_scope()->get_scope_mod_gen() == my_scope->get_scope_mod_gen()) { @@ -6019,7 +6027,7 @@ compile_time: return template_body->get_expr_governor(exp_val); } - void TemplateInstance::chk(Type *governor) + void TemplateInstance::chk(Type *governor, namedbool class_member_init) { if (!governor) FATAL_ERROR("TemplateInstance::chk()"); if (template_body->get_templatetype() == Template::IMPLICATION_MATCH) { @@ -6044,7 +6052,7 @@ compile_time: governor->chk_this_template_ref(template_body); governor->chk_this_template_generic(template_body, (derived_reference != 0 ? INCOMPLETE_ALLOWED : INCOMPLETE_NOT_ALLOWED), - OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, 0); + OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, class_member_init, 0); } Type *TemplateInstance::chk_Type(Type *governor) diff --git a/compiler2/ttcn3/TtcnTemplate.hh b/compiler2/ttcn3/TtcnTemplate.hh index 20b1857d3c63123c473e83b64c02d0ffc8476e61..8086b596c25fea47569eb04db9928d269b5d7666 100644 --- a/compiler2/ttcn3/TtcnTemplate.hh +++ b/compiler2/ttcn3/TtcnTemplate.hh @@ -626,7 +626,7 @@ namespace Ttcn { Type *get_expr_governor(Type::expected_value_t exp_val); /** Checks the entire template instance against \a governor. */ - void chk(Type *governor); + void chk(Type *governor, namedbool class_member_init = NOT_CLASS_MEMBER_INIT); /** Checks the member \a type (if present) against \a governor. * Returns the type that shall be considered in further checks. */ Type *chk_Type(Type *governor); diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc index 53b32fc3c4e5236d710d40d126634f96aa237b62..a9c5e8ae9900c823c9e0d5dfca1ab95c2c6fb529 100644 --- a/compiler2/ttcn3/Ttcnstuff.cc +++ b/compiler2/ttcn3/Ttcnstuff.cc @@ -3845,35 +3845,62 @@ namespace Ttcn { if (!external) { block = new StatementBlock(); for (size_t i = 0; i < members->get_nof_asss(); ++i) { - // note: the Definitions class rearranges its element alphabetically; + // note: the Definitions class rearranges its elements alphabetically; // here the members must be accessed in their original order Common::Assignment* member = members->get_ass_byIndex(i, false); bool is_template = false; + TemplateInstance* def_val = NULL; switch (member->get_asstype()) { + case Common::Assignment::A_CONST: + if (member->get_Value() != NULL) { + continue; // the constant has already been initialized at its definition + } + break; case Common::Assignment::A_TEMPLATE: + if (member->get_Template() != NULL) { + continue; // the template has already been initialized at its definition + } + is_template = true; + break; + case Common::Assignment::A_VAR: + if (member->get_Value() != NULL) { + // set the variable's initial value as the constructor parameter's default value + Def_Var* var_member = dynamic_cast<Def_Var*>(member); + if (var_member == NULL) { + FATAL_ERROR("ClassTypeBody::chk - Def_Var cast"); + } + def_val = new TemplateInstance(NULL, NULL, new Template(var_member->steal_Value())); + } + break; case Common::Assignment::A_VAR_TEMPLATE: is_template = true; - // no break - case Common::Assignment::A_CONST: - case Common::Assignment::A_VAR: { - // add a formal parameter for this member - Common::Identifier* id = member->get_id().clone(); - FormalPar* fp = new FormalPar(is_template ? - Common::Assignment::A_PAR_TEMPL_IN : Common::Assignment::A_PAR_VAL_IN, - member->get_Type()->clone(), id, NULL); - fp_list->add_fp(fp); - // add a statement, that assigns the parameter's value to the member - Reference* ref_lhs = new Reference(NULL, id->clone(), Ref_simple::REF_THIS); - Reference* ref_rhs = new Reference(NULL, id->clone()); - Common::Value* val_rhs = new Value(Common::Value::V_REFD, ref_rhs); - Template* temp_rhs = new Template(val_rhs); - Assignment* par_ass = new Assignment(ref_lhs, temp_rhs); - Statement* stmt = new Statement(Statement::S_ASSIGNMENT, par_ass); - block->add_stmt(stmt); - break; } + if (member->get_Template() != NULL) { + // set the template variable's initial value as the constructor parameter's default value + Def_Var_Template* var_temp_member = dynamic_cast<Def_Var_Template*>(member); + if (var_temp_member == NULL) { + FATAL_ERROR("ClassTypeBody::chk - Def_Var_Template cast"); + } + def_val = new TemplateInstance(NULL, NULL, var_temp_member->steal_Template()); + } + break; default: + continue; break; } + // add a formal parameter for this member if we've gotten this far + Common::Identifier* id = member->get_id().clone(); + FormalPar* fp = new FormalPar(is_template ? + Common::Assignment::A_PAR_TEMPL_IN : Common::Assignment::A_PAR_VAL_IN, + member->get_Type()->clone(), id, def_val); + fp_list->add_fp(fp); + // add a statement, that assigns the parameter's value to the member + Reference* ref_lhs = new Reference(NULL, id->clone(), Ref_simple::REF_THIS); + Reference* ref_rhs = new Reference(NULL, id->clone()); + Common::Value* val_rhs = new Value(Common::Value::V_REFD, ref_rhs); + Template* temp_rhs = new Template(val_rhs); + Assignment* par_ass = new Assignment(ref_lhs, temp_rhs); + Statement* stmt = new Statement(Statement::S_ASSIGNMENT, par_ass); + block->add_stmt(stmt); } } constructor = new Def_Constructor(fp_list, base_call, block); @@ -3883,6 +3910,29 @@ namespace Ttcn { default_constructor = true; } + if (constructor != NULL && !default_constructor && !name_clash && !trait) { + // make sure constants and templates are initialized + for (size_t i = 0; i < members->get_nof_asss(); ++i) { + Common::Assignment* member = members->get_ass_byIndex(i, false); + bool needs_init_check = false; + bool is_template = false; + switch (member->get_asstype()) { + case Common::Assignment::A_CONST: + needs_init_check = member->get_Value() == NULL; + break; + case Common::Assignment::A_TEMPLATE: + needs_init_check = member->get_Template() == NULL; + is_template = true; + break; + default: + break; + } + if (needs_init_check) { + constructor->add_uninit_member(&member->get_id(), is_template); + } + } + } + if (finally_block != NULL) { Error_Context cntxt(finally_block, "In class destructor"); finally_block->chk(); diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index 4719104158dd8befd6b65aef49ba677a19423d52..497705f0b25b64873f72db4be05ddc266335a814 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -2015,12 +2015,12 @@ DynamicMatch %left '*' '/' ModKeyword RemKeyword %left UnarySign -%expect 92 +%expect 93 %start GrammarRoot /* -XXX Source of conflicts (92 S/R): +XXX Source of conflicts (93 S/R): 1.) 13 conflicts in one state The Expression after 'return' keyword is optional in ReturnStatement. @@ -2028,7 +2028,7 @@ For 13 tokens the parser cannot decide whether the token is a part of the return expression (shift) or it is the beginning of the next statement (reduce). -2.) 14 distinct states, each with one conflict caused by token '[' +2.) 15 distinct states, each with one conflict caused by token '[' The local definitions in altsteps can be followed immediately by the guard expression. When the parser sees the '[' token it cannot decide whether it belongs to the local definition as array dimension or array subreference @@ -2048,6 +2048,7 @@ The situations are the following: - var t v := this.function(...) <here> [ - var t v := super.function(...) <here> [ - var t v := value<subrefs> <here> [ +- const t c <here> [ 3.) 1 conflict The sequence identifier.objid can be either the beginning of a module name @@ -3926,6 +3927,13 @@ SingleConstDef: // 90 $$.initial_value = $4; $$.yyloc = @$; } +| IDentifier optArrayDef + { + $$.id = $1; + $$.arrays = $2; + $$.initial_value = NULL; + $$.yyloc = @$; + } ; FunctionTypeDef: @@ -3975,6 +3983,11 @@ TemplateDef: // 93 $$ = new Def_Template($2, $4.name, $4.type, $4.fp_list, $5, $7); $$->set_location(infile, @$); } +| TemplateKeyword optTemplateRestriction optLazyOrFuzzyModifier BaseTemplate + { + $$ = new Def_Template($2, $4.name, $4.type, $4.fp_list, NULL, NULL); + $$->set_location(infile, @$); + } ; BaseTemplate: // 94 @@ -4003,7 +4016,7 @@ DerivedDef: // 97 ; optTemplateFormalParList: - /* empty */ optError { $$ = 0; } + /* empty */ { $$ = 0; } | '(' TemplateFormalParList optError ')' { $$ = $2; diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn index c133753a5e662e744a3d2e558b3e27d55b367753..53dabb26a3de7ebc029cec07a9e131f5679b9463 100644 --- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn +++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn @@ -492,7 +492,7 @@ type class C46 extends object { } type class C47 { - const integer m1 := 3; + const integer m1; public function m2() return boolean { return true; } function m3(in integer p) return charstring { return int2str(p); } function @final m4() { } @@ -748,6 +748,24 @@ function f_traits_good() runs on CT_RunsOn2 { log(v_t7.f(3)); } +type class C60 {//^In type definition// + private const integer a := b; + private const integer b := 3; + private var integer c := f(); //^In variable definition// //Reference to a static value was expected instead of the return value of function `@oop_SE.C60.f'// + private const integer d := (1 - d); //^In constant definition// //^In the operands of operation// //Circular reference in constant definition// + private const integer e; + private const integer g := e + 1; //^In constant definition// //Reference to uninitialized constant `e' in class member initialization// + private var Rec h := { num := e, str := "q" }; //^In variable definition// //^In value for record field// //Reference to uninitialized constant `e' in class member initialization// + private template integer i; + private template integer j := i; //^In template definition// //Reference to uninitialized template `i' in class member initialization// + private var template Rec k := { e, h.str }; //^In template variable definition// //^In template for record field// //Reference to uninitialized constant `e' in class member initialization// + private var template integer l; + private template integer m := (1, l); //^In template definition// //^In list item// //Reference to uninitialized template variable `l' in class member initialization// + private var charstring n; + private var template charstring o := pattern "ab?{n}"; //^In template variable definition// //^In character string pattern// //Reference to uninitialized variable `n' in class member initialization// + public function f() return integer { return 10; } +} + 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.// diff --git a/regression_test/oop/Makefile b/regression_test/oop/Makefile index a0b4ad72474c3d45e9abf493fea15800ae5a71ae..bb3758ec580c7d9f2187a94ae6d2e5ce6621d09c 100644 --- a/regression_test/oop/Makefile +++ b/regression_test/oop/Makefile @@ -17,7 +17,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = oop.ttcn exceptions.ttcn +TTCN3_MODULES = oop.ttcn exceptions.ttcn oop2.ttcn USER_SOURCES = ext.cc diff --git a/regression_test/oop/oop.cfg b/regression_test/oop/oop.cfg index e7e4a8c825cfc1af10eaf01723fbb6a32be13c1c..22f81ef085df51cba790becfa97df8b2d97c949e 100644 --- a/regression_test/oop/oop.cfg +++ b/regression_test/oop/oop.cfg @@ -23,3 +23,4 @@ LogEntityName := Yes [EXECUTE] oop.control exceptions.control +oop2.control diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn index 75f21adb6c86e66fa76e63713b861b7280aa9bbf..bca21d5a4737edb4c82c984a0a7dd26da4777556 100644 --- a/regression_test/oop/oop.ttcn +++ b/regression_test/oop/oop.ttcn @@ -176,8 +176,8 @@ type class SubClass extends BaseClass { } type class @final FinalClass extends SubClass { - private const integer m_final_const := 1; - private template charstring m_final_temp := ? length (1..4); + private const integer m_final_const; + private template charstring m_final_temp; private var float m_final_var := 1.0; private var template octetstring m_final_var_temp := ''O; diff --git a/regression_test/oop/oop2.ttcn b/regression_test/oop/oop2.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..ec3450ba03ffc076b8f50e1c65de0b8f1754c8bf --- /dev/null +++ b/regression_test/oop/oop2.ttcn @@ -0,0 +1,223 @@ +/****************************************************************************** + * 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 + * + ******************************************************************************/ +module oop2 { + +type component CT {} + +type class C1 { + private const integer m_const1; + private const integer m_const2 := 4; + private template integer m_temp1; + private template integer m_temp2 := (0..10); + private var integer m_var1; + private var integer m_var2 := 10; + private var template integer m_var_temp1; + private var template integer m_var_temp2 := (1, 2, 4, 8); + + public function test_members() { + if (m_const1 != 3) { + setverdict(fail, "m_const1 = ", m_const1); + } + if (m_const2 != 4) { + setverdict(fail, "m_const2 = ", m_const2); + } + if (log2str(m_temp1) != "?") { + setverdict(fail, "m_temp1 = ", m_temp1); + } + if (log2str(m_temp2) != "(0 .. 10)") { + setverdict(fail, "m_temp2 = ", m_temp2); + } + if (m_var1 != -1) { + setverdict(fail, "m_var1 = ", m_var1); + } + if (m_var2 != -2) { + setverdict(fail, "m_var2 = ", m_var2); + } + if (log2str(m_var_temp1) != "(0 .. infinity)") { + setverdict(fail, "m_var_temp1 = ", m_var_temp1); + } + if (log2str(m_var_temp2) != "(1, 2, 4, 8)") { + setverdict(fail, "m_var_temp2 = ", m_var_temp2); + } + } +} + +testcase tc_constructor_default() runs on CT { + var C1 x := C1.create(3, ?, -1, -2, (0..infinity), -); + x.test_members(); + setverdict(pass); +} + + +type class C2 { + private const integer m_const1; + private const integer m_const2 := 4; + private template integer m_temp1; + private template integer m_temp2 := (0..10); + private var integer m_var1; + private var integer m_var2 := 10; + private var template integer m_var_temp1; + private var template integer m_var_temp2 := (1, 2, 4, 8); + + create() { + m_const1 := 1; + m_temp1 := ?; + } + + public function test_members() { + if (m_const1 != 1) { + setverdict(fail, "m_const1 = ", m_const1); + } + if (m_const2 != 4) { + setverdict(fail, "m_const2 = ", m_const2); + } + if (log2str(m_temp1) != "?") { + setverdict(fail, "m_temp1 = ", m_temp1); + } + if (log2str(m_temp2) != "(0 .. 10)") { + setverdict(fail, "m_temp2 = ", m_temp2); + } + if (isbound(m_var1)) { + setverdict(fail, "m_var1 = ", m_var1); + } + if (m_var2 != 10) { + setverdict(fail, "m_var2 = ", m_var2); + } + if (isbound(m_var_temp1)) { + setverdict(fail, "m_var_temp1 = ", m_var_temp1); + } + if (log2str(m_var_temp2) != "(1, 2, 4, 8)") { + setverdict(fail, "m_var_temp2 = ", m_var_temp2); + } + } +} + +testcase tc_constructor_init() runs on CT { + var C2 x := C2.create; + x.test_members(); + setverdict(pass); +} + + +type class C3 { + private const integer m_const1; + private const integer m_const2 := 4; + private template integer m_temp1; + private template integer m_temp2 := (0..10); + private var integer m_var1; + private var integer m_var2 := 10; + private var template integer m_var_temp1; + private var template integer m_var_temp2 := (1, 2, 4, 8); + + create() { + m_temp1 := ?; + } +} + +testcase tc_constructor_uninit_const() runs on CT { + @try { + var C3 x := C3.create; + setverdict(fail, "Error expected."); + } + @catch (msg) { + var template charstring exp := pattern "*Constant member `m_const1' is not initialized by the end of the constructor's execution."; + if (match(msg, exp)) { + setverdict(pass); + } + else { + setverdict(fail, "Invalid error: ", msg); + } + } +} + + +type class C4 { + private const integer m_const1; + private const integer m_const2 := 4; + private template integer m_temp1; + private template integer m_temp2 := (0..10); + private var integer m_var1; + private var integer m_var2 := 10; + private var template integer m_var_temp1; + private var template integer m_var_temp2 := (1, 2, 4, 8); + + create() { + m_const1 := 1; + } +} + +testcase tc_constructor_uninit_temp() runs on CT { + @try { + var C4 x := C4.create; + setverdict(fail, "Error expected."); + } + @catch (msg) { + var template charstring exp := pattern "*Template member `m_temp1' is not initialized by the end of the constructor's execution."; + if (match(msg, exp)) { + setverdict(pass); + } + else { + setverdict(fail, "Invalid error: ", msg); + } + } +} + + +type record Rec { + integer num, + charstring str +} + +type class C5 { + private const integer c1 := c2; + private const integer c2 := 3; + private template integer t1 := (t2, c3); + private template integer t2 := (1..4); + private const integer c3 := 9; + private var Rec v1 := { c4, "x" }; + private const integer c4 := 10; + private var template Rec vt1 := { num := vt2, str := v3 }; + private var template integer vt2 := (0..100); + private var charstring v3 := "y"; + + create() { + if (c1 != 3) { + setverdict(fail, "c1 = ", c1); + } + template integer t1_exp := ((1..4), 9); + if (log2str(t1) != log2str(t1_exp)) { + setverdict(fail, "t1 = ", t1); + } + if (v1 != { 10, "x" }) { + setverdict(fail, "v1 = ", v1); + } + template Rec vt1_exp := { num := (0..100), str := "y" }; + if (log2str(vt1) != log2str(vt1_exp)) { + setverdict(fail, "vt1 = ", vt1); + } + } +} + +testcase tc_member_init_rearrange() runs on CT { + var C5 x := C5.create; // the actual tests are in the constructor + setverdict(pass); +} + +control { + execute(tc_constructor_default()); + execute(tc_constructor_init()); + execute(tc_constructor_uninit_const()); + execute(tc_constructor_uninit_temp()); + execute(tc_member_init_rearrange()); +} + +}