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