diff --git a/.gitignore b/.gitignore
index 4803da7469b4c370aaa2751465c27be30a26c397..2b8b272dc8c3db14beee19536f597b09aac0f460 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,16 +41,22 @@ autom4te.cache
 .Makefile.plugin.generated
 
 #tests
+
 /tests/ptests_config
 /tests/**/result/
 /tests/**/result_*/
+
+/tests/crowbar/*constfold
+/tests/crowbar/integer_bb_pretty
+/tests/crowbar/mutable
+/tests/crowbar/output-*
+/tests/crowbar/test_ghost_cfg
 /tests/journal/intra.byte
 /tests/misc/my_visitor_plugin/my_visitor.opt
 /tests/misc/my_visitor.sav
 /tests/*/*.opt
 /tests/pdg/*.dot
-/tests/crowbar/output-*
-/tests/crowbar/mutable
+
 /devel_tools/fc-time
 /devel_tools/fc-memuse
 /bin/ocamldep_transitive_closure
@@ -104,6 +110,8 @@ autom4te.cache
 /doc/code/qed
 /doc/code/wp
 
+/doc/doxygen
+
 /doc/pdg/call-f.eps
 /doc/pdg/call-f.fig
 /doc/pdg/call-f.pdf
@@ -186,10 +194,18 @@ Makefile.plugin.generated
 /src/kernel_internals/parsing/clexer.ml
 /src/kernel_internals/parsing/cparser.ml
 /src/kernel_internals/parsing/cparser.mli
-/src/plugins/value/domains/apron/apron_domain.ml
-/src/plugins/value/domains/numerors/numerors_domain.ml
 /src/kernel_services/ast_queries/json_compilation_database.ml
 /src/libraries/stdlib/transitioning.ml
+/src/plugins/gui/dgraph.ml
+/src/plugins/gui/dgraph.mli
+/src/plugins/gui/dgraph_helper.ml
+/src/plugins/gui/GSourceView.ml
+/src/plugins/gui/GSourceView.mli
+/src/plugins/gui/GSourceView2.ml
+/src/plugins/gui/GSourceView2.mli
+/src/plugins/gui/gtk_compat.ml
+/src/plugins/value/domains/apron/apron_domain.ml
+/src/plugins/value/domains/numerors/numerors_domain.ml
 
 # generated tar.gz files
 
@@ -199,14 +215,3 @@ hello-*.tar.gz
 #######################
 # should remain empty #
 #######################
-/src/plugins/gui/GSourceView2.mli
-/src/plugins/gui/GSourceView2.ml
-/src/plugins/gui/dgraph.ml
-/src/plugins/gui/dgraph.mli
-/src/plugins/gui/gtk_compat.ml
-/src/plugins/gui/GSourceView.ml
-/src/plugins/gui/GSourceView.mli
-/tests/crowbar/integer_bb_pretty
-/src/plugins/gui/dgraph_helper.ml
-/doc/doxygen
-/tests/crowbar/test_ghost_cfg
diff --git a/Makefile b/Makefile
index 42f3027d607538976c4081b72d9599c8990c398b..f957448149622595ff8b6905e187323dc27f3399 100644
--- a/Makefile
+++ b/Makefile
@@ -1438,6 +1438,10 @@ tests/crowbar/%: tests/crowbar/%.ml tests/crowbar/.%.depend .depend \
              -deps tests/crowbar/.$*.depend -deps .depend) \
         $<
 
+tests/crowbar/full-link-%: tests/crowbar/%.ml lib/fc/frama-c.cmxa
+	$(OCAMLOPT) $(OLINKFLAGS) -ccopt "-Llib/fc" -w -42 -package crowbar -o $@ \
+	lib/fc/frama-c.cmxa $<
+
 crowbar-%: tests/crowbar/%
 	$<
 
diff --git a/src/kernel_internals/typing/cabs2cil.ml b/src/kernel_internals/typing/cabs2cil.ml
index e51686df1b00a4ccb394dfcc3d5de8476e8f7648..481fde16c7eb3a4bf955c7730e5107c74cd29c0c 100644
--- a/src/kernel_internals/typing/cabs2cil.ml
+++ b/src/kernel_internals/typing/cabs2cil.ml
@@ -7199,58 +7199,49 @@ and doExp local_env
           | ADrop -> ADrop
           | _ -> AExp None
         in
-        (* if we are evaluating a constant expression, e1 is supposed to
-           evaluate to either true or false statically, and we can type-check
-           only the appropriate branch. In fact, 6.6§3 seems to indicate that
-           the dead branch can contain sub-expressions that are normally
-           forbidden in a constant expression context, such as function calls.
-        *)
         let is_true_cond = evaluate_cond_exp ce1 in
-        if asconst <> CNoConst && is_true_cond = `CTrue then begin
+        (* Now we must find the type of both branches, in order to compute
+         * the type of the result *)
+        let r2, se2, e2'o (* is an option. None means use e1 *), t2 =
           match e2.expr_node with
-          | A.NOTHING ->
-            (match ce1 with
-             | CEExp (_,e) -> finishExp [] empty e (Cil.typeOf e)
-             | _ ->
-               finishExp
-                 [] empty (Cil.one ~loc:e2.expr_loc) Cil.intType
-                 (* e1 is the result of logic operations that by
-                    definition of this branch evaluate to one. *))
+          | A.NOTHING -> begin (* The same as the type of e1 *)
+              match ce1 with
+              | CEExp (_, e1') ->
+                [], unspecified_chunk empty, None, typeOf e1'
+              (* Do not promote to bool *)
+              | _ -> [], unspecified_chunk empty, None, intType
+            end
           | _ ->
-            let _,c2,e2,t2 =
+            (* if e1 is false, e2 is only interesting for its type, but
+               we won't evaluate it. Hence, it can contain
+               non-const constructions *)
+            let asconst =
+              if is_true_cond = `CFalse then CMayConst else asconst
+            in
+            let r2, se2, e2', t2 =
               doExp (no_paren_local_env local_env) asconst e2 what'
             in
-            clean_up_chunk_locals c2;
-            finishExp [] empty e2 t2
+            r2, se2, Some e2', t2
+        in
+        (* Do e3 for real. See above for the value of asconst *)
+        let asconst' = if is_true_cond = `CTrue then CMayConst else asconst in
+        let r3, se3, e3', t3 =
+          doExp (no_paren_local_env local_env) asconst' e3 what'
+        in
+        let tresult = conditionalConversion t2 t3 in
+        if asconst <> CNoConst && is_true_cond = `CTrue then begin
+          clean_up_chunk_locals se2;
+          clean_up_chunk_locals se3;
+          let loc = e2.expr_loc in
+          let e2' = match e2'o with None -> Cil.one ~loc | Some e -> e in
+          let _,e2' = castTo t2 tresult e2' in
+          finishExp [] empty e2' tresult;
         end else if asconst <> CNoConst && is_true_cond = `CFalse then begin
-          let _,c3,e3,t3 =
-            doExp (no_paren_local_env local_env) asconst e3 what'
-          in
-          clean_up_chunk_locals c3;
-          finishExp [] empty e3 t3
+          clean_up_chunk_locals se2;
+          clean_up_chunk_locals se3;
+          let _,e3' = castTo t3 tresult e3' in
+          finishExp [] empty e3' tresult
         end else begin
-          (* Now we must find the type of both branches, in order to compute
-           * the type of the result *)
-          let r2, se2, e2'o (* is an option. None means use e1 *), t2 =
-            match e2.expr_node with
-            | A.NOTHING -> begin (* The same as the type of e1 *)
-                match ce1 with
-                | CEExp (_, e1') ->
-                  [], unspecified_chunk empty, None, typeOf e1'
-                (* Do not promote to bool *)
-                | _ -> [], unspecified_chunk empty, None, intType
-              end
-            | _ ->
-              let r2, se2, e2', t2 =
-                doExp (no_paren_local_env local_env) asconst e2 what'
-              in
-              r2, se2, Some e2', t2
-          in
-          (* Do e3 for real *)
-          let r3, se3, e3', t3 =
-            doExp (no_paren_local_env local_env) asconst e3 what'
-          in
-          let tresult = conditionalConversion t2 t3 in
           if not (isEmpty se2) then
             ConditionalSideEffectHook.apply (e,e2);
           if not (isEmpty se3) then
diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml
index b07aa521d24e2df794de12ce953d223341f51d6b..ef7e44c7b89ede003c9d485b7a5b6c544351af5a 100644
--- a/src/kernel_services/ast_queries/cil.ml
+++ b/src/kernel_services/ast_queries/cil.ml
@@ -208,8 +208,6 @@ let () =
 
 let selfMachine_is_computed = TheMachine.is_computed
 
-let debugConstFold = false
-
 let new_exp ~loc e = { eloc = loc; eid = Cil_const.Eid.next (); enode = e }
 
 let dummy_exp e = { eid = -1; enode = e; eloc = Cil_datatype.Location.unknown }
@@ -3051,7 +3049,16 @@ let integer_constant i = CInt64(Integer.of_int i, IInt, None)
 (* Construct an integer. Use only for values that fit on 31 bits *)
 let integer ~loc (i: int) = new_exp ~loc (Const (integer_constant i))
 
-let kfloat ~loc k f = new_exp ~loc (Const (CReal(f,k,None)))
+let kfloat ~loc k f =
+  let is_single_precision =
+    match k with FFloat -> true | FDouble | FLongDouble -> false
+  in
+  let f =
+    if is_single_precision then
+      Floating_point.round_to_single_precision_float f
+    else f
+  in
+  new_exp ~loc (Const (CReal(f,k,None)))
 
 let zero      ~loc = integer ~loc 0
 let one       ~loc = integer ~loc 1
@@ -3509,6 +3516,11 @@ let isArithmeticType t =
     (TInt _ | TEnum _ | TFloat _) -> true
   | _ -> false
 
+let isLongDoubleType t =
+  match unrollTypeSkel t with
+  | TFloat(FLongDouble,_) -> true
+  | _ -> false
+
 let isArithmeticOrPointerType t=
   match unrollTypeSkel t with
   | TInt _ | TEnum _ | TFloat _ | TPtr _ -> true
@@ -4398,33 +4410,48 @@ and bitsOffset (baset: typ) (off: offset) : int * int =
     See also {!Cil.constFoldVisitor}, which will run constFold on all
     expressions in a given AST node.*)
 and constFold (machdep: bool) (e: exp) : exp =
-  if debugConstFold then Kernel.debug "ConstFold to %a@." !pp_exp_ref e;
+  let dkey = Kernel.dkey_constfold in
+  Kernel.debug ~dkey "ConstFold %a@." !pp_exp_ref e;
   let loc = e.eloc in
   match e.enode with
     BinOp(bop, e1, e2, tres) -> constFoldBinOp ~loc machdep bop e1 e2 tres
-  | UnOp(unop, e1, tres) -> begin
-      try
-        let tk =
-          match unrollTypeSkel tres with
-          | TInt(ik, _) -> ik
-          | TEnum (ei,_) -> ei.ekind
-          | _ -> raise Not_found (* probably a float *)
-        in
-        let e1c = constFold machdep e1 in
-        match e1c.enode with
-          Const(CInt64(i,_ik,repr)) -> begin
-            match unop with
-              Neg ->
-              let repr = Extlib.opt_map (fun s -> "-" ^ s) repr in
-              kinteger64 ~loc ?repr ~kind:tk (Integer.neg i)
-            | BNot -> kinteger64 ~loc ~kind:tk (Integer.lognot i)
-            | LNot ->
-              if Integer.equal i Integer.zero then one ~loc
-              else zero ~loc
-          end
-        | _ -> if e1 == e1c then e else new_exp ~loc (UnOp(unop, e1c, tres))
-      with Not_found -> e
+  | UnOp(unop, e1, tres) when isIntegralType tres -> begin
+      let tk =
+        match unrollTypeSkel tres with
+        | TInt(ik, _) -> ik
+        | TEnum (ei,_) -> ei.ekind
+        | _ -> assert false (* tres is an integral type *)
+      in
+      let e1c = constFold machdep e1 in
+      match e1c.enode with
+        Const(CInt64(i,_ik,repr)) -> begin
+          match unop with
+            Neg ->
+            let repr = Extlib.opt_map (fun s -> "-" ^ s) repr in
+            kinteger64 ~loc ?repr ~kind:tk (Integer.neg i)
+          | BNot -> kinteger64 ~loc ~kind:tk (Integer.lognot i)
+          | LNot ->
+            if Integer.equal i Integer.zero then one ~loc
+            else zero ~loc
+        end
+      | _ -> if e1 == e1c then e else new_exp ~loc (UnOp(unop, e1c, tres))
+    end
+  | UnOp(unop, e1, tres) when isArithmeticType tres -> begin
+      let tk =
+        match unrollTypeSkel tres with
+        | TFloat(fk,_) -> fk
+        | _ -> assert false (*tres is arithmetic but not integral, i.e. Float *)
+      in
+      let e1c = constFold machdep e1 in
+      match e1c.enode with
+      | Const (CReal(f,_,_)) -> begin
+          match unop with
+          | Neg -> kfloat ~loc tk (-. f)
+          | _ -> if e1 == e1c then e else new_exp ~loc (UnOp(unop,e1c,tres))
+        end
+      | _ -> if e1 == e1c then e else new_exp ~loc (UnOp(unop,e1c,tres))
     end
+  | UnOp _ -> e
   (* Characters are integers *)
   | Const(CChr c) -> new_exp ~loc (Const(charConstToIntConstant c))
   | Const(CEnum {eival = v}) -> constFold machdep v
@@ -4468,16 +4495,14 @@ and constFold (machdep: bool) (e: exp) : exp =
     end
 
   | CastE (t, e) -> begin
-      if debugConstFold then
-        Kernel.debug "ConstFold CAST to to %a@." !pp_typ_ref t ;
+      Kernel.debug ~dkey "ConstFold CAST to %a@." !pp_typ_ref t ;
       let e = constFold machdep e in
       match e.enode, unrollType t with
       | Const(CInt64(i,_k,_)),(TInt(nk,a)|TEnum({ekind = nk},a)) when a = [] ->
         begin
           (* If the cast has attributes, leave it alone. *)
-          if debugConstFold then
-            Kernel.debug "ConstFold to %a : %a@."
-              !pp_ikind_ref nk Datatype.Integer.pretty i;
+          Kernel.debug ~dkey "ConstFold to %a : %a@."
+            !pp_ikind_ref nk Datatype.Integer.pretty i;
           (* Downcasts might truncate silently *)
           kinteger64 ~loc ~kind:nk i
         end
@@ -4494,6 +4519,20 @@ and constFold (machdep: bool) (e: exp) : exp =
           with Floating_point.Float_Non_representable_as_Int64 _ -> (* too big*)
             new_exp ~loc (CastE (t, e))
         end
+      | Const (CReal(f,_,_)), TFloat (FFloat,a) when a = [] ->
+        let f = Floating_point.round_to_single_precision_float f in
+        new_exp ~loc (Const (CReal (f,FFloat,None)))
+      | Const (CReal(f,_,_)), TFloat (FDouble,a) when a = [] ->
+        new_exp ~loc (Const (CReal (f,FDouble,None)))
+      (* We don't treat cast to long double, as we don't really know
+         how to handle this type anyway. *)
+      | Const (CInt64(i,_,_)), (TFloat(FFloat,a)) when a = [] ->
+        let f = Integer.to_float i in
+        let f = Floating_point.round_to_single_precision_float f in
+        new_exp ~loc (Const (CReal (f,FFloat,None)))
+      | Const (CInt64(i,_,_)), (TFloat(FDouble,a)) when a = [] ->
+        let f = Integer.to_float i in
+        new_exp ~loc (Const (CReal (f,FDouble,None)))
       | _, _ -> new_exp ~loc (CastE (t, e))
     end
   | Lval lv -> new_exp ~loc (Lval (constFoldLval machdep lv))
@@ -4651,6 +4690,18 @@ and constFoldBinOp ~loc (machdep: bool) bop e1 e2 tres =
       | Gt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) ->
         let i1', i2', _ = convertInts i1 ik1 i2 ik2 in
         if Integer.gt i1' i2' then one ~loc else zero ~loc
+      | Eq, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 = f2 then one ~loc else zero ~loc
+      | Ne, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 = f2 then zero ~loc else one ~loc
+      | Le, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 <= f2 then one ~loc else zero ~loc
+      | Ge, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 >= f2 then one ~loc else zero ~loc
+      | Lt, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 < f2 then one ~loc else zero ~loc
+      | Gt, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+        if f1 > f2 then one ~loc else zero ~loc
 
       (* We rely on the fact that LAnd/LOr appear in global initializers
          and should not have side effects. *)
@@ -4664,11 +4715,27 @@ and constFoldBinOp ~loc (machdep: bool) bop e1 e2 tres =
         one ~loc
       | _ -> new_exp ~loc (BinOp(bop, e1', e2', tres))
     in
-    if debugConstFold then
-      Format.printf "Folded %a to %a@."
-        !pp_exp_ref (new_exp ~loc (BinOp(bop, e1', e2', tres)))
-        !pp_exp_ref newe;
+    Kernel.debug ~dkey:Kernel.dkey_constfold "Folded %a to %a@."
+      !pp_exp_ref (new_exp ~loc (BinOp(bop, e1', e2', tres)))
+      !pp_exp_ref newe;
     newe
+  end else if isArithmeticType tres && not (isLongDoubleType tres) then begin
+    let tk =
+      match unrollTypeSkel tres with
+      | TFloat(fk,_) -> fk
+      | _ -> Kernel.fatal "constFoldBinOp: not a floating type"
+    in
+    match bop, e1'.enode, e2'.enode with
+    | PlusA, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+      kfloat ~loc tk (f1 +. f2)
+    | MinusA, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+      kfloat ~loc tk (f1 -. f2)
+    | Mult, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+      kfloat ~loc tk (f1 *. f2)
+    | Div, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 ->
+      (*might be infinity or NaN, but that's still a float*)
+      kfloat ~loc tk (f1 /. f2)
+    | _ -> new_exp ~loc (BinOp(bop,e1',e2',tres))
   end else
     new_exp ~loc (BinOp(bop, e1', e2', tres))
 
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 468438d093834bf3d11dcba23ae383702478c9fa..f52a143e1fd81843203fae6b3287d874108e57d9 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -49,6 +49,8 @@ let dkey_ast = register_category "ast"
 
 let dkey_check = register_category "check"
 
+let dkey_constfold = register_category "constfold"
+
 let dkey_comments = register_category "parser:comments"
 
 let dkey_dataflow = register_category "dataflow"
diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli
index d9e6e71f16b587a3bc481c545e095a62e503978b..b0170ce1a88d76ae84412fa161db8002d8e44a13 100644
--- a/src/kernel_services/plugin_entry_points/kernel.mli
+++ b/src/kernel_services/plugin_entry_points/kernel.mli
@@ -43,6 +43,8 @@ val dkey_ast: category
 
 val dkey_check: category
 
+val dkey_constfold: category
+
 val dkey_comments: category
 
 val dkey_compilation_db: category
diff --git a/src/libraries/utils/floating_point.mli b/src/libraries/utils/floating_point.mli
index 8e82a0a59b39867adac48ab0f6eed8e32a7c8880..aadafebbebffc7583ea0306eb04633389476c185 100644
--- a/src/libraries/utils/floating_point.mli
+++ b/src/libraries/utils/floating_point.mli
@@ -28,18 +28,16 @@ type c_rounding_mode =
 
 val string_of_c_rounding_mode : c_rounding_mode -> string
 
-(* replace "noalloc" with [@@noalloc] for OCaml version >= 4.03.0 *)
-[@@@ warning "-3"]
-
-external set_round_downward : unit -> unit = "set_round_downward" "noalloc"
-external set_round_upward : unit -> unit = "set_round_upward" "noalloc"
+external set_round_downward : unit -> unit = "set_round_downward" [@@noalloc]
+external set_round_upward : unit -> unit = "set_round_upward" [@@noalloc]
 external set_round_nearest_even : unit -> unit = 
-    "set_round_nearest_even" "noalloc"
-external set_round_toward_zero : unit -> unit = "set_round_toward_zero" "noalloc"
-external get_rounding_mode: unit -> c_rounding_mode = "get_rounding_mode" "noalloc"
-external set_rounding_mode: c_rounding_mode -> unit = "set_rounding_mode" "noalloc"
-
-[@@@ warning "+3"]
+    "set_round_nearest_even" [@@noalloc]
+external set_round_toward_zero : unit -> unit =
+  "set_round_toward_zero" [@@noalloc]
+external get_rounding_mode: unit -> c_rounding_mode =
+  "get_rounding_mode" [@@noalloc]
+external set_rounding_mode: c_rounding_mode -> unit =
+  "set_rounding_mode" [@@noalloc]
 
 external round_to_single_precision_float: float -> float = "round_to_float"
 
diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_rationals.c b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_rationals.c
index 789a97a40cde83610a53a2a7468076e315b15f5d..2161d2fc0f7e7621343e918328102589aa8ca0bf 100644
--- a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_rationals.c
+++ b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_rationals.c
@@ -20,9 +20,6 @@ int main(void)
 {
   int __retres;
   __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8);
-  __e_acsl_assert(3. != 1.5,(char *)"Assertion",(char *)"main",
-                  (char *)"3 != 1.5",12);
-  /*@ assert 3 ≢ 1.5; */ ;
   {
     __e_acsl_mpq_t __gen_e_acsl_;
     __e_acsl_mpq_t __gen_e_acsl__2;
@@ -42,7 +39,7 @@ int main(void)
     __gen_e_acsl_eq = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl_),
                                  (__e_acsl_mpq_struct const *)(__gen_e_acsl_add));
     __e_acsl_assert(__gen_e_acsl_eq == 0,(char *)"Assertion",(char *)"main",
-                    (char *)"3 == 1.5 + 1.5",13);
+                    (char *)"3 == 1.5 + 1.5",12);
     __gmpq_clear(__gen_e_acsl_);
     __gmpq_clear(__gen_e_acsl__2);
     __gmpq_clear(__gen_e_acsl__3);
