diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index f18e0fd3f..1f2124cbb 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2168,8 +2168,25 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s match List.map2 field_exps stmts ~f:init_field with | Ok result -> result - | Unequal_lengths -> - (* This can happen with union initializers. Skip them for now *) [] + | Unequal_lengths -> ( + match stmts with + | [stmt] -> + (* let's assume that the statement initialises the whole struct (e.g. a constructor call) *) + L.debug Capture Medium + "assuming initListExpr is initializing the whole struct %a in one go" Exp.pp var_exp ; + [init_expr_trans trans_state (var_exp, var_typ) stmt_info (Some stmt)] + | _ -> + (* This can happen with union initializers. Skip them for now *) + L.debug Capture Medium + "couldn't translate initListExpr properly: list lengths do not match:@\n\ + \ field_exps is %d: [%a]@\n\ + \ stmts is %d: [%a]@\n" + (List.length field_exps) + (Pp.seq ~sep:"," (Pp.pair ~fst:Exp.pp ~snd:(Typ.pp Pp.text))) + field_exps (List.length stmts) + (Pp.seq ~sep:"," (Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string)) + stmts ; + [] ) and initListExpr_builtin_trans trans_state stmt_info stmts var_exp var_typ = diff --git a/infer/tests/codetoanalyze/c/frontend/initialization/enum_initlistexpr.c.dot b/infer/tests/codetoanalyze/c/frontend/initialization/enum_initlistexpr.c.dot index 9a8be52bc..98341e0fe 100644 --- a/infer/tests/codetoanalyze/c/frontend/initialization/enum_initlistexpr.c.dot +++ b/infer/tests/codetoanalyze/c/frontend/initialization/enum_initlistexpr.c.dot @@ -7,15 +7,15 @@ digraph cfg { "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_2" [label="2: Exit union_initialize_FIXME \n " color=yellow style=filled] -"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_3" [label="3: DeclStmt \n VARIABLE_DECLARED(set_f1_implicit:U); [line 15, column 3]\n NULLIFY(&set_f1_implicit); [line 15, column 3]\n EXIT_SCOPE(set_f1_implicit); [line 15, column 3]\n APPLY_ABSTRACTION; [line 15, column 3]\n " shape="box"] +"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_3" [label="3: DeclStmt \n VARIABLE_DECLARED(set_f1_implicit:U); [line 15, column 3]\n VARIABLE_DECLARED(set_f1_implicit:U); [line 15, column 29]\n *&set_f1_implicit:int=1 [line 15, column 29]\n NULLIFY(&set_f1_implicit); [line 15, column 29]\n EXIT_SCOPE(set_f1_implicit); [line 15, column 29]\n APPLY_ABSTRACTION; [line 15, column 29]\n " shape="box"] "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_3" -> "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_2" ; -"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_4" [label="4: DeclStmt \n VARIABLE_DECLARED(set_f2:U); [line 14, column 3]\n NULLIFY(&set_f2); [line 14, column 3]\n EXIT_SCOPE(set_f2); [line 14, column 3]\n " shape="box"] +"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_4" [label="4: DeclStmt \n VARIABLE_DECLARED(set_f2:U); [line 14, column 3]\n VARIABLE_DECLARED(set_f2:U); [line 14, column 20]\n NULLIFY(&set_f2); [line 14, column 20]\n EXIT_SCOPE(set_f2); [line 14, column 20]\n " shape="box"] "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_4" -> "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_3" ; -"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_5" [label="5: DeclStmt \n VARIABLE_DECLARED(set_f1:U); [line 13, column 3]\n NULLIFY(&set_f1); [line 13, column 3]\n EXIT_SCOPE(set_f1); [line 13, column 3]\n " shape="box"] +"union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_5" [label="5: DeclStmt \n VARIABLE_DECLARED(set_f1:U); [line 13, column 3]\n VARIABLE_DECLARED(set_f1:U); [line 13, column 20]\n *&set_f1:int=2 [line 13, column 20]\n NULLIFY(&set_f1); [line 13, column 20]\n EXIT_SCOPE(set_f1); [line 13, column 20]\n " shape="box"] "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_5" -> "union_initialize_FIXME.324b85335f5d2e418a28cb97eb896f20_4" ; diff --git a/infer/tests/codetoanalyze/cpp/pulse/temporaries.cpp b/infer/tests/codetoanalyze/cpp/pulse/temporaries.cpp index 7dbfa9278..cb1882a5b 100644 --- a/infer/tests/codetoanalyze/cpp/pulse/temporaries.cpp +++ b/infer/tests/codetoanalyze/cpp/pulse/temporaries.cpp @@ -80,4 +80,31 @@ int FN_bind_temporary_to_const_bad() { return a_ptr->s_; } +struct AutoConvertibleFromA { + ~AutoConvertibleFromA() {} + + // auto-conversion between A and AutoConvertibleFromA + constexpr AutoConvertibleFromA(const A&) {} +}; + +struct InitListConstructible { + ~InitListConstructible() {} + InitListConstructible(const InitListConstructible&) noexcept; +}; + +A make_an_A(); // creates an A +InitListConstructible make_a_InitListConstructible(AutoConvertibleFromA); + +// test that the frontend deals with this correctly +void temporary_in_constructor_in_init_list_ok() { + while (true) { + // A -> AutoConvertibleFromA conversion requires a temporary to be + // materialized to hold the A& necessary for the conversion, then + // InitListConstructible's copy constructor generates the init list we want + // to test + InitListConstructible p = + InitListConstructible{make_a_InitListConstructible(make_an_A())}; + } +} + } // namespace temporaries