From 589e0edf50a81794baf23ec521ecd98cd038e912 Mon Sep 17 00:00:00 2001
From: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
Date: Thu, 6 Jul 2017 16:00:12 +0200
Subject: [PATCH] Implemented mtc and system clauses in altsteps and functions
 (Bug 519281)

Change-Id: I2dfa85d30b67a3d284464cbaabc9308cb308d5a4
Signed-off-by: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
---
 compiler2/AST.cc                              |  10 ++
 compiler2/AST.hh                              |   6 ++
 compiler2/Setting.cc                          |  50 +++++++++
 compiler2/Setting.hh                          |  12 +++
 compiler2/Type.cc                             |  67 ++++++++++++
 compiler2/Type.hh                             |   3 +
 compiler2/Type_chk.cc                         |   4 +-
 compiler2/ttcn3/AST_ttcn3.cc                  |  74 ++++++++++++-
 compiler2/ttcn3/AST_ttcn3.hh                  |  44 +++++++-
 compiler2/ttcn3/Statement.cc                  |   8 ++
 compiler2/ttcn3/compiler.y                    |  46 ++++++--
 .../Semantic_Analyser/Makefile.semantic       |   2 +-
 .../MtcSystemClause_SE.ttcn                   | 102 ++++++++++++++++++
 .../Semantic_Analyser/mtc_and_system_clause/t |   9 ++
 14 files changed, 420 insertions(+), 17 deletions(-)
 create mode 100644 function_test/Semantic_Analyser/mtc_and_system_clause/MtcSystemClause_SE.ttcn
 create mode 100755 function_test/Semantic_Analyser/mtc_and_system_clause/t

diff --git a/compiler2/AST.cc b/compiler2/AST.cc
index 88ffb738d..5fe91220a 100644
--- a/compiler2/AST.cc
+++ b/compiler2/AST.cc
@@ -1928,6 +1928,16 @@ namespace Common {
     return 0;
   }
   
+  Type *Assignment::get_MtcType()
+  {
+    return 0;
+  }
+  
+  Type *Assignment::get_SystemType()
+  {
+    return 0;
+  }
+  
   Type *Assignment::get_PortType()
   {
     return 0;
diff --git a/compiler2/AST.hh b/compiler2/AST.hh
index 9a5b303ff..0632d9935 100644
--- a/compiler2/AST.hh
+++ b/compiler2/AST.hh
@@ -589,6 +589,12 @@ namespace Common {
     /** Returns the component type referred by the 'runs on' clause of a
      * TTCN-3 definition */
     virtual Type *get_RunsOnType();
+    /** Returns the component type referred by the 'mtc' clause of a
+     * TTCN-3 definition */
+    virtual Type *get_MtcType();
+    /** Returns the component type referred by the 'system' clause of a
+     * TTCN-3 definition */
+    virtual Type *get_SystemType();
     /** Returns the port type referred by the 'port' clause of a
      * TTCN-3 function definition */
     virtual Type *get_PortType();
diff --git a/compiler2/Setting.cc b/compiler2/Setting.cc
index 3f4a4158e..7d8fcf422 100644
--- a/compiler2/Setting.cc
+++ b/compiler2/Setting.cc
@@ -692,6 +692,56 @@ namespace Common {
 	refd_comptype->get_typename().c_str());
     }
   }
