From 9366e8dbc8c6ed6cfbe87e6997e413ac7c99f729 Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Mon, 12 Feb 2018 11:28:32 -0800 Subject: [PATCH] [clang] add id -> pvar bindings to C++ lambda capture Summary: In Obj-C blocks, we explicitly insert reads of the captured vars. This does the same thing for C++. For example, `foo() { int x = 1; [x]() { return x; } }` would previously not contain a read of `x` in `foo`. Now, we'll create a temporary that reads from `x` and pass it to the closure value. Reviewed By: dulmarod Differential Revision: D6939997 fbshipit-source-id: f218afc --- infer/src/clang/cTrans.ml | 71 +++++++++++-------- .../cpp/shared/lambda/lambda1.cpp.dot | 12 ++-- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 1032b4912..93889543b 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -266,6 +266,27 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s {empty_res_trans with instrs= [call_instr']; exps= ret_exps; initd_exps} + (* Given a captured var, return the instruction to assign it to a temp *) + let assign_captured_var loc (cvar, typ) = + let id = Ident.create_fresh Ident.knormal in + let instr = Sil.Load (id, Exp.Lvar cvar, typ, loc) in + (id, instr) + + + let closure_trans closure_pname captured_vars context stmt_info expr_info = + let loc = CLocation.get_sil_location stmt_info context in + let open CContext in + let qual_type = expr_info.Clang_ast_t.ei_qual_type in + let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in + let ids_instrs = List.map ~f:(assign_captured_var loc) captured_vars in + let ids, instrs = List.unzip ids_instrs in + let captured_vars = + List.map2_exn ~f:(fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captured_vars + in + let closure = Exp.Closure {name= closure_pname; captured_vars} in + {empty_res_trans with instrs; exps= [(closure, typ)]} + + let stringLiteral_trans trans_state expr_info str = let typ = CType_decl.get_type_from_expr_info expr_info trans_state.context.CContext.tenv in let exp = Exp.Const (Const.Cstr str) in @@ -688,6 +709,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let pvar = Pvar.mk (Mangled.from_string name) procname in (pvar, CType_decl.qual_type_to_sil_type tenv class_qual_type) + let this_expr_trans stmt_info ?class_qual_type trans_state sil_loc = let this_pvar, this_typ = get_this_pvar_typ stmt_info ?class_qual_type trans_state.context in let exps = [(Exp.Lvar this_pvar, this_typ)] in @@ -2606,38 +2628,21 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s and blockExpr_trans trans_state stmt_info expr_info decl = let context = trans_state.context in let procname = Procdesc.get_proc_name context.CContext.procdesc in - let loc = - match stmt_info.Clang_ast_t.si_source_range with l1, _ -> - CLocation.clang_to_sil_location context.CContext.translation_unit_context l1 - in - (* Given a captured var, return the instruction to assign it to a temp *) - let assign_captured_var (cvar, typ) = - let id = Ident.create_fresh Ident.knormal in - let instr = Sil.Load (id, Exp.Lvar cvar, typ, loc) in - (id, instr) - in match decl with | Clang_ast_t.BlockDecl (_, block_decl_info) -> let open CContext in - let qual_type = expr_info.Clang_ast_t.ei_qual_type in let block_pname = CProcname.mk_fresh_block_procname procname in - let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in - let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in - let captureds = + let captured_pvars = CVar_decl.captured_vars_from_block_info context stmt_info.Clang_ast_t.si_source_range - captured_block_vars - in - let ids_instrs = List.map ~f:assign_captured_var captureds in - let ids, instrs = List.unzip ids_instrs in - let block_data = (context, qual_type, block_pname, captureds) in - F.function_decl context.translation_unit_context context.tenv context.cfg decl - (Some block_data) ; - let captured_vars = - List.map2_exn ~f:(fun id (pvar, typ) -> (Exp.Var id, pvar, typ)) ids captureds + block_decl_info.Clang_ast_t.bdi_captured_variables in - let closure = Exp.Closure {name= block_pname; captured_vars} in - {empty_res_trans with instrs; exps= [(closure, typ)]} + let res = closure_trans block_pname captured_pvars context stmt_info expr_info in + let qual_type = expr_info.Clang_ast_t.ei_qual_type in + let block_data = Some (context, qual_type, block_pname, captured_pvars) in + F.function_decl context.translation_unit_context context.tenv context.cfg decl block_data ; + res | _ -> + (* Block expression with no BlockDecl *) assert false @@ -2649,7 +2654,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let procname = Procdesc.get_proc_name context.procdesc in let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in - let make_captured_tuple (pvar, typ) = (Exp.Lvar pvar, pvar, typ) in let get_captured_pvar_typ decl_ref = CVar_decl.sil_var_of_captured_var decl_ref context stmt_info.Clang_ast_t.si_source_range procname @@ -2659,7 +2663,14 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | Clang_ast_t.VarDecl (_, _, _, {vdi_init_expr}) -> init_expr_trans trans_state (Exp.Lvar pvar, typ) stmt_info vdi_init_expr | _ -> - L.die ExternalError "Unexpected: capture-init statement without var decl" + CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range + "Capture-init statement without var decl" + in + let translate_normal_capture pvar_typ (trans_results_acc, captured_vars_acc) = + let loc = CLocation.get_sil_location stmt_info context in + let id, instr = assign_captured_var loc pvar_typ in + let trans_results = {empty_res_trans with instrs= [instr]} in + (trans_results :: trans_results_acc, (Exp.Var id, fst pvar_typ, snd pvar_typ) :: captured_vars_acc) in let translate_captured {Clang_ast_t.lci_captured_var; lci_init_captured_vardecl; lci_capture_this} @@ -2669,16 +2680,16 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* capture and init *) let pvar_typ = get_captured_pvar_typ captured_var_decl_ref in ( translate_capture_init pvar_typ init_decl :: trans_results_acc - , make_captured_tuple pvar_typ :: captured_vars_acc ) + , (Exp.Lvar (fst pvar_typ), fst pvar_typ, snd pvar_typ) :: captured_vars_acc ) | Some captured_var_decl_ref, None -> (* just capture *) let pvar_typ = get_captured_pvar_typ captured_var_decl_ref in - (trans_results_acc, make_captured_tuple pvar_typ :: captured_vars_acc) + translate_normal_capture pvar_typ acc | None, None -> if lci_capture_this then (* captured [this] *) let this_typ = get_this_pvar_typ stmt_info context in - (trans_results_acc, make_captured_tuple this_typ :: captured_vars_acc) + translate_normal_capture this_typ acc else acc | None, Some _ -> CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range diff --git a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot index aede50c0e..2b9fcfaf6 100644 --- a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot @@ -56,7 +56,7 @@ digraph cfg { "normal_capture#5533029764254319855.11493b249dddd657790695e287170b84_2" [label="2: Exit normal_capture \n " color=yellow style=filled] -"normal_capture#5533029764254319855.11493b249dddd657790695e287170b84_3" [label="3: Return Stmt \n n$0=_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator()((_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator(),&x,&y):normal_capture::lambda_shared_lambda_lambda1.cpp:33:10) [line 33, column 10]\n *&return:int=n$0 [line 33, column 3]\n " shape="box"] +"normal_capture#5533029764254319855.11493b249dddd657790695e287170b84_3" [label="3: Return Stmt \n n$1=*&x:int [line 33, column 10]\n n$0=*&y:int [line 33, column 10]\n n$2=_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator()((_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator(),(n$1 &x:int),(n$0 &y:int)):normal_capture::lambda_shared_lambda_lambda1.cpp:33:10) [line 33, column 10]\n *&return:int=n$2 [line 33, column 3]\n " shape="box"] "normal_capture#5533029764254319855.11493b249dddd657790695e287170b84_3" -> "normal_capture#5533029764254319855.11493b249dddd657790695e287170b84_2" ; @@ -79,7 +79,7 @@ digraph cfg { "capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_3" -> "capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_2" ; -"capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_4" [label="4: Call _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator() \n _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator()((_fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator(),&x):capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3) [line 38, column 3]\n " shape="box"] +"capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_4" [label="4: Call _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator() \n n$1=*&x:int [line 38, column 3]\n _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator()((_fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator(),(n$1 &x:int)):capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3) [line 38, column 3]\n " shape="box"] "capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_4" -> "capture_by_ref#4375601249296069049.1d794578c048d96b25fb1e90dbaa8225_3" ; @@ -136,7 +136,7 @@ digraph cfg { "capture_this_explicit#Capture#(13194085360619722149).2dba35a78268b10ad413414cc832a8f0_2" [label="2: Exit Capture_capture_this_explicit \n " color=yellow style=filled] -"capture_this_explicit#Capture#(13194085360619722149).2dba35a78268b10ad413414cc832a8f0_3" [label="3: DeclStmt \n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19=(_fun_Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19_operator(),&this) [line 55, column 19]\n _fun_Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19_(&lambda:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19&) [line 55, column 19]\n " shape="box"] +"capture_this_explicit#Capture#(13194085360619722149).2dba35a78268b10ad413414cc832a8f0_3" [label="3: DeclStmt \n n$1=*&this:Capture* [line 55, column 19]\n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19=(_fun_Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19_operator(),(n$1 &this:Capture*)) [line 55, column 19]\n _fun_Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19_(&lambda:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_explicit::lambda_shared_lambda_lambda1.cpp:55:19&) [line 55, column 19]\n " shape="box"] "capture_this_explicit#Capture#(13194085360619722149).2dba35a78268b10ad413414cc832a8f0_3" -> "capture_this_explicit#Capture#(13194085360619722149).2dba35a78268b10ad413414cc832a8f0_2" ; @@ -147,7 +147,7 @@ digraph cfg { "capture_star_this#Capture#(2506493005619132138).63fd6aa2a7efbd48dc1a62c0c2bd2161_2" [label="2: Exit Capture_capture_star_this \n " color=yellow style=filled] -"capture_star_this#Capture#(2506493005619132138).63fd6aa2a7efbd48dc1a62c0c2bd2161_3" [label="3: DeclStmt \n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19=(_fun_Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19_operator(),&this) [line 59, column 19]\n _fun_Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19_(&lambda:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19&) [line 59, column 19]\n " shape="box"] +"capture_star_this#Capture#(2506493005619132138).63fd6aa2a7efbd48dc1a62c0c2bd2161_3" [label="3: DeclStmt \n n$1=*&this:Capture* [line 59, column 19]\n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19=(_fun_Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19_operator(),(n$1 &this:Capture*)) [line 59, column 19]\n _fun_Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19_(&lambda:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_star_this::lambda_shared_lambda_lambda1.cpp:59:19&) [line 59, column 19]\n " shape="box"] "capture_star_this#Capture#(2506493005619132138).63fd6aa2a7efbd48dc1a62c0c2bd2161_3" -> "capture_star_this#Capture#(2506493005619132138).63fd6aa2a7efbd48dc1a62c0c2bd2161_2" ; @@ -158,7 +158,7 @@ digraph cfg { "capture_this_with_equal#Capture#(805776379555510952).ecd73e9a4e2bef0d060a242b61508f10_2" [label="2: Exit Capture_capture_this_with_equal \n " color=yellow style=filled] -"capture_this_with_equal#Capture#(805776379555510952).ecd73e9a4e2bef0d060a242b61508f10_3" [label="3: DeclStmt \n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19=(_fun_Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19_operator(),&this) [line 65, column 19]\n _fun_Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19_(&lambda:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19&) [line 65, column 19]\n " shape="box"] +"capture_this_with_equal#Capture#(805776379555510952).ecd73e9a4e2bef0d060a242b61508f10_3" [label="3: DeclStmt \n n$1=*&this:Capture* [line 65, column 19]\n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19=(_fun_Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19_operator(),(n$1 &this:Capture*)) [line 65, column 19]\n _fun_Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19_(&lambda:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_equal::lambda_shared_lambda_lambda1.cpp:65:19&) [line 65, column 19]\n " shape="box"] "capture_this_with_equal#Capture#(805776379555510952).ecd73e9a4e2bef0d060a242b61508f10_3" -> "capture_this_with_equal#Capture#(805776379555510952).ecd73e9a4e2bef0d060a242b61508f10_2" ; @@ -169,7 +169,7 @@ digraph cfg { "capture_this_with_auto#Capture#(15696525048884093218).38be242109186a45cc282c38962c68e2_2" [label="2: Exit Capture_capture_this_with_auto \n " color=yellow style=filled] -"capture_this_with_auto#Capture#(15696525048884093218).38be242109186a45cc282c38962c68e2_3" [label="3: DeclStmt \n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19=(_fun_Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19_operator(),&this) [line 69, column 19]\n _fun_Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19_(&lambda:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19&) [line 69, column 19]\n " shape="box"] +"capture_this_with_auto#Capture#(15696525048884093218).38be242109186a45cc282c38962c68e2_3" [label="3: DeclStmt \n n$1=*&this:Capture* [line 69, column 19]\n *&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19=(_fun_Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19_operator(),(n$1 &this:Capture*)) [line 69, column 19]\n _fun_Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19_(&lambda:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19*,&0$?%__sil_tmpSIL_materialize_temp__n$0:Capture::capture_this_with_auto::lambda_shared_lambda_lambda1.cpp:69:19&) [line 69, column 19]\n " shape="box"] "capture_this_with_auto#Capture#(15696525048884093218).38be242109186a45cc282c38962c68e2_3" -> "capture_this_with_auto#Capture#(15696525048884093218).38be242109186a45cc282c38962c68e2_2" ;