@@ -57,12 +54,12 @@ int main(void)
     __gen_e_acsl_eq_2 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl__4),
                                    (__e_acsl_mpq_struct const *)(__gen_e_acsl__4));
     __e_acsl_assert(__gen_e_acsl_eq_2 == 0,(char *)"Assertion",
-                    (char *)"main",(char *)"0.1 == 0.1",14);
+                    (char *)"main",(char *)"0.1 == 0.1",13);
     __gmpq_clear(__gen_e_acsl__4);
   }
   /*@ assert 0.1 ≡ 0.1; */ ;
-  __e_acsl_assert(1. == 1.,(char *)"Assertion",(char *)"main",
-                  (char *)"(double)1.0 == 1.0",15);
+  __e_acsl_assert(1,(char *)"Assertion",(char *)"main",
+                  (char *)"(double)1.0 == 1.0",14);
   /*@ assert (double)1.0 ≡ 1.0; */ ;
   {
     __e_acsl_mpq_t __gen_e_acsl__5;
@@ -78,7 +75,7 @@ int main(void)
     __gen_e_acsl_ne = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl__7),
                                  (__e_acsl_mpq_struct const *)(__gen_e_acsl__5));
     __e_acsl_assert(__gen_e_acsl_ne != 0,(char *)"Assertion",(char *)"main",
-                    (char *)"(double)0.1 != 0.1",16);
+                    (char *)"(double)0.1 != 0.1",15);
     __gmpq_clear(__gen_e_acsl__5);
     __gmpq_clear(__gen_e_acsl__7);
   }