+  
+  void Scope::chk_mtc_clause(Assignment *p_ass, const Location& p_loc,
+    const char *p_what, bool in_control_part)
+  {
+    // component type of the referred definition
+    Type *refd_comptype = p_ass->get_MtcType();
+    // definitions without 'mtc' can be called from anywhere
+    if (!refd_comptype) return;
+    if (in_control_part) {
+      p_loc.error("Function with mtc or system clause is not allowed in control part.");
+      return;
+    }
+    Type *t_comptype = get_mtc_system_comptype(false);
+    if (t_comptype) {
+      if (!refd_comptype->is_compatible_component_by_port(t_comptype)) {
+        // the 'mtc' clause of the referred definition is not compatible
+        // with that of the current scope (i.e. the referring definition)
+        p_loc.error("Mtc clause mismatch: A definition that runs on "
+          "component type `%s' cannot %s %s, which mtc clause is `%s'",
+          t_comptype->get_typename().c_str(), p_what,
+          p_ass->get_description().c_str(),
+          refd_comptype->get_typename().c_str());
+      }
+    }
+  }
+  
+  void Scope::chk_system_clause(Assignment *p_ass, const Location& p_loc,
+    const char *p_what, bool in_control_part)
+  {
+    // component type of the referred definition
+    Type *refd_comptype = p_ass->get_SystemType();
+    // definitions without 'system' can be called from anywhere
+    if (!refd_comptype) return;
+    if (in_control_part) {
+      p_loc.error("Function with mtc or system clause is not allowed in control part.");
+      return;
+    }
+    Type *t_comptype = get_mtc_system_comptype(true);
+    if (t_comptype) {
+      if (!refd_comptype->is_compatible_component_by_port(t_comptype)) {
+        // the 'system' clause of the referred definition is not compatible
+        // with that of the current scope (i.e. the referring definition)
+        p_loc.error("System clause mismatch: A definition with system "
+          "component type `%s' cannot %s %s, which system clause is `%s'",
+          t_comptype->get_typename().c_str(), p_what,
+          p_ass->get_description().c_str(),
+          refd_comptype->get_typename().c_str());
+      }
+    }
+  }
 
   // =================================
   // ===== Reference
diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh
index 11e8721f9..848b4fa5b 100644
--- a/compiler2/Setting.hh
+++ b/compiler2/Setting.hh
@@ -635,6 +635,18 @@ public:
      * \a p_what contains "call" or "activate". */
     void chk_runs_on_clause(Type *p_fat, const Location& p_loc,
       const char *p_what);
