From 3d246b6c0ec57530240fde7a9d3c794ab49ce969 Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Mon, 19 Aug 2019 17:18:29 +0200
Subject: [PATCH] [Kernel] Changes the behavior of makeFormalVar to make it
 easier to use

---
 src/kernel_services/ast_queries/cil.ml  | 33 +++++++++++++++----------
 src/kernel_services/ast_queries/cil.mli | 25 +++++++++++++++----
 tests/cil/insert_formal.ml              | 12 ++++++---
 3 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml
index f7023cb80fa..bc6dfe38314 100644
--- a/src/kernel_services/ast_queries/cil.ml
+++ b/src/kernel_services/ast_queries/cil.ml
@@ -5285,28 +5285,35 @@ let setMaxId (f: fundec) =
  * this one. If where = "^" then it is inserted first. If where = "$" then
  * it is inserted last. Otherwise where must be the name of a formal after
  * which to insert this. By default it is inserted at the end. *)
-let makeFormalVar fdec ?(where = "$") name typ : varinfo =
-  let makeit ghost name =
+let makeFormalVar fdec ?(ghost=fdec.svar.vghost) ?(where = "$") name typ : varinfo =
+  assert ((not fdec.svar.vghost) || ghost) ;
+  let makeit name =
     let vi = makeLocal ~ghost ~formal:true fdec name typ in
-    if ghost then vi.vattr <- addAttribute (Attr(frama_c_ghost, [])) vi.vattr ;
+    if ghost && not fdec.svar.vghost then
+      vi.vattr <- addAttribute (Attr(frama_c_ghost, [])) vi.vattr ;
     vi
   in
+  let error () = Kernel.fatal ~current:true
+      "makeFormalVar: cannot find insert-after formal %s" where
+  in
   (* Search for the insertion place *)
   let rec loopFormals acc = function
-    | [] when where = "$" || where = "$g" || where = "^g" ->
-      let ghost = where = "$g" || where = "^g" in
-      let vi = makeit ghost name in vi, List.rev (vi::acc)
     | [] ->
-      Kernel.fatal ~current:true
-        "makeFormalVar: cannot find insert-after formal %s" where
-    | f :: rest when f.vname = where ->
-      let vi = makeit f.vghost name in vi, List.rev_append acc (f :: vi :: rest)
-    | f :: rest when (f.vghost && where = "^g") ->
-      let vi = makeit true name in vi, List.rev_append acc (vi :: f :: rest)
+      if where = "$" || (ghost && where = "^") then
+        let vi = makeit name in vi, List.rev (vi :: acc)
+      else error ()
+    | f :: rest when not ghost && f.vghost ->
+      if where = "$" then
+        let vi = makeit name in vi, List.rev_append acc (vi :: f :: rest)
+      else error ()
+    | f :: rest when f.vname = where && f.vghost = ghost ->
+      let vi = makeit name in vi, List.rev_append acc (f :: vi :: rest)
+    | f :: rest when ghost && f.vghost && where = "^" ->
+      let vi = makeit name in vi, List.rev_append acc (vi :: f :: rest)
     | f :: rest -> loopFormals (f::acc) rest
   in
   let vi, newformals =
-    if where = "^" then let vi = makeit false name in vi, vi :: fdec.sformals
+    if where = "^" && not ghost then let vi = makeit name in vi, vi :: fdec.sformals
     else
       loopFormals [] fdec.sformals
   in
diff --git a/src/kernel_services/ast_queries/cil.mli b/src/kernel_services/ast_queries/cil.mli
index 71b9b2795cc..b5efeffc565 100644
--- a/src/kernel_services/ast_queries/cil.mli
+++ b/src/kernel_services/ast_queries/cil.mli
@@ -181,7 +181,10 @@ val selfFormalsDecl: State.t
   (** state of the table associating formals to each prototype. *)
 
 val makeFormalsVarDecl: ?ghost:bool -> (string * typ * attributes) -> varinfo
-  (** creates a new varinfo for the parameter of a prototype. *)
+  (** creates a new varinfo for the parameter of a prototype.
+      By default, this formal variable is not ghost.
+      @modify 19.0-Potassium+dev adds a parameter for ghost status
+  *)
 
 (** Update the formals of a function declaration from its identifier and its
     type. For a function definition, use {!Cil.setFormals}.
@@ -581,11 +584,11 @@ val isTypeTagType: logic_type -> bool
 val isVariadicListType: typ -> bool
 
 (** Obtain the argument list ([] if None).
-    @since Argon+dev Beware that it contains the ghost arguments. *)
+    @since 19.0-Potassium+dev Beware that it contains the ghost arguments. *)
 val argsToList:
   (string * typ * attributes) list option -> (string * typ * attributes) list
 