@@ -97,7 +94,7 @@ int main(void)
     */
     __e_acsl_assert((double)((float)__gen_e_acsl__9) != __gen_e_acsl__10,
                     (char *)"Assertion",(char *)"main",
-                    (char *)"(float)0.1 != (double)0.1",17);
+                    (char *)"(float)0.1 != (double)0.1",16);
     __gmpq_clear(__gen_e_acsl__8);
   }
   /*@ assert (float)0.1 ≢ (double)0.1; */ ;
@@ -126,7 +123,7 @@ int main(void)
     __gen_e_acsl_ne_2 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl__15),
                                    (__e_acsl_mpq_struct const *)(__gen_e_acsl_add_2));
     __e_acsl_assert(__gen_e_acsl_ne_2 != 0,(char *)"Assertion",
-                    (char *)"main",(char *)"(double)1.1 != 1 + 0.1",18);
+                    (char *)"main",(char *)"(double)1.1 != 1 + 0.1",17);
     __gmpq_clear(__gen_e_acsl__11);
     __gmpq_clear(__gen_e_acsl__13);
     __gmpq_clear(__gen_e_acsl__14);
@@ -161,7 +158,7 @@ int main(void)
     __gen_e_acsl_eq_3 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl_add_3),
                                    (__e_acsl_mpq_struct const *)(__gen_e_acsl_sub));
     __e_acsl_assert(__gen_e_acsl_eq_3 == 0,(char *)"Assertion",
-                    (char *)"main",(char *)"1 + 0.1 == 2 - 0.9",19);
+                    (char *)"main",(char *)"1 + 0.1 == 2 - 0.9",18);
     __gmpq_clear(__gen_e_acsl__16);
     __gmpq_clear(__gen_e_acsl__17);
     __gmpq_clear(__gen_e_acsl_add_3);
