diff --git a/src/kernel_internals/parsing/logic_parser.mly b/src/kernel_internals/parsing/logic_parser.mly
index 121ad96facc0f37bf6de65c4c7f03e57953649fb..8a41fe69f4f24827622a3d4d6c56ed638821d3eb 100644
--- a/src/kernel_internals/parsing/logic_parser.mly
+++ b/src/kernel_internals/parsing/logic_parser.mly
@@ -109,15 +109,23 @@
 
   let loc_ext d = { extended_node = d; extended_loc = loc () }
 
-  let concat_froms a1 a2 =
-    let compare_pair (b1,_) (b2,_) = is_same_lexpr b1 b2 in
+  let filter_from l = function
+    | FromAny ->
+      l, FromAny
+    | From ds ->
+      let f ds d = if List.exists (is_same_lexpr d) ds then ds else d :: ds in
+      l, From(List.(rev (fold_left f [] ds)))
+
+  let concat_froms cura newa =
+    let compare_pair (curb,_) (newb,_) = is_same_lexpr curb newb in
     (* NB: the following has an horrible complexity, but the order of
        clauses in the input is preserved. *)
-    let concat_one acc (_,f2 as p)  =
+    let concat_one acc (newloc, newf)  =
+      let (newloc, newf) as p = filter_from newloc newf in
       try
-        let (_,f1) = List.find (compare_pair p) acc
+        let (curloc,curf) = List.find (compare_pair p) acc
         in
-        match (f1, f2) with
+        match (curf, newf) with
           | _,FromAny ->
             (* the new fundeps does not give more information than the one
                which is already present. Just ignore it.
@@ -130,12 +138,28 @@
                  that we get the exact same clause if we try to
                  link the original contract with its pretty-printed version. *)
               Extlib.replace compare_pair p acc
-          | From _, From _ ->
-            (* we keep the two functional dependencies,
-               as they have to be proved separately. *)
-            acc @ [p]
+          | From curl, From newl ->
+            let incl l lin =
+              List.(for_all (fun e -> exists (is_same_lexpr e) lin) l)
+            in
+            let drop d k =
+              Kernel.warning ~current:false ~wkey:Kernel.wkey_multi_from
+                "Drop '%a' \\from at %a for more precise one at %a"
+                Logic_print.print_lexpr curloc
+                Cil_datatype.Location.pretty d.lexpr_loc
+                Cil_datatype.Location.pretty k.lexpr_loc
+            in
+            if incl curl newl then begin
+              if not (incl newl curl) then drop newloc curloc;
+              acc
+            end
+            else if incl newl curl then begin
+              drop curloc newloc;
+              Extlib.replace compare_pair p acc
+            end
+            else acc @ [p]
       with Not_found -> acc @ [p]
-    in List.fold_left concat_one a1 a2
+    in List.fold_left concat_one cura newa
 
   let concat_allocation fa1 fa2 =
     match fa1,fa2 with
@@ -151,7 +175,7 @@
       | Writes [], _  | Writes _, [] ->
         raise (
           Not_well_formed (loc(),"Mixing \\nothing and a real location"))
