From 4d552b291d8cf2e80f6cf07070f66763690f5a1c Mon Sep 17 00:00:00 2001 From: Nicolas Bellec <nicolas.bellec@cea.fr> Date: Wed, 24 Jan 2024 16:49:00 +0100 Subject: [PATCH] Merged TCastE and TLogic_coerce with a boolean --- src/kernel_internals/typing/asm_contracts.ml | 2 +- src/kernel_services/ast_data/alarms.ml | 2 +- src/kernel_services/ast_data/cil_types.ml | 14 ++-- .../ast_printing/cil_printer.ml | 14 ++-- .../ast_printing/cil_types_debug.ml | 4 +- src/kernel_services/ast_queries/ast_diff.ml | 10 +-- src/kernel_services/ast_queries/ast_info.ml | 2 +- src/kernel_services/ast_queries/cil.ml | 22 ++--- .../ast_queries/cil_datatype.ml | 27 +++---- .../ast_queries/logic_const.ml | 4 +- src/kernel_services/ast_queries/logic_to_c.ml | 21 +++-- .../ast_queries/logic_typing.ml | 51 ++++++------ .../ast_queries/logic_utils.ml | 67 ++++++++------- src/plugins/aorai/aorai_utils.ml | 20 ++--- .../e-acsl/src/analyses/bound_variables.ml | 4 +- src/plugins/e-acsl/src/analyses/interval.ml | 5 +- src/plugins/e-acsl/src/analyses/labels.ml | 4 +- .../e-acsl/src/analyses/memory_tracking.ml | 7 +- src/plugins/e-acsl/src/analyses/typing.ml | 21 ++--- .../src/code_generator/translate_terms.ml | 8 +- src/plugins/eva/legacy/eval_terms.ml | 81 ++++++++++--------- src/plugins/wp/LogicSemantics.ml | 6 +- src/plugins/wp/MemoryContext.ml | 4 +- src/plugins/wp/RefUsage.ml | 5 +- src/plugins/wp/RegionAccess.ml | 6 +- src/plugins/wp/wpPropId.ml | 2 +- tests/libc/check_const.ml | 2 +- 27 files changed, 206 insertions(+), 209 deletions(-) diff --git a/src/kernel_internals/typing/asm_contracts.ml b/src/kernel_internals/typing/asm_contracts.ml index 836d52abf98..5a117f92751 100644 --- a/src/kernel_internals/typing/asm_contracts.ml +++ b/src/kernel_internals/typing/asm_contracts.ml @@ -82,7 +82,7 @@ let access_ptr_elts ~loc tlv = let base, basetype = if Logic_utils.isLogicVoidPointerType basetype then begin let typ = Ctype Cil.charPtrType in - Logic_const.term ~loc (TCastE(Cil.charPtrType,base)) typ, typ + Logic_const.term ~loc (TCast(false, Ctype Cil.charPtrType,base)) typ, typ end else base, basetype in let offset = Logic_const.term ~loc (TBinOp (PlusPI, base, range)) basetype in diff --git a/src/kernel_services/ast_data/alarms.ml b/src/kernel_services/ast_data/alarms.ml index 16ab1a0a5cb..1fbd95cf544 100644 --- a/src/kernel_services/ast_data/alarms.ml +++ b/src/kernel_services/ast_data/alarms.ml @@ -519,7 +519,7 @@ let create_predicate ?(loc=Location.unknown) alarm = | _ -> Cil.voidPtrType in let zero = Cil.lzero () in - Logic_const.term (TCastE (typ, zero)) (Ctype typ) + Logic_const.term (TCast (false, Ctype typ, zero)) (Ctype typ) end | Some e -> Logic_utils.expr_to_term e in diff --git a/src/kernel_services/ast_data/cil_types.ml b/src/kernel_services/ast_data/cil_types.ml index 55ea8321125..9fb991e9ecc 100644 --- a/src/kernel_services/ast_data/cil_types.ml +++ b/src/kernel_services/ast_data/cil_types.ml @@ -1362,7 +1362,13 @@ and term_node = | TAlignOfE of term (** alignment of the type of an expression. *) | TUnOp of unop * term (** unary operator. *) | TBinOp of binop * term * term (** binary operators. *) - | TCastE of typ * term (** cast to a C type. *) + | TCast of bool * logic_type * term + (** cast to a C type (if bool is false) + or an implicit conversion from C type to a logic type (if bool is true). + In the second case: + The logic type must not be a Ctype. + In particular, used to denote lifting to Linteger and Lreal. + *) | TAddrOf of term_lval (** address of a term. *) | TStartOf of term_lval (** beginning of an array. *) @@ -1380,11 +1386,7 @@ and term_node = | Toffset of logic_label * term (** offset from the base address of a pointer. *) | Tblock_length of logic_label * term (** length of the block pointed to by the term. *) | Tnull (** the null pointer. *) - | TLogic_coerce of logic_type * term - (** implicit conversion from a C type to a logic type. - The logic type must not be a Ctype. In particular, used to denote - lifting to Linteger and Lreal. - *) + | TUpdate of term * term_offset * term (** functional update of a field. *) | Ttypeof of term (** type tag for a term. *) diff --git a/src/kernel_services/ast_printing/cil_printer.ml b/src/kernel_services/ast_printing/cil_printer.ml index b8d83736750..a9d7c981037 100644 --- a/src/kernel_services/ast_printing/cil_printer.ml +++ b/src/kernel_services/ast_printing/cil_printer.ml @@ -360,7 +360,7 @@ module Precedence = struct | Tapp({ l_var_info },[],[_;_]) when l_var_info.lv_name = "\\repeat" -> bitwiseLevel (* Unary *) - | TCastE(_,_) + | TCast(false,_,_) | TAddrOf(_) | TStartOf(_) | TUnOp((Neg|BNot|LNot),_) -> unaryLevel @@ -382,7 +382,7 @@ module Precedence = struct | TConst _ | Tnull | TLval (TResult _,TNoOffset) | Tcomprehension _ | Tempty_set -> 0 | Tif (_, _, _) -> questionLevel - | TLogic_coerce(_,e) -> (getParenthLevelLogic e.term_node) + 1 + | TCast (true,_,e) -> (getParenthLevelLogic e.term_node) + 1 (* Create an expression of the same shape, and use {!getParenthLevel} *) let getParenthLevelAttrParam = function @@ -468,12 +468,12 @@ let is_same_direction_rel dir op = let remove_no_op_coerce t = match t.term_node with - | TLogic_coerce (ty,t) when Cil.no_op_coerce ty t -> t + | TCast (true, ty,t) when Cil.no_op_coerce ty t -> t | _ -> t let rec is_singleton t = match t.term_node with - | TLogic_coerce(Ltype ({ lt_name = "set"},_), t') -> is_singleton t' + | TCast (true, Ltype ({ lt_name = "set"},_), t') -> is_singleton t' | _ -> not (Logic_const.is_set_type t.term_type) (* when pretty-printing relation chains, a < b && b' < c, it can happen that @@ -2547,7 +2547,7 @@ class cil_printer () = object (self) fprintf fmt "@[%a@]" self#tand_list (get_tand_list l [r]) | TBinOp (op,l,r) -> fprintf fmt "@[%a@ %a@ %a@]" term l self#term_binop op term r - | TCastE (ty,t) -> + | TCast (false, Ctype ty,t) -> begin match ty, t.term_node with | TFloat(fk,_) , TConst(LReal r as cst) when not Kernel.(is_debug_key_enabled dkey_print_logic_coercions) && @@ -2556,6 +2556,8 @@ class cil_printer () = object (self) | _ -> fprintf fmt "(%a)%a" (self#typ None) ty term t end + | TCast(false,_,_) -> + Kernel.fatal "Found a TCast to ctype without a Ctype associated" | TAddrOf lv -> fprintf fmt "&%a" (self#term_lval_prec Precedence.addrOfLevel) lv | TStartOf lv -> @@ -2659,7 +2661,7 @@ class cil_printer () = object (self) self#quantifiers args) pp_defn term body - | TLogic_coerce(ty,t) -> + | TCast (true, ty,t) -> if (not (Cil.no_op_coerce ty t)) || Kernel.is_debug_key_enabled Kernel.dkey_print_logic_coercions then diff --git a/src/kernel_services/ast_printing/cil_types_debug.ml b/src/kernel_services/ast_printing/cil_types_debug.ml index 97cbc21081f..bdd64597f86 100644 --- a/src/kernel_services/ast_printing/cil_types_debug.ml +++ b/src/kernel_services/ast_printing/cil_types_debug.ml @@ -660,7 +660,7 @@ and pp_term_node fmt = function | TUnOp(unop,term) -> Format.fprintf fmt "TUnOp(%a,%a)" pp_unop unop pp_term term | TBinOp(binop,term1,term2) -> Format.fprintf fmt "TBinOp(%a,%a,%a)" pp_binop binop pp_term term1 pp_term term2 - | TCastE(typ,term) -> Format.fprintf fmt "TCastE(%a,%a)" pp_typ typ pp_term term + | TCast(logic,typ,term) -> Format.fprintf fmt "TCast(%a,%a,%a)" pp_bool logic pp_logic_type typ pp_term term | TAddrOf(term_lval) -> Format.fprintf fmt "TAddrOf(%a)" pp_term_lval term_lval | TStartOf(term_lval) -> Format.fprintf fmt "TStartOf(%a)" pp_term_lval term_lval | Tapp(logic_info,logic_label_list,term_list) -> @@ -681,8 +681,6 @@ and pp_term_node fmt = function | Tblock_length(logic_label,term) -> Format.fprintf fmt "Tblock_length(%a,%a)" pp_logic_label logic_label pp_term term | Tnull -> Format.fprintf fmt "Tnull" - | TLogic_coerce(logic_type,term) -> - Format.fprintf fmt "TLogic_coerce(%a,%a)" pp_logic_type logic_type pp_term term | TUpdate(term1,term_offset,term2) -> Format.fprintf fmt "TUpdate(%a,%a,%a)" pp_term term1 pp_term_offset term_offset pp_term term2 | Ttypeof(term) -> Format.fprintf fmt "Ttypeof(%a)" pp_term term diff --git a/src/kernel_services/ast_queries/ast_diff.ml b/src/kernel_services/ast_queries/ast_diff.ml index 222d4c77a26..3b73ea2acc6 100644 --- a/src/kernel_services/ast_queries/ast_diff.ml +++ b/src/kernel_services/ast_queries/ast_diff.ml @@ -582,8 +582,8 @@ and is_same_term_node t t' env = | TUnOp(op,t), TUnOp(op',t') -> Unop.equal op op' && is_same_term t t' env | TBinOp(op,t1,t2), TBinOp(op',t1',t2') -> Binop.equal op op' && is_same_term t1 t1' env && is_same_term t2 t2' env - | TCastE(typ,term), TCastE(typ',term') -> - is_same_type typ typ' env && is_same_term term term' env + | TCast(is_logic, typ, term), TCast(is_logic', typ', term') -> + is_logic = is_logic' && is_same_logic_type typ typ' env && is_same_term term term' env | TAddrOf lv, TAddrOf lv' | TStartOf lv, TStartOf lv' -> is_same_term_lval lv lv' env | Tapp(f,labs,args), Tapp(f',labs',args') -> @@ -609,8 +609,6 @@ and is_same_term_node t t' env = | Tblock_length(l,t), Tblock_length(l',t') -> is_same_logic_label l l' env && is_same_term t t' env | Tnull, Tnull -> true - | TLogic_coerce(typ,t), TLogic_coerce(typ',t') -> - is_same_logic_type typ typ' env && is_same_term t t' env | TUpdate(a,o,v), TUpdate(a',o',v') -> is_same_term a a' env && is_same_term_offset o o' env && @@ -634,9 +632,9 @@ and is_same_term_node t t' env = is_same_term t t' env end else false | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ - | TAlignOfE _ | TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _ + | TAlignOfE _ | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ | Tbase_addr _ - | Toffset _ | Tblock_length _ | Tnull | TLogic_coerce _ | TUpdate _ + | Toffset _ | Tblock_length _ | Tnull | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set | Tunion _ | Tinter _ | Tcomprehension _ | Tlet _ | Trange _), _ -> false diff --git a/src/kernel_services/ast_queries/ast_info.ml b/src/kernel_services/ast_queries/ast_info.ml index e1c019546c4..5030a6d76bd 100644 --- a/src/kernel_services/ast_queries/ast_info.ml +++ b/src/kernel_services/ast_queries/ast_info.ml @@ -307,7 +307,7 @@ let constant_term loc i = let rec is_null_term t = match t.term_node with | TConst c when is_integral_logic_const c -> Integer.equal (value_of_integral_logic_const c) Integer.zero - | TCastE(_,t) -> is_null_term t + | TCast(false, _,t) -> is_null_term t | _ -> false (* ************************************************************************** *) diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml index 6a38cc02b36..4a40c63ae67 100644 --- a/src/kernel_services/ast_queries/cil.ml +++ b/src/kernel_services/ast_queries/cil.ml @@ -1467,10 +1467,15 @@ and childrenTermNode vis tn = let t1' = vTerm t1 in let t2' = vTerm t2 in if t1' != t1 || t2' != t2 then TBinOp(op,t1',t2') else tn - | TCastE(ty,te) -> + | TCast(false, Ctype ty,te) -> let ty' = vTyp ty in let te' = vTerm te in - if ty' != ty || te' != te then TCastE(ty',te') else tn + if ty' != ty || te' != te then TCast(false, Ctype ty',te') else tn + | TCast (true, ty,t) -> + let ty' = visitCilLogicType vis ty in + let t' = visitCilTerm vis t in + if ty' != ty || t' != t then TCast (true, ty',t') else tn + | TCast(false,_,_) -> Kernel.fatal "TCast to ctype without Ctype" | TAddrOf tl -> let tl' = vTermLval tl in if tl' != tl then TAddrOf tl' else tn @@ -1552,10 +1557,6 @@ and childrenTermNode vis tn = let def'= visitCilLogicInfo vis def in let body' = visitCilTerm vis body in if def != def' || body != body' then Tlet(def',body') else tn - | TLogic_coerce(ty,t) -> - let ty' = visitCilLogicType vis ty in - let t' = visitCilTerm vis t in - if ty' != ty || t' != t then TLogic_coerce(ty',t') else tn and visitCilLogicLabel vis l = doVisitCil vis @@ -3186,14 +3187,14 @@ let isZero (e: exp) : bool = let rec isLogicZero t = match t.term_node with | TConst (Integer (n,_)) -> Integer.equal n Integer.zero | TConst (LChr c) -> Char.code c = 0 - | TCastE(_, t) -> isLogicZero t + | TCast(false, _, t) -> isLogicZero t | _ -> false let isLogicNull t = isLogicZero t || (let rec aux t = match t.term_node with | Tnull -> true - | TCastE(_, t) -> aux t + | TCast(false,_, t) -> aux t | _ -> false in aux t) @@ -3461,7 +3462,7 @@ let rec stripCasts (e: exp) = match e.enode with CastE(_, e') -> stripCasts e' | _ -> e let rec stripTermCasts (t: term) = - match t.term_node with TCastE(_, t') -> stripTermCasts t' | _ -> t + match t.term_node with TCast(false,_, t') -> stripTermCasts t' | _ -> t (* Separate out the storage-modifier name attributes *) let separateStorageModifiers (al: attribute list) = @@ -7356,7 +7357,7 @@ let rec free_vars_term bound_vars t = match t.term_node with | TSizeOfE t | TAlignOfE t | TUnOp (_,t) - | TCastE (_,t) + | TCast (_,_,t) | Tat (t,_) | Toffset (_,t) | Tbase_addr (_,t) @@ -7429,7 +7430,6 @@ let rec free_vars_term bound_vars t = match t.term_node with free_vars_term (Logic_var.Set.add d.l_var_info bound_vars) b in Logic_var.Set.union fvd fvb - | TLogic_coerce(_,t) -> free_vars_term bound_vars t and free_vars_lval bv (h,o) = Logic_var.Set.union diff --git a/src/kernel_services/ast_queries/cil_datatype.ml b/src/kernel_services/ast_queries/cil_datatype.ml index 0e02f014f61..ef018a9add1 100644 --- a/src/kernel_services/ast_queries/cil_datatype.ml +++ b/src/kernel_services/ast_queries/cil_datatype.ml @@ -93,7 +93,7 @@ let rank_term = function | TAlignOfE _ -> 6 | TUnOp _ -> 7 | TBinOp _ -> 8 - | TCastE _ -> 9 + | TCast (false,_,_) -> 9 | TAddrOf _ -> 10 | TStartOf _ -> 11 | Tapp _ -> 12 @@ -114,7 +114,7 @@ let rank_term = function | Tlet _ -> 29 | Tcomprehension _ -> 30 | Toffset _ -> 31 - | TLogic_coerce _ -> 32 + | TCast (true, _,_) -> 32 let rank_predicate = function | Pfalse -> 0 @@ -1638,9 +1638,11 @@ let rec compare_term t1 t2 = if c <> 0 then c else let cx = compare_term x1 x2 in if cx <> 0 then cx else compare_term y1 y2 - | TCastE(ty1,t1) , TCastE(ty2,t2) -> - let c = Typ.compare ty1 ty2 in - if c <> 0 then c else compare_term t1 t2 + | TCast (false, ty1,e1), TCast (false, ty2,e2) + | TCast (true, ty1,e1) , TCast (true, ty2,e2) -> + let ct = Logic_type.compare ty1 ty2 in + if ct <> 0 then ct + else compare_term e1 e2 | Tapp(f1,labs1,ts1) , Tapp(f2,labs2,ts2) -> let cf = Logic_info.compare f1 f2 in if cf <> 0 then cf else @@ -1683,18 +1685,13 @@ let rec compare_term t1 t2 = else let cq = compare_list Logic_var.compare q1 q2 in if cq <> 0 then cq else Option.compare compare_predicate p1 p2 - | TLogic_coerce(ty1,e1), TLogic_coerce(ty2,e2) -> - let ct = Logic_type.compare ty1 ty2 in - if ct <> 0 then ct - else compare_term e1 e2 | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ - | TAlignOfE _ | TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _ + | TAlignOfE _ | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ | Tbase_addr _ | Tblock_length _ | Toffset _ | Tnull | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set | Tunion _ | Tinter _ | Tcomprehension _ - | Trange _ | Tlet _ - | TLogic_coerce _), _ -> assert false + | Trange _ | Tlet _ ), _ -> assert false and compare_tlval (h1,off1) (h2,off2) = let ch = compare_tlhost h1 h2 in @@ -1854,9 +1851,12 @@ let rec hash_term (acc,depth,tot) t = hash_term (acc+19+Hashtbl.hash bop,depth-1,tot-2) t1 in hash_term (hash1,depth-1,tot1) t2 - | TCastE(ty,t) -> + | TCast(false, Ctype ty,t) -> let hash1 = Typ.hash ty in hash_term (acc+23+hash1,depth-1,tot-2) t + | TCast(true,_,e) -> hash_term (acc + 113, depth - 1, tot - 1) e + (* TODO (NB) : Check the magic values here (see if it can't be merged) *) + | TCast(false,_,_) -> assert false | TAddrOf lv -> hash_tlval (acc+29,depth-1,tot-1) lv | TStartOf lv -> hash_tlval (acc+31,depth-1,tot-1) lv | Tapp (li,labs,apps) -> @@ -1935,7 +1935,6 @@ let rec hash_term (acc,depth,tot) t = hash_term (acc + 109 + Hashtbl.hash li.l_var_info.lv_name, depth-1, tot-1) t - | TLogic_coerce(_,e) -> hash_term (acc + 113, depth - 1, tot - 1) e end and hash_tlval (acc,depth,tot) (h,o) = diff --git a/src/kernel_services/ast_queries/logic_const.ml b/src/kernel_services/ast_queries/logic_const.ml index ccea4480273..34d0e0a7f32 100644 --- a/src/kernel_services/ast_queries/logic_const.ml +++ b/src/kernel_services/ast_queries/logic_const.ml @@ -309,10 +309,10 @@ let tat ?(loc=Cil_datatype.Location.unknown) (t,label) = let told ?(loc=Cil_datatype.Location.unknown) t = tat ~loc (t,old_label) let tcast ?(loc=Cil_datatype.Location.unknown) t ct = - term ~loc (TCastE (ct, t)) (Ctype ct) + term ~loc (TCast(false, Ctype ct, t)) (Ctype ct) let tlogic_coerce ?(loc=Cil_datatype.Location.unknown) t lt = - term ~loc (TLogic_coerce (lt, t)) lt + term ~loc (TCast (true, lt, t)) lt let tvar ?(loc=Cil_datatype.Location.unknown) lv = term ~loc (TLval(TVar lv,TNoOffset)) lv.lv_type diff --git a/src/kernel_services/ast_queries/logic_to_c.ml b/src/kernel_services/ast_queries/logic_to_c.ml index 2b0ab82e024..971013e5757 100644 --- a/src/kernel_services/ast_queries/logic_to_c.ml +++ b/src/kernel_services/ast_queries/logic_to_c.ml @@ -115,7 +115,7 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} = (* TODO: Very likely to fail on large integer and incorrect on reals not representable as floats *) [new_exp ~loc (Const (Logic_utils.lconstant_to_constant constant))] - | TCastE (typ, lexp) -> + | TCast (false, Ctype typ, lexp) -> List.map (fun x -> new_exp ~loc (CastE (typ, x))) (loc_to_exp ?result lexp) | TAlignOf typ -> [new_exp ~loc (AlignOf typ)] @@ -129,15 +129,15 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} = | Tinter _ | Tcomprehension _ -> error_lval() | Tat ({term_node = TAddrOf (TVar _, TNoOffset)} as taddroflval, _) -> loc_to_exp ?result taddroflval - | TLogic_coerce(Linteger, t) when Logic_typing.is_integral_type t.term_type -> + | TCast (true, Linteger, t) when Logic_typing.is_integral_type t.term_type -> loc_to_exp ?result t - | TLogic_coerce(Lreal, t) when Logic_typing.is_integral_type t.term_type -> + | TCast (true, Lreal, t) when Logic_typing.is_integral_type t.term_type -> List.map (fun x -> new_exp ~loc (CastE (logic_type_to_typ Lreal, x))) (loc_to_exp ?result t) - | TLogic_coerce(Lreal, t) when Logic_typing.is_arithmetic_type t.term_type -> + | TCast (true, Lreal, t) when Logic_typing.is_arithmetic_type t.term_type -> loc_to_exp ?result t - | TLogic_coerce (set, t) + | TCast (true, set, t) when Logic_const.is_set_type set && Logic_utils.is_same_type @@ -154,7 +154,7 @@ and loc_to_exp ?result {term_node = lnode ; term_type = ltype; term_loc = loc} = | Toffset _ | Tblock_length _ | TUpdate _ | Ttypeof _ | Ttype _ - | TLogic_coerce _ + | TCast _ -> error_lval () let rec loc_to_lval ?result t = @@ -167,7 +167,7 @@ let rec loc_to_lval ?result t = (* coercions to arithmetic types cannot be lval. We only have to consider a coercion to set here. *) - | TLogic_coerce(set, t) when + | TCast (true, set, t) when Logic_typing.is_set_type set && Logic_utils.is_same_type (Logic_typing.type_of_set_elem set) t.term_type -> @@ -175,10 +175,10 @@ let rec loc_to_lval ?result t = | Tinter _ -> error_lval() (* TODO *) | Tcomprehension _ -> error_lval() | TSizeOfE _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TSizeOfStr _ - | TConst _ | TCastE _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _ + | TConst _ | TCast _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _ | Tat _ | Toffset _ | Tbase_addr _ | Tblock_length _ | Tnull | Trange _ | TDataCons _ | TUpdate _ | Tlambda _ - | Ttypeof _ | Ttype _ | Tlet _ | TLogic_coerce _ -> + | Ttypeof _ | Ttype _ | Tlet _ -> error_lval () let loc_to_offset ?result loc = @@ -198,11 +198,10 @@ let loc_to_offset ?result loc = | Tempty_set -> h,[] | Trange _ | TAddrOf _ | Tat _ | TSizeOfE _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TSizeOfStr _ - | TConst _ | TCastE _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _ + | TConst _ | TCast _ | TAlignOf _ | TSizeOf _ | Tapp _ | Tif _ | Toffset _ | Tbase_addr _ | Tblock_length _ | Tnull | TDataCons _ | TUpdate _ | Tlambda _ | Ttypeof _ | Ttype _ | Tcomprehension _ | Tinter _ | Tlet _ - | TLogic_coerce _ -> error_lval () in snd (aux None loc.term_node) diff --git a/src/kernel_services/ast_queries/logic_typing.ml b/src/kernel_services/ast_queries/logic_typing.ml index 4cfddc62f89..1eac2474cd7 100644 --- a/src/kernel_services/ast_queries/logic_typing.ml +++ b/src/kernel_services/ast_queries/logic_typing.ml @@ -192,10 +192,10 @@ let optimize_comprehension term = let lv = Logic_const.addTermOffsetLval o lv in let ty = Cil.typeOfTermLval lv in Logic_utils.mk_logic_StartOf (Logic_const.term ~loc (TLval lv) ty)) - | TLogic_coerce(lt,{ term_node = TLval(TVar y,TNoOffset)}) when is_x y -> + | TCast (true, lt,{ term_node = TLval(TVar y,TNoOffset)}) when is_x y -> (* { (lt)x | \subset(x, set) } -> (lt set)set *) { t with - term_node = TLogic_coerce(Logic_const.make_set_type lt,set); + term_node = TCast (true, Logic_const.make_set_type lt,set); term_type = Logic_const.make_set_type lt } | _ -> term in @@ -206,8 +206,8 @@ let optimize_comprehension term = { pred_content = Papp({l_var_info = {lv_name="\\subset"}},[],[elt;set]) }) -> (match elt.term_node with - | TLogic_coerce - (_, + | TCast + (true,_, { term_node = TLval(TVar y, TNoOffset) }) when Cil_datatype.Logic_var.equal x y -> @@ -228,22 +228,22 @@ let lift_set f loc = | Tempty_set -> loc (* coercion from a set to another set: keep the current coercion over the result of the transformation. *) - | TLogic_coerce(set,t1) + | TCast (true, set,t1) when is_set_type set && is_set_type t1.term_type -> let res = aux t1 in - { loc with term_node = TLogic_coerce(set, res) } + { loc with term_node = TCast (true, set, res) } (* coercion from a singleton to a set: performs the transformation. *) - | TLogic_coerce(oset, t1) when is_set_type oset -> + | TCast (true, oset, t1) when is_set_type oset -> let t = f t1 in let nset = make_set_type t.term_type in (* performs the coercion into a set. *) let singleton_coerce = - { t with term_node = TLogic_coerce(nset, t); term_type = nset } + { t with term_node = TCast (true, nset, t); term_type = nset } in (* see whether we have to coerce the set type itself. *) if is_same_type oset nset then singleton_coerce - else { loc with term_node = TLogic_coerce(oset, singleton_coerce) } + else { loc with term_node = TCast (true, oset, singleton_coerce) } (* if we a term of type set, try to apply f to each element of x by using a comprehension, and see whether we can get rid of said comprehension afterwards. *) @@ -257,7 +257,7 @@ let lift_set f loc = let t2 = Logic_const.tvar ~loc:loc.term_loc x in let t2 = Logic_const.term - ~loc:loc.term_loc (TLogic_coerce (loc.term_type,t2)) loc.term_type + ~loc:loc.term_loc (TCast (true, loc.term_type,t2)) loc.term_type in let p = Logic_const.papp ~loc:loc.term_loc (sub, [], [t2;loc]) in let c = { loc with term_node = Tcomprehension(t,[x],Some p) } in @@ -1057,7 +1057,7 @@ struct | TLval _ -> true | TUnOp(_,t) -> needs_at t | TBinOp(_,t1,t2) -> needs_at t1 || needs_at t2 - | TCastE(_,t) -> needs_at t + | TCast(_,_,t) -> needs_at t | TAddrOf (_,o) -> needs_at_offset o | TStartOf (_,o) -> needs_at_offset o | Tapp(_,_,l) | TDataCons(_,l) -> List.exists needs_at l @@ -1071,7 +1071,6 @@ struct | Trange (Some t1, Some t2) -> needs_at t1 || needs_at t2 | Tlet(_,t) -> needs_at t | Tif(t1,t2,t3) -> needs_at t1 || needs_at t2 || needs_at t3 - | TLogic_coerce(_,t) -> needs_at t and needs_at_offset = function | TNoOffset -> false | TIndex (t,o) -> needs_at t || needs_at_offset o @@ -1124,7 +1123,7 @@ struct if isPointerType newt && isLogicNull e && not (isLogicZero e) then (* \null can have any pointer type, see ACSL manual. *) (if force then - Logic_const.term ~loc (TCastE (newt, e)) (Ctype newt) + Logic_const.term ~loc (TCast (false, Ctype newt, e)) (Ctype newt) else { e with term_type = Ctype newt }) else if isPointerType newt && isArrayType oldt then begin @@ -1225,13 +1224,13 @@ struct | Tinter l -> { e with term_type = real_type; term_node = Tinter (List.map aux l) } | Tempty_set -> { e with term_type = real_type } - | TLogic_coerce(t2,e) when Cil.no_op_coerce t2 e -> + | TCast (true,t2,e) when Cil.no_op_coerce t2 e -> let e = aux e in - { e with term_type = real_type; term_node = TLogic_coerce(real_type,e) } + { e with term_type = real_type; term_node = TCast (true, real_type,e) } | _ when Cil.isLogicArithmeticType real_type -> Logic_utils.numeric_coerce real_type e | _ -> - { e with term_type = real_type; term_node = TLogic_coerce(real_type,e) } + { e with term_type = real_type; term_node = TCast (true, real_type,e) } in if is_same_type e.term_type t then e else aux e @@ -1248,7 +1247,7 @@ struct let range = trange ~loc (Some (lzero ~loc ()), Some sizeof) in let converted_type = set_conversion (Ctype Cil.charPtrType) t.term_type in - let cast = term ~loc (TCastE(Cil.charPtrType, t)) converted_type in + let cast = term ~loc (TCast(false, Ctype Cil.charPtrType, t)) converted_type in term ~loc (TBinOp(PlusPI,cast,range)) (make_set_type converted_type) in lift_set convert_one_location t @@ -1263,7 +1262,7 @@ struct if explicit then begin match Logic_const.unroll_ltdef newt with | Ctype cnewt -> - { e with term_node = TCastE(cnewt,e); term_type = newt } + { e with term_node = TCast(false, Ctype cnewt,e); term_type = newt } | _ -> e end else e end else if is_enum_cst e newt then { e with term_type = newt } @@ -1284,7 +1283,7 @@ struct logic_coerce Linteger e | t1, Ctype t2 when Logic_const.is_boolean_type t1 && is_integral_type newt && explicit -> - Logic_const.term ~loc (TCastE (t2,e)) newt + Logic_const.term ~loc (TCast (false, Ctype t2,e)) newt | ty1, Ltype({lt_name="set"},[ty2]) when is_pointer_type ty1 && is_plain_pointer_type ty2 && @@ -1429,7 +1428,7 @@ struct (* Integer 0 is also a valid pointer. *) | Linteger, Ctype ty when Cil.isPointerType ty && isLogicNull oterm -> nt, { oterm with - term_node = TCastE(ty,oterm); + term_node = TCast(false, Ctype ty,oterm); term_type = nt } | Linteger, Ctype ty when Cil.isIntegralType ty -> (try @@ -2058,7 +2057,7 @@ struct known_vars, kont (eta_expand term.term_loc term.term_name env v) | TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ | TAlignOfE _ - | TUnOp _ | TBinOp _ | TCastE _ | TAddrOf _ | TStartOf _ + | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _ | Tapp _ | TDataCons _ | Tbase_addr _ | Toffset _ | Tblock_length _ | Tnull | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set @@ -2068,7 +2067,7 @@ struct idea that you can always replace a term by a set of terms *) | Tunion _ | Tinter _ | Tcomprehension _ - | Trange _ | TLogic_coerce _ + | Trange _ -> known_vars, kont term | Tlambda (quants,term) -> @@ -2366,11 +2365,11 @@ struct | Tunion l | Tinter l -> List.for_all aux l - | TLogic_coerce (_,t) | Tat (t, _) | Tcomprehension (t,_,_) | Tlet (_, t) + | TCast (true,_,t) | Tat (t, _) | Tcomprehension (t,_,_) | Tlet (_, t) -> aux t | Trange _ | TConst _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ | TAlignOf _ - | TAlignOfE _ | TUnOp (_,_) | TBinOp (_,_,_) | TCastE (_,_) + | TAlignOfE _ | TUnOp (_,_) | TBinOp (_,_,_) | TCast (false,_,_) | Tlambda (_,_) | TDataCons (_,_) | Tbase_addr (_,_) | Toffset (_,_) | Tblock_length (_,_) | Tnull | Tapp _ | TUpdate (_,_,_) | Ttypeof _ | Ttype _ -> @@ -3159,7 +3158,7 @@ struct let check_lval t = match t.term_node with TLval lv - | TLogic_coerce(_,{term_node = TLval lv }) + | TCast (true, _,{term_node = TLval lv }) | Tat({term_node = TLval lv},_) -> f lv t | TStartOf lv | Tat ({term_node = TStartOf lv}, _) -> @@ -3183,7 +3182,7 @@ struct term_type = type_of_pointed t.term_type; term_node = TLval lv } | TLval lv - | TLogic_coerce(_,{term_node = TLval lv }) + | TCast (true, _,{term_node = TLval lv }) | Tat({term_node = TLval lv},_) -> f lv t | TStartOf lv | Tat ({term_node = TStartOf lv}, _) diff --git a/src/kernel_services/ast_queries/logic_utils.ml b/src/kernel_services/ast_queries/logic_utils.ml index 7a2b471b5d8..3dcd4013e17 100644 --- a/src/kernel_services/ast_queries/logic_utils.ml +++ b/src/kernel_services/ast_queries/logic_utils.ml @@ -236,16 +236,16 @@ let mk_cast ?loc ?(force=false) newt t = let newt' = Cil.type_remove_attributes_for_logic_type newt in if equal_ltype (Ctype newt') t.term_type then t else let rec unroll_cast e = match e.term_node with - | TCastE(oldt,e) + | TCast(false, Ctype oldt,e) when (Cil.isPointerType newt' && Cil.isPointerType oldt) || equal_ltype (Ctype (Cil.type_remove_attributes_for_logic_type oldt)) (Ctype newt') -> unroll_cast e - | TLogic_coerce(Linteger,e) + | TCast(true,Linteger,e) when Cil.isArithmeticOrPointerType newt' -> unroll_cast e - | TLogic_coerce(Lreal,e) + | TCast(true,Lreal,e) when Cil.isFloatingType newt' -> unroll_cast e | _ -> e @@ -254,7 +254,7 @@ let mk_cast ?loc ?(force=false) newt t = let loc = match loc with None -> t.term_loc | Some loc -> loc in (* we keep newt as the cast target, as newt' might have unrolled typedefs in order to remove attributes, resulting in a less user-friendly type *) - Logic_const.term ~loc (TCastE (newt, tres)) (Ctype newt') + Logic_const.term ~loc (TCast (false, Ctype newt, tres)) (Ctype newt') (* -------------------------------------------------------------------------- *) @@ -319,23 +319,23 @@ let parse_float ?loc literal = let vreal = Logic_const.term ?loc (TConst(LReal creal)) Lreal in if is_flt then let ty = TFloat(fk,[]) in - Logic_const.term ?loc (TCastE(ty,vreal)) (Ctype ty) + Logic_const.term ?loc (TCast(false, Ctype ty,vreal)) (Ctype ty) else vreal let mk_coerce ltyp t = - Logic_const.term ~loc:t.term_loc (TLogic_coerce(ltyp, t)) ltyp + Logic_const.term ~loc:t.term_loc (TCast (true, ltyp, t)) ltyp let rec numeric_coerce ltyp t = let oldt = unroll_type t.term_type in match t.term_node with - | TLogic_coerce(lt,e) when Cil.no_op_coerce lt e -> + | TCast (true, lt,e) when Cil.no_op_coerce lt e -> (* coercion hidden by the printer, but still present *) numeric_coerce ltyp e | TConst(LEnum _) | TConst(Integer _) when ltyp = Linteger -> { t with term_type = Linteger } | TConst(LReal _ ) when ltyp = Lreal -> { t with term_type = Lreal } - | TCastE(ty,e) -> + | TCast (false, Ctype ty,e) -> begin match ltyp, Cil.unrollType ty, e.term_node with | Linteger, TInt(ik,_), TConst(Integer(v,_)) when Cil.fitsInInt ik v -> { e with term_type = Linteger } @@ -658,7 +658,7 @@ let array_with_range arr size = let remove_logic_coerce t = match t.term_node with - | TLogic_coerce(_,t) -> t + | TCast (true, _,t) -> t | _ -> t let rec remove_term_offset o = @@ -954,8 +954,8 @@ let rec is_same_term t1 t2 = | TUnOp (o1,t1), TUnOp(o2,t2) -> o1 = o2 && is_same_term t1 t2 | TBinOp(o1,l1,r1), TBinOp(o2,l2,r2) -> is_same_binop o1 o2 && is_same_term l1 l2 && is_same_term r1 r2 - | TCastE(typ1,t1), TCastE(typ2,t2) -> - Cil_datatype.TypByName.equal typ1 typ2 && is_same_term t1 t2 + | TCast (b1, ty1,t1), TCast (b2, ty2,t2) -> + b1 = b2 && is_same_type ty1 ty2 && is_same_term t1 t2 | TAddrOf l1, TAddrOf l2 -> is_same_tlval l1 l2 | TStartOf l1, TStartOf l2 -> is_same_tlval l1 l2 | Tapp(f1,labels1, args1), Tapp(f2, labels2, args2) -> @@ -993,15 +993,13 @@ let rec is_same_term t1 t2 = is_same_opt is_same_term l1 l2 && is_same_opt is_same_term h1 h2 | Tlet(d1,b1), Tlet(d2,b2) -> is_same_logic_info d1 d2 && is_same_term b1 b2 - | TLogic_coerce(ty1,t1), TLogic_coerce(ty2,t2) -> - is_same_type ty1 ty2 && is_same_term t1 t2 | (TConst _ | TLval _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ - | TAlignOf _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TCastE _ + | TAlignOf _ | TAlignOfE _ | TUnOp _ | TBinOp _ | TCast _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ | Tbase_addr _ | Tblock_length _ | Toffset _ | Tnull | TUpdate _ | Ttypeof _ | Ttype _ | Tcomprehension _ | Tempty_set | Tunion _ | Tinter _ | Trange _ - | Tlet _ | TLogic_coerce _ + | Tlet _ ),_ -> false and is_same_logic_info l1 l2 = @@ -1508,9 +1506,14 @@ let rec hash_term (acc,depth,tot) t = hash_term (acc+152+Hashtbl.hash bop,depth-1,tot-2) t1 in hash_term (hash1,depth-1,tot1) t2 - | TCastE(ty,t) -> + | TCast (false, Ctype ty,t) -> let hash1 = Cil_datatype.TypByName.hash ty in hash_term (acc+171+hash1,depth-1,tot-2) t + | TCast (true, _,t) -> + hash_term (acc + 587, depth - 1, tot - 1) t + | TCast (false, _,_) -> assert false + (* TODO (NB) : Should check the magic values here to see if we can merge + them *) | TAddrOf lv -> hash_term_lval (acc+190,depth-1,tot-1) lv | TStartOf lv -> hash_term_lval (acc+209,depth-1,tot-1) lv | Tapp (li,labs,apps) -> hash_app (acc,depth,tot) li labs apps @@ -1583,8 +1586,6 @@ let rec hash_term (acc,depth,tot) t = hash_term (acc + 570 + Hashtbl.hash li.l_var_info.lv_name, depth-1, tot-1) t - | TLogic_coerce(_,t) -> - hash_term (acc + 587, depth - 1, tot - 1) t end and hash_app (acc,depth,tot) li labs apps = @@ -1740,11 +1741,12 @@ let rec compare_term t1 t2 = else res | TBinOp _, _ -> 1 | _, TBinOp _ -> -1 - | TCastE(typ1,t1), TCastE(typ2,t2) -> - let res = Cil_datatype.TypByName.compare typ1 typ2 in + | TCast (false, ty1,t1), TCast (false, ty2,t2) + | TCast (true, ty1,t1), TCast (true, ty2,t2) -> + let res = Cil_datatype.Logic_type_ByName.compare ty1 ty2 in if res = 0 then compare_term t1 t2 else res - | TCastE _, _ -> 1 - | _, TCastE _ -> -1 + | TCast (false,_,_), _ -> 1 + | _, TCast (false,_,_) -> -1 | TAddrOf l1, TAddrOf l2 -> compare_tlval l1 l2 | TAddrOf _, _ -> 1 | _, TAddrOf _ -> -1 @@ -1835,9 +1837,6 @@ let rec compare_term t1 t2 = if res = 0 then compare_term b1 b2 else res | Tlet _, _ -> 1 | _, Tlet _ -> -1 - | TLogic_coerce(ty1,t1), TLogic_coerce(ty2,t2) -> - let res = Cil_datatype.Logic_type_ByName.compare ty1 ty2 in - if res = 0 then compare_term t1 t2 else res and compare_logic_info l1 l2 = let res = compare_logic_signature l1 l2 in @@ -2446,30 +2445,28 @@ let rec constFoldTermToInt ?(machdep=true) (e: term) : Integer.t option = with Cil.SizeOfError _ -> None end | TAlignOfE _ -> None (* exp case is very complex, and possibly incorrect *) - | TCastE (typ, e) -> constFoldCastToInt ~machdep typ e + | TCast (false, Ctype typ, e) -> constFoldCastToInt ~machdep typ e + | TCast (true, Linteger, e) -> constFoldTermToInt ~machdep e | Toffset (_, t) -> if machdep then constFoldToffset t else None | Tif (c, e1, e2) -> begin - match constFoldTermToInt ~machdep c with - | None -> None - | Some i -> - constFoldTermToInt ~machdep (if Integer.is_zero i then e2 else e1) + Option.bind (constFoldTermToInt ~machdep c) + (fun i -> constFoldTermToInt ~machdep (if Integer.is_zero i then e2 else e1)) end - | TLogic_coerce (lt, e) -> - if lt = Linteger then constFoldTermToInt ~machdep e else None | Tnull -> Some Integer.zero | Tapp (li, _, [{term_node = (Tunion args | - TLogic_coerce (_, {term_node = Tunion args}))}]) + TCast (true, _, {term_node = Tunion args}))}]) when is_max_function li -> constFoldMinMax ~machdep Integer.max args | Tapp (li, _, [{term_node = (Tunion args | - TLogic_coerce (_, {term_node = Tunion args}))}]) + TCast (true, _, {term_node = Tunion args}))}]) when is_min_function li -> constFoldMinMax ~machdep Integer.min args | TLval _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tat _ | Tbase_addr _ | Tblock_length _ | TUpdate _ | Ttypeof _ | Ttype _ | Tempty_set | Tunion _ | Tinter _ - | Tcomprehension _ | Trange _ | Tlet _ -> + | Tcomprehension _ | Trange _ | Tlet _ + | TCast _ -> None and constFoldCastToInt ~machdep typ e = diff --git a/src/plugins/aorai/aorai_utils.ml b/src/plugins/aorai/aorai_utils.ml index 23685c5dde7..395295a3904 100644 --- a/src/plugins/aorai/aorai_utils.ml +++ b/src/plugins/aorai/aorai_utils.ml @@ -165,13 +165,12 @@ let isCrossableAtInit tr func = bool_res (comp (Char.compare c1 c2)) | TConst(LReal r1), TConst (LReal r2) -> bool_res (comp (compare r1.r_nearest r2.r_nearest)) - | TCastE(ty1,t1), TCastE(ty2,t2) + | TCast (false, Ctype ty1,t1), TCast (false, Ctype ty2,t2) when Cil_datatype.Typ.equal ty1 ty2 -> comparison comp t1 t2 | _ -> t in (match op, t1.term_node, t2.term_node with - | PlusA, TConst(Integer(i1,_)), TConst(Integer(i2,_)) -> { t with term_node = TConst(Integer(Integer.add i1 i2,None))} @@ -208,11 +207,11 @@ let isCrossableAtInit tr func = | LOr, t1, t2 -> bool3_res t (Bool3.bool3or (is_true t1) (is_true t2)) | _ -> t) - | TCastE(ty,t1) -> + | TCast (false, Ctype ty,t1) -> let t1 = aux t1 in (match t1.term_type with - Ctype ty1 when Cil_datatype.Typ.equal ty ty1 -> t1 - | _ -> { t with term_node = TCastE(ty,t1) }) + | Ctype ty1 when Cil_datatype.Typ.equal ty ty1 -> t1 + | _ -> { t with term_node = TCast (false, Ctype ty,t1) }) | _ -> t and aux_lv (base,off) = match base with @@ -283,7 +282,8 @@ let isCrossableAtInit tr func = Bool3.bool3_of_bool (comp (Char.compare c1 c2)) | TConst(LReal r1), TConst (LReal r2) -> Bool3.bool3_of_bool (comp (compare r1.r_nearest r2.r_nearest)) - | TCastE(ty1,t1), TCastE(ty2,t2) when Cil_datatype.Typ.equal ty1 ty2 -> + | TCast (false, Ctype ty1,t1), TCast (false, Ctype ty2,t2) + when Cil_datatype.Typ.equal ty1 ty2 -> comparison t1 t2 | _ -> Bool3.Undefined in @@ -419,7 +419,7 @@ let rec term_to_exp t res = | TBinOp (binop, t1, t2)-> new_exp ~loc (BinOp(binop, term_to_exp t1 res, term_to_exp t2 res, Cil.intType)) - | TCastE(ty, {term_node = TConst(LReal lreal)}) when Cil.isFloatingType ty -> + | TCast (false, Ctype ty, {term_node = TConst(LReal lreal)}) when Cil.isFloatingType ty -> (match Cil.unrollType ty with | TFloat(fk,_) -> new_exp ~loc @@ -427,10 +427,10 @@ let rec term_to_exp t res = | _ -> Aorai_option.fatal "A floating-point type was expected, got %a." Printer.pp_typ ty) - | TCastE (ty, t) -> new_exp ~loc (CastE (ty, term_to_exp t res)) + | TCast (false, Ctype ty, t) -> new_exp ~loc (CastE (ty, term_to_exp t res)) | TAddrOf tlval -> new_exp ~loc (AddrOf (tlval_to_lval tlval res)) | TStartOf tlval -> new_exp ~loc (StartOf (tlval_to_lval tlval res)) - | TLogic_coerce (_,t) -> term_to_exp t res + | TCast (true, _,t) -> term_to_exp t res | _ -> Aorai_option.fatal "Term %a cannot be transformed into exp." @@ -510,7 +510,7 @@ let get_bhv_aux_fct kf bhv = [Normal, Logic_const.( new_predicate - (prel (Req,tlogic_coerce (tresult ret_typ) Linteger,lone())))] + (prel (Req, tlogic_coerce (tresult ret_typ) Linteger,lone())))] in let bhv_in = Cil.mk_behavior ~name:bhv.b_name ~assumes ~assigns ~post_cond () diff --git a/src/plugins/e-acsl/src/analyses/bound_variables.ml b/src/plugins/e-acsl/src/analyses/bound_variables.ml index 7764bd1d100..7bf460e21c6 100644 --- a/src/plugins/e-acsl/src/analyses/bound_variables.ml +++ b/src/plugins/e-acsl/src/analyses/bound_variables.ml @@ -247,7 +247,7 @@ end = struct let get_bounded_var t ctxt = let rec aux t = match t.term_node with - | TLogic_coerce(_, t) -> aux t + | TCast (true, _, t) -> aux t | TLval(TVar lv, TNoOffset) when Logic_var.Set.mem lv ctxt.bounded_vars -> Some lv | _ -> None @@ -524,7 +524,7 @@ let extract_constraint ctxt t1 r t2 = is not a variable ([TLval(TVar _, TNoOffset)]). *) let rec _get_logic_var_opt t = match t.term_node with - | TLogic_coerce(_, t) -> _get_logic_var_opt t + | TCast (true, _, t) -> _get_logic_var_opt t | TLval(TVar x, TNoOffset) -> Some x | _ -> None in diff --git a/src/plugins/e-acsl/src/analyses/interval.ml b/src/plugins/e-acsl/src/analyses/interval.ml index 79f27b6ae31..679f8530323 100644 --- a/src/plugins/e-acsl/src/analyses/interval.ml +++ b/src/plugins/e-acsl/src/analyses/interval.ml @@ -392,10 +392,12 @@ let rec infer ~force ~logic_env t = let i2 = infer ~force ~logic_env t2 in Error.map2 (lift_arith_binop (ival_arith_binop op)) i1 i2 - | TCastE (ty, t) -> + | TCast (false, Ctype ty, t) -> let src = infer ~force ~logic_env t in let dst = interv_of_typ ty in Error.map (fun src -> cast ~src ~dst) src + | TCast (true, _, t) -> get_res (infer ~force ~logic_env t) + | TCast (false, _,_) -> assert false | Tif (t1, t2, t3) -> ignore (infer ~force ~logic_env t1); let logic_env_tbranch, logic_env_fbranch = @@ -440,7 +442,6 @@ let rec infer ~force ~logic_env t = | TPtr _ -> Lazy.force interv_of_unknown_block | _ -> assert false) | Tnull -> singleton_of_int 0 - | TLogic_coerce (_, t) -> get_res (infer ~force ~logic_env t) | Tapp (li,_,args) -> (match li.l_body with | LBpred _ | LBterm _ -> diff --git a/src/plugins/e-acsl/src/analyses/labels.ml b/src/plugins/e-acsl/src/analyses/labels.ml index 36325279ded..29fe58ee990 100644 --- a/src/plugins/e-acsl/src/analyses/labels.ml +++ b/src/plugins/e-acsl/src/analyses/labels.ml @@ -324,8 +324,8 @@ end = struct do_term ?error env t | TLval lv | TAddrOf lv | TStartOf lv -> do_term_lval ?error env lv - | TSizeOfE t | TAlignOfE t | TUnOp (_, t) | TCastE (_, t) | Tlambda (_, t) - | TLogic_coerce (_, t) -> + | TSizeOfE t | TAlignOfE t | TUnOp (_, t) + | TCast (_, _, t) | Tlambda (_, t) -> do_term ?error env t | TBinOp (_, t1, t2) -> let error = do_term ?error env t1 in diff --git a/src/plugins/e-acsl/src/analyses/memory_tracking.ml b/src/plugins/e-acsl/src/analyses/memory_tracking.ml index e0aacb1c1fe..ccaa156f127 100644 --- a/src/plugins/e-acsl/src/analyses/memory_tracking.ml +++ b/src/plugins/e-acsl/src/analyses/memory_tracking.ml @@ -303,7 +303,7 @@ module rec Transfer and register_term kf varinfos term = match term.term_node with | TLval tlv | TAddrOf tlv | TStartOf tlv -> register_term_lval kf varinfos tlv - | TCastE(_, t) | Tat(t, _) -> + | TCast (_, _, t) | Tat(t, _) -> register_term kf varinfos t | Tlet(li, t) -> if may_alias li then Error.not_yet "let-binding on array or pointer" @@ -339,7 +339,6 @@ module rec Transfer | Tbase_addr _ -> Error.not_yet "\\base_addr" | Toffset _ -> Error.not_yet "\\offset" | Tblock_length _ -> Error.not_yet "\\block_length" - | TLogic_coerce(_, t) -> register_term kf varinfos t | TUpdate _ -> Error.not_yet "functional update" | Ttypeof _ -> Error.not_yet "typeof" | Tempty_set -> Error.not_yet "empty set" @@ -396,10 +395,10 @@ module rec Transfer (* no left-value inside inside: skip for efficiency *) Cil.SkipChildren | TUnOp _ | TBinOp _ | Ttypeof _ | TSizeOfE _ - | TLval _ | TAlignOfE _ | TCastE _ | TAddrOf _ + | TLval _ | TAlignOfE _ | TCast _ | TAddrOf _ | TStartOf _ | Tapp _ | Tlambda _ | TDataCons _ | Tif _ | Tat _ | TUpdate _ | Tunion _ | Tinter _ - | Tcomprehension _ | Trange _ | TLogic_coerce _ -> + | Tcomprehension _ | Trange _ -> (* potential sub-term inside *) Cil.DoChildren method !vlogic_label _ = Cil.SkipChildren diff --git a/src/plugins/e-acsl/src/analyses/typing.ml b/src/plugins/e-acsl/src/analyses/typing.ml index 00650b57443..3dbec883bfe 100644 --- a/src/plugins/e-acsl/src/analyses/typing.ml +++ b/src/plugins/e-acsl/src/analyses/typing.ml @@ -428,7 +428,7 @@ let rec type_term order to lower the number of explicit casts *) let rec cast_first t1 t2 = match t1.term_node with | TLval _ -> false - | TLogic_coerce(_, t) -> cast_first t t2 + | TCast (true, _, t) -> cast_first t t2 | _ -> true in let cast_first = cast_first t1 t2 in @@ -457,7 +457,7 @@ let rec type_term ignore (type_term ~use_gmp_opt:true ~ctx:c_int ~profile t2); ty - | TCastE(_, t') -> + | TCast (false, Ctype _, t') -> (* compute the smallest interval from the whole term [t] *) let i = Interval.get_from_profile ~profile t in (* nothing more to do: [i] is already more precise than what we could @@ -466,6 +466,14 @@ let rec type_term ignore (type_term ~use_gmp_opt:true ~ctx ~profile t'); ctx + | TCast (true, _, t') -> + let i = Interval.get_from_profile ~profile t in + ignore (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t'); + ty_of_interv ~use_gmp_opt i + (* TODO (NB) : Maybe can be merged ? *) + + | TCast (false, _,_) -> assert false + | Tif (t1, t2, t3) -> let ctx1 = mk_ctx ~use_gmp_opt:false c_int (* an int must be generated *) @@ -479,11 +487,6 @@ let rec type_term ignore (type_term ~use_gmp_opt:true ~ctx ~profile t3); ctx - | TLogic_coerce (_, t') -> - let i = Interval.get_from_profile ~profile t in - ignore (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t'); - ty_of_interv ~use_gmp_opt i - | Tat (t, _) -> (type_term ~use_gmp_opt ~arith_operand ?ctx ~profile t).ty @@ -534,7 +537,7 @@ let rec type_term the kernel introduces a coercion to integer, so we will always see integer here.*) begin match x.term_node with - |TLogic_coerce _ -> None + | TCast (true,_,_) -> None |_ -> if Options.Gmp_only.get() then Some Gmpz else None end | Lreal -> Some Real @@ -567,7 +570,7 @@ let rec type_term the kernel introduces a coercion to integer, so we will always see integer here.*) begin match x.term_node with - | TLogic_coerce _ -> None + | TCast (true,_,_) -> None |_ -> if Options.Gmp_only.get() then Some Gmpz else None end | Lreal -> Some Real diff --git a/src/plugins/e-acsl/src/code_generator/translate_terms.ml b/src/plugins/e-acsl/src/code_generator/translate_terms.ml index c025a21d251..c8d95953029 100644 --- a/src/plugins/e-acsl/src/code_generator/translate_terms.ml +++ b/src/plugins/e-acsl/src/code_generator/translate_terms.ml @@ -473,8 +473,7 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t = match t.term_node with | TConst _ -> "cst_" | TLval (TVar { lv_name }, _) -> lv_name ^ "_" - | TCastE (_, t) -> term_to_name t - | TLogic_coerce (_, t) -> term_to_name t + | TCast (_,_, t) -> term_to_name t | _ -> "" in let ctx = Typing.get_number_ty ~logic_env t in @@ -724,7 +723,7 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t = | C_float _ | Rational | Real | Nan -> assert false end - | TCastE(ty, t') -> + | TCast (false, Ctype ty, t') -> let e, adata, env = to_exp ~adata kf env t' in let e, env = Typed_number.add_cast @@ -738,7 +737,8 @@ and context_insensitive_term_to_exp ~adata ?(inplace=false) kf env t = e in e, adata, env, Analyses_types.C_number, "" - | TLogic_coerce (_, t) -> context_insensitive_term_to_exp ~adata kf env t + | TCast (true, _, t) -> context_insensitive_term_to_exp ~adata kf env t + | TCast (false, _,_) -> assert false | TAddrOf lv -> let lv, env, _ = tlval_to_lval kf env lv in let e = Cil.mkAddrOf ~loc lv in diff --git a/src/plugins/eva/legacy/eval_terms.ml b/src/plugins/eva/legacy/eval_terms.ml index 6f7b8fe7f10..709c0be2138 100644 --- a/src/plugins/eva/legacy/eval_terms.ml +++ b/src/plugins/eva/legacy/eval_terms.ml @@ -604,9 +604,9 @@ let pass_logic_cast exn typ trm = let is_same_term_coerce t1 t2 = match t1.term_node, t2.term_node with - | TLogic_coerce _, TLogic_coerce _ -> Logic_utils.is_same_term t1 t2 - | TLogic_coerce (_,t1), _ -> Logic_utils.is_same_term t1 t2 - | _, TLogic_coerce(_,t2) -> Logic_utils.is_same_term t1 t2 + | TCast (true,_,_), TCast (true,_,_) -> Logic_utils.is_same_term t1 t2 + | TCast (true, _,t1), _ -> Logic_utils.is_same_term t1 t2 + | _, TCast (true, _,t2) -> Logic_utils.is_same_term t1 t2 | _ -> Logic_utils.is_same_term t1 t2 (* Constrain the ACSL range [idx] when it is used to access an array of @@ -1142,7 +1142,7 @@ let rec eval_term ~alarm_mode env t = etype = Cil.intType; eunder; eover; empty; } - | TCastE (typ, t) -> + | TCast (false, Ctype typ, t) -> let r = eval_term ~alarm_mode env t in (* See if the cast does something. If not, we can keep eunder as is.*) if is_noop_cast ~src_typ:t.term_type ~dst_typ:typ @@ -1153,6 +1153,36 @@ let rec eval_term ~alarm_mode env t = let eover = cast ~src_typ:r.etype ~dst_typ:typ r.eover in { etype = typ; ldeps = r.ldeps; eunder = under_from_over eover; eover; empty = r.empty; } + | TCast (false, _,_) -> assert false + + | TCast (true, ltyp, t) -> + let r = eval_term ~alarm_mode env t in + (* we must handle coercion from singleton to set, for which there is + nothing to do, AND coercion from an integer type to a floating-point + type, that require a conversion. *) + (match Logic_const.plain_or_set Fun.id ltyp with + | Linteger when Logic_typing.is_integral_type t.term_type + || Logic_const.is_boolean_type t.term_type -> r + | Ctype typ when Cil.isIntegralOrPointerType typ -> r + | Lreal -> + let eover = + if Logic_typing.is_integral_type t.term_type + then V.cast_int_to_float Fval.Real r.eover + else V.cast_float_to_float Fval.Real r.eover + in + { etype = Cil.longDoubleType; (* hack until logic type *) + ldeps = r.ldeps; + eover; eunder = under_from_over eover; + empty = r.empty } + | _ -> + if Logic_const.is_boolean_type ltyp + && Logic_typing.is_integral_type t.term_type + then cast_to_bool r + else + unsupported + (Format.asprintf "logic coercion %a -> %a@." + Printer.pp_logic_type t.term_type Printer.pp_logic_type ltyp) + ) | Tif (tcond, ttrue, tfalse) -> eval_tif eval_term Cvalue.V.join Cvalue.V.meet ~alarm_mode env @@ -1193,35 +1223,6 @@ let rec eval_term ~alarm_mode env t = eover = Cvalue.V.singleton_zero; empty = false; } - | TLogic_coerce(ltyp, t) -> - let r = eval_term ~alarm_mode env t in - (* we must handle coercion from singleton to set, for which there is - nothing to do, AND coercion from an integer type to a floating-point - type, that require a conversion. *) - (match Logic_const.plain_or_set Fun.id ltyp with - | Linteger when Logic_typing.is_integral_type t.term_type - || Logic_const.is_boolean_type t.term_type -> r - | Ctype typ when Cil.isIntegralOrPointerType typ -> r - | Lreal -> - let eover = - if Logic_typing.is_integral_type t.term_type - then V.cast_int_to_float Fval.Real r.eover - else V.cast_float_to_float Fval.Real r.eover - in - { etype = Cil.longDoubleType; (* hack until logic type *) - ldeps = r.ldeps; - eover; eunder = under_from_over eover; - empty = r.empty } - | _ -> - if Logic_const.is_boolean_type ltyp - && Logic_typing.is_integral_type t.term_type - then cast_to_bool r - else - unsupported - (Format.asprintf "logic coercion %a -> %a@." - Printer.pp_logic_type t.term_type Printer.pp_logic_type ltyp) - ) - (* TODO: the meaning of the label in \offset and \base_addr is not obvious at all *) | Toffset (_lbl, t) -> @@ -1781,7 +1782,7 @@ and eval_term_as_lval ~alarm_mode env t = | Tat (t, lab) -> ignore (env_state env lab); eval_term_as_lval ~alarm_mode { env with e_cur = lab } t - | TLogic_coerce (_lt, t) -> + | TCast (true, _lt, t) -> (* Logic coerce on locations (that are pointers) can only introduce sets, that do not change the abstract value. *) eval_term_as_lval ~alarm_mode env t @@ -1816,7 +1817,7 @@ and eval_term_as_exact_locs ~alarm_mode env t = if Locations.is_bottom_loc loc then raise Not_an_exact_loc; Location (typ, loc) - | TLogic_coerce (Lreal, t) -> begin + | TCast (true, Lreal, t) -> begin match eval_term_as_exact_locs ~alarm_mode env t with | Logic_var _ as x -> x | Location (_, locs) as r -> @@ -1841,13 +1842,13 @@ and eval_term_as_exact_locs ~alarm_mode env t = r end - | TLogic_coerce (_, t) -> - (* Otherwise it is always ok to pass through a TLogic_coerce, as the destination + | TCast (true, _, t) -> + (* Otherwise it is always ok to pass through a TCast (true,_,_), as the destination type is always a supertype *) eval_term_as_exact_locs ~alarm_mode env t - | TCastE (ctype, t') -> - pass_logic_cast Not_an_exact_loc (Ctype ctype) t'; + | TCast (false, ctype, t') -> + pass_logic_cast Not_an_exact_loc ctype t'; eval_term_as_exact_locs ~alarm_mode env t' | Tunion [t] -> @@ -1947,7 +1948,7 @@ and reduce_by_valid env positive access (tset: term) = | TLval tlval -> aux_lval tlval env - | TCastE (typ, {term_node = TLval tlval}) -> aux_lval ~typ tlval env + | TCast (false, Ctype typ, {term_node = TLval tlval}) -> aux_lval ~typ tlval env | TAddrOf (TMem {term_node = TLval tlval}, offs) -> (try diff --git a/src/plugins/wp/LogicSemantics.ml b/src/plugins/wp/LogicSemantics.ml index 96baad2451d..cad0d5b3b93 100644 --- a/src/plugins/wp/LogicSemantics.ml +++ b/src/plugins/wp/LogicSemantics.ml @@ -672,8 +672,7 @@ struct | TUnOp(unop,t) -> term_unop unop (C.logic env t) | TBinOp(binop,a,b) -> term_binop env binop a b - | TCastE(ty,t) -> term_cast_to_ctype env ty t - | TLogic_coerce(typ,t) -> term_cast_to_ltype env typ t + | TCast (_, typ,t) -> term_cast_to_ltype env typ t | Tapp(f,ls,ts) -> let vs = List.map (val_of_term env) ts in @@ -941,8 +940,7 @@ struct Warning.error "Complex let-binding not implemented yet (%a)" Printer.pp_term t - | TCastE (_,t) - | TLogic_coerce(_,t) -> C.region env t + | TCast (_,_,t) -> C.region env t | TBinOp _ | TUnOp _ | Trange _ | TUpdate _ | Tapp _ | Tif _ | TConst _ | Tnull | TDataCons _ | Tlambda _ diff --git a/src/plugins/wp/MemoryContext.ml b/src/plugins/wp/MemoryContext.ml index 3412bfc6824..5840be85cb8 100644 --- a/src/plugins/wp/MemoryContext.ml +++ b/src/plugins/wp/MemoryContext.ml @@ -122,7 +122,7 @@ let rec addr_of_lval ?loc term = match term.term_node with | TLval lv -> Logic_utils.mk_logic_AddrOf ?loc lv typ - | TCastE (_, t) | TLogic_coerce (_, t) -> + | TCast (_,_, t) -> addr_of_lval ?loc t | Tif(c, t, e) -> let t = addr_of_lval ?loc t in @@ -320,7 +320,7 @@ let assigned_via_pointers kf = match t.term_node with | TLval (TMem _, _) -> true - | TCastE (_, t) | TLogic_coerce (_, t) + | TCast (_,_, t) | Tcomprehension(t, _, _) | Tat (t, _) -> assigned_via_pointer t | Tunion l | Tinter l -> diff --git a/src/plugins/wp/RefUsage.ml b/src/plugins/wp/RefUsage.ml index 958a36bfde7..13e0908d44a 100644 --- a/src/plugins/wp/RefUsage.ml +++ b/src/plugins/wp/RefUsage.ml @@ -419,8 +419,9 @@ and term (env:ctx) (t:term) : model = match t.term_node with | TBinOp((PlusPI|MinusPI),a,b) -> shift (term env a) (vterm env b) (* Casts *) - | TCastE(ty_tgt,t) -> cast (cast_ltyp ty_tgt t.term_type) (term env t) - | TLogic_coerce (_lt,t) -> term env t + | TCast (false, Ctype ty_tgt,t) -> cast (cast_ltyp ty_tgt t.term_type) (term env t) + | TCast (true, _lt,t) -> term env t + | TCast (false, _, _) -> assert false (* Term L-Values *) diff --git a/src/plugins/wp/RegionAccess.ml b/src/plugins/wp/RegionAccess.ml index f96af2972fd..4d1da962951 100644 --- a/src/plugins/wp/RegionAccess.ml +++ b/src/plugins/wp/RegionAccess.ml @@ -270,9 +270,9 @@ and cc_term_value (map:map) (term:term) = | Tat(t,_) -> cc_term_value map t - | TCastE(ty,t) -> cast ty @@ cc_term_value map t - | TLogic_coerce (Ctype ty,t) -> cast ty @@ cc_term_value map t - | TLogic_coerce (_,t) -> cc_term_value map t + | TCast (_, Ctype ty,t) -> cast ty @@ cc_term_value map t + | TCast (true, _,t) -> cc_term_value map t + | TCast (false, _,_) -> assert false | TConst _ | TSizeOf _ | TSizeOfE _ | TSizeOfStr _ diff --git a/src/plugins/wp/wpPropId.ml b/src/plugins/wp/wpPropId.ml index c025c2b8279..2cce251f7c3 100644 --- a/src/plugins/wp/wpPropId.ml +++ b/src/plugins/wp/wpPropId.ml @@ -622,7 +622,7 @@ let rec term_hints hs t = match t.term_node with | TLval(lv,_) -> lval_hints hs lv | TAddrOf(lv,_) -> lval_hints hs lv - | TCastE(_,t) -> term_hints hs t + | TCast (false, Ctype _,t) -> term_hints hs t | TBinOp((PlusPI|MinusPI),a,_) -> term_hints hs a | Tlet(_,t) -> term_hints hs t | _ -> () diff --git a/tests/libc/check_const.ml b/tests/libc/check_const.ml index 6996d5ed032..8a38a17b5c1 100644 --- a/tests/libc/check_const.ml +++ b/tests/libc/check_const.ml @@ -48,7 +48,7 @@ let check_annot kf _ (a: identified_predicate) = end | TBinOp ((PlusPI | MinusPI), ({term_node = TLval (TVar lvi, _)} | - {term_node = TCastE (_, {term_node = TLval (TVar lvi, _)})}), + {term_node = TCast (false,_, {term_node = TLval (TVar lvi, _)})}), _) | TLval (TVar lvi, _) -> begin match lvi.lv_origin with -- GitLab