@@ -192,7 +189,7 @@ int main(void)
     __gen_e_acsl_ne_3 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl__21),
                                    (__e_acsl_mpq_struct const *)(__gen_e_acsl_mul));
     __e_acsl_assert(__gen_e_acsl_ne_3 != 0,(char *)"Assertion",
-                    (char *)"main",(char *)"sum != x * y",23);
+                    (char *)"main",(char *)"sum != x * y",22);
     __gmpq_clear(__gen_e_acsl_y);
     __gmpq_clear(__gen_e_acsl__20);
     __gmpq_clear(__gen_e_acsl_mul);
@@ -220,7 +217,7 @@ int main(void)
     __gen_e_acsl_ne_4 = __gmpq_cmp((__e_acsl_mpq_struct const *)(__gen_e_acsl__24),
                                    (__e_acsl_mpq_struct const *)(__gen_e_acsl_add_4));
     __e_acsl_assert(__gen_e_acsl_ne_4 != 0,(char *)"Assertion",
-                    (char *)"main",(char *)"1.1d != 1 + 0.1",30);
+                    (char *)"main",(char *)"1.1d != 1 + 0.1",29);
     __gmpq_clear(__gen_e_acsl__22);
     __gmpq_clear(__gen_e_acsl__23);
     __gmpq_clear(__gen_e_acsl_add_4);
diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/rationals.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/rationals.res.oracle
index a6a2923fc7d78b732768d31af599c9bae4a98cc8..6b6e958fe3307d88f08470895bdaf3de1960c169 100644
--- a/src/plugins/e-acsl/tests/arith/oracle_ci/rationals.res.oracle
+++ b/src/plugins/e-acsl/tests/arith/oracle_ci/rationals.res.oracle
@@ -1,45 +1,45 @@
-[kernel:parser:decimal-float] tests/arith/rationals.c:20: Warning: 
+[kernel:parser:decimal-float] tests/arith/rationals.c:19: Warning: 
   Floating-point constant 0.2f is not represented exactly. Will use 0x1.99999a0000000p-3.
   (warn-once: no further messages from category 'parser:decimal-float' will be emitted)
 [e-acsl] beginning translation.
 [e-acsl] Warning: R to float: double rounding might cause unsoundness
-[e-acsl] tests/arith/rationals.c:17: Warning: 
+[e-acsl] tests/arith/rationals.c:16: Warning: 
   E-ACSL construct `predicate with no definition nor reads clause'
   is not yet supported.
   Ignoring annotation.
 [e-acsl] translation done in project "e-acsl".
-[eva:alarm] tests/arith/rationals.c:13: Warning: 
+[eva:alarm] tests/arith/rationals.c:12: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:14: Warning: 
+[eva:alarm] tests/arith/rationals.c:13: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:14: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/rationals.c:16: Warning: 
+[eva:alarm] tests/arith/rationals.c:13: Warning: assertion got status unknown.
+[eva:alarm] tests/arith/rationals.c:15: Warning: 
   non-finite double value. assert \is_finite(__gen_e_acsl__6);
-[eva:alarm] tests/arith/rationals.c:16: Warning: 
+[eva:alarm] tests/arith/rationals.c:15: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:16: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/rationals.c:17: Warning: 
+[eva:alarm] tests/arith/rationals.c:15: Warning: assertion got status unknown.
+[eva:alarm] tests/arith/rationals.c:16: Warning: 
   non-finite double value. assert \is_finite(__gen_e_acsl__9);
-[eva:alarm] tests/arith/rationals.c:17: Warning: 
+[eva:alarm] tests/arith/rationals.c:16: Warning: 
   non-finite double value. assert \is_finite(__gen_e_acsl__10);
-[eva:alarm] tests/arith/rationals.c:17: Warning: 
+[eva:alarm] tests/arith/rationals.c:16: Warning: 
   non-finite float value. assert \is_finite((float)__gen_e_acsl__9);
-[eva:alarm] tests/arith/rationals.c:17: Warning: 
+[eva:alarm] tests/arith/rationals.c:16: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:18: Warning: 
+[eva:alarm] tests/arith/rationals.c:17: Warning: 
   non-finite double value. assert \is_finite(__gen_e_acsl__12);
+[eva:alarm] tests/arith/rationals.c:17: Warning: 
+  function __e_acsl_assert: precondition got status unknown.
+[eva:alarm] tests/arith/rationals.c:17: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/rationals.c:18: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/rationals.c:18: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/rationals.c:19: Warning: 
-  function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:19: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/rationals.c:23: Warning: 
+[eva:alarm] tests/arith/rationals.c:22: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/rationals.c:4: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/rationals.c:4: Warning: 
   function __gen_e_acsl_avg: postcondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:30: Warning: 
+[eva:alarm] tests/arith/rationals.c:29: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/rationals.c:30: Warning: assertion got status unknown.
+[eva:alarm] tests/arith/rationals.c:29: Warning: assertion got status unknown.
diff --git a/src/plugins/e-acsl/tests/arith/oracle_dev/rationals.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_dev/rationals.res.oracle
index ab4a875d1ad88731e1251bb3bf2f3097a47a32ea..590199db8f04040ab84e966d5307b0dfc39f2ec5 100644
--- a/src/plugins/e-acsl/tests/arith/oracle_dev/rationals.res.oracle
+++ b/src/plugins/e-acsl/tests/arith/oracle_dev/rationals.res.oracle
@@ -1,4 +1,4 @@
 [kernel] Parsing tests/arith/rationals.c (with preprocessing)
-[kernel:parser:decimal-float] tests/arith/rationals.c:20: Warning: 
+[kernel:parser:decimal-float] tests/arith/rationals.c:19: Warning: 
   Floating-point constant 0.2f is not represented exactly. Will use 0x1.99999a0000000p-3.
   (warn-once: no further messages from category 'parser:decimal-float' will be emitted)
diff --git a/src/plugins/e-acsl/tests/arith/rationals.c b/src/plugins/e-acsl/tests/arith/rationals.c
index 84c8b0949b4d44178f43101ad840b05ad734d50e..18ed5111f7089b4cb079af9d45d206907818ee31 100644
--- a/src/plugins/e-acsl/tests/arith/rationals.c
+++ b/src/plugins/e-acsl/tests/arith/rationals.c
@@ -9,7 +9,6 @@ double avg(double a, double b) {
 }
 
 int main(void) {
-  /*@ assert 3 != 1.5; */ ;
   /*@ assert 3 == 1.5 + 1.5; */ ;
   /*@ assert 0.1 == 0.1; */ ;
   /*@ assert (double)1.0 == 1.0; */ ;
diff --git a/tests/crowbar/constfold.ml b/tests/crowbar/constfold.ml
new file mode 100644
index 0000000000000000000000000000000000000000..b98c69153c173ba6dd2cbae5cf252e3459196a44
--- /dev/null
+++ b/tests/crowbar/constfold.ml
@@ -0,0 +1,230 @@
+open Cabs
+open Crowbar
+
+let loc = Cabshelper.cabslu
+
+let gen_int_type =
+  choose [
+    const Tint;
+    const Tlong;
+    const Tunsigned;
+  ]
+
+let gen_type =
+  choose [
+    gen_int_type;
+    const Tfloat;
+    const Tdouble;
+  ]
+
+let mk_exp expr_node = { expr_loc = loc; expr_node }
+
+let needs_int_unary = function
+  | NOT | BNOT -> true
+  | _ -> false
+
+let gen_unary =
+  choose [
+    const NOT;
+    const BNOT;
+    const MINUS;
+    const PLUS;
+  ]
+
+(* NB: we don't generate shifts and division/modulo operands to avoid
+   undefined operations. Overflows alarms are deactivated as well. *)
+
+let needs_int_binary = function
+  | AND | OR | BAND | BOR | XOR -> true
+  | _ -> false
+
+let gen_binary =
+  choose [
+    const AND;
+    const OR;
+    const BAND;
+    const BOR;
+    const XOR;
+    const ADD;
+    const SUB;
+    const MUL;
+    const EQ;
+    const NE;
+    const LT;
+    const GT;
+    const LE;
+    const GE;
+  ]
+
+(* int32 generator as the default machdep is 32 bit.
+   Moreover, we only generate positive integers here, as negative ones are
+   supposed to be given by unary -
+*)
+let gen_constant =
+  choose [
+    map [ range 4 ]
+      (fun i -> mk_exp (CONSTANT (CONST_INT (string_of_int i))));
+    map [ float ]
+      (fun f ->
+         let up = 4.0 in
+         let f = if f < 0.0 then 0. else f in
+         let f = if f > up then up else f in
+         mk_exp (CONSTANT (CONST_FLOAT (string_of_float f))))
+  ]
+
+let mk_cast t e = mk_exp (CAST (([SpecType t],JUSTBASE), SINGLE_INIT e))
+
+let protected_cast t e =
+  let max = mk_exp (CONSTANT(CONST_INT("255"))) in
+  let min =
+    match t with
+    | Tunsigned -> mk_exp(CONSTANT(CONST_INT("0")))
+    | _ ->  mk_exp (UNARY(MINUS,max))
+  in
+  let maxr = mk_cast t max in
+  let minr = mk_cast t min in
+  mk_exp(
+    QUESTION(
+      mk_exp(BINARY(GE,e,min)),
+      mk_exp(QUESTION(mk_exp(BINARY(LE,e,max)),e,maxr)),
+      minr))
+
+let force_int typ e =
+  let e = protected_cast typ e in
+  mk_exp (CAST (([SpecType typ],JUSTBASE), SINGLE_INIT e))
+
+let gen_expr =
+  fix
+    (fun gen_expr ->
+       choose [
+         gen_constant;
+         map [ gen_int_type; gen_unary; gen_expr]
+           (fun t u e ->
+              let e = if needs_int_unary u then force_int t e else e in
+              mk_exp (UNARY(u,e)));
+         map [ gen_int_type; gen_binary; gen_expr; gen_expr ]
+           (fun t b e1 e2 ->
+              let e1,e2 =
+                if needs_int_binary b then
+                  force_int t e1, force_int t e2
+                else e1,e2
+              in
+              mk_exp (BINARY (b,e1,e2)));
+         map [ gen_expr; gen_expr; gen_expr ]
+           (fun c et ef -> mk_exp (QUESTION (c,et,ef)));
+         map [ gen_type; gen_expr ]
+           (fun t e ->
+              let e = protected_cast t e in
+              mk_exp (CAST (([SpecType t],JUSTBASE), SINGLE_INIT e)));
+       ])
+
+let gen_cabs typ expr =
+  let expr = protected_cast typ expr in
+  (Datatype.Filepath.dummy,
+   [ false,
+     DECDEF(
+       None,
+       ([SpecType typ],
+        [("a",
+          ARRAY(JUSTBASE,[],{ expr_loc = loc; expr_node = NOTHING}),[],loc),
+         COMPOUND_INIT [NEXT_INIT, SINGLE_INIT expr]]),
+       loc);
+     false,
+     DECDEF(None,([SpecType Tint],[("result", JUSTBASE,[],loc),NO_INIT]),loc);
+     false,
+     FUNDEF(
+      None,([SpecType Tvoid],("f", PROTO(JUSTBASE,[],[],false),[],loc)),
+      { blabels = [];
+        battrs = [];
+        bstmts = [
+          { stmt_ghost = false;
+            stmt_node =
+              DEFINITION(
+                DECDEF(
+                  None,
+                  ([SpecType typ], [("x",JUSTBASE,[],loc),SINGLE_INIT expr]),
+                  loc))};
+          { stmt_ghost = false;
+            stmt_node =
+              COMPUTATION(
+                mk_exp(
+                  BINARY(
+                    ASSIGN,
+                    mk_exp (VARIABLE "result"),
+                    mk_exp (
+                      BINARY(
+                        EQ,
+                        mk_exp (VARIABLE "x"),
+                        mk_exp(
+                          INDEX(
+                            mk_exp (VARIABLE "a"),
+                            mk_exp (CONSTANT (CONST_INT "0")))))))), loc)}
+          ]
+      },
+    loc,loc)])
+
+let () = Kernel.AutoLoadPlugins.off()
+
+let () = Project.set_current (Project.create "my_project")
+
+let () = Dynamic.set_module_load_path [ "lib/plugins" ]
+
+let () = Dynamic.load_module "frama-c-eva"
+
+let on_from_name s f = Project.on (Project.from_unique_name s) f ()
+
+let () =
+  Cmdline.(
+    parse_and_boot
+      ~on_from_name:{ on_from_name }
+      ~get_toplevel:(fun () f -> f ())
+      ~play_analysis:(fun _ -> ()))
+
+let run typ expr =
+  Project.clear ();
+  let loc = Cil_datatype.Location.unknown in
+  let cabs = gen_cabs typ expr in
+  Kernel.SignedOverflow.off ();
+  Kernel.SignedDowncast.off ();
+  Kernel.UnsignedOverflow.off ();
+  Kernel.UnsignedDowncast.off ();
+  Kernel.add_debug_keys Kernel.dkey_constfold;
+  (* otherwise, we must load scope in addition to eva. *)
+  Dynamic.Parameter.Bool.off "-eva-remove-redundant-alarms" ();
+  Errorloc.clear_errors ();
+  Format.printf "Cabs is@\n%a@." Cprint.printFile cabs;
+  let cil =
+    try Cabs2cil.convFile cabs
+    with exn ->
+      failf "Failed to typecheck cabs: %s@\n%a@."
+        (Printexc.to_string exn)
+        Cprint.printFile cabs
+  in
+  if Errorloc.had_errors () then begin
+    failf "Failed to typecheck cabs (had errors)@\n%a@."
+      Cprint.printFile cabs
+  end;
+  File.prepare_cil_file cil;
+  Kernel.MainFunction.set "f";
+  !Db.Value.compute ();
+  let kf = Globals.Functions.find_by_name "f" in
+  let r = Globals.Vars.find_from_astinfo "result" Cil_types.VGlobal in
+  let ret = Kernel_function.find_return kf in
+  let state = Db.Value.get_stmt_state ret in
+  let v1 =
+    !Db.Value.eval_expr
+      ~with_alarms:CilE.warn_none_mode state (Cil.evar ~loc r)
+  in
+  let itv =
+    try Cvalue.V.project_ival v1
+    with exn ->
+      failf "Eva analysis did not reduce to a constant: %s@\n%t@."
+        (Printexc.to_string exn)
+        (fun fmt -> File.pretty_ast ~fmt ())
+  in
+  if not (Ival.is_one itv) then begin
+    failf "const fold did not reduce to identical value:@\n%t@."
+      (fun fmt -> File.pretty_ast ~fmt ())
+  end
+
+let () = add_test ~name:"constfold" [gen_type; gen_expr] run
diff --git a/tests/syntax/compile_constant.c b/tests/syntax/compile_constant.c
new file mode 100644
index 0000000000000000000000000000000000000000..7dcef8ed9d028f7e170e9f4b87d7a531d73d0aa4
--- /dev/null
+++ b/tests/syntax/compile_constant.c
@@ -0,0 +1,18 @@
+#define M0(x) (x)*(x)<4.0?0.0:1.0
+char pixels[] = {M0(0.0), M0(1), M0(2.0f)};
+
+/* tests below should evaluate to 2. */
+
+char test_neg = { (-0.) ? 1. : 2. };
+
+char test_ge = { ((-1.) >= 0.) ? 1. : 2. };
+
+char test_cast[] = { 1 >= (0?1U:(-1)) ? 1. : 2.,
+                   ((double)1) >= (0?1U:(-1)) ? 1. : 2. };
+
+double a = 2 >= 5 ? 5 ? (long)0 || 0 ? 0. >= 0 ?: 0 : 2 : 5 : 0;
+
+extern int f(void);
+
+/* no call should be evaluated. */
+char no_call[] = { 1 ? 1 : f(), 0?f():2 };
diff --git a/tests/syntax/oracle/compile_constant.res.oracle b/tests/syntax/oracle/compile_constant.res.oracle
new file mode 100644
index 0000000000000000000000000000000000000000..b979c0f88dc4faab3ab08f39b414e081ed5ac5be
--- /dev/null
+++ b/tests/syntax/oracle/compile_constant.res.oracle
@@ -0,0 +1,9 @@
+[kernel] Parsing tests/syntax/compile_constant.c (with preprocessing)
+/* Generated by Frama-C */
+char pixels[3] = {(char)0.0, (char)0.0, (char)1.0};
+char test_neg = (char)2.;
+char test_ge = (char)2.;
+char test_cast[2] = {(char)2., (char)2.};
+double a = (double)0;
+char no_call[2] = {(char)1, (char)2};
+