From f39c69684311bb9a80f8b47c7b5adaf02b42b1ac Mon Sep 17 00:00:00 2001
From: Michele Alberti <michele.alberti@cea.fr>
Date: Tue, 10 Oct 2023 15:47:08 +0200
Subject: [PATCH] [oneret] Find the original declaration block of retvar.

---
 src/kernel_internals/typing/oneret.ml | 61 +++++++++++++++++++--------
 1 file changed, 43 insertions(+), 18 deletions(-)

diff --git a/src/kernel_internals/typing/oneret.ml b/src/kernel_internals/typing/oneret.ml
index 881f297878a..5eb2215e207 100644
--- a/src/kernel_internals/typing/oneret.ml
+++ b/src/kernel_internals/typing/oneret.ml
@@ -141,7 +141,7 @@ let encapsulate_local_vars f =
       (fun v -> Cil.hasAttribute Cabs2cil.frama_c_destructor v.vattr)
       f.sbody.blocals
   then begin
-    let exception Found of (block * stmt) in
+    let exception Found of (block Stack.t * stmt) in
     let vis = object
       val sb = Stack.create ()
       inherit Cil.nopCilVisitor
@@ -151,24 +151,31 @@ let encapsulate_local_vars f =
 
       method! vstmt s =
         match s.skind with
-        | Return _ -> raise (Found (Stack.top sb,s));
+        | Return _ -> raise (Found (sb, s));
         | _ -> DoChildren
     end
     in
-    let ret_block, ret =
+    let stack_block, ret_stmt =
       try
         ignore (visitCilBlock vis f.sbody);
         Kernel.fatal "No return statement found inside %a"
           Cil_printer.pp_varinfo f.svar
       with Found res -> res
     in
-    let ret_block_body =
+    let ret_block = Stack.top stack_block in
+    let ret_block_bstmts =
       List.filter
-        (fun s -> not (Cil_datatype.Stmt.equal ret s))
+        (fun s -> not (Cil_datatype.Stmt.equal ret_stmt s))
         ret_block.bstmts
     in
+    ret_block.bstmts <- ret_block_bstmts;
+    let s1 = Cil.mkStmt (Block f.sbody) in
+    let b = Cil.mkBlock [ s1; ret_stmt] in
+    (* As we filtered [ret_stmt] out its original block, we now need to move the
+       declaration of the return variable into [b]. Before doing that, we must
+       remove such a declaration from its original block. *)
     let retvar =
-      match ret.skind with
+      match ret_stmt.skind with
       | Return(None, _) -> None
       | Return(Some {enode = Lval (Var v,NoOffset)}, _) -> Some v
       | Return _ ->
@@ -176,19 +183,37 @@ let encapsulate_local_vars f =
       | _ ->
         Kernel.fatal "find_return did not return Return node"
     in
-    let filter_retvar_vi blocals =
-      Option.fold retvar
-        ~none:blocals
-        ~some:(fun retvar_vi ->
-            List.filter
-              (fun vi -> not (Cil_datatype.Varinfo.equal retvar_vi vi))
-              blocals)
+    (* Retrieve the block declaring [retvar], if any. *)
+    let retvar_decl_block =
+      match retvar with
+      | None -> None
+      | Some retvar ->
+        let contains_retvar =
+          List.exists (Cil_datatype.Varinfo.equal retvar)
+        in
+        let rec find_decl_block stack =
+          let block = Stack.pop_opt stack in
+          match block with
+          | None ->
+            Kernel.fatal "No block found declaring return variable %a"
+              Cil_printer.pp_varinfo retvar
+          | Some block ->
+            if contains_retvar block.blocals
+            then Some block
+            else find_decl_block stack
+        in
+        find_decl_block stack_block
     in
-    ret_block.bstmts <- ret_block_body;
-    ret_block.blocals <- filter_retvar_vi ret_block.blocals;
-    f.sbody.blocals <- filter_retvar_vi f.sbody.blocals;
-    let s1 = Cil.mkStmt (Block f.sbody) in
-    let b = Cil.mkBlock [ s1; ret] in
+    (* Filter [retvar] out its original declaration block [retvar_decl_block],
+       if any, as we will add such declaration to the outermost block [b]. *)
+    Option.fold retvar_decl_block ~none:() ~some:(fun retvar_decl_block ->
+        let retvar = Option.get retvar in
+        retvar_decl_block.blocals <-
+          List.filter
+            (fun vi -> not (Cil_datatype.Varinfo.equal retvar vi))
+            retvar_decl_block.blocals);
+    (* We can now safely add [retvar] into [b]'s declarations, and use [b] as
+       the new function's body block. *)
     b.blocals <- Option.to_list retvar;
     f.sbody <- b
   end
-- 
GitLab