-      | Writes a1, a2 -> Writes (concat_froms a2 a1)
+      | Writes a1, a2 -> Writes (concat_froms (concat_froms [] a2) a1)
 
   let concat_loop_assigns_allocation annots bhvs2 a2 fa2=
     (* NB: this is supposed to merge assigns related to named behaviors, in
diff --git a/src/kernel_services/ast_printing/cil_printer.ml b/src/kernel_services/ast_printing/cil_printer.ml
index 6567141ad0a51d2dbd1cff12ccae4751edb12368..cbe560e6038c0caf1e5f5507bc9c9530c3637b7d 100644
--- a/src/kernel_services/ast_printing/cil_printer.ml
+++ b/src/kernel_services/ast_printing/cil_printer.ml
@@ -2912,12 +2912,17 @@ class cil_printer () = object (self)
           (function (a,_) -> not (Logic_const.is_exit_status a.it_content))
           l
       in
+      let unique_assigned_locs =
+        let same t1 t2 = Cil_datatype.Term.equal t1.it_content t2.it_content in
+        let f l (a,_) = if List.exists (same a) l then l else a :: l in
+        List.rev (List.fold_left f [] without_result)
+      in
       fprintf fmt "@[<h>%t%a@]"
         (fun fmt -> if without_result <> [] then
             Format.fprintf fmt "%a " self#pp_acsl_keyword kw)
         (Pretty_utils.pp_list ~sep:",@ " ~suf:";@]"
-           (fun fmt (t, _) -> self#identified_term fmt t))
-        without_result
+           (fun fmt t -> self#identified_term fmt t))
+        unique_assigned_locs
 
   method private assigns_deps kw fmt = function
     | WritesAny -> ()
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 0ddeab5c75a42c32227c2d5099582104a5a112c4..27e2b1cd3fe12941cac241bd352aad73593f1e89 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -185,6 +185,8 @@ let wkey_no_proto = register_warn_category "typing:no-proto"
 
 let wkey_missing_spec = register_warn_category "annot:missing-spec"
 
+let wkey_multi_from = register_warn_category "annot:multi-from"
+
 let wkey_decimal_float = register_warn_category "parser:decimal-float"
 let () = set_warn_status wkey_decimal_float Log.Wonce
 
diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli
index f62ba3b05e3b0e7eaae81d3e521ffc219007cccf..c6ffe271274d0566b44115791d6a158d672cc056 100644
--- a/src/kernel_services/plugin_entry_points/kernel.mli
+++ b/src/kernel_services/plugin_entry_points/kernel.mli
@@ -175,6 +175,8 @@ val wkey_no_proto: warn_category
 
 val wkey_missing_spec: warn_category
 
+val wkey_multi_from: warn_category
+
 val wkey_decimal_float: warn_category
 
 val wkey_acsl_extension: warn_category
diff --git a/tests/libc/oracle/fc_libc.1.res.oracle b/tests/libc/oracle/fc_libc.1.res.oracle
index 1c7f3e7c9488445e723a1e84af235443d579c607..ea25b25f657c75f8ceeeaed060cf712e5c7268bb 100644
--- a/tests/libc/oracle/fc_libc.1.res.oracle
+++ b/tests/libc/oracle/fc_libc.1.res.oracle
@@ -3994,7 +3994,7 @@ extern size_t strcspn(char const *s, char const *reject);
 /*@ requires valid_string_s: valid_read_string(s);
     requires valid_string_accept: valid_read_string(accept);
     ensures result_bounded: 0 ≤ \result ≤ strlen(\old(s));
-    assigns \result, \result;
+    assigns \result;
     assigns \result \from *(s + (0 ..)), *(accept + (0 ..));
     assigns \result
       \from (indirect: *(s + (0 ..))), (indirect: *(accept + (0 ..)));
diff --git a/tests/rte/oracle/assign4.res.oracle b/tests/rte/oracle/assign4.res.oracle
index e835835a444036c29505eac0bde563c5fcc12dce..143f1a6b3fcb116c94c4f1f3e00b27372d1e075d 100644
--- a/tests/rte/oracle/assign4.res.oracle
+++ b/tests/rte/oracle/assign4.res.oracle
@@ -5,10 +5,8 @@
     assigns \result \from min, max; */
 int choose1(int min, int max);
 
-/*@ assigns \result, \result;
-    assigns \result \from min, max, min, max;
-    assigns \result \from min, max, min, max;
- */
+/*@ assigns \result;
+    assigns \result \from min, max; */
 int choose2(int min, int max);
 
 int main(void)
diff --git a/tests/rte/oracle/assign5.res.oracle b/tests/rte/oracle/assign5.res.oracle
index 7240925afa98a9cc66e358cbd24e22615203e5b6..52d1def1f07ac9c260c9f52025366357dfa448a3 100644
--- a/tests/rte/oracle/assign5.res.oracle
+++ b/tests/rte/oracle/assign5.res.oracle
@@ -1,14 +1,16 @@
 [kernel] Parsing tests/rte/assign5.c (with preprocessing)
+[kernel:annot:multi-from] Warning: 
+  Drop '*p' \from at tests/rte/assign5.c:9 for more precise one at tests/rte/assign5.c:10
+[kernel:annot:multi-from] Warning: 
+  Drop '*p' \from at tests/rte/assign5.c:19 for more precise one at tests/rte/assign5.c:18
 [rte] annotating function main
 /* Generated by Frama-C */
-/*@ assigns *p, *p;
-    assigns *p \from x;
+/*@ assigns *p;
     assigns *p \from \nothing; */
 int f(int *p, int x);
 
-/*@ assigns *p, *p;
-    assigns *p \from \nothing;
-    assigns *p \from x; */
+/*@ assigns *p;
+    assigns *p \from \nothing; */
 int g(int *p, int x);
 
 int main(void)
diff --git a/tests/syntax/multiple_assigns.i b/tests/syntax/multiple_assigns.i
new file mode 100644
index 0000000000000000000000000000000000000000..d20a1dfcda46f0720ce70523677b4472dd709f80
--- /dev/null
+++ b/tests/syntax/multiple_assigns.i
@@ -0,0 +1,10 @@
+int z;
+
+/*@ assigns z, z;
+    assigns z \from z;
+    assigns z, z;
+ */
+void function(void)
+{
+  return;
+}
diff --git a/tests/syntax/multiple_froms.i b/tests/syntax/multiple_froms.i
new file mode 100644
index 0000000000000000000000000000000000000000..6a0a25687f9e2960e533cbec4ac5dbc0dc21e286
--- /dev/null
+++ b/tests/syntax/multiple_froms.i
@@ -0,0 +1,17 @@
+int a, b, c, d, e;
+
+// Reminder: assigns are visited in reverse
+
+/*@ assigns a;
+    assigns a \from a, a, b, c, c; // more precise so replace the next one
+    assigns a \from c, b, d, e, a;
+    assigns a;
+    assigns b \from a, e, b, d, c; // is ignored because the next one is more precise
+    assigns b \from a, e;
+    assigns c \from c, c, c, c, c; // both are kept (no inclusion)
+    assigns c \from d;
+ */
+void function(void)
+{
+  return;
+}
diff --git a/tests/syntax/oracle/multiple_assigns.res.oracle b/tests/syntax/oracle/multiple_assigns.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..0cda603d543618256b3d8bc527983157bf1538ed
--- /dev/null
+++ b/tests/syntax/oracle/multiple_assigns.res.oracle
@@ -0,0 +1,11 @@
+[kernel] Parsing tests/syntax/multiple_assigns.i (no preprocessing)
+/* Generated by Frama-C */
+int z;
+/*@ assigns z;
+    assigns z \from z; */
+void function(void)
+{
+  return;
+}
+
+
diff --git a/tests/syntax/oracle/multiple_froms.res.oracle b/tests/syntax/oracle/multiple_froms.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..b90f4dc55f6e2c31b6f7656f8f8cc0ecfa6cf03d
--- /dev/null
+++ b/tests/syntax/oracle/multiple_froms.res.oracle
@@ -0,0 +1,23 @@
+[kernel] Parsing tests/syntax/multiple_froms.i (no preprocessing)
+[kernel:annot:multi-from] Warning: 
+  Drop 'b' \from at tests/syntax/multiple_froms.i:9 for more precise one at tests/syntax/multiple_froms.i:10
+[kernel:annot:multi-from] Warning: 
+  Drop 'a' \from at tests/syntax/multiple_froms.i:7 for more precise one at tests/syntax/multiple_froms.i:6
+/* Generated by Frama-C */
+int a;
+int b;
+int c;
+int d;
+int e;
+/*@ assigns a, b, c;
+    assigns a \from a, b, c;
+    assigns b \from a, e;
+    assigns c \from c;
+    assigns c \from d;
+ */
+void function(void)
+{
+  return;
+}
+
+