Patchwork [Cilkplus] Check invalid gotos, increments and report errors

login
register
mail settings
Submitter Iyer, Balaji V
Date Dec. 13, 2012, 3:39 a.m.
Message ID <BF230D13CA30DD48930C31D40993300016CEB966@FMSMSX102.amr.corp.intel.com>
Download mbox | patch
Permalink /patch/205717/
State New
Headers show

Comments

Iyer, Balaji V - Dec. 13, 2012, 3:39 a.m.
Hello Everyone,
	This patch is for Cilk Plus branch affecting mainly the C compiler. It checks to see if the gotos and increment expressions inside cilk_for are valid and report errors otherwise.

Thanks,

Balaji V. Iyer.
Richard Henderson - Jan. 2, 2013, 11:11 p.m.
On 12/12/2012 07:39 PM, Iyer, Balaji V wrote:
> +	  error_at (EXPR_LOCATION (orig_incr),
> +		    "Invalid loop increment operation.");

Error messages should not be Capitalized, nor contain trailing punctuation.


r~

Patch

Index: gcc/c-family/c-cilk.c
===================================================================
--- gcc/c-family/c-cilk.c	(revision 194366)
+++ gcc/c-family/c-cilk.c	(working copy)
@@ -1292,8 +1292,9 @@ 
 	 them in code that spawns. */
       if ((TREE_CODE (arg) == VAR_DECL) && DECL_HARD_REGISTER (arg))
 	{
-	  error ("explicit register variable %qD may not be modified in spawn",
-		 arg);
+	  error_at (EXPR_LOCATION (arg),
+		    "explicit register variable %qD may not be modified in "
+		    "spawn", arg);
 	  arg = null_pointer_node;
 	}
       else
@@ -1464,7 +1465,8 @@ 
       return copy_decl_no_change (decl, id);
 
     case LABEL_DECL:
-      error ("Invalid use of label %q+D in spawn", decl);
+      error_at (EXPR_LOCATION (decl),
+		"Invalid use of label %q+D in spawn", decl);
       return error_mark_node;
 
     case RESULT_DECL:
@@ -1544,7 +1546,8 @@ 
   if (! (flags & ECF_NOTHROW) && flag_exceptions)
     *throws = true;
   if (flags & ECF_RETURNS_TWICE)
-    error ("Can not spawn call to function that returns twice");
+    error_at (EXPR_LOCATION (t),
+	      "Can not spawn call to function that returns twice");
   return 0;
 }
 
@@ -1761,6 +1764,7 @@ 
   tree cond = FOR_COND (loop);
   tree init = CILK_FOR_INIT (loop);
   tree incr = cilk_simplify_tree (FOR_EXPR (loop));
+  tree orig_incr = cilk_simplify_tree (FOR_EXPR (loop)); /* Copy for LOC.  */ 
   tree grain = CILK_FOR_GRAIN (loop);
   tree body = FOR_BODY (loop);
   
@@ -1937,9 +1941,12 @@ 
 	  exactly_one = incr_direction == -1;
 	}
       else
-	gcc_unreachable ();
+	{
+	  error_at (EXPR_LOCATION (orig_incr),
+		    "Invalid loop increment operation.");
+	  cfd->invalid = true;
+	}
       break;
-
     default:
       gcc_unreachable ();
     }
@@ -2865,3 +2872,6 @@ 
     }
   return decl;
 }
+
+
+  
Index: gcc/c-family/ChangeLog.cilkplus
===================================================================
--- gcc/c-family/ChangeLog.cilkplus	(revision 194366)
+++ gcc/c-family/ChangeLog.cilkplus	(working copy)
@@ -1,3 +1,11 @@ 
+2012-12-12  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+	* c-typeck.c (c_finish_cilk_loop) Added location for error reporting.
+	* c-cilk.c (wrapper_parm_cb): Likewise.
+	(copy_decl_for_cilk): Likewise.
+	(check_outlined_calls): Likewise.
+	(extract_for_fields): Reported an error instead of gcc_unreachable ().
+
 2012-12-10  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
 	* c-cpp-elem-function.c: New file.
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 194366)
+++ gcc/c/c-typeck.c	(working copy)
@@ -10982,19 +10982,19 @@ 
 
   if (!cond)
     {
-      error ("cilk_for missing condition");
+      error ("_Cilk_for missing condition");
       return;
     }
   if (!incr)
     {
-      error ("cilk_for missing increment");
+      error ("_Cilk_for missing increment");
       return;
     }
 
   /* If the condition is zero don't generate a loop construct.  */
   if (TREE_CONSTANT (cond))
     {
-      error ("cilk_for has constant condition");
+      error_at (EXPR_LOCATION (cond), "_Cilk_for has constant condition");
       return;
     }
   if (!cvar)
