|
|
|
(*
|
|
|
|
* Copyright (c) 2013 - present Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*)
|
|
|
|
|
|
|
|
(** Utility module for translating unary and binary operations and compound assignments *)
|
|
|
|
|
|
|
|
open! IStd
|
|
|
|
module L = Logging
|
|
|
|
|
|
|
|
(* Returns the translation of assignment when ARC mode is enabled in Obj-C *)
|
|
|
|
(* For __weak and __unsafe_unretained the translation is the same as non-ARC *)
|
|
|
|
(* (this is because, in these cases, there is no change in the reference counter *)
|
|
|
|
(* of the pointee).*)
|
|
|
|
(* The difference is when the lvalue is a __strong or __autoreleasing. In those*)
|
|
|
|
(* case we need to add proper retain/release.*)
|
|
|
|
(* See document: "Objective-C Automatic Reference Counting" describing the semantics *)
|
|
|
|
let assignment_arc_mode e1 typ e2 loc rhs_owning_method is_e1_decl =
|
|
|
|
let assign = Sil.Store (e1, typ, e2, loc) in
|
|
|
|
let retain_pname = BuiltinDecl.__objc_retain in
|
|
|
|
let release_pname = BuiltinDecl.__objc_release in
|
|
|
|
let autorelease_pname = BuiltinDecl.__set_autorelease_attribute in
|
|
|
|
let mk_call procname e t =
|
|
|
|
let bi_retain = Exp.Const (Const.Cfun procname) in
|
|
|
|
Sil.Call (None, bi_retain, [(e, t)], loc, CallFlags.default)
|
|
|
|
in
|
|
|
|
match typ.Typ.desc with
|
|
|
|
| Typ.Tptr (_, Typ.Pk_pointer) when not rhs_owning_method && not is_e1_decl
|
|
|
|
-> (* for __strong e1 = e2 the semantics is*)
|
|
|
|
(* retain(e2); tmp=e1; e1=e2; release(tmp); *)
|
|
|
|
let retain = mk_call retain_pname e2 typ in
|
|
|
|
let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let tmp_assign = Sil.Load (id, e1, typ, loc) in
|
|
|
|
let release = mk_call release_pname (Exp.Var id) typ in
|
|
|
|
(e1, [retain; tmp_assign; assign; release])
|
|
|
|
| Typ.Tptr (_, Typ.Pk_pointer) when not rhs_owning_method && is_e1_decl
|
|
|
|
-> (* for A __strong *e1 = e2 the semantics is*)
|
|
|
|
(* retain(e2); e1=e2; *)
|
|
|
|
let retain = mk_call retain_pname e2 typ in
|
|
|
|
(e1, [retain; assign])
|
|
|
|
| Typ.Tptr (_, Typ.Pk_objc_weak) | Typ.Tptr (_, Typ.Pk_objc_unsafe_unretained)
|
|
|
|
-> (e1, [assign])
|
|
|
|
| Typ.Tptr (_, Typ.Pk_objc_autoreleasing)
|
|
|
|
-> (* for __autoreleasing e1 = e2 the semantics is*)
|
|
|
|
(* retain(e2); autorelease(e2); e1=e2; *)
|
|
|
|
let retain = mk_call retain_pname e2 typ in
|
|
|
|
let autorelease = mk_call autorelease_pname e2 typ in
|
|
|
|
(e1, [retain; autorelease; assign])
|
|
|
|
| _
|
|
|
|
-> (e1, [assign])
|
|
|
|
|
|
|
|
(* Returns a pair ([binary_expression], instructions) for binary operator representing a *)
|
|
|
|
(* CompoundAssignment. "binary_expression" is returned when we are calculating an expression*)
|
|
|
|
(* "instructions" is not empty when the binary operator is actually a statement like an *)
|
|
|
|
(* assignment. *)
|
|
|
|
let compound_assignment_binary_operation_instruction boi e1 typ e2 loc =
|
|
|
|
let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let instr1 = Sil.Load (id, e1, typ, loc) in
|
|
|
|
let e_res, instr_op =
|
|
|
|
match boi.Clang_ast_t.boi_kind with
|
|
|
|
| `AddAssign
|
|
|
|
-> let e1_plus_e2 = Exp.BinOp (Binop.PlusA, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_plus_e2, loc)])
|
|
|
|
| `SubAssign
|
|
|
|
-> let e1_sub_e2 = Exp.BinOp (Binop.MinusA, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_sub_e2, loc)])
|
|
|
|
| `MulAssign
|
|
|
|
-> let e1_mul_e2 = Exp.BinOp (Binop.Mult, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_mul_e2, loc)])
|
|
|
|
| `DivAssign
|
|
|
|
-> let e1_div_e2 = Exp.BinOp (Binop.Div, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_div_e2, loc)])
|
|
|
|
| `ShlAssign
|
|
|
|
-> let e1_shl_e2 = Exp.BinOp (Binop.Shiftlt, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_shl_e2, loc)])
|
|
|
|
| `ShrAssign
|
|
|
|
-> let e1_shr_e2 = Exp.BinOp (Binop.Shiftrt, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_shr_e2, loc)])
|
|
|
|
| `RemAssign
|
|
|
|
-> let e1_mod_e2 = Exp.BinOp (Binop.Mod, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_mod_e2, loc)])
|
|
|
|
| `AndAssign
|
|
|
|
-> let e1_and_e2 = Exp.BinOp (Binop.BAnd, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_and_e2, loc)])
|
|
|
|
| `OrAssign
|
|
|
|
-> let e1_or_e2 = Exp.BinOp (Binop.BOr, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_or_e2, loc)])
|
|
|
|
| `XorAssign
|
|
|
|
-> let e1_xor_e2 = Exp.BinOp (Binop.BXor, Exp.Var id, e2) in
|
|
|
|
(e1, [Sil.Store (e1, typ, e1_xor_e2, loc)])
|
|
|
|
| _
|
|
|
|
-> assert false
|
|
|
|
in
|
|
|
|
(e_res, instr1 :: instr_op)
|
|
|
|
|
|
|
|
(* Returns a pair ([binary_expression], instructions). "binary_expression" *)
|
|
|
|
(* is returned when we are calculating an expression "instructions" is not *)
|
|
|
|
(* empty when the binary operator is actually a statement like an *)
|
|
|
|
(* assignment. *)
|
|
|
|
let binary_operation_instruction boi e1 typ e2 loc rhs_owning_method =
|
|
|
|
let binop_exp op = Exp.BinOp (op, e1, e2) in
|
|
|
|
match boi.Clang_ast_t.boi_kind with
|
|
|
|
| `Add
|
|
|
|
-> (binop_exp Binop.PlusA, [])
|
|
|
|
| `Mul
|
|
|
|
-> (binop_exp Binop.Mult, [])
|
|
|
|
| `Div
|
|
|
|
-> (binop_exp Binop.Div, [])
|
|
|
|
| `Rem
|
|
|
|
-> (binop_exp Binop.Mod, [])
|
|
|
|
| `Sub
|
|
|
|
-> (binop_exp Binop.MinusA, [])
|
|
|
|
| `Shl
|
|
|
|
-> (binop_exp Binop.Shiftlt, [])
|
|
|
|
| `Shr
|
|
|
|
-> (binop_exp Binop.Shiftrt, [])
|
|
|
|
| `Or
|
|
|
|
-> (binop_exp Binop.BOr, [])
|
|
|
|
| `And
|
|
|
|
-> (binop_exp Binop.BAnd, [])
|
|
|
|
| `Xor
|
|
|
|
-> (binop_exp Binop.BXor, [])
|
|
|
|
| `LT
|
|
|
|
-> (binop_exp Binop.Lt, [])
|
|
|
|
| `GT
|
|
|
|
-> (binop_exp Binop.Gt, [])
|
|
|
|
| `LE
|
|
|
|
-> (binop_exp Binop.Le, [])
|
|
|
|
| `GE
|
|
|
|
-> (binop_exp Binop.Ge, [])
|
|
|
|
| `NE
|
|
|
|
-> (binop_exp Binop.Ne, [])
|
|
|
|
| `EQ
|
|
|
|
-> (binop_exp Binop.Eq, [])
|
|
|
|
| `LAnd
|
|
|
|
-> (binop_exp Binop.LAnd, [])
|
|
|
|
| `LOr
|
|
|
|
-> (binop_exp Binop.LOr, [])
|
|
|
|
| `Assign
|
|
|
|
-> if !Config.arc_mode && ObjcInterface_decl.is_pointer_to_objc_class typ then
|
|
|
|
assignment_arc_mode e1 typ e2 loc rhs_owning_method false
|
|
|
|
else (e1, [Sil.Store (e1, typ, e2, loc)])
|
|
|
|
| `Comma
|
|
|
|
-> (e2, []) (* C99 6.5.17-2 *)
|
|
|
|
| `MulAssign
|
|
|
|
| `DivAssign
|
|
|
|
| `RemAssign
|
|
|
|
| `AddAssign
|
|
|
|
| `SubAssign
|
|
|
|
| `ShlAssign
|
|
|
|
| `ShrAssign
|
|
|
|
| `AndAssign
|
|
|
|
| `XorAssign
|
|
|
|
| `OrAssign
|
|
|
|
-> compound_assignment_binary_operation_instruction boi e1 typ e2 loc
|
|
|
|
(* We should not get here. *)
|
|
|
|
(* These should be treated by compound_assignment_binary_operation_instruction*)
|
|
|
|
| bok
|
|
|
|
-> L.(debug Capture Medium)
|
|
|
|
"@\nWARNING: Missing translation for Binary Operator Kind %s. Construct ignored...@\n"
|
|
|
|
(Clang_ast_j.string_of_binary_operator_kind bok) ;
|
|
|
|
(Exp.minus_one, [])
|
|
|
|
|
|
|
|
let unary_operation_instruction translation_unit_context uoi e typ loc =
|
|
|
|
let un_exp op = Exp.UnOp (op, e, Some typ) in
|
|
|
|
match uoi.Clang_ast_t.uoi_kind with
|
|
|
|
| `PostInc
|
|
|
|
-> let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let instr1 = Sil.Load (id, e, typ, loc) in
|
|
|
|
let e_plus_1 = Exp.BinOp (Binop.PlusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
|
|
|
|
(Exp.Var id, [instr1; Sil.Store (e, typ, e_plus_1, loc)])
|
|
|
|
| `PreInc
|
|
|
|
-> let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let instr1 = Sil.Load (id, e, typ, loc) in
|
|
|
|
let e_plus_1 = Exp.BinOp (Binop.PlusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
|
|
|
|
let exp =
|
|
|
|
if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_plus_1
|
|
|
|
in
|
|
|
|
(exp, [instr1; Sil.Store (e, typ, e_plus_1, loc)])
|
|
|
|
| `PostDec
|
|
|
|
-> let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let instr1 = Sil.Load (id, e, typ, loc) in
|
|
|
|
let e_minus_1 = Exp.BinOp (Binop.MinusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
|
|
|
|
(Exp.Var id, [instr1; Sil.Store (e, typ, e_minus_1, loc)])
|
|
|
|
| `PreDec
|
|
|
|
-> let id = Ident.create_fresh Ident.knormal in
|
|
|
|
let instr1 = Sil.Load (id, e, typ, loc) in
|
|
|
|
let e_minus_1 = Exp.BinOp (Binop.MinusA, Exp.Var id, Exp.Const (Const.Cint IntLit.one)) in
|
|
|
|
let exp =
|
|
|
|
if CGeneral_utils.is_cpp_translation translation_unit_context then e else e_minus_1
|
|
|
|
in
|
|
|
|
(exp, [instr1; Sil.Store (e, typ, e_minus_1, loc)])
|
|
|
|
| `Not
|
|
|
|
-> (un_exp Unop.BNot, [])
|
|
|
|
| `Minus
|
|
|
|
-> (un_exp Unop.Neg, [])
|
|
|
|
| `Plus
|
|
|
|
-> (e, [])
|
|
|
|
| `LNot
|
|
|
|
-> (un_exp Unop.LNot, [])
|
|
|
|
| `Deref
|
|
|
|
-> (* Actual dereferencing is handled by implicit cast from rvalue to lvalue *)
|
|
|
|
(e, [])
|
|
|
|
| `AddrOf
|
|
|
|
-> (e, [])
|
|
|
|
| `Real | `Imag | `Extension | `Coawait
|
|
|
|
-> let uok = Clang_ast_j.string_of_unary_operator_kind uoi.Clang_ast_t.uoi_kind in
|
|
|
|
L.(debug Capture Medium)
|
|
|
|
"@\nWARNING: Missing translation for Unary Operator Kind %s. The construct has been ignored...@\n"
|
|
|
|
uok ;
|
|
|
|
(e, [])
|
|
|
|
|
|
|
|
let bin_op_to_string boi =
|
|
|
|
match boi.Clang_ast_t.boi_kind with
|
|
|
|
| `PtrMemD
|
|
|
|
-> "PtrMemD"
|
|
|
|
| `PtrMemI
|
|
|
|
-> "PtrMemI"
|
|
|
|
| `Mul
|
|
|
|
-> "Mul"
|
|
|
|
| `Div
|
|
|
|
-> "Div"
|
|
|
|
| `Rem
|
|
|
|
-> "Rem"
|
|
|
|
| `Add
|
|
|
|
-> "Add"
|
|
|
|
| `Sub
|
|
|
|
-> "Sub"
|
|
|
|
| `Shl
|
|
|
|
-> "Shl"
|
|
|
|
| `Shr
|
|
|
|
-> "Shr"
|
|
|
|
| `LT
|
|
|
|
-> "LT"
|
|
|
|
| `GT
|
|
|
|
-> "GT"
|
|
|
|
| `LE
|
|
|
|
-> "LE"
|
|
|
|
| `GE
|
|
|
|
-> "GE"
|
|
|
|
| `EQ
|
|
|
|
-> "EQ"
|
|
|
|
| `NE
|
|
|
|
-> "NE"
|
|
|
|
| `And
|
|
|
|
-> "And"
|
|
|
|
| `Xor
|
|
|
|
-> "Xor"
|
|
|
|
| `Or
|
|
|
|
-> "Or"
|
|
|
|
| `LAnd
|
|
|
|
-> "LAnd"
|
|
|
|
| `LOr
|
|
|
|
-> "LOr"
|
|
|
|
| `Assign
|
|
|
|
-> "Assign"
|
|
|
|
| `MulAssign
|
|
|
|
-> "MulAssign"
|
|
|
|
| `DivAssign
|
|
|
|
-> "DivAssign"
|
|
|
|
| `RemAssign
|
|
|
|
-> "RemAssing"
|
|
|
|
| `AddAssign
|
|
|
|
-> "AddAssign"
|
|
|
|
| `SubAssign
|
|
|
|
-> "SubAssign"
|
|
|
|
| `ShlAssign
|
|
|
|
-> "ShlAssign"
|
|
|
|
| `ShrAssign
|
|
|
|
-> "ShrAssign"
|
|
|
|
| `AndAssign
|
|
|
|
-> "AndAssign"
|
|
|
|
| `XorAssign
|
|
|
|
-> "XorAssign"
|
|
|
|
| `OrAssign
|
|
|
|
-> "OrAssign"
|
|
|
|
| `Comma
|
|
|
|
-> "Comma"
|
|
|
|
|
|
|
|
let sil_const_plus_one const =
|
|
|
|
match const with
|
|
|
|
| Exp.Const Const.Cint n
|
|
|
|
-> Exp.Const (Const.Cint (IntLit.add n IntLit.one))
|
|
|
|
| _
|
|
|
|
-> Exp.BinOp (Binop.PlusA, const, Exp.Const (Const.Cint IntLit.one))
|