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,annots_after,contract = Db.Properties.predicates_on_stmt s
    in
    CilE.start_stmt kinstr;
    d.value := interp_annot !(d.value) annots_before;
    let valid_behaviors =
      match contract with
          None -> []
        | Some c -> extract_valid_behaviors !(d.value) c
    in
    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 >= Value_parameters.SemanticUnrollingLevel.get ()
          then begin
              let state = State_set.join states in
              let joined =
                Relations_type.Model.join
                  current.widening_state
                  state
              in
              let r =
                if (REACH.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
        (*NdV: this does not seem to be the right place to evaluate
          statement post-conditions. Maybe Dataflow should be refined.*)

        CilE.start_stmt kinstr;
        d.value := interp_annot !(d.value) annots_after;
        d.value := check_postconditions "statement" !(d.value) valid_behaviors;
        update_current !(d.value);
        CilE.end_stmt ();
        match s.skind with
        | Return _ ->
            Dataflow.SUse d
        | Loop _ ->
            if d.counter_unroll >= Value_parameters.SemanticUnrollingLevel.get () 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