From c353e3caf3ea32c66bc2436b7b1996e6899b2b6f Mon Sep 17 00:00:00 2001
From: Virgile Prevosto <virgile.prevosto@m4x.org>
Date: Wed, 28 Feb 2024 20:16:12 +0100
Subject: [PATCH] [conversion] C++ classes can live inside extern "C" context

---
 convert.ml                                   | 65 +++-----------------
 framaCIRGen_src/Clang_utils.cpp              |  6 +-
 tests/class/oracle/extern_c_class.res.oracle | 25 ++++++++
 3 files changed, 34 insertions(+), 62 deletions(-)

diff --git a/convert.ml b/convert.ml
index cc94061e..6196db1e 100644
--- a/convert.ml
+++ b/convert.ml
@@ -2597,7 +2597,10 @@ let bare_or_derived_type env most_derived n =
 
 let make_class_decl env name tkind kind inherits fields body has_virtual =
   let n, t = Convert_env.typedef_normalize env name tkind in
-  let class_name = Mangling.mangle n t None in
+  let class_name =
+    if Convert_env.is_extern_c env then n.decl_name
+    else Mangling.mangle n t None
+  in
   let loc = Convert_env.get_loc env in
   let create_class_type base tb =
     { qualifier = []; plain_type = (Struct (base,tb)) }
@@ -3629,9 +3632,10 @@ and convert_class_component (env, implicits, types, fields, others) meth =
                :: others))
     | CCompound(loc,name,kind,inherits,body,tkind,has_virtual) ->
       let new_env = Convert_env.set_loc env loc in
+      let is_extern_c = Convert_env.is_extern_c env in
       let qualified_name = Convert_env.qualify new_env name in
       let new_env =
-        make_class_env new_env (Declaration name) kind tkind false
+        make_class_env new_env (Declaration name) kind tkind is_extern_c
       in
       let new_env,new_implicits,subtypes,subfields,subothers =
         match body with
@@ -3743,7 +3747,8 @@ and convert_class_component (env, implicits, types, fields, others) meth =
 
 and convert_class env name tkind kind inherits body has_virtual =
   let qualified_name = make_qualified_name env name in
-  let this_env = make_class_env env name kind tkind false in
+  let is_extern_c = Convert_env.is_extern_c env in
+  let this_env = make_class_env env name kind tkind is_extern_c in
   let new_env, implicits, types, fields, others =
     match body with
     | None -> this_env, [], [], [], []
@@ -3775,60 +3780,6 @@ and convert_class env name tkind kind inherits body has_virtual =
   List.fold_right add_glob my_implicits |>
   Convert_env.reset_current_class
 
-let rec convert_pod_field (cfields, typs, env) field =
-  match field with
-  | CFieldDecl(loc, name, typ, bf_info,is_mutable) ->
-    let env = Convert_env.set_loc env loc in
-    let cloc = Cil_datatype.Location.of_lexing_loc loc in
-    let env, (base,decl) = convert_specifiers env typ false in
-    let base =
-      if is_mutable then
-        SpecAttr (add_attr env Cil.frama_c_mutable []) :: base
-      else base
-    in
-    let bf_length = Option.map (convert_bitfield_info env) bf_info in
-    FIELD(base, [(name,decl JUSTBASE,[],cloc),bf_length])::cfields,
-    (name, typ) :: typs, env
-  | CCompound(_, name, kind, _, body, tn, _) ->
-      let dname = Declaration name in
-      let env = convert_pod env dname kind tn body in
-      cfields, typs, env
-  | _ ->
-    Convert_env.fatal env "Unknown declaration in extern C structure definition"
-
-and convert_pod env name kind tn body =
-  let loc = Convert_env.get_loc env in
-  let name =
-    match name with
-    | Declaration name -> name
-    | Implementation name -> name.decl_name
-  in
-  let env =
-    Convert_env.add_aggregate env (Cxx_utils.empty_qual name) kind tn true
-  in
-  let fields, env =
-    match body with
-      | None -> None, env
-      | Some body ->
-        let fields, typs, env =
-          List.fold_left convert_pod_field ([], [], env) body
-        in
-        Some (List.rev fields),
-        Convert_env.add_struct
-          env (Cxx_utils.empty_qual name,tn) (List.rev typs)
-  in
-  let type_decl =
-    match kind with
-      | CClass | CStruct -> Tstruct (name, fields, [])
-      | CUnion -> Tunion(name, fields,[])
-  in
-  Convert_env.add_c_global
-    env (ONLYTYPEDEF ([SpecType type_decl], loc))
-
-let convert_class env name tkind kind inherits body has_virtual =
-  if Convert_env.is_extern_c env then convert_pod env name kind tkind body
-  else convert_class env name tkind kind inherits body has_virtual
-
 let make_global_cons_init env name init =
   let loc = Convert_env.get_loc env in
   FUNDEF(None,([SpecType Tvoid; SpecAttr("__constructor__",[])],
diff --git a/framaCIRGen_src/Clang_utils.cpp b/framaCIRGen_src/Clang_utils.cpp
index b671d4ba..0f5b2837 100644
--- a/framaCIRGen_src/Clang_utils.cpp
+++ b/framaCIRGen_src/Clang_utils.cpp
@@ -1692,11 +1692,7 @@ Clang_utils::makePlainType(
         tkind templateParameters = NULL;
         const char* dec_name = get_aggregate_name(record, &templateParameters);
         const clang::DeclContext* ctx = record->getDeclContext();
-        qualified_name name;
-        if (!isExternCContext(ctx))
-          name = makeQualifiedName(ctx,dec_name,record);
-        else
-          name = qualified_name_cons(NULL, dec_name);
+        qualified_name name = makeQualifiedName(ctx,dec_name,record);
         switch (tagKind) {
           case clang::TTK_Struct:
           case clang::TTK_Class:
diff --git a/tests/class/oracle/extern_c_class.res.oracle b/tests/class/oracle/extern_c_class.res.oracle
index e69de29b..ba5027bb 100644
--- a/tests/class/oracle/extern_c_class.res.oracle
+++ b/tests/class/oracle/extern_c_class.res.oracle
@@ -0,0 +1,25 @@
+[kernel] Parsing extern_c_class.cpp (external front-end)
+Now output intermediate result
+/* Generated by Frama-C */
+struct C {
+   
+};
+void set(struct C *this, int *t);
+
+int get_x(struct C *this);
+
+/*@ requires \valid(this); */
+void set(struct C *this, int *t)
+{
+  *t = get_x(this);
+  return;
+}
+
+int get_x(struct C *this)
+{
+  int __retres;
+  __retres = 0;
+  return __retres;
+}
+
+
-- 
GitLab