@@ -11004,7 +11004,7 @@ 
     }
   if (clab)
     {
-      error ("cilk_for has continue");
+      error_at (EXPR_LOCATION (clab), "_Cilk_for has continue");
       return;
     }
 
Index: gcc/c/c-objc-common.h
===================================================================
--- gcc/c/c-objc-common.h	(revision 194366)
+++ gcc/c/c-objc-common.h	(working copy)
@@ -120,4 +120,7 @@ 
 
 #undef LANG_HOOKS_ELEM_FN_CREATE_FN
 #define LANG_HOOKS_ELEM_FN_CREATE_FN elem_fn_create_fn
+
+#undef LANG_HOOKS_CILK_CHECK_CTRL_FLOW
+#define LANG_HOOKS_CILK_CHECK_CTRL_FLOW cilk_check_ctrl_flow
 #endif /* GCC_C_OBJC_COMMON */
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/cilk_for_incr_errors.c
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/cilk_for_incr_errors.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/cilk_for_incr_errors.c	(revision 0)
@@ -0,0 +1,22 @@ 
+#define ARRAY_SIZE 100000
+
+int main(void)
+{
+  int ii = 0;
+  int array[ARRAY_SIZE];
+  
+  _Cilk_for (ii = 0; ii < 10; ii <<= 2) /* { dg-error "Invalid loop increment operation." } */
+    array[ii] = 5;
+
+  _Cilk_for (ii = 0; ii < 10; ii *= 2) /* { dg-error "Invalid loop increment operation." } */
+    array[ii] = 5;
+
+  _Cilk_for (ii = 0; ii < 10; ii /= 2) /* { dg-error "Invalid loop increment operation." } */
+    array[ii] = 5;
+
+  _Cilk_for (ii = 0; ii < 10; ii = 5) /* { dg-error "Invalid loop increment operation." } */
+    array[ii] = 5;
+
+  _Cilk_for (ii = 0; ii < 10; ii >>= 2) /* { dg-error "Invalid loop increment operation." } */
+    array[ii] = 5;
+}
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/errors.exp
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/errors.exp	(revision 0)
+++ gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/errors.exp	(revision 0)
@@ -0,0 +1,59 @@ 
+#   Copyright (C) 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Written by Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+if { ![istarget i?86*-*-*] && ![istarget x86_64-*-*] } then {
+      return
+}
+
+
+load_lib gcc-dg.exp
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O0" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O1" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O2" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O3" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O0 -g" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O1 -g" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O2 -g" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] " -ldl -lcilkrts -I $srcdir/../../libcilkrts/include -std=c99 -fcilkplus -O3 -g" " "
+dg-finish
+
+dg-finish
+
Index: gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/goto_inside_cilkfor.c
===================================================================
--- gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/goto_inside_cilkfor.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cilk-plus/cilk_keywords_test/errors/goto_inside_cilkfor.c	(revision 0)
@@ -0,0 +1,49 @@ 
+/* Checks goto inside cilk_for and outside of cilk_for.  */
+
+#define ARRAY_SIZE 10000
+int a[ARRAY_SIZE], b[ARRAY_SIZE][ARRAY_SIZE];
+int main (int argc, char **argv)
+{
+    int i = 0, q = 0, j = 0;
+    _Cilk_for (i = 0; i < ARRAY_SIZE; i++)
+    {
+l1:
+	a[i] = i;
+l2:
+	if (i%2)
+	  q+=2;
+    }
+    goto l1; /* { dg-error "Goto label is inside a _Cilk_for while the goto itself is outside." }   */
+    if(a[(ARRAY_SIZE / 2)] == (ARRAY_SIZE / 2))
+        goto l2; /* { dg-error "Goto label is inside a _Cilk_for while the goto itself is outside." } */
+
+    _Cilk_for (i = 0; i < ARRAY_SIZE; i++)
+    {
+      /* Goto jumps into another Cilk_for.  */
+        goto l2; /* { dg-error "goto destination is outside the _Cilk_for scope." }  */
+	a[i] = i;
+l3:
+	goto l3; /* This is OK!  */
+    }
+    if(a[(ARRAY_SIZE / 2)] == (ARRAY_SIZE / 2))
+      goto l4; /* This is OK!  */
+    else
+        goto l3; /* { dg-error "Goto label is inside a _Cilk_for while the goto itself is outside." } */
+
+    _Cilk_for (i = 0; i < ARRAY_SIZE; i++) {
+l5:
+	if (i % 5) {
+	    _Cilk_for (j = 0; j < ARRAY_SIZE; j++) {
+		goto l5; /* { dg-error "goto destination is outside the _Cilk_for scope." } */
+		b[i][j] = (i+j);
+l6:
+	      q++;
+	      goto l6; /* This is OK!  */
+	    }
+	    goto l6; /* { dg-error "goto destination is outside the _Cilk_for scope." } */
+	}
+    }
+
+l4:
+    return 0;
+}
Index: gcc/testsuite/ChangeLog.cilkplus
===================================================================
--- gcc/testsuite/ChangeLog.cilkplus	(revision 194366)
+++ gcc/testsuite/ChangeLog.cilkplus	(working copy)
@@ -1,3 +1,11 @@ 
+2012-12-12  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+	* gcc.dg/cilk-plus/cilk_keywords_test/errors/goto_inside_cilkfor.c: 
+	New test.
+	* gcc.dg/cilk-plus/cilk_keywords_test/errors/cilk_for_incr_errors.c:
+	Likewise.
+	* gcc.dg/cilk-plus/cilk_keywords_test/errors/errors.exp: New script.
+
 2012-12-10  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
 	* gcc.dg/cilk-plus/elem_fn_tests/test1.c: Remove.
