let get_downcast_assertion
    ~simplify_constants:simplify_constants
    ~warning:warning
    cast_typ expr =
  let e_typ = Cil.typeOf expr
  in
    match e_typ with
      | TInt (_,_) ->
          let szTo = bitsSizeOf cast_typ
          and szFrom = bitsSizeOf e_typ
          in
            if (szTo < szFrom) then
              (* downcast: the expression result should fit on szTo bits *)
              let (minType,maxType) = (get_signed_min szTo, get_signed_max szTo)
              in let term = translate_C_expr_to_term ~cast:false expr in
              let assertion_le ()   = assertion_le term maxType
              and assertion_ge ()   = assertion_ge term minType
              in
              let ceval =
                if simplify_constants then (
                  match get_expr_val expr with
                    | Some a64 -> (* constant expr *)
                        Some (Int64.compare a64 minType >= 0,
                              Int64.compare a64 maxType <= 0)
                    | None -> None
                ) else None
              in match ceval with
                | None ->
                    let full_assertion () =
                      Logic_const.pand (assertion_le (), assertion_ge ())
                    in [ (full_assertion (), None) ]
                | Some (emin,emax) -> (
                    match (emin,emax) with
                      | (true,true-> []
                      | (true,false->
                          let assertion  = assertion_le () in
                            if warning then
                              rte_warn
                                "signed downcast assert broken: %a"
                                d_predicate_named assertion
                            ;
                            [ (assertion, Some (make_check_false ())) ]
                      | (false,true->
                          let assertion = assertion_ge () in
                            if warning then
                              rte_warn
                                "signed downcast assert broken: %a"
                                d_predicate_named assertion
                            ;
                            [ (assertion_le (), Some (make_check_false ())) ]

                      | (false,false-> assert false (* should not happen *)

                  )
            else []
      | _ -> []