From ab427fd3f3216832f095b944c46d86266e032f8b Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Mon, 17 Jun 2019 03:55:12 -0700 Subject: [PATCH] [clang] cache of names of C++ temporaries Summary: Needed for next diff: we'll need to do 2 passes on the AST to collect the temporaries to destroy at the end of an `ExprWithCleanups`, but the SIL names of these temporaries are generated freshly on the fly so they would get different names if we do it naively. This adds a hashmap to the translation context so the temporary corresponding to a given `MaterializeTemporyExpr` is only generated once and then reused. Reviewed By: mbouaziz Differential Revision: D15674212 fbshipit-source-id: 0e16062d9 --- infer/src/clang/cContext.ml | 15 +++++-------- infer/src/clang/cContext.mli | 11 +++++---- infer/src/clang/cTrans.ml | 42 +++++++++++++---------------------- infer/src/clang/cVar_decl.ml | 24 ++++++++++++++++++++ infer/src/clang/cVar_decl.mli | 8 +++++++ 5 files changed, 58 insertions(+), 42 deletions(-) diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index 85db4415d..ef3780cd4 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -7,16 +7,9 @@ open! IStd module Hashtbl = Caml.Hashtbl - -(** Contains current class and current method to be translated as well as local variables, *) - -(** and the cg, cfg, and tenv corresponding to the current file. *) - module StmtMap = ClangPointers.Map -type pointer = int [@@deriving compare] - -(* = Clang_ast_t.pointer *) +type pointer = (* = Clang_ast_t.pointer *) int [@@deriving compare] type curr_class = ContextClsDeclPtr of pointer | ContextNoCls [@@deriving compare] @@ -32,7 +25,8 @@ type t = ; outer_context: t option ; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t ; label_map: str_node_map - ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t } + ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t + ; temporary_names: (Clang_ast_t.pointer, Pvar.t * Typ.t) Hashtbl.t } let create_context translation_unit_context tenv cfg procdesc immediate_curr_class return_param_typ outer_context vars_to_destroy = @@ -45,7 +39,8 @@ let create_context translation_unit_context tenv cfg procdesc immediate_curr_cla ; outer_context ; blocks_static_vars= Typ.Procname.Map.empty ; label_map= Hashtbl.create 17 - ; vars_to_destroy } + ; vars_to_destroy + ; temporary_names= Hashtbl.create 0 } let rec is_objc_method context = diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index 829923096..86727370f 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -7,9 +7,8 @@ open! IStd -(** Contains current class and current method to be translated as well as local variables, *) - -(** and the cg, cfg, and tenv corresponding to the current file. *) +(** Contains current class and current method to be translated as well as local variables, + and the cfg, and tenv corresponding to the current file. *) module StmtMap = ClangPointers.Map @@ -29,9 +28,9 @@ type t = ; mutable blocks_static_vars: (Pvar.t * Typ.t) list Typ.Procname.Map.t ; label_map: str_node_map ; vars_to_destroy: Clang_ast_t.decl list StmtMap.t - (** mapping from a statement to a list of variables, that go out of scope after the end of the - statement *) - } + (** mapping from a statement to a list of variables, that go out of scope after the end of + the statement *) + ; temporary_names: (Clang_ast_t.pointer, Pvar.t * Typ.t) Caml.Hashtbl.t } val get_curr_class : t -> curr_class diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 32255632d..08b84fad1 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -195,21 +195,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s Ident.NameGenerator.set_current ident_state - let mk_temp_sil_var procdesc var_name_suffix = - let procname = Procdesc.get_proc_name procdesc in - Pvar.mk_tmp var_name_suffix procname - - - let mk_temp_sil_var_for_expr tenv procdesc var_name_prefix expr_info = - let qual_type = expr_info.Clang_ast_t.ei_qual_type in - let typ = CType_decl.qual_type_to_sil_type tenv qual_type in - (mk_temp_sil_var procdesc var_name_prefix, typ) - - - let create_var_exp_tmp_var trans_state expr_info var_name = + let create_var_exp_tmp_var trans_state expr_info ~clang_pointer ~var_name = let context = trans_state.context in let procdesc = context.CContext.procdesc in - let pvar, typ = mk_temp_sil_var_for_expr context.CContext.tenv procdesc var_name expr_info in + let pvar, typ = + CVar_decl.mk_temp_sil_var_for_expr context ~name:var_name ~clang_pointer expr_info + in let var_data = ProcAttributes.{name= Pvar.get_name pvar; typ; modify_in_block= false; is_constexpr= false} in @@ -246,7 +237,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s exp | _ -> let procdesc = trans_state.context.CContext.procdesc in - let pvar = mk_temp_sil_var procdesc "__temp_return_" in + let pvar = CVar_decl.mk_temp_sil_var procdesc ~name:"__temp_return_" in let var_data : ProcAttributes.var_data = { name= Pvar.get_name pvar ; typ= return_type @@ -1541,7 +1532,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s Procdesc.Node.Join_node [] in Procdesc.node_set_succs_exn context.procdesc join_node succ_nodes [] ; - let pvar = mk_temp_sil_var procdesc "SIL_temp_conditional___" in + let pvar = CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_temp_conditional___" in let var_data = ProcAttributes. {name= Pvar.get_name pvar; typ= var_typ; modify_in_block= false; is_constexpr= false} @@ -2204,7 +2195,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | Some var_exp_typ -> var_exp_typ | None -> - create_var_exp_tmp_var trans_state expr_info "SIL_init_list__" + create_var_exp_tmp_var trans_state expr_info ~var_name:"SIL_init_list__" + ~clang_pointer:stmt_info.Clang_ast_t.si_pointer in if List.is_empty stmts then (* perform zero initialization of a primitive type, record types will have @@ -2985,12 +2977,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s and materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info = let context = trans_state.context in let procdesc = context.CContext.procdesc in - (* typ_tmp is 'best guess' type of variable - translation may decide to use different type - later *) - let pvar, typ_tmp = - mk_temp_sil_var_for_expr context.CContext.tenv procdesc Pvar.materialized_cpp_temporary - expr_info - in + let pvar, typ_tmp = CVar_decl.materialize_cpp_temporary context stmt_info expr_info in let temp_exp = match stmt_list with [p] -> p | _ -> assert false in let var_exp_typ = (Exp.Lvar pvar, typ_tmp) in let res_trans = init_expr_trans trans_state var_exp_typ stmt_info (Some temp_exp) in @@ -3002,11 +2989,14 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s res_trans - and compoundLiteralExpr_trans trans_state stmt_list expr_info = + and compoundLiteralExpr_trans trans_state stmt_list stmt_info expr_info = let stmt = match stmt_list with [stmt] -> stmt | _ -> assert false in let var_exp_typ = if Option.is_some trans_state.var_exp_typ then trans_state.var_exp_typ - else Some (create_var_exp_tmp_var trans_state expr_info "SIL_compound_literal__") + else + Some + (create_var_exp_tmp_var trans_state expr_info ~var_name:"SIL_compound_literal__" + ~clang_pointer:stmt_info.Clang_ast_t.si_pointer) in let trans_state' = {trans_state with var_exp_typ} in instruction trans_state' stmt @@ -3523,8 +3513,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s cxxDeleteExpr_trans trans_state stmt_info stmt_list delete_expr_info | MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) -> materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info - | CompoundLiteralExpr (_, stmt_list, expr_info) -> - compoundLiteralExpr_trans trans_state stmt_list expr_info + | CompoundLiteralExpr (stmt_info, stmt_list, expr_info) -> + compoundLiteralExpr_trans trans_state stmt_list stmt_info expr_info | InitListExpr (stmt_info, stmts, expr_info) -> initListExpr_trans trans_state stmt_info expr_info stmts | CXXBindTemporaryExpr ({Clang_ast_t.si_source_range}, stmt_list, _, _) -> diff --git a/infer/src/clang/cVar_decl.ml b/infer/src/clang/cVar_decl.ml index 4985ef088..cd54e5cb7 100644 --- a/infer/src/clang/cVar_decl.ml +++ b/infer/src/clang/cVar_decl.ml @@ -118,3 +118,27 @@ let captured_vars_from_block_info context source_range captured_vars = List.map ~f:(fun cv -> Option.value_exn cv.Clang_ast_t.bcv_variable) captured_vars in List.filter_map ~f:(sil_var_of_captured_var context source_range procname) cv_decl_ref_list + + +let mk_temp_sil_var procdesc ~name = + let procname = Procdesc.get_proc_name procdesc in + Pvar.mk_tmp name procname + + +let mk_temp_sil_var_for_expr context ~name ~clang_pointer expr_info = + match Caml.Hashtbl.find_opt context.CContext.temporary_names clang_pointer with + | Some pvar_typ -> + pvar_typ + | None -> + let qual_type = expr_info.Clang_ast_t.ei_qual_type in + let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in + let pvar_typ = (mk_temp_sil_var context.CContext.procdesc ~name, typ) in + Caml.Hashtbl.add context.CContext.temporary_names clang_pointer pvar_typ ; + pvar_typ + + +let materialize_cpp_temporary context stmt_info expr_info = + (* the type we get here is a 'best effort' type - the translation may decide to use different type + later *) + mk_temp_sil_var_for_expr context ~name:Pvar.materialized_cpp_temporary + ~clang_pointer:stmt_info.Clang_ast_t.si_pointer expr_info diff --git a/infer/src/clang/cVar_decl.mli b/infer/src/clang/cVar_decl.mli index b2c674fac..739ffae2e 100644 --- a/infer/src/clang/cVar_decl.mli +++ b/infer/src/clang/cVar_decl.mli @@ -30,3 +30,11 @@ val captured_vars_from_block_info : -> Clang_ast_t.source_range -> Clang_ast_t.block_captured_variable list -> (Pvar.t * Typ.t) list + +val mk_temp_sil_var : Procdesc.t -> name:string -> Pvar.t + +val mk_temp_sil_var_for_expr : + CContext.t -> name:string -> clang_pointer:int -> Clang_ast_t.expr_info -> Pvar.t * Typ.t + +val materialize_cpp_temporary : + CContext.t -> Clang_ast_t.stmt_info -> Clang_ast_t.expr_info -> Pvar.t * Typ.t