Index: gcc/cilk.c
===================================================================
--- gcc/cilk.c	(revision 194366)
+++ gcc/cilk.c	(working copy)
@@ -37,6 +37,16 @@ 
 #include "output.h"
 #include "dwarf2out.h"
 
+
+/* The only reason why we have this struct is that we need a void * to pass
+   into the walk_tree function.  */
+
+struct label_list_struct
+{
+  vec <tree, va_gc> *labels;
+};
+
+
 tree cilk_trees[(int) CILK_TI_MAX];
 
 static HOST_WIDE_INT worker_tail_offset;
@@ -1406,3 +1416,150 @@ 
     return true;
   return false;
 }
+
+
+/* Helper function for walk_trees.  *WALK_SUBTREES is seto to zero if it
+   encounters a CILK_FOR, LABEL_DECL or GOTO in *TP.  If LABEL_DECL is found
+   then the value is pushed into the list pointed by DATA.  */
+
+static tree
+store_labels (tree *tp, int *walk_subtrees, void *data)
+{
+  struct label_list_struct *label_list = (struct label_list_struct *)data;
+
+  if (!tp || !*tp)
+    return NULL_TREE;
+  else if (TREE_CODE (*tp) == CILK_FOR_STMT
+	   || TREE_CODE (*tp) == GOTO_EXPR)
+    *walk_subtrees = 0;
+  else if (TREE_CODE (*tp) == LABEL_DECL)
+    {
+      *walk_subtrees = 0;
+      vec_safe_push (label_list->labels, *tp);
+    }
+  else
+    *walk_subtrees = 1;
+  return NULL_TREE;
+}
+
+/* Finds all the labels in STMT that is not inside a CILK_FOR.  */
+
+static struct label_list_struct
+find_all_labels (tree stmt)
+{
+  struct label_list_struct label_list;
+
+  label_list.labels = NULL;
+  walk_tree (&stmt, store_labels, (void *)&label_list, NULL);
+  return label_list;
+}
+
+/* Helper function for walk_trees.  If the *TP is GOTO_EXPR it will check if 
+   its destination label is in the list in *DATA.  *WALK_SUBTREES is always 
+   set to one.  */
+
+static tree
+check_goto_labels_inside_cilk_for_body (tree *tp, int *walk_subtrees,
+					void *data)
+{
+  size_t ii = 0;
+  tree ii_t = NULL_TREE;
+  bool label_ok = false;
+  struct label_list_struct *label_list = (struct label_list_struct *)data;
+  if (!tp || !*tp)
+    return NULL_TREE;
+
+  if (TREE_CODE (*tp) == GOTO_EXPR)
+    {
+      tree goto_label = GOTO_DESTINATION (*tp);
+      for (ii = 0; vec_safe_iterate (label_list->labels, ii, &ii_t); ii++)
+	if (ii_t == goto_label)
+	  label_ok = true;
+      
+      if (!label_ok)
+	{
+	  error_at (EXPR_LOCATION (*tp), "goto destination is outside the "
+		    "_Cilk_for scope.");
+	  *tp = error_mark_node;
+	}
+    }
+  else if (TREE_CODE (*tp) == CILK_FOR_STMT)
+    *walk_subtrees = 0;
+  else
+    *walk_subtrees = 1;
+  return NULL_TREE;
+}
+
+/* Helper function for walk_tree. If *TP is a CILK_FOR_STMT, then it will find
+   all the labels in it and then walks through the body to see if the gotos in
+   it are using the local labels.  */
+
+static tree
+check_gotos_inside_cilk_for (tree *tp, int *walk_subtrees,
+			     void *data ATTRIBUTE_UNUSED)
+{
+  struct label_list_struct label_list;
+  if (!tp || !*tp)
+    return NULL_TREE;
+
+  if (TREE_CODE (*tp) == CILK_FOR_STMT)
+    {
+      label_list = find_all_labels (FOR_BODY (*tp));
+      walk_tree (&FOR_BODY (*tp), check_goto_labels_inside_cilk_for_body,
+		 (void *) &label_list, NULL);
+    }
+  *walk_subtrees = 1;
+  return NULL_TREE;
+}
+
+/* Helper function for walk_tree.  */
+
+static tree
+check_gotos_outside_cilk_for (tree *tp, int *walk_subtrees,
+			      void *data)
+{
+  tree ii_t = NULL_TREE;
+  size_t ii = 0;
+  bool label_ok = false;
+  struct label_list_struct *label_list = (struct label_list_struct *) data;
+  if (!tp || !*tp)
+    return NULL_TREE;
+
+  if (TREE_CODE (*tp) == GOTO_EXPR)
+    {
+      tree goto_label = GOTO_DESTINATION (*tp);
+      *walk_subtrees = 0;
+      for (ii = 0; vec_safe_iterate (label_list->labels, ii, &ii_t); ii++)
+	if (ii_t == goto_label)
+	  label_ok = true;
+
+      if (!label_ok)
+	{
+	  error_at (EXPR_LOCATION (*tp), "Goto label is inside a _Cilk_for "
+		    "while the goto itself is outside.");
+	  *tp = error_mark_node;
+	}
+    }
+  else if (TREE_CODE (*tp) == CILK_FOR_STMT)
+    *walk_subtrees = 0;
+  else
+    *walk_subtrees = 1;
+
+  return NULL_TREE;
+}
+ 
+/* Checks some of the control flow changing statements (e.g. goto) in *FNBODY
+   are valid.  */
+
+void
+cilk_check_ctrl_flow (tree *fnbody)
+{
+  struct label_list_struct label_list;
+  if (!fnbody)
+    return;
+  walk_tree (fnbody, check_gotos_inside_cilk_for, NULL, NULL);
+
+  label_list = find_all_labels (*fnbody);
+  walk_tree (fnbody, check_gotos_outside_cilk_for, (void *) &label_list, NULL);
+  return;
+}
Index: gcc/cilk.h
===================================================================
--- gcc/cilk.h	(revision 194366)
+++ gcc/cilk.h	(working copy)
@@ -296,6 +296,7 @@ 
 void gimplify_cilk_spawn (tree *, gimple_seq *, gimple_seq *);
 void gimplify_cilk_sync (tree *, gimple_seq *);
 void gimplify_cilk_for (tree *, gimple_seq *, gimple_seq *);
