let doStmt (s: stmt) (d: t) =
    let reachable, _ = reachables d in
    let kinstr = Kstmt s in
    CilE.start_stmt kinstr;
    let changed =
      try
        update_current_exn !(d.value);
        true
      with State_set.Unchanged -> false
    in
    CilE.end_stmt ();

    let annots_before, contract =
      Annotations.single_fold_stmt
        (fun a (before, spec as acc) -> match a with
         | Before
             (User { annot_content = AStmtSpec spec' }
             | AI (_,{annot_content = AStmtSpec spec' }) )
           ->
             let spec = match spec with
               | None -> spec'
               | Some s -> Logic_utils.merge_funspec s spec'; s
             in
             (before, Some spec)
         | Before (AI (_, b) | User b) -> b :: before, spec
         | After _ -> acc)
        s
        ([], None)
    in
    CilE.start_stmt kinstr;
    List.iter
      (fun annot ->
         d.value := interp_annot !(d.value) annot)
      annots_before;
    Extlib.may
      (fun spec ->
         d.value:=check_preconditions ~slevel "statement" !(d.value) spec.spec_requires)
      contract;
    CilE.end_stmt ();

    let states = !(d.value) in
    d.value := State_set.empty;

    if (not reachable) || (not changed) then
      Dataflow.SDefault
    else begin
        let current = find_current kinstr in
        let d =
          if d.counter_unroll >= AnalysisParam.slevel
          then begin
              let state = State_set.join states in
              let joined =
                Relations_type.Model.join
                  current.widening_state
                  state
              in
              let r =
                if (AnalysisParam.is_natural_loop s) &&
                  (current.widening = 0)
                then
                  let wh_key_set, wh_hints = getWidenHints s in
                  let widen_hints =
                    true, wh_key_set(* no longer used thanks to 0/1 widening*),
                    wh_hints
                  in
                  let _,result = Relations_type.Model.widen
                    widen_hints
                    current.widening_state
                    joined
                  in
                  result
                else
                  joined
              in
              let new_widening =
                if current.widening = 0 then 1 else pred current.widening
              in
              InstrHashtbl.replace current_table kinstr
                { current with widening = new_widening ; widening_state = r };

              {
                counter_unroll = d.counter_unroll;
                value = ref (State_set.singleton r);
              }

          end
          else { d with value = ref states }
        in
        CilE.start_stmt kinstr;
        update_current !(d.value);
        CilE.end_stmt ();
        match s.skind with
        | Return _ ->
            Dataflow.SUse d
        | Loop _ ->
            if d.counter_unroll >= AnalysisParam.slevel
            then
              Value_parameters.result ~once:true ~current:true
                "entering loop for the first time";
            Dataflow.SUse d
        | UnspecifiedSequence seq ->
            CilE.start_stmt kinstr;
            State_set.iter
              (fun state -> check_unspecified_sequence state seq) states;
            CilE.end_stmt ();
            Dataflow.SUse d
        | _ -> Dataflow.SUse d
    end