diff --git a/src/kernel_services/ast_data/property_status.ml b/src/kernel_services/ast_data/property_status.ml index dc9123908981c12063b1e803d5ed09ccea31fbf2..e6eae23d70bc2188c05864ec06ac01ad72a44682 100644 --- a/src/kernel_services/ast_data/property_status.ml +++ b/src/kernel_services/ast_data/property_status.ml @@ -338,19 +338,57 @@ let merge_distinct_emitted x y = match x, y with | False_if_reachable, True | True, False_if_reachable -> raise Unmergeable +type property_kind = + | Hypothesis (* Admitted property with a [Considered_valid] status. *) + | Unverifiable (* Postconditions and assigns of functions without code. *) + | Consequence of Property.identified_property list (* Logical consequence. *) + | Tautology (* Always valid. *) + | Ignored (* Property with no logical status. *) + | Other + let is_admitted_code_annot = function | Cil_types.AAssert (_, tp) | Cil_types.AInvariant (_, _, tp) -> tp.tp_kind = Admit | _ -> false let rec is_admitted = function + | Property.IPAxiom _ -> true | Property.IPPredicate ip -> ip.ip_pred.ip_content.tp_kind = Admit - | IPAxiom _ -> true | IPLemma lemma -> lemma.il_pred.tp_kind = Admit | IPCodeAnnot ca -> is_admitted_code_annot ca.ica_ca.annot_content | IPPropertyInstance instance -> is_admitted instance.ii_ip | _ -> false +let is_verifiable = function + | Property.IPPredicate {ip_kind = PKEnsures _ | PKTerminates; ip_kf = kf } + | IPAssigns {ias_kf = kf} + | IPFrom {if_kf = kf} + | IPAllocation {ial_kf = kf} -> Kernel_function.has_definition kf + | _ -> true + +let property_kind = function + | Property.IPAxiomatic {iax_props} -> Consequence iax_props + | IPBehavior {ib_kf; ib_kinstr; ib_active; ib_bhv} -> + (* logical consequence of its postconditions *) + let active = Datatype.String.Set.elements ib_active in + let post = Property.ip_post_cond_of_behavior ib_kf ib_kinstr active ib_bhv in + Consequence post + | IPReachable {ir_kf; ir_kinstr; ir_program_point} -> + begin + match ir_kf, ir_kinstr, ir_program_point with + | None, Kglobal, Before -> Tautology + | None, Kglobal, After -> assert false + | None, Kstmt _, _ -> + Kernel.fatal "reachability of a stmt without function" + | Some kf, Kglobal, Before when Kernel_function.is_main kf -> Tautology + | _ -> Other + end + | p -> + if Property.has_status p then + if is_admitted p then Hypothesis else + if is_verifiable p then Other else Unverifiable + else Ignored + module Register_hook = Hook.Build (struct type t = Property.t end) let register_property_add_hook = Register_hook.extend @@ -369,71 +407,11 @@ let rec register ppt = Register_hook.apply ppt; register_as_kernel_logical_consequence ppt -(* the functions below and this one MUST be synchronized *) and register_as_kernel_logical_consequence ppt = - let open Property in match ppt with - | IPAxiom _ - | IPPredicate {ip_kind = PKAssumes _} -> - (* always valid, but must be verifiable by the end-user, - see [is_not_verifiable_but_valid] *) - () - | IPAxiomatic {iax_props} -> logical_consequence Emitter.kernel ppt iax_props - | IPBehavior {ib_kf; ib_kinstr; ib_active; ib_bhv} -> - let active = Datatype.String.Set.elements ib_active in - (* logical consequence of its postconditions *) - logical_consequence - Emitter.kernel ppt (ip_post_cond_of_behavior ib_kf ib_kinstr active ib_bhv) - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kglobal; - ir_program_point = Before} -> - (* valid: global properties are always reachable *) - emit_valid ppt - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kglobal; - ir_program_point = After} -> - assert false - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kstmt _} -> - Kernel.fatal "reachability of a stmt without function" - | IPReachable {ir_kf = Some kf; ir_kinstr = Cil_types.Kglobal; - ir_program_point = Before} -> - let f = kf.Cil_types.fundec in - if Ast_info.Function.get_name f = Kernel.MainFunction.get_plain_string () - (* main is always reachable *) - then emit_valid ppt - | IPOther _ | IPReachable _ - | IPExtended _ - | IPPredicate _ | IPCodeAnnot _ | IPComplete _ - | IPDisjoint _ | IPAssigns _ | IPFrom _ - | IPAllocation _ | IPDecrease _ | IPLemma _ - | IPPropertyInstance _ - | IPTypeInvariant _ | IPGlobalInvariant _ -> - () - -(* the functions above and below MUST be synchronized *) -and is_kernel_logical_consequence ppt = - let open Property in match ppt with - | IPPredicate {ip_kind = PKAssumes _} - | IPBehavior _ - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kglobal; - ir_program_point = Before} -> - true - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kglobal; - ir_program_point = After} -> - assert false - | IPReachable {ir_kf = None; ir_kinstr = Cil_types.Kstmt _} -> - Kernel.fatal "reachability of a stmt without function" - | IPReachable {ir_kf = Some kf; ir_kinstr = Cil_types.Kglobal; - ir_program_point = Before} -> - let f = kf.Cil_types.fundec in (* main is always reachable *) - Ast_info.Function.get_name f = Kernel.MainFunction.get_plain_string () - | IPAxiom _ - | IPExtended _ - | IPAxiomatic _ - | IPOther _ | IPReachable _ - | IPPredicate _ | IPCodeAnnot _ | IPComplete _ - | IPDisjoint _ | IPAssigns _ | IPFrom _ - | IPAllocation _ | IPDecrease _ | IPLemma _ - | IPPropertyInstance _ - | IPTypeInvariant _ | IPGlobalInvariant _ -> - false + match property_kind ppt with + | Consequence ips -> logical_consequence Emitter.kernel ppt ips + | Tautology -> emit_valid ppt + | Hypothesis | Unverifiable | Ignored | Other -> () and unsafe_emit_and_get e ~hyps ~auto ppt ?(distinct=false) s = Kernel.feedback ~dkey:Kernel.dkey_prop_status_emit @@ -505,7 +483,7 @@ and unsafe_emit_and_get e ~hyps ~auto ppt ?(distinct=false) s = (match hyps with | [] -> let reach_ppt = Property.ip_reachable_ppt ppt in - if is_kernel_logical_consequence reach_ppt then emit_valid reach_ppt; + if property_kind reach_ppt = Tautology then emit_valid reach_ppt; add { emitter with properties = [ reach_ppt ] } s | _ :: _ -> Kernel.fatal "Emitter %a proves invalidity of %a under \ hypotheses: unsound!" Emitter.pretty e Property.pretty ppt)); @@ -555,24 +533,13 @@ let () = register_as_kernel_logical_consequence let emit_and_get e ~hyps ppt ?distinct s = - let open Property in begin match ppt with - | IPBehavior _ | IPAxiom _ | IPAxiomatic _ - | IPPredicate {ip_kind = PKAssumes _} -> - Kernel.fatal - "only the kernel should set the status of property %a" - pretty - ppt - | IPPredicate _ | IPCodeAnnot _ | IPComplete _ - | IPDisjoint _ | IPAssigns _ | IPFrom _ - | IPDecrease _ | IPLemma _ | IPReachable _ - | IPAllocation _ | IPOther _ - | IPPropertyInstance _ - | IPExtended _ - | IPTypeInvariant _ | IPGlobalInvariant _ -> () - end; - if is_admitted ppt - then True (* TODO: fail here? *) - else unsafe_emit_and_get e ~hyps ~auto:false ppt ?distinct s + match property_kind ppt with + | Hypothesis | Consequence _ | Ignored -> + Kernel.fatal + "Only the kernel should set the status of property %a (%a, %a)" + Property.pretty ppt Emitter.pretty e Emitted_status.pretty s + | Other | Tautology | Unverifiable -> + unsafe_emit_and_get e ~hyps ~auto:false ppt ?distinct s let emit e ~hyps ppt ?distinct s = ignore (emit_and_get e ~hyps ppt ?distinct s) @@ -660,33 +627,10 @@ let conjunction s1 s2 = match s1, s2 with | True, True -> True let is_not_verifiable_but_valid ppt status = - is_admitted ppt || - match status with - | Never_tried -> - (match ppt with - | Property.IPOther _ -> - (* Non-ACSL properties are not verifiable *) - false - | Property.IPReachable _ -> false - | Property.IPAxiom _ | Property.IPAxiomatic _ -> true - | _ -> - match Property.get_kf ppt with - | None -> false - | Some kf -> - (* cannot use module [Kernel_function] nor [Globals] here *) - let f = kf.Cil_types.fundec in - if Ast_info.Function.is_definition f then - false - else - (* postconditions of functions without code are not verifiable *) - let open Property in match ppt with - | IPPredicate {ip_kind = PKEnsures _ | PKTerminates} - | IPAssigns _ | IPAllocation _ - | IPFrom _ -> true - | _ -> false) - | Best((True | False_if_reachable | False_and_reachable | Dont_know), _) - | Inconsistent _ -> - false + match property_kind ppt with + | Hypothesis -> true + | Unverifiable -> status = Never_tried + | Other | Consequence _ | Tautology | Ignored -> false let rec compute_automatic_status _e properties = let local_get p = @@ -734,12 +678,8 @@ and get_status ?(must_register=true) ppt = match ppt with | Property.IPOther _ | Property.IPReachable _ | Property.IPPropertyInstance _ -> - if must_register then begin - register ppt; - if is_kernel_logical_consequence ppt then get_status ppt - else Never_tried - end else - Never_tried + if must_register then register ppt; + Never_tried | Property.IPBehavior _ | Property.IPExtended _ | Property.IPPredicate _ | Property.IPCodeAnnot _ | Property.IPComplete _ @@ -755,24 +695,25 @@ and get_status ?(must_register=true) ppt = let get ppt = get_status ppt let automatically_proven ppt = - is_kernel_logical_consequence ppt - && - (* nobody else tried to prove it *) - try - let by_emitter = Status.find ppt in + match property_kind ppt with + | Hypothesis | Unverifiable | Ignored | Other -> false + | Consequence _ | Tautology -> + (* nobody else tried to prove it *) try - Emitter_with_properties.Hashtbl.iter - (fun e _ -> - if not (Emitter.equal - (Emitter.Usable_emitter.get e.emitter) - Emitter.kernel) - then raise Exit) - by_emitter; + let by_emitter = Status.find ppt in + try + Emitter_with_properties.Hashtbl.iter + (fun e _ -> + if not (Emitter.equal + (Emitter.Usable_emitter.get e.emitter) + Emitter.kernel) + then raise Exit) + by_emitter; + true + with Exit -> + false + with Not_found -> true - with Exit -> - false - with Not_found -> - true (**************************************************************************)