From e342fcf1bfdb76af808bdd392cb4c1e041b090cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Fri, 23 Aug 2019 16:17:20 +0200
Subject: [PATCH] [Eva] New file abstract defining the Internal and External
 module types.

These module definitions were previously in abstract_value, abstract_location
and abstract_domain. They are now grouped in this new file for the three
abstractions.
These module types should only be useful for the engine, and need not to be
visible in the implementation of the various abstractions.

New module type Leaf in abstract_value, abstract_location and abstract_domain
with the key identifying the module. The internal structure is no longer needed
in these abstractions, and is instead built by the engine from this key.

Keys are no longer exported outside the modules.
For abstract domains, the key is automatically created by the functor
Domain_builder.Complete from the domain name.

Many changes throughout the analyzer:
- in the engine, Abstract_value.{Internal|External} becomes
  Abstract.Value.{Internal|External}.
- in the abstractions, Abstract_value.Internal becomes Abstract_value.Leaf.
---
 Makefile                                      |   2 +-
 headers/header_spec.txt                       |   2 +
 src/plugins/value/domains/abstract_domain.mli |  74 +------
 .../value/domains/apron/apron_domain.ko.ml    |  15 +-
 .../value/domains/apron/apron_domain.mli      |  12 +-
 .../value/domains/apron/apron_domain.ok.ml    |  17 +-
 .../value/domains/cvalue/cvalue_domain.ml     |  11 +-
 .../value/domains/cvalue/cvalue_domain.mli    |  13 +-
 .../value/domains/cvalue/locals_scoping.ml    |   2 -
 .../value/domains/cvalue/locals_scoping.mli   |   2 -
 src/plugins/value/domains/domain_builder.ml   |   7 +-
 src/plugins/value/domains/domain_builder.mli  |  26 +--
 src/plugins/value/domains/domain_lift.ml      |   1 -
 src/plugins/value/domains/domain_product.ml   |   2 -
 .../value/domains/equality/equality_domain.ml |   9 +-
 .../domains/equality/equality_domain.mli      |   7 +-
 .../value/domains/gauges/gauges_domain.ml     |   4 +-
 .../value/domains/gauges/gauges_domain.mli    |   2 +-
 src/plugins/value/domains/inout_domain.ml     |   4 +-
 src/plugins/value/domains/inout_domain.mli    |   4 +-
 .../domains/numerors/numerors_domain.mli      |   8 +-
 .../domains/numerors/numerors_domain.ok.ml    |  21 +-
 src/plugins/value/domains/offsm_domain.ml     |   1 -
 src/plugins/value/domains/offsm_domain.mli    |   2 +-
 src/plugins/value/domains/printer_domain.mli  |   4 +-
 src/plugins/value/domains/sign_domain.mli     |   4 +-
 src/plugins/value/domains/simple_memory.ml    |   3 -
 src/plugins/value/domains/simple_memory.mli   |   4 +-
 src/plugins/value/domains/symbolic_locs.ml    |   1 -
 src/plugins/value/domains/symbolic_locs.mli   |   2 +-
 src/plugins/value/domains/traces_domain.ml    |   6 +-
 src/plugins/value/domains/traces_domain.mli   |   2 +-
 src/plugins/value/domains/unit_domain.ml      |   2 +-
 src/plugins/value/domains/unit_domain.mli     |   2 +-
 src/plugins/value/engine/abstractions.ml      | 205 +++++++++++-------
 src/plugins/value/engine/abstractions.mli     |   8 +-
 src/plugins/value/engine/compute_functions.ml |  19 +-
 src/plugins/value/engine/evaluation.ml        |   2 +-
 src/plugins/value/engine/evaluation.mli       |   2 +-
 src/plugins/value/engine/initialization.ml    |  14 +-
 src/plugins/value/engine/initialization.mli   |   2 +-
 src/plugins/value/engine/iterator.ml          |   4 +-
 src/plugins/value/engine/partition.ml         |   4 +-
 .../value/engine/partitioning_index.ml        |   7 +-
 .../value/engine/partitioning_index.mli       |   3 +-
 .../value/engine/subdivided_evaluation.ml     |   8 +-
 .../value/engine/subdivided_evaluation.mli    |   2 +-
 .../value/engine/transfer_specification.ml    |   8 +-
 src/plugins/value/engine/transfer_stmt.ml     |  12 +-
 src/plugins/value/gui_files/gui_eval.ml       |   6 +-
 src/plugins/value/gui_files/gui_types.ml      |   4 +-
 src/plugins/value/register.ml                 |   9 +-
 src/plugins/value/utils/abstract.ml           |  75 +++++++
 src/plugins/value/utils/abstract.mli          | 113 ++++++++++
 .../value/values/abstract_location.mli        |  17 +-
 src/plugins/value/values/abstract_value.mli   |  17 +-
 src/plugins/value/values/location_lift.ml     |   4 +-
 src/plugins/value/values/location_lift.mli    |   8 +-
 src/plugins/value/values/main_locations.ml    |   4 +-
 src/plugins/value/values/main_locations.mli   |   6 +-
 src/plugins/value/values/main_values.ml       |   8 +-
 src/plugins/value/values/main_values.mli      |  10 +-
 .../value/values/numerors/numerors_value.ml   |   3 +-
 .../value/values/numerors/numerors_value.mli  |   4 +-
 src/plugins/value/values/offsm_value.ml       |  11 +-
 src/plugins/value/values/offsm_value.mli      |   7 +-
 src/plugins/value/values/sign_value.ml        |   3 +-
 src/plugins/value/values/sign_value.mli       |   4 +-
 src/plugins/value/values/value_product.ml     |   6 +-
 src/plugins/value/values/value_product.mli    |   6 +-
 70 files changed, 502 insertions(+), 401 deletions(-)
 create mode 100644 src/plugins/value/utils/abstract.ml
 create mode 100644 src/plugins/value/utils/abstract.mli

diff --git a/Makefile b/Makefile
index ce5d740b6d4..334437fc823 100644
--- a/Makefile
+++ b/Makefile
@@ -878,7 +878,7 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \
 	slevel/per_stmt_slevel \
 	utils/library_functions \
 	utils/eval_typ utils/backward_formals \
-	alarmset eval utils/structure \
+	alarmset eval utils/structure utils/abstract \
 	values/value_product values/location_lift \
 	values/cvalue_forward values/cvalue_backward \
 	values/main_values values/main_locations \
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index f5f65ba9305..b66be1d6251 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -1272,6 +1272,8 @@ src/plugins/value/slevel/split_strategy.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/slevel/split_strategy.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/test.assert.sh: .ignore
 src/plugins/value/test.sh: .ignore
+src/plugins/value/utils/abstract.ml: CEA_LGPL_OR_PROPRIETARY
+src/plugins/value/utils/abstract.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/utils/backward_formals.ml: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/utils/backward_formals.mli: CEA_LGPL_OR_PROPRIETARY
 src/plugins/value/utils/eval_typ.ml: CEA_LGPL_OR_PROPRIETARY
diff --git a/src/plugins/value/domains/abstract_domain.mli b/src/plugins/value/domains/abstract_domain.mli
index 9bf4563c8cd..4c77a147588 100644
--- a/src/plugins/value/domains/abstract_domain.mli
+++ b/src/plugins/value/domains/abstract_domain.mli
@@ -396,73 +396,12 @@ module type S = sig
   val initialize_variable_using_type: init_kind -> varinfo -> t -> t
 
   include Recycle with type t := t
-end
-
-
-(** Keys identify abstract domains through the type of their abstract values. *)
-type 'a key = 'a Structure.Key_Domain.key
-
-(** Describes the internal structure of a domain.
-    Used internally to automatically generate efficient accessors from a
-    generic abstract domain, which may be a combination of several domains,
-    to a specific one. *)
-type 'a structure = 'a Structure.Key_Domain.structure =
-  | Void : 'a structure
-  | Leaf : 'a key -> 'a structure
-  | Node : 'a structure * 'b structure -> ('a * 'b) structure
-
-(**
-   For a simple 'leaf' domain, the structure should be:
-     [let key = Structure.Key_Domain.create_key "name_of_the_domain";;
-      let structure = Leaf key;;]
-
-   Then, the key should be exported by the domain, to allow the use of the
-   functions defined in the {!Interface} interface below.
-
-   A compound domain may use the {!Node} constructor to provide a separate
-   access to each of its parts.
-
-   A domain can also use the {!Void} constructor to prevent access to itself.
-*)
-
-(** Structure of a domain. *)
-module type S_with_Structure = sig
-  include S
-
-  (** A structure matching the type of the domain. *)
-  val structure : t structure
 
   (** Category for the messages about the domain.
       Must be created through {!Value_parameters.register_category}. *)
   val log_category : Value_parameters.category
 end
 
-(** External interface of a domain, with accessors.
-    Automatically built by the functor {!Structure.Open}.
-    When a generic domain is a combination of several domains, these functions
-    allow interacting with its subparts. Note that their behavior is undefined
-    if the overall domain contains several times the same domain. *)
-module type Interface = sig
-  type t
-
-  (** Tests whether a key belongs to the domain. *)
-  val mem : 'a key -> bool
-
-  (** For a key of type [k key]:
-      - if the states of this domain (of type [t]) contain a part (of type [k])
-        from the domain identified by the key,
-        then [get key] returns an accessor for this part of a state.
-      - otherwise, [get key] returns None. *)
-  val get : 'a key -> (t -> 'a) option
-
-  (** For a key of type [k key]:
-      - if the states of this domain (of type [t]) contain a part (of type [k])
-        from the domain identified by the key,
-        then [set key d state] returns the state [state] in which this part
-        has been replaced by [d].
-      - otherwise, [set key _] is the identity function. *)
-  val set : 'a key -> 'a -> t -> t
-end
 
 (** Automatic storage of the states computed during the analysis. *)
 module type Store = sig
@@ -487,7 +426,7 @@ end
 (** Full implementation of domains. Automatically built by
     {!Domain_builder.Complete} from an {!S_with_Structure} domain. *)
 module type Internal = sig