+void cilk_check_ctrl_flow (tree *);
 extern tree cilk_call_setjmp (tree);
 extern tree make_cilk_frame (tree);
 extern tree build_cilk_function_exit (tree, bool, bool);
Index: gcc/ChangeLog.cilkplus
===================================================================
--- gcc/ChangeLog.cilkplus	(revision 194366)
+++ gcc/ChangeLog.cilkplus	(working copy)
@@ -1,3 +1,18 @@ 
+2012-12-12  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+	* c/c-objc-common.h (LANG_HOOKS_CILK_CHECK_CTRL_FLOW): New define.
+	* cilk.c (store_labels): New function.
+	(find_all_labels): Likewise.
+	(check_goto_labels_inside_cilk_for_body): Likewise.
+	(check_gotos_inside_cilk_for): Likewise.
+	(check_gotos_outside_cilk_for): Likewise.
+	(check_cilk_ctrl_flow): Likewise.
+	* langhooks.c (lhd_cilk_check_ctrl_flow): Likewise.
+	* langhooks.h (struct lang_hooks_for_cilkplus): New function pointer.
+	* gimplify.c (gimplify_function_tree): Called cilk_check_ctrl_flow
+	function that is part of lang_hooks.
+	* langhooks-def.h (LANG_HOOKS_CILK): New field added.
+
 2012-12-10  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
 	* doc/tm.texi (TARGET_CILKPLUS_BUILTIN_MAP_PROCESSOR_TO_ATTR): Added
