From 5f2c73dde65942a82dab96a0de62b5755f84a654 Mon Sep 17 00:00:00 2001 From: Botond Baranyi <botond.baranyi@ericsson.com> Date: Tue, 2 May 2017 17:32:06 +0200 Subject: [PATCH] Added error messages for using two consecutive length restrictions Change-Id: Iba255ddd2b713b9b5e2876f863c829746cefc73d Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com> --- compiler2/Type_chk.cc | 1 + compiler2/Value.cc | 87 +++++++++++-------- compiler2/Value.hh | 3 + compiler2/ttcn3/TtcnTemplate.cc | 25 +++++- compiler2/ttcn3/TtcnTemplate.hh | 2 + compiler2/ttcn3/compiler.y | 4 +- .../TTCN3_SA_ttcn3adhoc_TD.script | 6 +- .../template_concat/TemplateConcat_SE.ttcn | 4 + 8 files changed, 89 insertions(+), 43 deletions(-) diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 3e8d4c034..38be2da74 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -5525,6 +5525,7 @@ bool Type::chk_this_template_generic(Template *t, namedbool incomplete_allowed, namedbool implicit_omit, Common::Assignment *lhs) { bool self_ref = false; + t->chk_concat_double_length_res(); // get_template_refd_last evaluates concatenations between templates known at // compile-time Ttcn::Template::templatetype_t tt = t->get_template_refd_last()->get_templatetype(); diff --git a/compiler2/Value.cc b/compiler2/Value.cc index 6e712ad55..26a5e118e 100644 --- a/compiler2/Value.cc +++ b/compiler2/Value.cc @@ -78,6 +78,7 @@ namespace Common { Value::Value(const Value& p) : GovernedSimple(p), valuetype(p.valuetype), my_governor(0) + , in_brackets(p.in_brackets) { switch(valuetype) { case V_ERROR: @@ -697,7 +698,7 @@ namespace Common { } Value::Value(valuetype_t p_vt) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_NULL: @@ -719,7 +720,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, bool p_val_bool) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_BOOL: @@ -731,7 +732,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, const Int& p_val_Int) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_INT: @@ -743,7 +744,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, int_val_t *p_val_Int) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype){ case V_INT: @@ -755,7 +756,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, string *p_val_str) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_val_str) FATAL_ERROR("NULL parameter"); switch(valuetype) { @@ -772,7 +773,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, ustring *p_val_ustr) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (p_vt != V_USTR || !p_val_ustr) FATAL_ERROR("Value::Value()"); set_val_ustr(p_val_ustr); @@ -780,7 +781,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, CharSyms *p_char_syms) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (!p_char_syms) FATAL_ERROR("NULL parameter"); switch (valuetype) { @@ -793,7 +794,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, Identifier *p_val_id) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_val_id) FATAL_ERROR("NULL parameter"); @@ -809,7 +810,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, Identifier *p_id, Value *p_val) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_id || !p_val) FATAL_ERROR("NULL parameter"); @@ -824,7 +825,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, const Real& p_val_Real) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { switch(valuetype) { case V_REAL: @@ -836,7 +837,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, Values *p_vs) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_vs) FATAL_ERROR("NULL parameter"); switch(valuetype) { @@ -852,7 +853,7 @@ namespace Common { Value::Value(valuetype_t p_vt, Value *p_v, Ttcn::ParsedActualParameters *p_t_list) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_v || !p_t_list) FATAL_ERROR("NULL parameter"); switch(valuetype) { @@ -868,7 +869,7 @@ namespace Common { // - Value::Value(operationtype_t p_optype) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -894,7 +895,7 @@ namespace Common { // v1 Value::Value(operationtype_t p_optype, Value *p_v1) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -950,7 +951,7 @@ namespace Common { // v1 [r2] b4 Value::Value(operationtype_t p_optype, Value* p_v1, Ttcn::Ref_base *p_r2, bool p_b4) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -971,7 +972,7 @@ namespace Common { // ti1 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -997,7 +998,7 @@ namespace Common { // r1 Value::Value(operationtype_t p_optype, Ttcn::Ref_base *p_r1) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1015,7 +1016,7 @@ namespace Common { // r1 [r2] b4 Value::Value(operationtype_t p_optype, Ttcn::Ref_base* p_r1, Ttcn::Ref_base* p_r2, bool p_b4) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1036,7 +1037,7 @@ namespace Common { // v1 t_list2 Value::Value(operationtype_t p_optype, Value *p_v1, Ttcn::ParsedActualParameters *p_ap_list) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1054,7 +1055,7 @@ namespace Common { //v1 t_list2 v3 Value::Value(operationtype_t p_optype, Value *p_v1, Ttcn::ParsedActualParameters *p_t_list2, Value *p_v3) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1072,7 +1073,7 @@ namespace Common { // r1 [v2] or [r1] v2 Value::Value(operationtype_t p_optype, Ttcn::Ref_base *p_r1, Value *p_v2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1096,7 +1097,7 @@ namespace Common { // r1 [v2] [v3] b4 Value::Value(operationtype_t p_optype, Ttcn::Ref_base *p_r1, Value *p_v2, Value *p_v3, bool p_b4) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1115,7 +1116,7 @@ namespace Common { // v1 v2 Value::Value(operationtype_t p_optype, Value *p_v1, Value *p_v2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1166,7 +1167,7 @@ namespace Common { // ti1 v2 v3 ti4 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2, Value *p_v3, TemplateInstance *p_ti4) : - GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1185,7 +1186,7 @@ namespace Common { // v1 v2 v3 Value::Value(operationtype_t p_optype, Value *p_v1, Value *p_v2, Value *p_v3) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1203,7 +1204,7 @@ namespace Common { // ti1 [v2] Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1221,7 +1222,7 @@ namespace Common { // ti1 v2 v3 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, Value *p_v2, Value *p_v3) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype=p_optype; u.expr.state=EXPR_NOT_CHECKED; @@ -1240,7 +1241,7 @@ namespace Common { // ti1 t2 v3 b4 Value::Value(operationtype_t p_optype, TemplateInstance *p_ti1, TemplateInstance *p_t2, Value *p_v3, bool p_b4) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype=p_optype; u.expr.state=EXPR_NOT_CHECKED; @@ -1259,7 +1260,7 @@ namespace Common { // v1 t2 Value::Value(operationtype_t p_optype, Value *p_v1, TemplateInstance *p_t2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1277,7 +1278,7 @@ namespace Common { // r1 i2 Value::Value(operationtype_t p_optype, Ttcn::Reference *p_r1, Identifier *p_i2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1293,7 +1294,7 @@ namespace Common { } Value::Value(operationtype_t p_optype, LogArguments *p_logargs) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1309,7 +1310,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, macrotype_t p_macrotype) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (p_vt != V_MACRO) FATAL_ERROR("Value::Value()"); switch (p_macrotype) { @@ -1330,7 +1331,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, NamedValues *p_nvs) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_nvs) FATAL_ERROR("NULL parameter"); switch(valuetype) { @@ -1344,7 +1345,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, Reference *p_ref) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (!p_ref) FATAL_ERROR("NULL parameter: Value::Value()"); switch(p_vt) { @@ -1361,7 +1362,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, Block *p_block) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if(!p_block) FATAL_ERROR("NULL parameter"); switch(valuetype) { @@ -1374,7 +1375,7 @@ namespace Common { } Value::Value(valuetype_t p_vt, verdict_t p_verdict) - : GovernedSimple(S_V), valuetype(p_vt), my_governor(0) + : GovernedSimple(S_V), valuetype(p_vt), my_governor(0), in_brackets(false) { if (valuetype != V_VERDICT) FATAL_ERROR("Value::Value()"); switch (p_verdict) { @@ -1391,7 +1392,7 @@ namespace Common { } Value::Value(operationtype_t p_optype, Ttcn::Ref_base *p_r1, Ttcn::Ref_base *p_r2) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -1412,7 +1413,7 @@ namespace Common { // r1 r2 [v3] Value::Value(operationtype_t p_optype, Ttcn::Ref_base *p_r1, Ttcn::Ref_base *p_r2, Value *p_v3) - : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0) + : GovernedSimple(S_V), valuetype(V_EXPR), my_governor(0), in_brackets(false) { u.expr.v_optype = p_optype; u.expr.state = EXPR_NOT_CHECKED; @@ -14468,6 +14469,16 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr) DEBUG(level, "Value: unknown type: %d", valuetype); } // switch } + + void Value::set_is_in_brackets() + { + in_brackets = true; + } + + bool Value::get_is_in_brackets() const + { + return in_brackets; + } void Value::add_string_element(size_t index, Value *v_element, map<size_t, Value>*& string_elements) diff --git a/compiler2/Value.hh b/compiler2/Value.hh index 363142a35..df1e70d5c 100644 --- a/compiler2/Value.hh +++ b/compiler2/Value.hh @@ -299,6 +299,7 @@ namespace Common { valuetype_t valuetype; Type *my_governor; + bool in_brackets; union { bool val_bool; int_val_t *val_Int; @@ -1024,6 +1025,8 @@ namespace Common { bool needs_short_circuit(); public: virtual void dump(unsigned level) const; + void set_is_in_brackets(); + bool get_is_in_brackets() const; private: inline void set_val_str(string *p_val_str) { u.str.val_str = p_val_str; u.str.str_elements = 0; } diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc index 58fe369f7..ad7e6b6bc 100644 --- a/compiler2/ttcn3/TtcnTemplate.cc +++ b/compiler2/ttcn3/TtcnTemplate.cc @@ -102,6 +102,7 @@ namespace Ttcn { } u.concat.op1 = p.u.concat.op1->clone(); u.concat.op2 = p.u.concat.op2->clone(); + u.concat.in_brackets = p.u.concat.in_brackets; break; // default: // FATAL_ERROR("Template::Template()"); @@ -315,9 +316,15 @@ namespace Ttcn { if (!use_runtime_2) { FATAL_ERROR("Template::create_stringRepr()"); } + if (u.concat.in_brackets) { + ret_val += " ( "; + } ret_val += u.concat.op1->create_stringRepr(); ret_val += " & "; ret_val += u.concat.op2->create_stringRepr(); + if (u.concat.in_brackets) { + ret_val += " ) "; + } break; default: ret_val += "<unknown template>"; @@ -374,6 +381,7 @@ namespace Ttcn { u.concat.op1->set_location(*v->get_concat_operand(true)); u.concat.op2 = new Template(v->get_concat_operand(false)->clone()); u.concat.op2->set_location(*v->get_concat_operand(false)); + u.concat.in_brackets = v->get_is_in_brackets(); delete v; break; } @@ -1202,7 +1210,9 @@ namespace Ttcn { void Template::set_length_restriction(LengthRestriction *p_lr) { if (p_lr == NULL) return; - if (length_restriction) FATAL_ERROR("Template::set_length_restriction()"); + if (length_restriction != NULL) { + p_lr->error("Two length restrictions are not allowed next to each other"); + } length_restriction = p_lr; } @@ -1721,7 +1731,7 @@ namespace Ttcn { } return first ? u.concat.op1 : u.concat.op2; } - + Template* Template::get_template_refd(ReferenceChain *refch) { unsigned int const prev_err_count = get_error_count(); @@ -2440,6 +2450,17 @@ end: u.invoke.ap_list = parlist; } } + + void Template::chk_concat_double_length_res() + { + if (templatetype == TEMPLATE_CONCAT && length_restriction != NULL && + u.concat.op2->length_restriction != NULL && !u.concat.in_brackets) { + length_restriction->error("Two length restrictions are not allowed next " + "to each other"); + note("Try using brackets around the template concatenation"); + set_templatetype(TEMPLATE_ERROR); + } + } Templates *Template::harbinger(Template *t, bool from_permutation, bool killer) { diff --git a/compiler2/ttcn3/TtcnTemplate.hh b/compiler2/ttcn3/TtcnTemplate.hh index 16b1fa50d..f4f8ccd6f 100644 --- a/compiler2/ttcn3/TtcnTemplate.hh +++ b/compiler2/ttcn3/TtcnTemplate.hh @@ -132,6 +132,7 @@ namespace Ttcn { struct { Template* op1; Template* op2; + bool in_brackets; } concat; } u; @@ -359,6 +360,7 @@ namespace Ttcn { void chk_specific_value(bool allow_omit); void chk_specific_value_generic(); void chk_invoke(); + void chk_concat_double_length_res(); /** Copy template elements from the "all from" into the template. * diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y index dcfbbc531..9cb4f35f6 100644 --- a/compiler2/ttcn3/compiler.y +++ b/compiler2/ttcn3/compiler.y @@ -9052,8 +9052,8 @@ Assignment: // 594 /* This can not be a single CompoundExpression (as opposed to Expression) */ SingleExpression: // 595 - '(' SingleExpression ')' { $$ = $2; } -| '(' error SingleExpression ')' { $$ = $3; } + '(' SingleExpression ')' { $$ = $2; $$->set_is_in_brackets(); } +| '(' error SingleExpression ')' { $$ = $3; $$->set_is_in_brackets(); } | '(' error ')' { $$ = new Value(Value::V_ERROR); diff --git a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script index 284efbf92..7563d2c7f 100644 --- a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script +++ b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script @@ -7309,11 +7309,15 @@ control {} with{erroneous ""} (?im)\berror: Type `@virag.MYREC2' and type `@virag.MYREC' have no common encoding <END_RESULT> +RESULT FTRT COUNT 1> +(?im)\berror: Type `VisibleString' and type `@virag.MYREC' have no common encoding +<END_RESULT> + <RESULT COUNT 3> (?im)\berror: The `erroneous' attribute can be used only on template and constant definitions <END_RESULT> -<RESULT FTRT COUNT 32> +<RESULT FTRT COUNT 33> (?is)\berror: <END_RESULT> diff --git a/function_test/Semantic_Analyser/template_concat/TemplateConcat_SE.ttcn b/function_test/Semantic_Analyser/template_concat/TemplateConcat_SE.ttcn index 95fbcc089..733eca49e 100644 --- a/function_test/Semantic_Analyser/template_concat/TemplateConcat_SE.ttcn +++ b/function_test/Semantic_Analyser/template_concat/TemplateConcat_SE.ttcn @@ -119,4 +119,8 @@ template HexSubtype t_hex7 := t_hex_value & * length(3) & '5'H; //^In template d template CharSubtype t_char7 := "abc" & c_char; //^In template definition// //is not a valid value for type `charstring' which has subtype// template UnicharSubtype t_unichar7 := c_char & t_unichar_value; //^In template definition// //is not a valid value for type `universal charstring' which has subtype// +/* testing double length restriction (both the second operand and the concatenation result have length restrictions and they're not separated by brackets) */ +template octetstring t_oct8 := 'ABCD'O & ? length(2) length(4); //^In template definition// //Two length restrictions are not allowed next to each other// //Try using brackets around the template concatenation// +template RecOfInt t_recof8 := t_recof & * length(2) length(4..5); //^In template definition// //Two length restrictions are not allowed next to each other// //Try using brackets around the template concatenation// + } -- GitLab