-(** @since Argon+dev
+(** @since 19.0-Potassium+dev
    Obtain the argument lists (non-ghost, ghosts) ([], [] if None) *)
 val argsToPairOfLists:
   (string * typ * attributes) list option ->
@@ -658,7 +661,9 @@ val splitFunctionTypeVI:
   The [ghost] argument defaults to [false], and corresponds to the field
   [vghost] .
   The first unnamed argument specifies whether the varinfo is for a global and
-  the second is for formals. *)
+  the second is for formals.
+  @modify 19.0-Potassium adds an optional ghost parameter
+*)
 val makeVarinfo:
   ?source:bool -> ?temp:bool -> ?referenced:bool -> ?ghost:bool -> bool -> bool
   -> string -> typ -> varinfo
@@ -668,8 +673,18 @@ val makeVarinfo:
     insert this one. If where = "^" then it is inserted first. If where = "$"
     then it is inserted last. Otherwise where must be the name of a formal
     after which to insert this. By default it is inserted at the end.
+
+    The [ghost] parameter indicates if the variable should be inserted in the
+    list of formals or ghost formals. By default, it takes the ghost status of
+    the function where the formal is inserted. Note that:
+
+    - specifying ghost to false if the function is ghost leads to an error
+    - when [where] is specified, its status must be the same as the formal to
+      insert (else, it cannot be found in the list of ghost or non ghost formals)
+
+    @modify 19.0-Potassium adds the optional ghost parameter
 *)
-val makeFormalVar: fundec -> ?where:string -> string -> typ -> varinfo
+val makeFormalVar: fundec -> ?ghost:bool -> ?where:string -> string -> typ -> varinfo
 
 (** Make a local variable and add it to a function's slocals and to the given
     block (only if insert = true, which is the default).
diff --git a/tests/cil/insert_formal.ml b/tests/cil/insert_formal.ml
index dd545df87cc..18e26925e70 100644
--- a/tests/cil/insert_formal.ml
+++ b/tests/cil/insert_formal.ml
@@ -6,9 +6,10 @@ class visitor = object
   method! vfunc f =
     let insert_circ f = Cil.makeFormalVar f ~where:"^" "x" Cil.intType in
     let insert_dollar f = Cil.makeFormalVar f ~where:"$" "x" Cil.intType in
-    let insert_circ_g f = Cil.makeFormalVar f ~where:"^g" "x" Cil.intType in
-    let insert_dollar_g f = Cil.makeFormalVar f ~where:"$g" "x" Cil.intType in
+    let insert_circ_g f = Cil.makeFormalVar f ~ghost:true ~where:"^" "x" Cil.intType in
+    let insert_dollar_g f = Cil.makeFormalVar f ~ghost:true ~where:"$" "x" Cil.intType in
     let insert_a f = Cil.makeFormalVar f ~where:"a" "x" Cil.intType in
+    let insert_a_g f = Cil.makeFormalVar f ~ghost:true ~where:"a" "x" Cil.intType in
     let circ_list = [
       "void_circumflex" ;
       "a_circumflex" ;
@@ -31,12 +32,14 @@ class visitor = object
     ] in
     let a_list = [
       "a_a" ;
-      "ghost_a_a" ;
       "a_b_c_a" ;
       "b_a_c_a" ;
+      "a_ghost_b_c_a" ;
+    ] in
+    let a_g_list = [
+      "ghost_a_a" ;
       "all_ghost_a_b_c_a" ;
       "all_ghost_b_a_c_a" ;
-      "a_ghost_b_c_a" ;
       "b_ghost_a_c_a"
     ] in
     if List.mem f.svar.vname circ_list then ignore(insert_circ f) ;
@@ -44,6 +47,7 @@ class visitor = object
     if List.mem f.svar.vname circ_g_list then ignore(insert_circ_g f) ;
     if List.mem f.svar.vname dollar_g_list then ignore(insert_dollar_g f) ;
     if List.mem f.svar.vname a_list then ignore(insert_a f) ;
+    if List.mem f.svar.vname a_g_list then ignore(insert_a_g f) ;
     Cil.DoChildren
 end
 
-- 
GitLab