Index: gcc/langhooks.c
===================================================================
--- gcc/langhooks.c	(revision 194366)
+++ gcc/langhooks.c	(working copy)
@@ -730,3 +730,8 @@ 
 {
   return;
 }
+
+void lhd_cilk_check_ctrl_flow (tree *x ATTRIBUTE_UNUSED)
+{
+  return;
+}
Index: gcc/langhooks.h
===================================================================
--- gcc/langhooks.h	(revision 194366)
+++ gcc/langhooks.h	(working copy)
@@ -235,6 +235,7 @@ 
   void (*gimplify_cilk_spawn) (tree *, gimple_seq *, gimple_seq *);
   void (*gimplify_cilk_for) (tree *, gimple_seq *, gimple_seq *);
   void (*gimplify_cilk_sync) (tree *, gimple_seq *);
+  void (*cilk_check_ctrl_flow) (tree *);
   void (*elem_fn_create_fn) (tree);
 };
 
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	(revision 194366)
+++ gcc/gimplify.c	(working copy)
@@ -8415,6 +8415,8 @@ 
 
   gcc_assert (!gimple_body (fndecl));
 
+  if (flag_enable_cilk)
+    lang_hooks.cilkplus.cilk_check_ctrl_flow (&DECL_SAVED_TREE (fndecl));
 
   /* Here we check to see if we have a function with the attribute "vector."  
      If so, then we must clone it to masked/unmasked when apropriate.  */
Index: gcc/langhooks-def.h
===================================================================
--- gcc/langhooks-def.h	(revision 194366)
+++ gcc/langhooks-def.h	(working copy)
@@ -217,6 +217,7 @@ 
 void lhd_gimplify_cilk_for (tree *, gimple_seq *, gimple_seq *);
 void lhd_gimplify_cilk_sync (tree *, gimple_seq *);
 void lhd_elem_fn_create_fn (tree);
+void lhd_cilk_check_ctrl_flow (tree *);
 #define LANG_HOOKS_CILK_RECOGNIZE_SPAWN hook_bool_tree_false
 #define LANG_HOOKS_CILK_VALID_CTOR hook_bool_tree_false
 #define LANG_HOOKS_CILK_VALID_SPAWN lhd_cilk_valid_spawn
@@ -224,6 +225,7 @@ 
 #define LANG_HOOKS_GIMPLIFY_CILK_FOR   lhd_gimplify_cilk_for
 #define LANG_HOOKS_GIMPLIFY_CILK_SYNC  lhd_gimplify_cilk_sync
 #define LANG_HOOKS_ELEM_FN_CREATE_FN   lhd_elem_fn_create_fn
+#define LANG_HOOKS_CILK_CHECK_CTRL_FLOW lhd_cilk_check_ctrl_flow
 #define LANG_HOOKS_CILK {		\
   LANG_HOOKS_CILK_RECOGNIZE_SPAWN,	\
   LANG_HOOKS_CILK_VALID_CTOR,		\
@@ -231,6 +233,7 @@ 
   LANG_HOOKS_GIMPLIFY_CILK_SPAWN,      	\
   LANG_HOOKS_GIMPLIFY_CILK_FOR,		\
   LANG_HOOKS_GIMPLIFY_CILK_SYNC,	\
+  LANG_HOOKS_CILK_CHECK_CTRL_FLOW,      \
   LANG_HOOKS_ELEM_FN_CREATE_FN          \
 }