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) =
        (min_signed_number szTo, max_signed_number szTo)
      in
      let term = translate_C_expr_to_term ~cast:false expr in
      let assertion_le ()   = assertion_le term maxType in
      let assertion_ge ()   = assertion_ge term minType in
      let ceval =
        if simplify_constants then (
          match get_expr_val expr with
          | Some a64 -> (* constant expr *)
            Some (My_bigint.ge a64 minType,
                  My_bigint.le a64 maxType)
          | 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
              fmt_warn_signed_downcast_assert
              d_predicate_named assertion ;
          [ assertion, Some Property_status.False_if_reachable ]
        | (false,true->
          let assertion = assertion_ge () in
          if warning then
            rte_warn
              fmt_warn_signed_downcast_assert
              d_predicate_named assertion ;
          [ assertion_le (), Some Property_status.False_if_reachable ]

        | (false,false-> assert false (* should not happen *))
    else []
  | _ -> []