-  include S_with_Structure
+  include S
   module Store: Store with type state := state
 
   (** This function is called after the analysis. The argument is the state
@@ -497,11 +436,14 @@ module type Internal = sig
   val post_analysis: t or_bottom -> unit
 end
 
-(** Final interface of domains, as generated and used by Eva, with generic
-    accessors for domains. *)
-module type External = sig
+type 't key = 't Structure.Key_Domain.key
+
+(** Signature for a leaf module of a domain. *)
+module type Leaf = sig
   include Internal
-  include Interface with type t := state
+
+  (** The key identifies the domain and the type [t] of its states. *)
+  val key: t key
 end
 
 
diff --git a/src/plugins/value/domains/apron/apron_domain.ko.ml b/src/plugins/value/domains/apron/apron_domain.ko.ml
index 9ccb3680e29..cde2dc82ad6 100644
--- a/src/plugins/value/domains/apron/apron_domain.ko.ml
+++ b/src/plugins/value/domains/apron/apron_domain.ko.ml
@@ -22,11 +22,14 @@
 
 let ok = false
 
-module type S = Abstract_domain.Internal
+module type S = Abstract_domain.Leaf
   with type value = Main_values.Interval.t
    and type location = Precise_locs.precise_location
 
-module U = Unit_domain.Make (Main_values.Interval) (Main_locations.PLoc)
+module U = struct
+  include Unit_domain.Make (Main_values.Interval) (Main_locations.PLoc)
+  let key = Structure.Key_Domain.create_key "dummy_apron"
+end
 
 module Octagon = U
 module Box = U
@@ -34,14 +37,6 @@ module Polka_Loose = U
 module Polka_Strict = U
 module Polka_Equalities = U
 
-let dummy_key = Structure.Key_Domain.create_key "dummy_apron"
-let octagon_key = dummy_key
-let box_key = dummy_key
-let polka_loose_key = dummy_key
-let polka_strict_key = dummy_key
-let polka_equalities_key = dummy_key
-
-
 (*
 Local Variables:
 compile-command: "make -C ../../../.."
diff --git a/src/plugins/value/domains/apron/apron_domain.mli b/src/plugins/value/domains/apron/apron_domain.mli
index 19c6611afb1..b330002eca9 100644
--- a/src/plugins/value/domains/apron/apron_domain.mli
+++ b/src/plugins/value/domains/apron/apron_domain.mli
@@ -28,7 +28,7 @@
 val ok : bool
 
 (** Signature of an Apron domain in Eva. *)
-module type S = Abstract_domain.Internal
+module type S = Abstract_domain.Leaf
   with type value = Main_values.Interval.t
    and type location = Precise_locs.precise_location
 
@@ -51,16 +51,6 @@ module Polka_Strict : S
 (** Linear equalities. *)
 module Polka_Equalities : S
 
-
-(** Domain keys for the Apron domains in Eva. *)
-
-val octagon_key : Octagon.t Abstract_domain.key
-val box_key : Box.t Abstract_domain.key
-val polka_loose_key : Polka_Loose.t Abstract_domain.key
-val polka_strict_key : Polka_Strict.t Abstract_domain.key
-val polka_equalities_key : Polka_Equalities.t Abstract_domain.key
-
-
 (*
 Local Variables:
 compile-command: "make -C ../../../.."
diff --git a/src/plugins/value/domains/apron/apron_domain.ok.ml b/src/plugins/value/domains/apron/apron_domain.ok.ml
index e69f47ab862..160d5ced136 100644
--- a/src/plugins/value/domains/apron/apron_domain.ok.ml
+++ b/src/plugins/value/domains/apron/apron_domain.ok.ml
@@ -32,7 +32,7 @@ let ok = true
 
 let debug = false
 
-module type S = Abstract_domain.Internal
+module type S = Abstract_domain.Leaf
   with type value = Main_values.Interval.t
    and type location = Precise_locs.precise_location
 
@@ -362,7 +362,6 @@ module Make
        type t
        val manager: t Manager.t
        val name: string
-       val key: t Abstract1.t Abstract_domain.key
      end)
 = struct
 
@@ -371,8 +370,6 @@ module Make
   type location = Precise_locs.precise_location
 
   let man = Man.manager
-
-  let structure = Abstract_domain.Leaf Man.key
   let log_category = dkey
 
   let empty_env = Environment.make [||] [||]
@@ -725,44 +722,32 @@ module Make
 end
 
 
-let octagon_key = Structure.Key_Domain.create_key "apron-octagon"
-let box_key = Structure.Key_Domain.create_key "apron-box"
-let polka_loose_key = Structure.Key_Domain.create_key "polka-loose"
-let polka_strict_key = Structure.Key_Domain.create_key "polka-strict"
-let polka_equalities_key = Structure.Key_Domain.create_key "polka-equalities"
-
-
 module Apron_Octagon = struct
   type t = Oct.t
   let manager = Oct.manager_alloc ()
   let name = "Apron octagon domain"
-  let key = octagon_key
 end
 
 module Apron_Box = struct
   type t = Box.t
   let manager = Box.manager_alloc ()
   let name = "Apron box domain"
-  let key = box_key
 end
 
 module Apron_Polka_Loose = struct
   type t = Polka.loose Polka.t
   let manager = Polka.manager_alloc_loose ()
   let name = "Polka loose polyhedra domain"
-  let key = polka_loose_key
 end
 module Apron_Polka_Strict = struct
   type t = Polka.strict Polka.t
   let manager = Polka.manager_alloc_strict ()
   let name = "Polka strict polyhedra domain"
-  let key = polka_strict_key
 end
 module Apron_Polka_Equalities = struct
   type t = Polka.equalities Polka.t
   let manager = Polka.manager_alloc_equalities ()
   let name = "Polka linear equalities domain"
-  let key = polka_equalities_key
 end
 
 (** Apron manager allocation changes the rounding mode. *)
diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml
index 841850c4fef..3c0579fa646 100644
--- a/src/plugins/value/domains/cvalue/cvalue_domain.ml
+++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml
@@ -29,7 +29,7 @@ let extract get = match get key with
   | None -> fun _ -> Cvalue.Model.top
   | Some get -> function
     | `Bottom -> Cvalue.Model.bottom
-    | `Value state -> get state
+    | `Value state -> fst (get state)
 
 module Model = struct
 
@@ -168,10 +168,6 @@ module State = struct
 
   type state = Model.t * Locals_scoping.clobbered_set
 
-  let structure =
-    Abstract_domain.Node (Abstract_domain.Leaf key,
-                          Abstract_domain.Leaf Locals_scoping.key)
-
   let log_category = Value_parameters.dkey_cvalue_domain
 
   include Datatype.Make_with_collections (
@@ -193,6 +189,7 @@ module State = struct
     end )
 
   let name = "Cvalue domain"
+  let key = key
 
   type value = Model.value
   type location = Model.location
@@ -562,12 +559,12 @@ module Subpart = struct
   let hash = Model.hash_subtree
   let equal = Model.equal_subtree
 end
-let distinct_subpart a b =
+let distinct_subpart (a, _) (b, _) =
   if Model.equal a b then None
   else
     try Model.comp_prefixes a b; None
     with Model.Found_prefix (p, s1, s2) -> Some (p, s1, s2)
-let find_subpart s prefix = Model.find_prefix s prefix
+let find_subpart (s, _) prefix = Model.find_prefix s prefix
 
 (*
 Local Variables:
diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.mli b/src/plugins/value/domains/cvalue/cvalue_domain.mli
index 34436ded0ad..bd1284006ff 100644
--- a/src/plugins/value/domains/cvalue/cvalue_domain.mli
+++ b/src/plugins/value/domains/cvalue/cvalue_domain.mli
@@ -22,15 +22,14 @@
 
 (** Main domain of the Value Analysis. *)
 
-module State : Abstract_domain.Internal
+module State : Abstract_domain.Leaf
   with type value = Main_values.CVal.t
    and type location = Main_locations.PLoc.location
-
-
-val key : Cvalue.Model.t Abstract_domain.key
+   and type state = Cvalue.Model.t * Locals_scoping.clobbered_set
 
 val extract :
-  (Cvalue.Model.t Abstract_domain.key -> ('state -> Cvalue.Model.t) option) ->
+  (State.t Structure.Key_Domain.key ->
+   ('state -> State.t) option) ->
   'state Eval.or_bottom -> Cvalue.Model.t
 
 val inject : Cvalue.Model.t -> State.t
@@ -42,8 +41,8 @@ val project : State.t -> Cvalue.Model.t
 type prefix
 module Subpart : Hashtbl.HashedType
 val distinct_subpart :
-  Cvalue.Model.t -> Cvalue.Model.t -> (prefix * Subpart.t * Subpart.t) option
-val find_subpart : Cvalue.Model.t -> prefix -> Subpart.t option
+  State.t -> State.t -> (prefix * Subpart.t * Subpart.t) option
+val find_subpart : State.t -> prefix -> Subpart.t option
 
 
 
diff --git a/src/plugins/value/domains/cvalue/locals_scoping.ml b/src/plugins/value/domains/cvalue/locals_scoping.ml
index 2059c345c71..0399ececdac 100644
--- a/src/plugins/value/domains/cvalue/locals_scoping.ml
+++ b/src/plugins/value/domains/cvalue/locals_scoping.ml
@@ -27,8 +27,6 @@ type clobbered_set = {
   mutable clob: Base.SetLattice.t
 }
 
-let key = Structure.Key_Domain.create_key "clobbered_set"
-
 let structural_descr =
   let open Structural_descr in
   t_record [| Base.SetLattice.packed_descr |]
diff --git a/src/plugins/value/domains/cvalue/locals_scoping.mli b/src/plugins/value/domains/cvalue/locals_scoping.mli
index e0b8c5d181d..8f083545385 100644
--- a/src/plugins/value/domains/cvalue/locals_scoping.mli
+++ b/src/plugins/value/domains/cvalue/locals_scoping.mli
@@ -30,8 +30,6 @@ type clobbered_set = {
   mutable clob: Base.SetLattice.t
 }
 
-val key: clobbered_set Abstract_domain.key
-
 val structural_descr: Structural_descr.t
 
 val bottom: unit -> clobbered_set
diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml
index b27b01329e1..7406f3753dd 100644
--- a/src/plugins/value/domains/domain_builder.ml
+++ b/src/plugins/value/domains/domain_builder.ml
@@ -22,7 +22,7 @@
 
 
 module type InputDomain = sig
-  include Abstract_domain.S_with_Structure
+  include Abstract_domain.S
   val storage: unit -> bool
 end
 
@@ -33,6 +33,9 @@ module Complete
   include Domain
   module Store = Domain_store.Make (Domain)
 
+  let key: Domain.t Structure.Key_Domain.key =
+    Structure.Key_Domain.create_key Domain.name
+
   let post_analysis _state = ()
 end
 
@@ -57,7 +60,6 @@ module Make_Minimal
 
   include Domain
 
-  let structure = Abstract_domain.Void
   let log_category = Value_parameters.register_category ("d-" ^ name)
 
   type value = Value.t
@@ -185,7 +187,6 @@ module Complete_Simple_Cvalue (Domain: Simpler_domains.Simple_Cvalue)
          (Domain) (struct let module_name = Domain.name end)
        : Datatype.S_with_collections with type t := t)
 
-    let structure = Abstract_domain.Void
     let log_category = Value_parameters.register_category ("d-" ^ name)
 
     type value = Cvalue.V.t
diff --git a/src/plugins/value/domains/domain_builder.mli b/src/plugins/value/domains/domain_builder.mli
index 7d3b426a606..1eddbb4b8b5 100644
--- a/src/plugins/value/domains/domain_builder.mli
+++ b/src/plugins/value/domains/domain_builder.mli
@@ -24,34 +24,34 @@
     simplified interfaces. *)
 
 module type InputDomain = sig
-  include Abstract_domain.S_with_Structure
+  include Abstract_domain.S
   val storage: unit -> bool
 end
 
 module Complete
     (Domain: InputDomain)
-  : Abstract_domain.Internal with type state = Domain.state
-                              and type value = Domain.value
-                              and type location = Domain.location
+  : Abstract_domain.Leaf with type state = Domain.state
+                          and type value = Domain.value
+                          and type location = Domain.location
 
 module Complete_Minimal
     (Value: Abstract_value.S)
     (Location: Abstract_location.S)
     (Domain: Simpler_domains.Minimal)
-  : Abstract_domain.Internal with type value = Value.t
-                              and type location = Location.location
-                              and type state = Domain.t
+  : Abstract_domain.Leaf with type value = Value.t
+                          and type location = Location.location
+                          and type state = Domain.t
 
 module Complete_Minimal_with_datatype
     (Value: Abstract_value.S)
     (Location: Abstract_location.S)
     (Domain: Simpler_domains.Minimal_with_datatype)
-  : Abstract_domain.Internal with type value = Value.t
-                              and type location = Location.location
-                              and type state = Domain.t
+  : Abstract_domain.Leaf with type value = Value.t
+                          and type location = Location.location
+                          and type state = Domain.t
 
 module Complete_Simple_Cvalue
     (Domain: Simpler_domains.Simple_Cvalue)
-  : Abstract_domain.Internal with type value = Cvalue.V.t
-                              and type location = Precise_locs.precise_location
-                              and type state = Domain.t
+  : Abstract_domain.Leaf with type value = Cvalue.V.t
+                          and type location = Precise_locs.precise_location
+                          and type state = Domain.t
diff --git a/src/plugins/value/domains/domain_lift.ml b/src/plugins/value/domains/domain_lift.ml
index 02eaa96e98d..d53990a56cc 100644
--- a/src/plugins/value/domains/domain_lift.ml
+++ b/src/plugins/value/domains/domain_lift.ml
@@ -45,7 +45,6 @@ module Make
   include (Domain : Datatype.S_with_collections with type t = Domain.t)
   include (Domain : Abstract_domain.Lattice with type state = Domain.state)
 
-  let structure = Domain.structure
   let log_category = Domain.log_category
 
   type value = Convert.extended_value
diff --git a/src/plugins/value/domains/domain_product.ml b/src/plugins/value/domains/domain_product.ml
index e596deec5d4..d35d7c7c791 100644
--- a/src/plugins/value/domains/domain_product.ml
+++ b/src/plugins/value/domains/domain_product.ml
@@ -51,8 +51,6 @@ module Make
       (struct let module_name = name end)
   type state = t
 
-  let structure = Abstract_domain.Node (Left.structure, Right.structure)
-
   let log_category = product_category
 
   let top = Left.top, Right.top
diff --git a/src/plugins/value/domains/equality/equality_domain.ml b/src/plugins/value/domains/equality/equality_domain.ml
index 7ccb02c9721..7186aaebe57 100644
--- a/src/plugins/value/domains/equality/equality_domain.ml
+++ b/src/plugins/value/domains/equality/equality_domain.ml
@@ -122,9 +122,8 @@ module Internal = struct
   type state = t
 
   let name = "Equality domain"
-  let key = Structure.Key_Domain.create_key "equality_domain"
-  let structure : t Abstract_domain.structure = Abstract_domain.Leaf key
   let log_category = dkey
+  let key = Structure.Key_Domain.create_key "equality_domain"
 
   type equalities = Equality.Set.t
   let project (t, _, _) = t
@@ -180,13 +179,13 @@ module Store = Domain_store.Make (Internal)
 (* ------------------------- Abstract Domain -------------------------------- *)
 
 module Make
-    (Value : Abstract_value.External)
+    (Value : Abstract.Value.External)
 = struct
 
   include Internal
   module Store = Store
 
-  let get_cvalue = Value.get Main_values.cvalue_key
+  let get_cvalue = Value.get Main_values.CVal.key
 
   type value = Value.t
   type location = Precise_locs.precise_location
@@ -218,7 +217,7 @@ module Make
         let c = get v in
         if Cvalue.V.is_imprecise c then
           let c' = Cvalue.V.topify_with_origin Origin.top c in
-          Value.set Main_values.cvalue_key c' v
+          Value.set Main_values.CVal.key c' v
         else v
 
   let coop_eval oracle equalities atom_src =
diff --git a/src/plugins/value/domains/equality/equality_domain.mli b/src/plugins/value/domains/equality/equality_domain.mli
index 6f6d0416541..1242e9d2e9c 100644
--- a/src/plugins/value/domains/equality/equality_domain.mli
+++ b/src/plugins/value/domains/equality/equality_domain.mli
@@ -31,10 +31,9 @@ type call_init_state =
   | ISEmpty (** completely empty state, without impact on Memexec. *)
 
 
-module Make (Value : Abstract_value.External) : sig
-  include Abstract_domain.Internal with type value = Value.t
-                                    and type location = Precise_locs.precise_location
-  val key : t Abstract_domain.key
+module Make (Value : Abstract.Value.External) : sig
+  include Abstract_domain.Leaf with type value = Value.t
+                                and type location = Precise_locs.precise_location
 
   val pretty_debug : Format.formatter -> t -> unit
 
diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml
index 1af31275192..e45fc726212 100644
--- a/src/plugins/value/domains/gauges/gauges_domain.ml
+++ b/src/plugins/value/domains/gauges/gauges_domain.ml
@@ -1120,7 +1120,7 @@ end
 
 let dkey = Value_parameters.register_category "d-gauges"
 
-module D_Impl : Abstract_domain.S_with_Structure
+module D_Impl : Abstract_domain.S
   with type state = G.t
    and type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
@@ -1132,8 +1132,6 @@ module D_Impl : Abstract_domain.S_with_Structure
   include G
 
   let name = "Gauges domain"
-
-  let structure = Abstract_domain.Void
   let log_category = dkey
 
   let empty _ = G.empty
diff --git a/src/plugins/value/domains/gauges/gauges_domain.mli b/src/plugins/value/domains/gauges/gauges_domain.mli
index a1609d838a0..f51fdfbc660 100644
--- a/src/plugins/value/domains/gauges/gauges_domain.mli
+++ b/src/plugins/value/domains/gauges/gauges_domain.mli
@@ -23,6 +23,6 @@
 (** Gauges domain ("Arnaud Venet: The Gauge Domain: Scalable Analysis of
     Linear Inequality Invariants. CAV 2012") *)
 
-module D: Abstract_domain.Internal
+module D: Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
diff --git a/src/plugins/value/domains/inout_domain.ml b/src/plugins/value/domains/inout_domain.ml
index 12ba3cd1528..1a5a4888c93 100644
--- a/src/plugins/value/domains/inout_domain.ml
+++ b/src/plugins/value/domains/inout_domain.ml
@@ -204,8 +204,6 @@ module Transfer = struct
 
 end
 
-let key = Structure.Key_Domain.create_key "inout domain"
-
 module Internal
   (*: Domain_builder.InputDomain
     with type state = inout
@@ -221,7 +219,7 @@ module Internal
              include Abstract_domain.Lattice with type state := state
            end)
 
-  let structure : t Abstract_domain.structure = Abstract_domain.Leaf key
+  let name = "inout"
   let log_category = Value_parameters.register_category "d-inout"
 
   let enter_scope _kf _vars state = state
diff --git a/src/plugins/value/domains/inout_domain.mli b/src/plugins/value/domains/inout_domain.mli
index 0304f94f690..f759f59bfe6 100644
--- a/src/plugins/value/domains/inout_domain.mli
+++ b/src/plugins/value/domains/inout_domain.mli
@@ -22,8 +22,6 @@
 
 (** Computation of inputs of outputs. *)
 
-module D: Abstract_domain.Internal
+module D: Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
-
-val key: D.t Abstract_domain.key
diff --git a/src/plugins/value/domains/numerors/numerors_domain.mli b/src/plugins/value/domains/numerors/numerors_domain.mli
index 00b7a2ea972..c00510fa309 100644
--- a/src/plugins/value/domains/numerors/numerors_domain.mli
+++ b/src/plugins/value/domains/numerors/numerors_domain.mli
@@ -35,15 +35,15 @@ val ok: bool
     numerors values on casts from integer to floating-point values.
     Fails if numerors domain is not available.  *)
 val add_numerors_value:
-  (module Abstract_value.Internal) -> (module Abstract_value.Internal)
+  (module Abstract.Value.Internal) -> (module Abstract.Value.Internal)
 
 (* From a given abstract value product, creates the reduction function that
    reduces numerors values by using cvalues. Returns the identity if the given
    value product does not contain numerors and cvalue componants. *)
 val reduce_error:
-  (module Abstract_value.External with type t = 'v) -> ('v -> 'v)
+  (module Abstract.Value.External with type t = 'v) -> ('v -> 'v)
 
 (** Returns the numerors domain module, if available. Fails otherwise. *)
 val numerors_domain:
-  unit -> (module Abstract_domain.Internal with type value = value
-                                            and type location = location)
+  unit -> (module Abstract_domain.Leaf with type value = value
+                                        and type location = location)
diff --git a/src/plugins/value/domains/numerors/numerors_domain.ok.ml b/src/plugins/value/domains/numerors/numerors_domain.ok.ml
index cf8e73a78c4..8603b8643b0 100644
--- a/src/plugins/value/domains/numerors/numerors_domain.ok.ml
+++ b/src/plugins/value/domains/numerors/numerors_domain.ok.ml
@@ -27,7 +27,7 @@ open Cil_types
 
 type value = Numerors_value.t
 type location = Precise_locs.precise_location
-let value_key = Numerors_value.error_key
+let value_key = Numerors_value.key
 
 let ok = true
 
@@ -87,12 +87,15 @@ module Numerors_Value = struct
     ]
 end
 
-let add_numerors_value (module Value: Abstract_value.Internal) =
+let add_numerors_value (module Value: Abstract.Value.Internal) =
   let module External_Value = Structure.Open (Structure.Key_Value) (Value) in
   let module V = struct
     include Value_product.Make (Value) (Numerors_value)
 
-    let forward_cast = match External_Value.get Main_values.cvalue_key with
+    let structure =
+      Abstract.Value.(Node (Value.structure, Leaf Numerors_value.key))
+
+    let forward_cast = match External_Value.get Main_values.CVal.key with
       | None -> forward_cast
       | Some get_cvalue ->
         fun ~src_type ~dst_type (value, num) ->
@@ -116,13 +119,13 @@ let add_numerors_value (module Value: Abstract_value.Internal) =
           in
           value', num
   end in
-  (module V: Abstract_value.Internal)
+  (module V: Abstract.Value.Internal)
 
-let reduce_error (type v) (module V: Abstract_value.External with type t = v) =
-  match V.get Numerors_value.error_key, V.get Main_values.cvalue_key with
+let reduce_error (type v) (module V: Abstract.Value.External with type t = v) =
+  match V.get Numerors_value.key, V.get Main_values.CVal.key with
   | Some get_error, Some get_cvalue ->
     begin
-      let set_error = V.set Numerors_value.error_key in
+      let set_error = V.set Numerors_value.key in
       fun t ->
         let cvalue = get_cvalue t in
         try
@@ -159,5 +162,5 @@ end
 
 let numerors_domain () =
   Value_parameters.warning "The numerors domain is experimental.";
-  (module Domain: Abstract_domain.Internal with type value = value
-                                            and type location = location)
+  (module Domain: Abstract_domain.Leaf with type value = value
+                                        and type location = location)
diff --git a/src/plugins/value/domains/offsm_domain.ml b/src/plugins/value/domains/offsm_domain.ml
index 8ab4ee60ca7..f491384582b 100644
--- a/src/plugins/value/domains/offsm_domain.ml
+++ b/src/plugins/value/domains/offsm_domain.ml
@@ -103,7 +103,6 @@ module Internal  : Domain_builder.InputDomain
            end)
 
   let name = "Bitwise domain"
-  let structure = Abstract_domain.Void
   let log_category = dkey
 
   let empty _ = Memory.empty_map
diff --git a/src/plugins/value/domains/offsm_domain.mli b/src/plugins/value/domains/offsm_domain.mli
index 4567fc14d3f..8833d4b88cb 100644
--- a/src/plugins/value/domains/offsm_domain.mli
+++ b/src/plugins/value/domains/offsm_domain.mli
@@ -20,6 +20,6 @@
 (*                                                                        *)
 (**************************************************************************)
 
-module D : Abstract_domain.Internal
+module D : Abstract_domain.Leaf
   with type value = Offsm_value.offsm_or_top
    and type location = Precise_locs.precise_location
diff --git a/src/plugins/value/domains/printer_domain.mli b/src/plugins/value/domains/printer_domain.mli
index 5355cebbd9c..febfc6902d6 100644
--- a/src/plugins/value/domains/printer_domain.mli
+++ b/src/plugins/value/domains/printer_domain.mli
@@ -23,5 +23,5 @@
 (** An abstract domain built on top of the Simpler_domains.Simple_Cvalue
     interface that just prints the transfer functions called by the engine
     during an analysis. *)
-include Abstract_domain.Internal with type value = Cvalue.V.t
-                                  and type location = Precise_locs.precise_location
+include Abstract_domain.Leaf with type value = Cvalue.V.t
+                              and type location = Precise_locs.precise_location
diff --git a/src/plugins/value/domains/sign_domain.mli b/src/plugins/value/domains/sign_domain.mli
index fafc9f18c67..b32803feb65 100644
--- a/src/plugins/value/domains/sign_domain.mli
+++ b/src/plugins/value/domains/sign_domain.mli
@@ -22,5 +22,5 @@
 
 (** Abstraction of the sign of integer variables. *)
 
-include Abstract_domain.Internal with type value = Sign_value.t
-                                  and type location = Precise_locs.precise_location
+include Abstract_domain.Leaf with type value = Sign_value.t
+                              and type location = Precise_locs.precise_location
diff --git a/src/plugins/value/domains/simple_memory.ml b/src/plugins/value/domains/simple_memory.ml
index f312b589f11..ea175768582 100644
--- a/src/plugins/value/domains/simple_memory.ml
+++ b/src/plugins/value/domains/simple_memory.ml
@@ -188,9 +188,6 @@ module Make_Internal (Info: sig val name: string end) (Value: Value) = struct
   type value = Value.t
   type location = Precise_locs.precise_location
 
-  let key = Structure.Key_Domain.create_key (Info.name ^ " domain")
-  let structure : t Abstract_domain.structure = Abstract_domain.Leaf key
-
   let log_category = Value_parameters.register_category ("d-" ^ Info.name)
 
   let widen _kf _stmt = widen
diff --git a/src/plugins/value/domains/simple_memory.mli b/src/plugins/value/domains/simple_memory.mli
index e45eef5cb3a..0ea8a003a60 100644
--- a/src/plugins/value/domains/simple_memory.mli
+++ b/src/plugins/value/domains/simple_memory.mli
@@ -106,8 +106,8 @@ module Make_Domain
     (Value: Value)
   : sig
 
-    include Abstract_domain.Internal with type value = Value.t
-                                      and type location = Precise_locs.precise_location
+    include Abstract_domain.Leaf with type value = Value.t
+                                  and type location = Precise_locs.precise_location
 
     include S with type t := t
                and type value := Value.t
diff --git a/src/plugins/value/domains/symbolic_locs.ml b/src/plugins/value/domains/symbolic_locs.ml
index 42db4cd7cb5..00220370476 100644
--- a/src/plugins/value/domains/symbolic_locs.ml
+++ b/src/plugins/value/domains/symbolic_locs.ml
@@ -472,7 +472,6 @@ module Internal : Domain_builder.InputDomain
            end)
 
   let name = "Symbolic locations domain"
-  let structure = Abstract_domain.Void
   let log_category = dkey
 
   let empty _ = Memory.empty_map
diff --git a/src/plugins/value/domains/symbolic_locs.mli b/src/plugins/value/domains/symbolic_locs.mli
index 06cda3ce5eb..7cebf7b9f4c 100644
--- a/src/plugins/value/domains/symbolic_locs.mli
+++ b/src/plugins/value/domains/symbolic_locs.mli
@@ -23,6 +23,6 @@
 (** Domain that store information on non-precise l-values such as
     [t[i]] or [*p] when [i] or [p] is not exact. *)
 
-module D: Abstract_domain.Internal
+module D: Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
diff --git a/src/plugins/value/domains/traces_domain.ml b/src/plugins/value/domains/traces_domain.ml
index 68f7b320300..f7d5946d2dd 100644
--- a/src/plugins/value/domains/traces_domain.ml
+++ b/src/plugins/value/domains/traces_domain.ml
@@ -846,8 +846,6 @@ let rec complete_graph (graph:Graph.t) =
     ) graph Graph.empty
 
 
-let key = Structure.Key_Domain.create_key "traces domain"
-
 module Internal = struct
   type nonrec state = state
   type value = Cvalue.V.t
@@ -858,7 +856,6 @@ module Internal = struct
              include Abstract_domain.Lattice with type state := state
            end)
 
-  let structure : t Abstract_domain.structure = Abstract_domain.Leaf key
   let log_category = Value_parameters.register_category "d-traces"
 
   type origin = unit
@@ -1271,8 +1268,7 @@ let output_dot filename state =
   close_out out
 
 module D = struct
-  include Internal
-  module Store = Domain_store.Make(Internal)
+  include Domain_builder.Complete (Internal)
 
   let post_analysis state =
     let return_stmt = Kernel_function.find_return (fst (Globals.entry_point ())) in
diff --git a/src/plugins/value/domains/traces_domain.mli b/src/plugins/value/domains/traces_domain.mli
index 7319b2f20bc..a1c57a5359d 100644
--- a/src/plugins/value/domains/traces_domain.mli
+++ b/src/plugins/value/domains/traces_domain.mli
@@ -71,7 +71,7 @@ val current: state -> loops
 val globals: state -> Cil_types.varinfo list
 val entry_formals: state -> Cil_types.varinfo list
 
-module D: Abstract_domain.Internal
+module D: Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
    and type state = state
diff --git a/src/plugins/value/domains/unit_domain.ml b/src/plugins/value/domains/unit_domain.ml
index 4bb14526c7b..729932cbcb7 100644
--- a/src/plugins/value/domains/unit_domain.ml
+++ b/src/plugins/value/domains/unit_domain.ml
@@ -28,8 +28,8 @@ module Static = struct
     type state = t
 
     let name = "Unit domain"
-    let structure = Abstract_domain.Void
     let log_category = log_key
+    let structure = Abstract.Domain.Void
 
     let top = ()
     let is_included _ _ = true
diff --git a/src/plugins/value/domains/unit_domain.mli b/src/plugins/value/domains/unit_domain.mli
index 03a18359466..e1ed4495741 100644
--- a/src/plugins/value/domains/unit_domain.mli
+++ b/src/plugins/value/domains/unit_domain.mli
@@ -23,7 +23,7 @@
 module Make
     (Value: Abstract_value.S)
     (Loc: Abstract_location.S)
-  : Abstract_domain.Internal with type state = unit
+  : Abstract.Domain.Internal with type state = unit
                               and type value = Value.t
                               and type location = Loc.location
 
diff --git a/src/plugins/value/engine/abstractions.ml b/src/plugins/value/engine/abstractions.ml
index 256fe3fd89b..5360df332a1 100644
--- a/src/plugins/value/engine/abstractions.ml
+++ b/src/plugins/value/engine/abstractions.ml
@@ -79,14 +79,14 @@ let legacy_config = {
 }
 
 module type Value = sig
-  include Abstract_value.External
+  include Abstract.Value.External
   val reduce : t -> t
 end
 
 module type S = sig
   module Val : Value
-  module Loc : Abstract_location.External with type value = Val.t
-  module Dom : Abstract_domain.External with type value = Val.t
+  module Loc : Abstract.Location.External with type value = Val.t
+  module Dom : Abstract.Domain.External with type value = Val.t
                                          and type location = Loc.location
 end
 
@@ -103,13 +103,28 @@ end
 (* -------------------------------------------------------------------------- *)
 
 module type V = sig
-  include Abstract_value.External
-  val structure : t Abstract_value.structure
+  include Abstract.Value.External
+  val structure : t Abstract.Value.structure
 end
 
-module CVal = struct
+module Internal_CVal = struct
   include Main_values.CVal
-  include Structure.Open (Structure.Key_Value) (Main_values.CVal)
+  let structure = Abstract.Value.Leaf key
+end
+
+module CVal = struct
+  include Internal_CVal
+  include Structure.Open (Structure.Key_Value) (Internal_CVal)
+end
+
+module Internal_PLoc = struct
+  include Main_locations.PLoc
+  let structure = Abstract.Location.Leaf key
+end
+
+module Internal_Cvalue_Domain = struct
+  include Cvalue_domain.State
+  let structure = Abstract.Domain.Leaf key
 end
 
 let has_apron config =
@@ -122,18 +137,20 @@ let has_apron config =
    abstractions (if they are enabled). Do not display the intervals in the GUI
    in this case. *)
 let add_apron_value config value =
-  let module Left = ((val value: Abstract_value.Internal)) in
+  let module Left = ((val value: Abstract.Value.Internal)) in
   let module V = struct
     include Value_product.Make (Left) (Main_values.Interval)
     let pretty_typ =
       if config.cvalue
       then fun fmt typ (left, _right) -> Left.pretty_typ fmt typ left
       else pretty_typ
+    let structure =
+      Abstract.Value.(Node (Left.structure, Leaf Main_values.Interval.key))
   end in
-  (module V: Abstract_value.Internal)
+  (module V: Abstract.Value.Internal)
 
 let open_value_abstraction value =
-  let module Value = (val value : Abstract_value.Internal) in
+  let module Value = (val value : Abstract.Value.Internal) in
   (module struct
     include Value
     include Structure.Open (Structure.Key_Value) (Value)
@@ -142,14 +159,19 @@ let open_value_abstraction value =
 let build_value config =
   let value =
     if config.bitwise
-    then (module Offsm_value.CvalueOffsm : Abstract_value.Internal)
-    else (module Main_values.CVal : Abstract_value.Internal)
+    then (module Offsm_value.CvalueOffsm : Abstract.Value.Internal)
+    else (module Internal_CVal : Abstract.Value.Internal)
   in
   let value =
     if config.signs
     then
-      let module V = Value_product.Make ((val value)) (Sign_value) in
-      (module V: Abstract_value.Internal)
+      let module Value = (val value) in
+      let module V = struct
+        include Value_product.Make (Value) (Sign_value)
+        let structure =
+          Abstract.Value.(Node (Value.structure, Leaf Sign_value.key))
+      end in
+      (module V: Abstract.Value.Internal)
     else value
   in
   let value =
@@ -166,7 +188,7 @@ let build_value config =
 
 (* Builds a module conversion from a generic external value to a key. *)
 module Convert
-    (Value : Abstract_value.External)
+    (Value : Abstract.Value.External)
     (K : sig type v val key : v Abstract_value.key end)
 = struct
   type extended_value = Value.t
@@ -194,9 +216,9 @@ end
 (* Abstractions needed for the analysis: value, location and domain. *)
 module type Abstract = sig
   module Val : V
-  module Loc : Abstract_location.Internal with type value = Val.t
+  module Loc : Abstract.Location.Internal with type value = Val.t
                                            and type location = Precise_locs.precise_location
-  module Dom : Abstract_domain.Internal with type value = Val.t
+  module Dom : Abstract.Domain.Internal with type value = Val.t
                                          and type location = Loc.location
 end
 
@@ -205,13 +227,13 @@ let default_root_abstraction config =
   then
     (module struct
       module Val = CVal
-      module Loc = Main_locations.PLoc
-      module Dom = Cvalue_domain.State
+      module Loc = Internal_PLoc
+      module Dom = Internal_Cvalue_Domain
     end : Abstract)
   else
     (module struct
       module Val = CVal
-      module Loc = Main_locations.PLoc
+      module Loc = Internal_PLoc
       module Dom = Unit_domain.Make (Val) (Loc)
     end : Abstract)
 
@@ -219,20 +241,27 @@ let build_root_abstraction config value =
   let module Val = (val value : V) in
   let module K = struct
     type v = Cvalue.V.t
-    let key = Main_values.cvalue_key
+    let key = Main_values.CVal.key
   end in
   let module Conv = Convert (Val) (K) in
+  let module Loc = struct
+    include Location_lift.Make (Main_locations.PLoc) (Conv)
+    let structure = Abstract.Location.Leaf Internal_PLoc.key
+  end in
   if config.cvalue
   then
     (module struct
       module Val = Val
-      module Loc = Location_lift.Make (Main_locations.PLoc) (Conv)
-      module Dom = Domain_lift.Make (Cvalue_domain.State) (Conv)
+      module Loc = Loc
+      module Dom = struct
+        include Domain_lift.Make (Cvalue_domain.State) (Conv)
+        let structure = Abstract.Domain.Leaf Internal_Cvalue_Domain.key
+      end
     end : Abstract)
   else
     (module struct
       module Val = Val
-      module Loc = Location_lift.Make (Main_locations.PLoc) (Conv)
+      module Loc = Loc
       module Dom = Unit_domain.Make (Val) (Loc)
     end : Abstract)
 
@@ -242,17 +271,22 @@ let build_root_abstraction config value =
 (* -------------------------------------------------------------------------- *)
 
 let add_apron_domain abstract apron =
-  let module Abstract = (val abstract: Abstract) in
+  let module Acc = (val abstract: Abstract) in
   let module K = struct
     type v = Main_values.Interval.t
-    let key = Main_values.interval_key
+    let key = Main_values.Interval.key
   end in
-  let module Conv = Convert (Abstract.Val) (K) in
-  let module Apron = Domain_lift.Make ((val apron : Apron_domain.S)) (Conv) in
+  let module Conv = Convert (Acc.Val) (K) in
+  let module Apron = (val apron : Apron_domain.S) in
+  let structure = Abstract.Domain.Leaf Apron.key in
+  let module Apron = Domain_lift.Make (Apron) (Conv) in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
-    module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Apron)
+    module Val = Acc.Val
+    module Loc = Acc.Loc
+    module Dom = struct
+      include Domain_product.Make (Acc.Val) (Acc.Dom) (Apron)
+      let structure = Abstract.Domain.(Node (Acc.Dom.structure, structure))
+    end
   end : Abstract)
 
 let dkey_experimental = Value_parameters.register_category "experimental-ok"
@@ -273,32 +307,37 @@ let add_apron_domain abstractions apron =
 
 module CvalueEquality = Equality_domain.Make (CVal)
 
-let add_generic_equalities (module Abstract : Abstract) =
-  let module EqDom = Equality_domain.Make (Abstract.Val) in
-  let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (EqDom) in
+let add_generic_equalities (module Acc : Abstract) =
+  let module EqDom = Equality_domain.Make (Acc.Val) in
+  let module Dom = struct
+    include Domain_product.Make (Acc.Val) (Acc.Dom) (EqDom)
+    let structure = Abstract.Domain.(Node (Acc.Dom.structure, Leaf EqDom.key))
+  end in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
+    module Val = Acc.Val
+    module Loc = Acc.Loc
     module Dom = Dom
   end : Abstract)
 
-let add_equalities (type v) (module Abstract : Abstract with type Val.t = v) =
-  match Abstract.Val.structure with
+let add_equalities (type v) (module Acc : Abstract with type Val.t = v) =
+  match Acc.Val.structure with
   | Structure.Key_Value.Leaf key ->
     begin
-      match Structure.Key_Value.eq_type key Main_values.cvalue_key with
-      | None -> add_generic_equalities (module Abstract)
+      match Structure.Key_Value.eq_type key Main_values.CVal.key with
+      | None -> add_generic_equalities (module Acc)
       | Some Structure.Eq ->
-        let module Dom =
-          Domain_product.Make (Abstract.Val) (Abstract.Dom) (CvalueEquality)
-        in
+        let module Dom = struct
+          include Domain_product.Make (Acc.Val) (Acc.Dom) (CvalueEquality)
+            let structure =
+              Abstract.Domain.(Node (Acc.Dom.structure, Leaf CvalueEquality.key))
+        end in
         (module struct
-          module Val = Abstract.Val
-          module Loc = Abstract.Loc
+          module Val = Acc.Val
+          module Loc = Acc.Loc
           module Dom = Dom
         end : Abstract)
     end
-  | _ -> add_generic_equalities (module Abstract)
+  | _ -> add_generic_equalities (module Acc)
 
 
 (* -------------------------------------------------------------------------- *)
@@ -306,17 +345,21 @@ let add_equalities (type v) (module Abstract : Abstract with type Val.t = v) =
 (* -------------------------------------------------------------------------- *)
 
 let add_offsm abstract =
-  let module Abstract = (val abstract : Abstract) in
+  let module Acc = (val abstract : Abstract) in
   let module K = struct
     type v = Offsm_value.offsm_or_top
-    let key = Offsm_value.offsm_key
+    let key = Offsm_value.Offsm.key
   end in
-  let module Conv = Convert (Abstract.Val) (K) in
+  let module Conv = Convert (Acc.Val) (K) in
   let module Offsm = Domain_lift.Make (Offsm_domain.D) (Conv) in
-  let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Offsm) in
+  let module Dom = struct
+    include Domain_product.Make (Acc.Val) (Acc.Dom) (Offsm)
+    let structure =
+      Abstract.Domain.(Node (Acc.Dom.structure, Leaf Offsm_domain.D.key))
+  end in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
+    module Val = Acc.Val
+    module Loc = Acc.Loc
     module Dom = Dom
   end : Abstract)
 
@@ -324,23 +367,27 @@ let add_offsm abstract =
 (*                   Domains on standard locations and values                 *)
 (* -------------------------------------------------------------------------- *)
 
-module type Standard_abstraction = Abstract_domain.Internal
+module type Standard_abstraction = Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
 
 let add_standard_domain d abstract =
-  let module Abstract = (val abstract : Abstract) in
+  let module Acc = (val abstract : Abstract) in
   let module K = struct
     type v = Cvalue.V.t
-    let key = Main_values.cvalue_key
+    let key = Main_values.CVal.key
   end in
-  let module Conv = Convert (Abstract.Val) (K) in
+  let module Conv = Convert (Acc.Val) (K) in
   let module D = (val d: Standard_abstraction) in
   let module LD = Domain_lift.Make (D) (Conv) in
-  let module Dom = Domain_product.Make (Abstract.Val)(Abstract.Dom)(LD) in
+  let module Dom = struct
+    include Domain_product.Make (Acc.Val)(Acc.Dom)(LD)
+    let structure =
+      Abstract.Domain.(Node (Acc.Dom.structure, Leaf D.key))
+  end in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
+    module Val = Acc.Val
+    module Loc = Acc.Loc
     module Dom = Dom
   end : Abstract)
 
@@ -381,17 +428,21 @@ let add_inout =
 (* -------------------------------------------------------------------------- *)
 
 let add_signs abstract =
-  let module Abstract = (val abstract : Abstract) in
+  let module Acc = (val abstract : Abstract) in
   let module K = struct
     type v = Sign_value.t
-    let key = Sign_value.sign_key
+    let key = Sign_value.key
   end in
-  let module Conv = Convert (Abstract.Val) (K) in
+  let module Conv = Convert (Acc.Val) (K) in
   let module Sign = Domain_lift.Make (Sign_domain) (Conv) in
-  let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Sign) in
+  let module Dom = struct
+    include Domain_product.Make (Acc.Val) (Acc.Dom) (Sign)
+    let structure =
+      Abstract.Domain.(Node (Acc.Dom.structure, Leaf Sign_domain.key))
+  end in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
+    module Val = Acc.Val
+    module Loc = Acc.Loc
     module Dom = Dom
   end : Abstract)
 
@@ -400,18 +451,22 @@ let add_signs abstract =
 (* -------------------------------------------------------------------------- *)
 
 let add_errors abstract =
-  let module Abstract = (val abstract : Abstract) in
+  let module Acc = (val abstract : Abstract) in
   let module K = struct
     type v = Numerors_domain.value
     let key = Numerors_domain.value_key
   end in
-  let module Conv = Convert (Abstract.Val) (K) in
+  let module Conv = Convert (Acc.Val) (K) in
   let module Numerors = (val Numerors_domain.numerors_domain ()) in
   let module Errors = Domain_lift.Make (Numerors) (Conv) in
-  let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Errors) in
+  let module Dom = struct
+    include Domain_product.Make (Acc.Val) (Acc.Dom) (Errors)
+    let structure =
+      Abstract.Domain.(Node (Acc.Dom.structure, Leaf Numerors.key))
+  end in
   (module struct
-    module Val = Abstract.Val
-    module Loc = Abstract.Loc
+    module Val = Acc.Val
+    module Loc = Acc.Loc
     module Dom = Dom
   end : Abstract)
 
@@ -439,7 +494,7 @@ let build_abstractions config =
   let abstractions =
     match V.structure with
     | Structure.Key_Value.Leaf key
-      when Structure.Key_Value.equal key Main_values.cvalue_key ->
+      when Structure.Key_Value.equal key Main_values.CVal.key ->
       default_root_abstraction config
     | _ -> build_root_abstraction config value
   in
@@ -519,7 +574,7 @@ let build_abstractions config =
 
 
 (* Add the reduce function to the value module. *)
-module Reduce (Value : Abstract_value.External) = struct
+module Reduce (Value : Abstract.Value.External) = struct
 
   include Value
 
@@ -528,11 +583,11 @@ module Reduce (Value : Abstract_value.External) = struct
      other. If the Cvalue is not a scalar do nothing, because we do not
      currently use Apron for pointer offsets. *)
   let reduce_apron_itv =
-    match Value.get Main_values.interval_key, Value.get Main_values.cvalue_key with
+    match Value.get Main_values.Interval.key, Value.get Main_values.CVal.key with
     | Some get_interval, Some get_cvalue ->
       begin
-        let set_cvalue = Value.set Main_values.cvalue_key in
-        let set_interval = Value.set Main_values.interval_key in
+        let set_cvalue = Value.set Main_values.CVal.key in
+        let set_interval = Value.set Main_values.Interval.key in
         fun t ->
           match get_interval t with
           | None -> begin
diff --git a/src/plugins/value/engine/abstractions.mli b/src/plugins/value/engine/abstractions.mli
index 996f0aaa039..15837823e65 100644
--- a/src/plugins/value/engine/abstractions.mli
+++ b/src/plugins/value/engine/abstractions.mli
@@ -53,7 +53,7 @@ val configure : unit -> config
 
 
 module type Value = sig
-  include Abstract_value.External
+  include Abstract.Value.External
   val reduce : t -> t
 end
 
@@ -61,8 +61,8 @@ end
     abstractions.*)
 module type S = sig
   module Val : Value
-  module Loc : Abstract_location.External with type value = Val.t
-  module Dom : Abstract_domain.External with type value = Val.t
+  module Loc : Abstract.Location.External with type value = Val.t
+  module Dom : Abstract.Domain.External with type value = Val.t
                                          and type location = Loc.location
 end
 
@@ -78,7 +78,7 @@ module type Eva = sig
 end
 
 (** Type of abstractions that use the builtin types for values and locations *)
-module type Standard_abstraction = Abstract_domain.Internal
+module type Standard_abstraction = Abstract_domain.Leaf
   with type value = Cvalue.V.t
    and type location = Precise_locs.precise_location
 
diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml
index d265352833e..4440415631b 100644
--- a/src/plugins/value/engine/compute_functions.ml
+++ b/src/plugins/value/engine/compute_functions.ml
@@ -149,17 +149,17 @@ module Make (Abstract: Abstractions.Eva) = struct
   let initial_state = Init.initial_state
 
   let get_cvalue =
-    match Abstract.Dom.get Cvalue_domain.key with
+    match Abstract.Dom.get Cvalue_domain.State.key with
     | None -> fun _ -> Cvalue.Model.top
-    | Some get -> fun state -> get state
+    | Some get -> fun state -> Cvalue_domain.project (get state)
 
   let get_cval =
-    match Abstract.Val.get Main_values.cvalue_key with
+    match Abstract.Val.get Main_values.CVal.key with
     | None -> fun _ -> assert false
     | Some get -> fun value -> get value
 
   let get_ploc =
-    match Abstract.Loc.get Main_locations.ploc_key with
+    match Abstract.Loc.get Main_locations.PLoc.key with
     | None -> fun _ -> assert false
     | Some get -> fun location -> get location
 
@@ -312,17 +312,16 @@ module Make (Abstract: Abstractions.Eva) = struct
         let cvalue_states, cacheable =
           Builtins.apply_builtin builtin cvalue_call cvalue_state
         in
-        let insert (cvalue_state, clobbered_set) =
-          Abstract.Dom.set Locals_scoping.key clobbered_set
-            (Abstract.Dom.set Cvalue_domain.key cvalue_state final_state)
+        let insert cvalue_state =
+          Abstract.Dom.set Cvalue_domain.State.key cvalue_state final_state
         in
         let states = Bottom.bot_of_list (List.map insert cvalue_states) in
         Transfer.{states; cacheable; builtin=true}
 
   let compute_call =
-    if Abstract.Dom.mem Cvalue_domain.key
-    && Abstract.Val.mem Main_values.cvalue_key
-    && Abstract.Loc.mem Main_locations.ploc_key
+    if Abstract.Dom.mem Cvalue_domain.State.key
+    && Abstract.Val.mem Main_values.CVal.key
+    && Abstract.Loc.mem Main_locations.PLoc.key
     then compute_call_or_builtin
     else compute_and_cache_call
 
diff --git a/src/plugins/value/engine/evaluation.ml b/src/plugins/value/engine/evaluation.ml
index cc4018b105a..b56d0062033 100644
--- a/src/plugins/value/engine/evaluation.ml
+++ b/src/plugins/value/engine/evaluation.ml
@@ -263,7 +263,7 @@ let indeterminate_copy lval result alarms =
 
 
 module type Value = sig
-  include Abstract_value.External
+  include Abstract.Value.External
   val reduce : t -> t
 end
 
diff --git a/src/plugins/value/engine/evaluation.mli b/src/plugins/value/engine/evaluation.mli
index ad8886669f2..f7febc17e42 100644
--- a/src/plugins/value/engine/evaluation.mli
+++ b/src/plugins/value/engine/evaluation.mli
@@ -104,7 +104,7 @@ module type S = sig
 end
 
 module type Value = sig
-  include Abstract_value.External
+  include Abstract.Value.External
 
   (** Inter-reduction of values. Useful when the value module is a reduced
       product of several abstraction.
diff --git a/src/plugins/value/engine/initialization.ml b/src/plugins/value/engine/initialization.ml
index 317446467c2..6f15c07d5d6 100644
--- a/src/plugins/value/engine/initialization.ml
+++ b/src/plugins/value/engine/initialization.ml
@@ -80,7 +80,7 @@ let (>>>) t f = match t with
 let counter = ref 0
 
 module Make
-    (Domain: Abstract_domain.External)
+    (Domain: Abstract.Domain.External)
     (Eva: Evaluation.S with type state = Domain.state
                         and type loc = Domain.location)
     (Transfer: Transfer_stmt.S with type state = Domain.t)
@@ -270,7 +270,7 @@ module Make
   (* Use the values supplied in [actuals] for the formals of [kf], and
      bind them in [state] *)
   let add_supplied_main_formals kf actuals state =
-    match Domain.get Cvalue_domain.key with
+    match Domain.get Cvalue_domain.State.key with
     | None ->
       Value_parameters.abort "Function Db.Value.fun_set_args cannot be used \
                               without the Cvalue domain"
@@ -278,7 +278,7 @@ module Make
       let formals = Kernel_function.get_formals kf in
       if (List.length formals) <> List.length actuals then
         raise Db.Value.Incorrect_number_of_arguments;
-      let cvalue_state = get_cvalue state in
+      let cvalue_state = Cvalue_domain.project (get_cvalue state) in
       let add_actual state actual formal =
         let actual = Eval_op.offsetmap_of_v ~typ:formal.vtype actual in
         Cvalue.Model.add_base (Base.of_varinfo formal) actual state
@@ -286,8 +286,8 @@ module Make
       let cvalue_state =
         List.fold_left2 add_actual cvalue_state actuals formals
       in
-      let set_domain = Domain.set Cvalue_domain.key in
-      set_domain cvalue_state state
+      let set_domain = Domain.set Cvalue_domain.State.key in
+      set_domain (Cvalue_domain.inject cvalue_state) state
 
   let add_main_formals kf state =
     match Db.Value.fun_get_args () with
@@ -354,7 +354,9 @@ module Make
   let supplied_state () =
     let cvalue_state = Db.Value.globals_state () in
     if Cvalue.Model.is_reachable cvalue_state
-    then `Value (Domain.set Cvalue_domain.key cvalue_state Domain.top)
+    then
+      let cvalue_state = Cvalue_domain.inject cvalue_state in
+      `Value (Domain.set Cvalue_domain.State.key cvalue_state Domain.top)
     else `Bottom
 
   let initial_state ~lib_entry =
diff --git a/src/plugins/value/engine/initialization.mli b/src/plugins/value/engine/initialization.mli
index d3bf03c164d..f87a4799a8d 100644
--- a/src/plugins/value/engine/initialization.mli
+++ b/src/plugins/value/engine/initialization.mli
@@ -44,7 +44,7 @@ module type S = sig
 end
 
 module Make
-    (Domain: Abstract_domain.External)
+    (Domain: Abstract.Domain.External)
     (Eva: Evaluation.S with type state = Domain.state
                         and type loc = Domain.location)
     (Transfer: Transfer_stmt.S with type state = Domain.t)
diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml
index 541d61dd21f..0e83fb39280 100644
--- a/src/plugins/value/engine/iterator.ml
+++ b/src/plugins/value/engine/iterator.ml
@@ -433,10 +433,10 @@ module Make_Dataflow
       edge_info.fireable <- true;
     flow
 
-  let get_cvalue = Domain.get Cvalue_domain.key
+  let get_cvalue = Domain.get Cvalue_domain.State.key
   let gather_cvalues states =
     match get_cvalue with
-    | Some get -> List.map get states
+    | Some get -> List.map (fun s -> Cvalue_domain.project (get s)) states
     | None -> []
 
   let call_statement_callbacks (stmt : stmt) (f : flow) : unit =
diff --git a/src/plugins/value/engine/partition.ml b/src/plugins/value/engine/partition.ml
index 68686f72d14..644e3bf20b5 100644
--- a/src/plugins/value/engine/partition.ml
+++ b/src/plugins/value/engine/partition.ml
@@ -245,7 +245,7 @@ struct
                    all states"
     in
     (* Get the cvalue *)
-    let cvalue = match Abstract.Val.get Main_values.cvalue_key with
+    let cvalue = match Abstract.Val.get Main_values.CVal.key with
       | Some get_cvalue -> get_cvalue value
       | None -> fail ~exp "partitioning is disabled when the CValue domain is \
                            not active"
@@ -325,7 +325,7 @@ struct
 
   (* --- Applying partitioning actions onto flows --------------------------- *)
 
-  let stamp_by_value = match Abstract.Val.get Main_values.cvalue_key with
+  let stamp_by_value = match Abstract.Val.get Main_values.CVal.key with
     | None -> fun _ _ _ -> None
     | Some get -> fun expr expected_values state ->
       let typ = Cil.typeOf expr in
diff --git a/src/plugins/value/engine/partitioning_index.ml b/src/plugins/value/engine/partitioning_index.ml
index 08a2f449cf0..af420297323 100644
--- a/src/plugins/value/engine/partitioning_index.ml
+++ b/src/plugins/value/engine/partitioning_index.ml
@@ -23,7 +23,8 @@
 module type Domain = sig
   include Abstract_domain.Lattice
   include Datatype.S_with_collections with type t = state
-  include Abstract_domain.Interface with type t := state
+  include Abstract.Interface with type t := state
+                              and type 'a key := 'a Abstract_domain.key
 end
 
 (** Partition of the abstract states, computed for each node by the
@@ -45,12 +46,12 @@ module Make
 
   (* Optimizations relying on specific features of the cvalue domain. *)
 
-  let distinct_subpart = match Domain.get Cvalue_domain.key with
+  let distinct_subpart = match Domain.get Cvalue_domain.State.key with
     | None -> fun _ _ -> None
     | Some get ->
       fun s1 s2 -> Cvalue_domain.distinct_subpart (get s1) (get s2)
 
-  let find_subpart = match Domain.get Cvalue_domain.key with
+  let find_subpart = match Domain.get Cvalue_domain.State.key with
     | None -> fun _ _ -> None
     | Some get ->
       fun state prefix -> Cvalue_domain.find_subpart (get state) prefix
diff --git a/src/plugins/value/engine/partitioning_index.mli b/src/plugins/value/engine/partitioning_index.mli
index b4488a2eef7..9a72e4b44bb 100644
--- a/src/plugins/value/engine/partitioning_index.mli
+++ b/src/plugins/value/engine/partitioning_index.mli
@@ -33,7 +33,8 @@
 module type Domain = sig
   include Abstract_domain.Lattice
   include Datatype.S_with_collections with type t = state
-  include Abstract_domain.Interface with type t := state
+  include Abstract.Interface with type t := state
+                              and type 'a key := 'a Abstract_domain.key
 end
 
 module Make (Domain: Domain) : sig
diff --git a/src/plugins/value/engine/subdivided_evaluation.ml b/src/plugins/value/engine/subdivided_evaluation.ml
index ae1efe494c8..3d0e928ef9f 100644
--- a/src/plugins/value/engine/subdivided_evaluation.ml
+++ b/src/plugins/value/engine/subdivided_evaluation.ml
@@ -368,7 +368,7 @@ module type Forward_Evaluation = sig
 end
 
 module Make
-    (Value : Abstract_value.External)
+    (Value : Abstract.Value.External)
     (Loc : Abstract_location.S with type value = Value.t)
     (Valuation: Valuation with type value = Value.t
                            and type loc = Loc.location)
@@ -379,15 +379,15 @@ module Make
   (* Values are converted to {!Cvalue.V.t}, because those are
      currently the only values on which we can split. *)
 
-  let get_cval = match Value.get Main_values.cvalue_key with
+  let get_cval = match Value.get Main_values.CVal.key with
     | Some get -> get
     | None -> fun _ -> Cvalue.V.top
 
   let set_cval =
-    let set = Value.set Main_values.cvalue_key in
+    let set = Value.set Main_values.CVal.key in
     fun cval v -> set cval v
 
-  let activated = Value.mem Main_values.cvalue_key
+  let activated = Value.mem Main_values.CVal.key
 
   module Clear = Clear_Valuation (Valuation)
 
diff --git a/src/plugins/value/engine/subdivided_evaluation.mli b/src/plugins/value/engine/subdivided_evaluation.mli
index 745624c4575..71d582bb70d 100644
--- a/src/plugins/value/engine/subdivided_evaluation.mli
+++ b/src/plugins/value/engine/subdivided_evaluation.mli
@@ -36,7 +36,7 @@ module type Forward_Evaluation = sig
 end
 
 module Make
-    (Value : Abstract_value.External)
+    (Value : Abstract.Value.External)
     (Loc: Abstract_location.S with type value = Value.t)
     (Valuation: Eval.Valuation with type value = Value.t
                                 and type loc = Loc.location)
diff --git a/src/plugins/value/engine/transfer_specification.ml b/src/plugins/value/engine/transfer_specification.ml
index d5438b227de..69171aaeec7 100644
--- a/src/plugins/value/engine/transfer_specification.ml
+++ b/src/plugins/value/engine/transfer_specification.ml
@@ -227,14 +227,14 @@ module Make
 
   (* Extraction of the precise location and of the cvalue domain:
      needed to evaluate the location of an assigns clause. *)
-  let get_ploc = match Location.get Main_locations.ploc_key with
+  let get_ploc = match Location.get Main_locations.PLoc.key with
     | None -> fun _ -> Main_locations.PLoc.top
     | Some get -> get
-  let set_ploc = Location.set Main_locations.ploc_key
+  let set_ploc = Location.set Main_locations.PLoc.key
   let set_location loc = set_ploc (Main_locations.PLoc.make loc)
-  let get_cvalue_state = match Domain.get Cvalue_domain.key with
+  let get_cvalue_state = match Domain.get Cvalue_domain.State.key with
     | None -> fun _ -> Cvalue.Model.top
-    | Some get -> get
+    | Some get -> fun s -> Cvalue_domain.project (get s)
 
   let make_env state = Eval_terms.env_assigns (get_cvalue_state state)
 
diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml
index e7be6f8f582..c0f99adcbda 100644
--- a/src/plugins/value/engine/transfer_stmt.ml
+++ b/src/plugins/value/engine/transfer_stmt.ml
@@ -318,7 +318,7 @@ module Make (Abstract: Abstractions.Eva) = struct
   (* ------------------- Retro propagation on formals ----------------------- *)
 
 
-  let get_precise_location = Location.get Main_locations.ploc_key
+  let get_precise_location = Location.get Main_locations.PLoc.key
 
   (* [is_safe_argument valuation expr] is true iff the expression [expr] could
      not have been written during the last call.
@@ -559,9 +559,9 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   (* ----------------- show_each and dump_each directives ------------------- *)
 
-  let extract_cvalue = match Domain.get Cvalue_domain.key with
+  let extract_cvalue = match Domain.get Cvalue_domain.State.key with
     | None -> fun _ -> Cvalue.Model.top
-    | Some get -> get
+    | Some get -> fun s -> Cvalue_domain.project (get s)
 
   (* The product of domains formats the printing of each leaf domains, by
      checking their log_category and adding their name before the dump. If the
@@ -609,7 +609,7 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   (* For non scalar expressions, prints the offsetmap of the cvalue domain. *)
   let show_offsm =
-    match Domain.get Cvalue_domain.key, Location.get Main_locations.ploc_key with
+    match Domain.get Cvalue_domain.State.key, Location.get Main_locations.PLoc.key with
     | None, _ | _, None ->
       fun fmt _ _ -> Format.fprintf fmt "%s" (Unicode.top_string ())
     | Some get_cvalue, Some get_ploc ->
@@ -622,7 +622,7 @@ module Make (Abstract: Abstractions.Eva) = struct
                 fst (Eval.lvaluate ~for_writing:false state lval)
                 >>- fun (_, loc, _) ->
                 let ploc = get_ploc loc
-                and cvalue_state = get_cvalue state in
+                and cvalue_state = Cvalue_domain.project (get_cvalue state) in
                 Eval_op.offsetmap_of_loc ploc cvalue_state
               in
               let typ = Cil.typeOf expr in
@@ -634,7 +634,7 @@ module Make (Abstract: Abstractions.Eva) = struct
 
   (* For scalar expressions, prints the cvalue component of their values. *)
   let show_value =
-    match Value.get Main_values.cvalue_key with
+    match Value.get Main_values.CVal.key with
     | None -> fun fmt _ _ -> Format.fprintf fmt "%s" (Unicode.top_string ())
     | Some get_cval ->
       fun fmt expr state ->
diff --git a/src/plugins/value/gui_files/gui_eval.ml b/src/plugins/value/gui_files/gui_eval.ml
index 108079350d9..2c64ede8741 100644
--- a/src/plugins/value/gui_files/gui_eval.ml
+++ b/src/plugins/value/gui_files/gui_eval.ml
@@ -144,12 +144,12 @@ module Make (X: Analysis.S) = struct
   module Analysis = X
 
   let get_cvalue_state =
-    match X.Dom.get Cvalue_domain.key with
+    match X.Dom.get Cvalue_domain.State.key with
     | None -> fun _ -> Cvalue.Model.top
-    | Some get -> fun state -> get state
+    | Some get -> fun state -> Cvalue_domain.project (get state)
 
   let get_precise_loc =
-    match X.Loc.get Main_locations.ploc_key with
+    match X.Loc.get Main_locations.PLoc.key with
     | None -> fun _ -> Precise_locs.loc_top
     | Some get -> fun loc -> get loc
 
diff --git a/src/plugins/value/gui_files/gui_types.ml b/src/plugins/value/gui_files/gui_types.ml
index 683fa039860..f4fad0001bc 100644
--- a/src/plugins/value/gui_files/gui_types.ml
+++ b/src/plugins/value/gui_files/gui_types.ml
@@ -167,8 +167,8 @@ module Make (V: Abstractions.Value) = struct
     | GA_After r1, GA_After r2 -> equal_gui_res r1 r2
     | (GA_After _ | GA_NA | GA_Unchanged | GA_Bottom), _ -> false
 
-  let get_cvalue = V.get Main_values.cvalue_key
-  let from_cvalue v = V.set Main_values.cvalue_key v V.top
+  let get_cvalue = V.get Main_values.CVal.key
+  let from_cvalue v = V.set Main_values.CVal.key v V.top
 
   let var_of_base base acc =
     try
diff --git a/src/plugins/value/register.ml b/src/plugins/value/register.ml
index b7198f21219..d3103749d06 100644
--- a/src/plugins/value/register.ml
+++ b/src/plugins/value/register.ml
@@ -169,9 +169,14 @@ let () =
 
 open Eval
 
-module Val = struct
+module CVal = struct
   include Main_values.CVal
-  include Structure.Open (Structure.Key_Value) (Main_values.CVal)
+  let structure = Abstract.Value.Leaf key
+end
+
+module Val = struct
+  include CVal
+  include Structure.Open (Structure.Key_Value) (CVal)
   let reduce t = t
 end
 
diff --git a/src/plugins/value/utils/abstract.ml b/src/plugins/value/utils/abstract.ml
new file mode 100644
index 00000000000..54cf436f968
--- /dev/null
+++ b/src/plugins/value/utils/abstract.ml
@@ -0,0 +1,75 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2019                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It 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 Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** External interface of an abstraction, built by {!Structure.Open}. *)
+module type Interface = sig
+  type t
+  type 'a key
+  val mem : 'a key -> bool
+  val get : 'a key -> (t -> 'a) option
+  val set : 'a key -> 'a -> t -> t
+end
+
+module Value = struct
+  include Structure.Key_Value
+
+  module type Internal = sig
+    include Abstract_value.S
+    val structure: t structure
+  end
+
+  module type External = sig
+    include Internal
+    include Structure.External with type t := t
+                                and type 'a key := 'a key
+  end
+end
+
+module Location = struct
+  include Structure.Key_Location
+
+  module type Internal = sig
+    include Abstract_location.S
+    val structure: location structure
+  end
+
+  module type External = sig
+    include Internal
+    include Structure.External with type t := location
+                                and type 'a key := 'a key
+  end
+end
+
+module Domain = struct
+  include Structure.Key_Domain
+
+  module type Internal = sig
+    include Abstract_domain.Internal
+    val structure: t structure
+  end
+
+  module type External = sig
+    include Internal
+    include Structure.External with type t := t
+                                and type 'a key := 'a key
+  end
+end
diff --git a/src/plugins/value/utils/abstract.mli b/src/plugins/value/utils/abstract.mli
new file mode 100644
index 00000000000..ad5037857fb
--- /dev/null
+++ b/src/plugins/value/utils/abstract.mli
@@ -0,0 +1,113 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2019                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It 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 Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Internal and External signature of abstractions used in the Eva engine. *)
+
+(** Internal modules contains a [structure] value that describes the internal
+    structure of the abstraction. This structure is used to automatically
+    generate efficient accessors from a generic compound abstraction to specific
+    leaf abstractions. *)
+
+(** External modules export direct accessors to their leaf components.
+    When a generic abstraction is a product of several specific abstractions,
+    they allow interacting with each leaf abstraction identified by a key.
+    Note that their behavior is undefined if an abstraction contains
+    several times the same leaf module. *)
+
+(** External interface of an abstraction, built by {!Structure.Open}. *)
+module type Interface = sig
+  type t
+  type 'a key
+
+  (** Tests whether a key belongs to the module. *)
+  val mem : 'a key -> bool
+
+  (** For a key of type [k key]:
+      - if the values of type [t] contain a subpart of type [k] from a module
+        identified by the key, then [get key] returns an accessor for it.
+      - otherwise, [get key] returns None. *)
+  val get : 'a key -> (t -> 'a) option
+
+  (** For a key of type [k key]:
+      - if the values of type [t] contain a subpart of type [k] from a module
+        identified by the key, then [set key v t] returns the value [t] in which
+        this subpart has been replaced by [v].
+      - otherwise, [set key _] is the identity function. *)
+  val set : 'a key -> 'a -> t -> t
+end
+
+(** Key and structure for abstract values.
+    See {structure.mli} for more details. *)
+module Value : sig
+  include Structure.Shape
+    with type 'a key = 'a Structure.Key_Value.key
+     and type 'a structure = 'a Structure.Key_Value.structure
+
+  module type Internal = sig
+    include Abstract_value.S
+    val structure: t structure
+  end
+
+  module type External = sig
+    include Internal
+    include Interface with type t := t
+                       and type 'a key := 'a key
+  end
+end
+
+(** Key and structure for abstract locations.
+    See {structure.mli} for more details. *)
+module Location : sig
+  include Structure.Shape
+    with type 'a key = 'a Structure.Key_Location.key
+     and type 'a structure = 'a Structure.Key_Location.structure
+
+  module type Internal = sig
+    include Abstract_location.S
+    val structure: location structure
+  end
+
+  module type External = sig
+    include Internal
+    include Interface with type t := location
+                       and type 'a key := 'a key
+  end
+end
+
+(** Key and structure for abstract domains.
+    See {structure.mli} for more details. *)
+module Domain : sig
+  include Structure.Shape
+    with type 'a key = 'a Structure.Key_Domain.key
+     and type 'a structure = 'a Structure.Key_Domain.structure
+
+  module type Internal = sig
+    include Abstract_domain.Internal
+    val structure: t structure
+  end
+
+  module type External = sig
+    include Internal
+    include Interface with type t := t
+                       and type 'a key := 'a key
+  end
+end
diff --git a/src/plugins/value/values/abstract_location.mli b/src/plugins/value/values/abstract_location.mli
index 41990872759..6242ecc18d1 100644
--- a/src/plugins/value/values/abstract_location.mli
+++ b/src/plugins/value/values/abstract_location.mli
@@ -119,21 +119,14 @@ module type S = sig
     typ -> index:value -> remaining:offset -> offset -> (value * offset) or_bottom
 end
 
-(** Key and structure for locations. See {structure.mli},
-    and {domain.mli} where the mechanism is explained in detail.*)
+type 'loc key = 'loc Structure.Key_Location.key
 
-type 'a key = 'a Structure.Key_Location.key
-type 'a structure = 'a Structure.Key_Location.structure
-
-module type Internal = sig
+(** Signature for a leaf module of abstract locations. *)
+module type Leaf = sig
   include S
-  val structure : location structure
-end
 
-module type External = sig
-  include S
-  include Structure.External with type t := location
-                              and type 'a key := 'a key
+  (** The key identifies the module and the type [t] of abstract locations. *)
+  val key: location key
 end
 
 (*
diff --git a/src/plugins/value/values/abstract_value.mli b/src/plugins/value/values/abstract_value.mli
index 25fab072de6..c6efd632718 100644
--- a/src/plugins/value/values/abstract_value.mli
+++ b/src/plugins/value/values/abstract_value.mli
@@ -181,21 +181,14 @@ module type S = sig
 
 end
 
-(** Key and structure for values. See {structure.mli},
-    and {domain.mli} where the mechanism is explained in detail.*)
+type 'v key = 'v Structure.Key_Value.key
 
-type 'a key = 'a Structure.Key_Value.key
-type 'a structure = 'a Structure.Key_Value.structure
-
-module type Internal = sig
+(** Signature for a leaf module of abstract values. *)
+module type Leaf = sig
   include S
-  val structure : t structure
-end
 
-module type External = sig
-  include S
-  include Structure.External with type t := t
-                              and type 'a key := 'a key
+  (** The key identifies the module and the type [t] of abstract values. *)
+  val key: t key
 end
 
 
diff --git a/src/plugins/value/values/location_lift.ml b/src/plugins/value/values/location_lift.ml
index ce5ae27c864..4ae36f3622c 100644
--- a/src/plugins/value/values/location_lift.ml
+++ b/src/plugins/value/values/location_lift.ml
@@ -32,12 +32,12 @@ module type Conversion = sig
 end
 
 module Make
-    (Loc: Abstract_location.Internal)
+    (Loc: Abstract_location.S)
     (Convert : Conversion with type internal_value := Loc.value)
 = struct
 
   (* Import most of [Loc] *)
-  include (Loc: Abstract_location.Internal
+  include (Loc: Abstract_location.S
            with type value := Loc.value (* we are converting this type *)
             and type location = Loc.location
             and type offset = Loc.offset)
diff --git a/src/plugins/value/values/location_lift.mli b/src/plugins/value/values/location_lift.mli
index 1eb2d98d38c..602fbcee455 100644
--- a/src/plugins/value/values/location_lift.mli
+++ b/src/plugins/value/values/location_lift.mli
@@ -30,11 +30,11 @@ module type Conversion = sig
 end
 
 module Make
-    (Loc: Abstract_location.Internal)
+    (Loc: Abstract_location.S)
     (Convert : Conversion with type internal_value := Loc.value)
-  : Abstract_location.Internal with type location = Loc.location
-                                and type offset = Loc.offset
-                                and type value = Convert.extended_value
+  : Abstract_location.S with type location = Loc.location
+                         and type offset = Loc.offset
+                         and type value = Convert.extended_value
 
 
 (*
diff --git a/src/plugins/value/values/main_locations.ml b/src/plugins/value/values/main_locations.ml
index f98119eab16..8722ef35172 100644
--- a/src/plugins/value/values/main_locations.ml
+++ b/src/plugins/value/values/main_locations.ml
@@ -22,8 +22,6 @@
 
 open Cil_types
 
-let ploc_key = Structure.Key_Location.create_key "precise_locs"
-
 module PLoc = struct
 
   type value = Cvalue.V.t
@@ -32,7 +30,7 @@ module PLoc = struct
     | Precise of Precise_locs.precise_offset
     | Imprecise of Cvalue.V.t (* when the offset contains addresses *)
 
-  let structure = Structure.Key_Location.Leaf ploc_key
+  let key = Structure.Key_Location.create_key "precise_locs"
 
   let equal_loc = Precise_locs.equal_loc
   let equal_offset o1 o2 = match o1, o2 with
diff --git a/src/plugins/value/values/main_locations.mli b/src/plugins/value/values/main_locations.mli
index 28d11c16b76..7701838d407 100644
--- a/src/plugins/value/values/main_locations.mli
+++ b/src/plugins/value/values/main_locations.mli
@@ -25,7 +25,7 @@
 (** Abstract locations built over Precise_locs. *)
 module PLoc : sig
 
-  include Abstract_location.Internal
+  include Abstract_location.Leaf
     with type value = Cvalue.V.t
      and type location = Precise_locs.precise_location
 
@@ -33,10 +33,6 @@ module PLoc : sig
 
 end
 
-(** Key for precise locs. *)
-val ploc_key : PLoc.location Abstract_location.key
-
-
 (*
 Local Variables:
 compile-command: "make -C ../../../.."
diff --git a/src/plugins/value/values/main_values.ml b/src/plugins/value/values/main_values.ml
index f5bec06d977..83b93bbfb63 100644
--- a/src/plugins/value/values/main_values.ml
+++ b/src/plugins/value/values/main_values.ml
@@ -22,12 +22,10 @@
 
 open Cil_types
 
-let cvalue_key = Structure.Key_Value.create_key "cvalue"
-
 module CVal = struct
   include Cvalue.V
 
-  let structure = Structure.Key_Value.Leaf cvalue_key
+  let key = Structure.Key_Value.create_key "cvalue"
 
   let zero = Cvalue.V.singleton_zero
   let one = Cvalue.V.singleton_one
@@ -135,12 +133,10 @@ module CVal = struct
     with Abstract_interp.Error_Top -> `Top, true
 end
 
-let interval_key = Structure.Key_Value.create_key "interval"
-
 module Interval = struct
 
   include Datatype.Option (Ival)
-  let structure = Structure.Key_Value.Leaf interval_key
+  let key = Structure.Key_Value.create_key "interval"
 
   let pretty_typ _ = pretty
 
diff --git a/src/plugins/value/values/main_values.mli b/src/plugins/value/values/main_values.mli
index fd148fcfcc5..4923f3182ed 100644
--- a/src/plugins/value/values/main_values.mli
+++ b/src/plugins/value/values/main_values.mli
@@ -23,17 +23,11 @@
 (** Main numeric values of Eva. *)
 
 (** Abstract values built over Cvalue.V *)
-module CVal : Abstract_value.Internal with type t = Cvalue.V.t
-
-(** Key for cvalues. *)
-val cvalue_key : CVal.t Abstract_value.key
+module CVal : Abstract_value.Leaf with type t = Cvalue.V.t
 
 (** Dummy interval: no forward nor backward propagations.
     [None] is top. *)
-module Interval : Abstract_value.Internal with type t = Ival.t option
-
-(** Key for intervals. *)
-val interval_key : Interval.t Abstract_value.key
+module Interval : Abstract_value.Leaf with type t = Ival.t option
 
 (*
 Local Variables:
diff --git a/src/plugins/value/values/numerors/numerors_value.ml b/src/plugins/value/values/numerors/numerors_value.ml
index 8fa47dc923f..6ef7042aa69 100644
--- a/src/plugins/value/values/numerors/numerors_value.ml
+++ b/src/plugins/value/values/numerors/numerors_value.ml
@@ -116,8 +116,7 @@ end
 include Datatype.Make(T)
 let pretty_debug = pretty
 let pretty_typ _ = pretty
-let error_key = Structure.Key_Value.create_key "numerors_values"
-let structure = Structure.Key_Value.Leaf error_key
+let key = Structure.Key_Value.create_key "numerors_values"
 
 
 (*-----------------------------------------------------------------------------
diff --git a/src/plugins/value/values/numerors/numerors_value.mli b/src/plugins/value/values/numerors/numerors_value.mli
index 44da21eca97..3c87147b3e3 100644
--- a/src/plugins/value/values/numerors/numerors_value.mli
+++ b/src/plugins/value/values/numerors/numerors_value.mli
@@ -20,15 +20,13 @@
 (*                                                                        *)
 (**************************************************************************)
 
-include Abstract_value.Internal
+include Abstract_value.Leaf
 
 val pretty_debug : t Pretty_utils.formatter
 
 (** Reduction of an error value according to a floating-point interval. *)
 val reduce: Fval.t -> t -> t Eval.or_bottom
 
-val error_key : t Structure.Key_Value.key
-
 val set_absolute_to_top : t -> t
 val set_relative_to_top : t -> t
 
diff --git a/src/plugins/value/values/offsm_value.ml b/src/plugins/value/values/offsm_value.ml
index a447493695d..2a6bab76fb2 100644
--- a/src/plugins/value/values/offsm_value.ml
+++ b/src/plugins/value/values/offsm_value.ml
@@ -381,12 +381,10 @@ module Datatype_Offsm_or_top = Datatype.Make_with_collections(struct
   end)
 
 
-let offsm_key = Structure.Key_Value.create_key "offsetmap_value"
-
-module Offsm : Abstract_value.Internal with type t = offsm_or_top = struct
+module Offsm : Abstract_value.Leaf with type t = offsm_or_top = struct
   include Datatype_Offsm_or_top
 
-  let structure = Structure.Key_Value.Leaf offsm_key
+  let key = Structure.Key_Value.create_key "offsetmap_value"
 
   let pretty_typ typ fmt = function
     | Top as o -> pretty fmt o
@@ -480,10 +478,13 @@ module Offsm : Abstract_value.Internal with type t = offsm_or_top = struct
 end
 
 
-module CvalueOffsm : Abstract_value.Internal with type t = V.t * offsm_or_top
+module CvalueOffsm : Abstract.Value.Internal with type t = V.t * offsm_or_top
 = struct
   include Value_product.Make (Main_values.CVal) (Offsm)
 
+  let structure =
+    Abstract.Value.(Node (Leaf Main_values.CVal.key, Leaf Offsm.key))
+
   let size typ = Integer.of_int (Cil.bitsSizeOf typ)
 
   (* Extract an offsetmap from a pair, by converting the value when needed. *)
diff --git a/src/plugins/value/values/offsm_value.mli b/src/plugins/value/values/offsm_value.mli
index 088bf7f0843..6465583c14e 100644
--- a/src/plugins/value/values/offsm_value.mli
+++ b/src/plugins/value/values/offsm_value.mli
@@ -22,13 +22,10 @@
 
 type offsm_or_top = O of Cvalue.V_Offsetmap.t | Top
 
-val offsm_key : offsm_or_top Structure.Key_Value.key
-
 val cast :
   old_size: Integer.t -> new_size: Integer.t -> signed: bool ->
   Cvalue.V_Offsetmap.t -> Cvalue.V_Offsetmap.t
 
+module Offsm : Abstract_value.Leaf with type t = offsm_or_top
 
-module Offsm : Abstract_value.Internal with type t = offsm_or_top
-
-module CvalueOffsm : Abstract_value.Internal with type t = Cvalue.V.t * offsm_or_top
+module CvalueOffsm : Abstract.Value.Internal with type t = Cvalue.V.t * offsm_or_top
diff --git a/src/plugins/value/values/sign_value.ml b/src/plugins/value/values/sign_value.ml
index 211ce3cd5b2..66ebbb989c5 100644
--- a/src/plugins/value/values/sign_value.ml
+++ b/src/plugins/value/values/sign_value.ml
@@ -271,5 +271,4 @@ let backward_cast ~src_typ:_ ~dst_typ:_ ~src_val:_ ~dst_val:_ = `Value None
 (** {2 Misc} *)
 
 (* Eva boilerplate, used to retrieve the domain. *)
-let sign_key = Structure.Key_Value.create_key "sign_values"
-let structure = Structure.Key_Value.Leaf sign_key
+let key = Structure.Key_Value.create_key "sign_values"
diff --git a/src/plugins/value/values/sign_value.mli b/src/plugins/value/values/sign_value.mli
index 9a71c60d69c..44b761fb982 100644
--- a/src/plugins/value/values/sign_value.mli
+++ b/src/plugins/value/values/sign_value.mli
@@ -22,8 +22,6 @@
 
 (** Sign domain: abstraction of integer numerical values by their signs. *)
 
-include Abstract_value.Internal
+include Abstract_value.Leaf
 
 val pretty_debug: t Pretty_utils.formatter
-
-val sign_key : t Structure.Key_Value.key
diff --git a/src/plugins/value/values/value_product.ml b/src/plugins/value/values/value_product.ml
index 131d47bfa68..5a088c52838 100644
--- a/src/plugins/value/values/value_product.ml
+++ b/src/plugins/value/values/value_product.ml
@@ -23,14 +23,12 @@
 open Eval
 
 module Make
-    (Left: Abstract_value.Internal)
-    (Right: Abstract_value.Internal)
+    (Left: Abstract_value.S)
+    (Right: Abstract_value.S)
 = struct
 
   include Datatype.Pair (Left) (Right)
 
-  let structure = Structure.Key_Value.Node (Left.structure, Right.structure)
-
   let pretty_typ typ =
     Pretty_utils.pp_pair ~pre:"@[" ~sep:",@ " ~suf:"@]"
       (Left.pretty_typ typ) (Right.pretty_typ typ)
diff --git a/src/plugins/value/values/value_product.mli b/src/plugins/value/values/value_product.mli
index f6369ee2efd..c24505d85e3 100644
--- a/src/plugins/value/values/value_product.mli
+++ b/src/plugins/value/values/value_product.mli
@@ -23,9 +23,9 @@
 (** Cartesian product of two value abstractions. *)
 
 module Make
-    (Left: Abstract_value.Internal)
-    (Right: Abstract_value.Internal)
-  : Abstract_value.Internal with type t = Left.t * Right.t
+    (Left: Abstract_value.S)
+    (Right: Abstract_value.S)
+  : Abstract_value.S with type t = Left.t * Right.t
 
 
 (*
-- 
GitLab