+    /** Checks the 'mtc' clause of definition \a p_ass that it can
+     * be called from this scope unit. Parameters \a p_loc and \a
+     * p_what are used in error messages. \a p_what contains "call" or
+     * "activate". */
+    void chk_mtc_clause(Assignment *p_ass, const Location& p_loc,
+      const char *p_what, bool in_control_part);
+    /** Checks the 'system' clause of definition \a p_ass that it can
+     * be called from this scope unit. Parameters \a p_loc and \a
+     * p_what are used in error messages. \a p_what contains "call" or
+     * "activate". */
+    void chk_system_clause(Assignment *p_ass, const Location& p_loc,
+      const char *p_what, bool in_control_part);
   };
 
   /**
diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 39f339c68..f170a3386 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -3695,6 +3695,73 @@ namespace Common {
     }
     }
   }
+  
+
+  bool Type::is_compatible_component_by_port(Type *p_type) {
+    chk();
+    p_type->chk();
+    Type *t1 = get_type_refd_last();
+    Type *t2 = p_type->get_type_refd_last();
+    if (t1->typetype != T_COMPONENT || t2->typetype != T_COMPONENT) {
+      return false;
+    }
+    ComponentTypeBody* b1 = t1->get_CompBody();
+    ComponentTypeBody* b2 = t2->get_CompBody();
+    
+    // Does b2 contains every port with the same type and name as b1?
+    for (size_t i = 0; i < b1->get_nof_asss(); i++) {
+      Assignment * ass = b1->get_ass_byIndex(i);
+      if (ass->get_asstype() == Assignment::A_PORT) {
+        Type *port_type = ass->get_Type()->get_type_refd_last();
+        const Identifier& id = ass->get_id();
+        bool found = false;
+        for (size_t j = 0; j < b2->get_nof_asss(); j++) {
+          Assignment * ass2 = b2->get_ass_byIndex(j);
+          const Identifier& id2 = ass2->get_id();
+          if (id == id2 && ass2->get_asstype() == Assignment::A_PORT) {
+            Type *port_type2 = ass2->get_Type()->get_type_refd_last();
+            if (port_type != port_type2) {
+              return false;
+            } else {
+              found = true;
+              break;
+            }
+          }
+        }
+        if (!found) {
+          return false;
+        }
+      }
+    }
+    
+    // Does b1 contains every port with the same type and name as b2?
+    for (size_t i = 0; i < b2->get_nof_asss(); i++) {
+      Assignment * ass = b2->get_ass_byIndex(i);
+      if (ass->get_asstype() == Assignment::A_PORT) {
+        Type *port_type = ass->get_Type()->get_type_refd_last();
+        const Identifier& id = ass->get_id();
+        bool found = false;
+        for (size_t j = 0; j < b1->get_nof_asss(); j++) {
+          Assignment * ass2 = b1->get_ass_byIndex(j);
+          const Identifier& id2 = ass2->get_id();
+          if (id == id2 && ass2->get_asstype() == Assignment::A_PORT) {
+            Type *port_type2 = ass2->get_Type()->get_type_refd_last();
+            if (port_type != port_type2) {
+              return false;
+            } else {
+              found = true;
+              break;
+            }
+          }
+        }
+        if (!found) {
+          return false;
+        }
+      }
+    }
+    
+    return true;
+  }
 
   bool Type::is_compatible(Type *p_type, TypeCompatInfo *p_info, Location* p_loc,
                            TypeChain *p_left_chain, TypeChain *p_right_chain,
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index e43dc4a8b..0b5bc3843 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -682,6 +682,9 @@ namespace Common {
                        TypeChain *p_left_chain = NULL,
                        TypeChain *p_right_chain = NULL,
                        bool p_is_inline_template = false);
+    /** Check if the port definitions of the component types are the same
+     */
+    bool is_compatible_component_by_port(Type *p_type);
     /** Check if the restrictions of a T_SEQOF/T_SETOF are "compatible" with
      *  the given type \a p_type.  Can be called only as a T_SEQOF/T_SETOF.
      *  Currently, used for structured types only.  \a p_type can be any kind
diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index 21169edc8..d3c0e8aa4 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -5628,7 +5628,7 @@ void Type::chk_this_template_incorrect_field() {
     case T_SET_T:
     case T_OPENTYPE:
       for (size_t i = 0; i < t->get_nof_comps(); i++) {
-        Error_Context cntxt(t->get_comp_byIndex(i), "In field `%s'", t->get_comp_byIndex(i)->get_name().get_dispname().c_str());
+        Error_Context cntxt2(t->get_comp_byIndex(i), "In field `%s'", t->get_comp_byIndex(i)->get_name().get_dispname().c_str());
         t->get_comp_byIndex(i)->get_type()->chk_this_template_incorrect_field();
       }
       break;
@@ -5646,7 +5646,7 @@ void Type::chk_this_template_incorrect_field() {
           case Assignment::A_VAR_TEMPLATE:   /**< template variable, dynamic template (TTCN-3) */
           case Assignment::A_PORT:           /**< port (TTCN-3) */
           {
-            Error_Context cntxt(ass, "In field `%s'", ass->get_id().get_dispname().c_str());
+            Error_Context cntxt2(ass, "In field `%s'", ass->get_id().get_dispname().c_str());
             ass->get_Type()->chk_this_template_incorrect_field();
           }
         default:
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index bde891ec0..8e727d3fd 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -6268,7 +6268,8 @@ namespace Ttcn {
   // =================================
 
   Def_Function::Def_Function(Identifier *p_id, FormalParList *p_fpl,
-                             Reference *p_runs_on_ref, Reference *p_port_ref,
+                             Reference *p_runs_on_ref, Reference *p_mtc_ref,
+                             Reference *p_system_ref, Reference *p_port_ref,
                              Type *p_return_type,
                              bool returns_template,
                              template_restriction_t p_template_restriction,
@@ -6276,6 +6277,8 @@ namespace Ttcn {
     : Def_Function_Base(false, p_id, p_fpl, p_return_type, returns_template,
         p_template_restriction),
         runs_on_ref(p_runs_on_ref), runs_on_type(0),
+        mtc_ref(p_mtc_ref), mtc_type(0),
+        system_ref(p_system_ref), system_type(0),
         port_ref(p_port_ref), port_type(0), block(p_block),
         is_startable(false), transparent(false)
   {
@@ -6286,6 +6289,8 @@ namespace Ttcn {
   Def_Function::~Def_Function()
   {
     delete runs_on_ref;
+    delete mtc_ref;
+    delete system_ref;
     delete port_ref;
     delete block;
   }
@@ -6299,6 +6304,8 @@ namespace Ttcn {
   {
     Def_Function_Base::set_fullname(p_fullname);
     if (runs_on_ref) runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>");
+    if (mtc_ref) mtc_ref->set_fullname(p_fullname + ".<mtc_type>");
+    if (system_ref) system_ref->set_fullname(p_fullname + ".<system_type>");
     if (port_ref) port_ref->set_fullname(p_fullname + ".<port_type>");
     block->set_fullname(p_fullname + ".<statement_block>");
   }
@@ -6310,10 +6317,24 @@ namespace Ttcn {
 
     Def_Function_Base::set_my_scope(&bridgeScope);
     if (runs_on_ref) runs_on_ref->set_my_scope(&bridgeScope);
+    if (mtc_ref) mtc_ref->set_my_scope(&bridgeScope);
+    if (system_ref) system_ref->set_my_scope(&bridgeScope);
     if (port_ref) port_ref->set_my_scope(&bridgeScope);
     block->set_my_scope(fp_list);
   }
 
+  Type *Def_Function::get_MtcType()
+  {
+    if (!checked) chk();
+    return mtc_type;
+  }
+  
+  Type *Def_Function::get_SystemType()
+  {
+    if (!checked) chk();
+    return system_type;
+  }
+  
   Type *Def_Function::get_RunsOnType()
   {
     if (!checked) chk();
@@ -6362,6 +6383,17 @@ namespace Ttcn {
       }
     }
     
+    // checking the `mtc' clause
+    if (mtc_ref) {
+      Error_Context cntxt2(mtc_ref, "In `mtc' clause");
+      mtc_type = mtc_ref->chk_comptype_ref();
+    }
+    
+    // checking the `system' clause
+    if (system_ref) {
+      Error_Context cntxt2(system_ref, "In `system' clause");
+      system_type = system_ref->chk_comptype_ref();
+    }
     
     // checking the formal parameter list, the check must come before the 
     // chk_prototype() function call.
@@ -7584,10 +7616,12 @@ namespace Ttcn {
   // =================================
 
   Def_Altstep::Def_Altstep(Identifier *p_id, FormalParList *p_fpl,
-                           Reference *p_runs_on_ref, StatementBlock *p_sb,
+                           Reference *p_runs_on_ref, Reference *p_mtc_ref,
+                           Reference *p_system_ref, StatementBlock *p_sb,
                            AltGuards *p_ags)
     : Definition(A_ALTSTEP, p_id), fp_list(p_fpl), runs_on_ref(p_runs_on_ref),
-      runs_on_type(0), sb(p_sb), ags(p_ags)
+      runs_on_type(0), mtc_ref(p_mtc_ref), mtc_type(0),
+      system_ref(p_system_ref), system_type(0), sb(p_sb), ags(p_ags)
   {
     if (!p_fpl || !p_sb || !p_ags)
       FATAL_ERROR("Def_Altstep::Def_Altstep()");
@@ -7601,6 +7635,8 @@ namespace Ttcn {
   {
     delete fp_list;
     delete runs_on_ref;
+    delete mtc_ref;
+    delete system_ref;
     delete sb;
     delete ags;
   }
@@ -7615,6 +7651,8 @@ namespace Ttcn {
     Definition::set_fullname(p_fullname);
     fp_list->set_fullname(p_fullname + ".<formal_par_list>");
     if (runs_on_ref) runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>");
+    if (mtc_ref) mtc_ref->set_fullname(p_fullname + ".<mtc_type>");
+    if (system_ref) system_ref->set_fullname(p_fullname + ".<system_type>");
     sb->set_fullname(p_fullname+".<block>");
     ags->set_fullname(p_fullname + ".<guards>");
   }
@@ -7627,6 +7665,8 @@ namespace Ttcn {
     Definition::set_my_scope(&bridgeScope);
     // the scope of the parameter list is set during checking
     if (runs_on_ref) runs_on_ref->set_my_scope(&bridgeScope);
+    if (mtc_ref) mtc_ref->set_my_scope(&bridgeScope);
+    if (system_ref) system_ref->set_my_scope(&bridgeScope);
     sb->set_my_scope(fp_list);
     ags->set_my_scope(sb);
   }
@@ -7636,6 +7676,18 @@ namespace Ttcn {
     if (!checked) chk();
     return runs_on_type;
   }
+  
+  Type *Def_Altstep::get_MtcType()
+  {
+    if (!checked) chk();
+    return mtc_type;
+  }
+  
+  Type *Def_Altstep::get_SystemType()
+  {
+    if (!checked) chk();
+    return system_type;
+  }
 
   FormalParList *Def_Altstep::get_FormalParList()
   {
@@ -7666,6 +7718,14 @@ namespace Ttcn {
         parlist_scope = runs_on_scope;
       }
     }
+    if (mtc_ref) {
+      Error_Context cntxt2(mtc_ref, "In `mtc' clause");
+      mtc_type = mtc_ref->chk_comptype_ref();
+    }
+    if (system_ref) {
+      Error_Context cntxt2(system_ref, "In `system' clause");
+      system_type = system_ref->chk_comptype_ref();
+    }
     fp_list->set_my_scope(parlist_scope);
     fp_list->chk(asstype);
     sb->chk();
@@ -7832,6 +7892,14 @@ namespace Ttcn {
       DEBUG(level + 1, "Runs on clause:");
       runs_on_ref->dump(level + 2);
     }
+    if (mtc_ref) {
+      DEBUG(level + 1, "Mtc clause:");
+      mtc_ref->dump(level + 2);
+    }
+    if (system_ref) {
+      DEBUG(level + 1, "System clause:");
+      system_ref->dump(level + 2);
+    }
     /*
     DEBUG(level + 1, "Local definitions:");
     sb->dump(level + 2);
diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh
index 85d246bfd..aeb433e38 100644
--- a/compiler2/ttcn3/AST_ttcn3.hh
+++ b/compiler2/ttcn3/AST_ttcn3.hh
@@ -1402,6 +1402,22 @@ namespace Ttcn {
      * It is NULL if the function has no 'runs on' clause or \a runs_on_ref is
      * erroneous. */
     Type *runs_on_type;
+    /** The 'mtc' clause (i.e. a reference to a TTCN-3 component type)
+     * It is NULL if the function has no 'mtc' clause. */
+    Reference *mtc_ref;
+    /** Points to the object describing the component type referred by
+     * 'mtc' clause.
+     * It is NULL if the function has no 'mtc' clause or \a mtc_ref is
+     * erroneous. */
+    Type *mtc_type;
+    /** The 'system' clause (i.e. a reference to a TTCN-3 component type)
+     * It is NULL if the function has no 'system' clause. */
+    Reference *system_ref;
+    /** Points to the object describing the component type referred by
+     * 'system' clause.
+     * It is NULL if the function has no 'system' clause or \a system_ref is
+     * erroneous. */
+    Type *system_type;
     /** The 'port' clause (i.e. a reference to a TTCN-3 port type)
      * It is NULL if the function has no 'port' clause. */
     Reference *port_ref;
@@ -1433,6 +1449,8 @@ namespace Ttcn {
      * @param p_id function name
      * @param p_fpl formal parameter list
      * @param p_runs_on_ref "runs on", else NULL
+     * @param p_mtc_ref "mtc", else NULL
+     * @param p_system_ref "system", else NULL
      * @param p_port_ref "port", else NULL
      * @param p_return_type return type, may be NULL
      * @param returns_template true if the return value is a template
@@ -1440,7 +1458,8 @@ namespace Ttcn {
      * @param p_block the body of the function
      */
     Def_Function(Identifier *p_id, FormalParList *p_fpl,
-                 Reference *p_runs_on_ref, Reference *p_port_ref,
+                 Reference *p_runs_on_ref, Reference *p_mtc_ref,
+                 Reference *p_system_ref, Reference *p_port_ref,
                  Type *p_return_type,
                  bool returns_template,
                  template_restriction_t p_template_restriction,
@@ -1450,6 +1469,8 @@ namespace Ttcn {
     virtual void set_fullname(const string& p_fullname);
     virtual void set_my_scope(Scope *p_scope);
     virtual Type *get_RunsOnType();
+    virtual Type *get_MtcType();
+    virtual Type *get_SystemType();
     virtual Type *get_PortType();
     /** Returns a scope that can access the definitions within component type
      * \a comptype and its parent is \a parent_scope.*/
@@ -1586,6 +1607,22 @@ namespace Ttcn {
      * It is NULL if the altstep has no 'runs on' clause or \a runs_on_ref is
      * erroneous. */
     Type *runs_on_type;
+    /** The 'mtc' clause (i.e. a reference to a TTCN-3 component type)
+     * It is NULL if the altstep has no 'mtc' clause. */
+    Reference *mtc_ref;
+    /** Points to the object describing the component type referred by
+     * 'mtc' clause.
+     * It is NULL if the altstep has no 'mtc' clause or \a mtc_ref is
+     * erroneous. */
+    Type *mtc_type;
+    /** The 'system' clause (i.e. a reference to a TTCN-3 component type)
+     * It is NULL if the altstep has no 'system' clause. */
+    Reference *system_ref;
+    /** Points to the object describing the component type referred by
+     * 'system' clause.
+     * It is NULL if the altstep has no 'system' clause or \a system_ref is
+     * erroneous. */
+    Type *system_type;
     StatementBlock *sb; /**< contains the local definitions */
     AltGuards *ags;
 
@@ -1597,13 +1634,16 @@ namespace Ttcn {
     Def_Altstep& operator=(const Def_Altstep& p);
   public:
     Def_Altstep(Identifier *p_id, FormalParList *p_fpl,
-                Reference *p_runs_on_ref, StatementBlock *p_sb,
+                Reference *p_runs_on_ref, Reference *p_mtc_ref,
+                Reference *p_system_ref, StatementBlock *p_sb,
                 AltGuards *p_ags);
     virtual ~Def_Altstep();
     virtual Def_Altstep *clone() const;
     virtual void set_fullname(const string& p_fullname);
     virtual void set_my_scope(Scope *p_scope);
     virtual Type *get_RunsOnType();
+    virtual Type *get_MtcType();
+    virtual Type *get_SystemType();
     virtual FormalParList *get_FormalParList();
     /** Returns a scope that can access the definitions within component type
      * \a comptype and its parent is \a parent_scope.*/
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 4e7448b4f..8c8115ab2 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -3125,6 +3125,11 @@ error:
       ref_pard->error("Function with `port' clause cannot be called directly.");
     }
     my_sb->chk_runs_on_clause(t_ass, *ref_pard, "call");
+    
+    bool in_control_part = my_sb->get_my_def() == NULL;
+    my_sb->chk_mtc_clause(t_ass, *ref_pard, "call", in_control_part);
+    my_sb->chk_system_clause(t_ass, *ref_pard, "call", in_control_part);
+    
     if (t_ass->get_Type())
       ref_pard->warning("The value returned by %s is not used",
 	      t_ass->get_description().c_str());
@@ -3375,6 +3380,9 @@ error:
     Error_Context cntxt(this, "In altstep instance");
     Common::Assignment *t_ass = ref_pard->get_refd_assignment();
     my_sb->chk_runs_on_clause(t_ass, *ref_pard, "call");
+    bool in_control_part = my_sb->get_my_def() == NULL;
+    my_sb->chk_mtc_clause(t_ass, *ref_pard, "call", in_control_part);
+    my_sb->chk_system_clause(t_ass, *ref_pard, "call", in_control_part);
   }
 
   void Statement::chk_return()
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index 1c3973ee8..898064d0c 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -470,6 +470,11 @@ static const string anyname("anytype");
     Ttcn::Reference *runsonref;
     Ttcn::Reference *systemref;
   } configspec;
+  
+  struct {
+    Ttcn::Reference *mtcref;
+    Ttcn::Reference *systemref;
+  } alt_tc_configspec;
 
   struct {
     Value *name;
@@ -1023,6 +1028,7 @@ static const string anyname("anytype");
 %type <reference> PortType optDerivedDef DerivedDef IndexSpec Signature
   VariableRef TimerRef Port PortOrAll ValueStoreSpec
   SenderSpec ComponentType optRunsOnSpec RunsOnSpec optSystemSpec optPortSpec
+  optMtcSpec
 %type <reference_or_any> PortOrAny TimerRefOrAny
 %type <valuerange> Range
 %type <type> NestedEnumDef NestedRecordDef NestedRecordOfDef NestedSetDef
@@ -1089,6 +1095,7 @@ AllOrTypeListWithTo TypeListWithFrom TypeListWithTo
 %type <reforid> Reference
 %type <initial> Initial
 %type <configspec> ConfigSpec
+%type <alt_tc_configspec> AltOrTcConfigSpec
 %type <createpar> optCreateParameter
 %type <applyop> ApplyOp
 %type <identifier_list> IdentifierList IdentifierListOrPredefType
@@ -1442,6 +1449,7 @@ optExtendsDef
 optFromClause
 optFunctionActualParList
 optFunctionFormalParList
+optMtcSpec
 optParDefaultValue
 optPortCallBody
 optReceiveParameter
@@ -1745,6 +1753,12 @@ Initial
 }
 ConfigSpec
 
+%destructor {
+  delete $$.mtcref;
+  delete $$.systemref;
+}
+AltOrTcConfigSpec
+
 %destructor {
   delete $$.name;
   delete $$.loc;
@@ -4175,11 +4189,11 @@ ValueofOp: // 162
 
 FunctionDef: // 164
   FunctionKeyword optDeterministicModifier IDentifier '(' optFunctionFormalParList ')'
-  optRunsOnSpec optPortSpec optReturnType optError StatementBlock
+  optRunsOnSpec AltOrTcConfigSpec optPortSpec optReturnType optError StatementBlock
   {
     $5->set_location(infile, @4, @6);
-    $$ = new Def_Function($3, $5, $7, $8, $9.type, $9.returns_template,
-                          $9.template_restriction, $11);
+    $$ = new Def_Function($3, $5, $7, $8.mtcref, $8.systemref, $9, $10.type, $10.returns_template,
+                          $10.template_restriction, $12);
     $$->set_location(infile, @$);
   }
 ;
@@ -4664,12 +4678,26 @@ ConfigSpec: // 202
   }
 ;
 
+AltOrTcConfigSpec:
+  optMtcSpec optSystemSpec
+  {
+    $$.mtcref=$1;
+    $$.systemref=$2;
+  }
+;
+
 optSystemSpec: // [203]
   /* empty */ { $$ = 0; }
 | SystemKeyword ComponentType { $$ = $2; }
 | SystemKeyword error { $$ = 0; }
 ;
 
+optMtcSpec:
+  /* empty */ { $$ = 0; }
+| MTCKeyword ComponentType { $$ = $2; }
+| MTCKeyword error { $$ = 0; }
+;
+
 TestcaseInstance: // 205
   ExecuteKeyword '(' TestcaseRef '(' optTestcaseActualParList ')'
   optTestcaseTimerValue optError ')'
@@ -4782,17 +4810,17 @@ TestcaseActualPar:
 
 AltstepDef: // 211
   AltstepKeyword IDentifier '(' optAltstepFormalParList ')' optRunsOnSpec
-  optError '{' AltstepLocalDefList AltGuardList optError '}'
+  AltOrTcConfigSpec optError '{' AltstepLocalDefList AltGuardList optError '}'
   {
     StatementBlock *sb = new StatementBlock;
-    for (size_t i = 0; i < $9.nElements; i++) {
-      Statement *stmt = new Statement(Statement::S_DEF, $9.elements[i]);
-      stmt->set_location(*$9.elements[i]);
+    for (size_t i = 0; i < $10.nElements; i++) {
+      Statement *stmt = new Statement(Statement::S_DEF, $10.elements[i]);
+      stmt->set_location(*$10.elements[i]);
       sb->add_stmt(stmt);
     }
-    Free($9.elements);
+    Free($10.elements);
     $4->set_location(infile, @4);
-    $$ = new Def_Altstep($2, $4, $6, sb, $10);
+    $$ = new Def_Altstep($2, $4, $6, $7.mtcref, $7.systemref, sb, $11);
     $$->set_location(infile, @$);
   }
 ;
diff --git a/function_test/Semantic_Analyser/Makefile.semantic b/function_test/Semantic_Analyser/Makefile.semantic
index dc3b085da..3a1908f6a 100644
--- a/function_test/Semantic_Analyser/Makefile.semantic
+++ b/function_test/Semantic_Analyser/Makefile.semantic
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 SADIRS := ver xer encode param template any_from pattern_ref float recof_index \
-port_translation
+port_translation mtc_and_system_clause
 ifdef RT2
 SADIRS += deprecated erroneous_attributes template_concat
 endif
diff --git a/function_test/Semantic_Analyser/mtc_and_system_clause/MtcSystemClause_SE.ttcn b/function_test/Semantic_Analyser/mtc_and_system_clause/MtcSystemClause_SE.ttcn
new file mode 100644
index 000000000..ddb37f5d1
--- /dev/null
+++ b/function_test/Semantic_Analyser/mtc_and_system_clause/MtcSystemClause_SE.ttcn
@@ -0,0 +1,102 @@
+/******************************************************************************
+ * Copyright (c) 2000-2017 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Szabo, Bence Janos
+ *
+ ******************************************************************************/
+
+module MtcSystemClause_SE { //^In TTCN-3 module//
+
+	type port P1 message {
+		inout integer;
+	} with {
+		extension "internal";
+	}
+
+	type component Comp1 {
+		var charstring cs;
+		port P1 p1;
+		timer mytimer;
+	}
+
+	type component Comp2 {
+		var integer i;
+		port P1 p2; /* Different name */
+		timer mytimer;
+	}
+
+	function diff_mtc() mtc Comp1 {
+	}
+
+	function diff_system() system Comp1 {
+	}
+
+	function diff_mtc_and_system() mtc Comp1 system Comp1 {
+	}
+
+	altstep alt_diff_mtc() runs on Comp1 mtc Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+	altstep alt_diff_system() runs on Comp1 system Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+	altstep alt_diff_mtc_and_system() runs on Comp1 mtc Comp1 system Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+	altstep alt_diff_mtc_bad() runs on Comp2 mtc Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+	altstep alt_diff_system_bad() runs on Comp2 system Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+	altstep alt_diff_mtc_and_system_bad() runs on Comp2 mtc Comp1 system Comp1 {
+		[]mytimer.timeout{
+
+		}
+	}
+
+
+
+	testcase tc_positive() runs on Comp1 system Comp1 {
+		diff_mtc(); 
+		diff_system(); 
+		diff_mtc_and_system();
+
+		alt_diff_mtc();
+		alt_diff_system();
+		alt_diff_mtc_and_system();
+	}
+
+	testcase tc_negative() runs on Comp2 system Comp2 { //^In testcase definition \`tc_negative\'\://
+		diff_mtc(); //^In function instance\:// //^error\: Mtc clause mismatch\: A definition that runs on component type \`\@MtcSystemClause_SE\.Comp2\' cannot call function \`\@MtcSystemClause_SE\.diff_mtc\'\, which mtc clause is \`\@MtcSystemClause_SE\.Comp1\'//
+		diff_system(); //^In function instance\:// //^error\: System clause mismatch\: A definition with system component type \`\@MtcSystemClause_SE\.Comp2\' cannot call function \`\@MtcSystemClause_SE\.diff_system\'\, which system clause is \`\@MtcSystemClause_SE\.Comp1\'//
+		diff_mtc_and_system(); //^In function instance\:// //^error\: System clause mismatch\: A definition with system component type \`\@MtcSystemClause_SE\.Comp2\' cannot call function \`\@MtcSystemClause_SE\.diff_mtc_and_system\'\, which system clause is \`\@MtcSystemClause_SE\.Comp1\'// //^error\: Mtc clause mismatch\: A definition that runs on component type \`\@MtcSystemClause_SE\.Comp2\' cannot call function \`\@MtcSystemClause_SE\.diff_mtc_and_system\'\, which mtc clause is \`\@MtcSystemClause_SE\.Comp1\'//
+
+		alt_diff_mtc_bad(); //^In altstep instance\:// //^error\: Mtc clause mismatch\: A definition that runs on component type \`\@MtcSystemClause_SE\.Comp2\' cannot call altstep \`\@MtcSystemClause_SE\.alt_diff_mtc_bad\'\, which mtc clause is \`\@MtcSystemClause_SE\.Comp1\'//
+		alt_diff_system_bad(); //^In altstep instance\:// //^error\: System clause mismatch\: A definition with system component type \`\@MtcSystemClause_SE\.Comp2\' cannot call altstep \`\@MtcSystemClause_SE\.alt_diff_system_bad\'\, which system clause is \`\@MtcSystemClause_SE\.Comp1\'//
+		alt_diff_mtc_and_system_bad(); //^In altstep instance\:// //^error\: System clause mismatch\: A definition with system component type \`\@MtcSystemClause_SE\.Comp2\' cannot call altstep \`\@MtcSystemClause_SE\.alt_diff_mtc_and_system_bad\'\, which system clause is \`\@MtcSystemClause_SE\.Comp1\'// //^error\: Mtc clause mismatch\: A definition that runs on component type \`\@MtcSystemClause_SE\.Comp2\' cannot call altstep \`\@MtcSystemClause_SE\.alt_diff_mtc_and_system_bad\'\, which mtc clause is \`\@MtcSystemClause_SE\.Comp1\'//
+	}
+
+
+
+}
diff --git a/function_test/Semantic_Analyser/mtc_and_system_clause/t b/function_test/Semantic_Analyser/mtc_and_system_clause/t
new file mode 100755
index 000000000..3a4b58ec1
--- /dev/null
+++ b/function_test/Semantic_Analyser/mtc_and_system_clause/t
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+# note this is called through "perl -w"
+use strict;
+
+my $self = $0;
+$self =~ s!/t!!;
+
+exec('make check --no-print-directory -s -C ' . $self);
+
-- 
GitLab