[clang] fix translation of `initListExpr` again

Summary:
So it turns out we need to translate even more cases. Pulse had a FP
before that this fixes.

Reviewed By: ezgicicek

Differential Revision: D16073629

fbshipit-source-id: c03460b5a
master
Jules Villard 5 years ago committed by Facebook Github Bot
parent 14ce445f81
commit e803a30c2d

@ -30,7 +30,7 @@ type 'a scope = {current: 'a list; current_kind: scope_kind; outers: ('a list *
(** executes [f] in new scope where [kind] has been pushed on top *) (** executes [f] in new scope where [kind] has been pushed on top *)
let in_ kind scope ~f = let in_ kind scope ~f =
L.debug Capture Verbose "<@[<v2>%s|" (string_of_kind kind) ; L.debug Capture Verbose "<@[<v2>%s|@," (string_of_kind kind) ;
let scope = let scope =
{current= []; current_kind= kind; outers= (scope.current, scope.current_kind) :: scope.outers} {current= []; current_kind= kind; outers= (scope.current, scope.current_kind) :: scope.outers}
in in
@ -38,7 +38,7 @@ let in_ kind scope ~f =
let (current, current_kind), outers = let (current, current_kind), outers =
match scope.outers with [] -> assert false | top :: rest -> (top, rest) match scope.outers with [] -> assert false | top :: rest -> (top, rest)
in in
L.debug Capture Verbose "@]%s>@\n" (string_of_kind scope.current_kind) ; L.debug Capture Verbose "@]@;/%s>" (string_of_kind scope.current_kind) ;
(scope.current, {current; current_kind; outers}, x) (scope.current, {current; current_kind; outers}, x)
@ -165,7 +165,7 @@ module Variables = struct
in in
(* the reverse order is the one we want to destroy the variables in at the end of the scope (* the reverse order is the one we want to destroy the variables in at the end of the scope
*) *)
L.debug Capture Verbose "+%a" (Pp.seq ~sep:"," pp_var_decl) new_vars ; L.debug Capture Verbose "+%a@," (Pp.seq ~sep:"," pp_var_decl) new_vars ;
(rev_append new_vars scope, map) (rev_append new_vars scope, map)
| _ -> ( | _ -> (
let stmt_info, stmt_list = Clang_ast_proj.get_stmt_tuple stmt in let stmt_info, stmt_list = Clang_ast_proj.get_stmt_tuple stmt in
@ -203,7 +203,8 @@ module Variables = struct
and visit_stmt_list stmt_list scope_map = and visit_stmt_list stmt_list scope_map =
List.fold stmt_list ~f:(fun scope_map stmt -> visit_stmt stmt scope_map) ~init:scope_map List.fold stmt_list ~init:scope_map ~f:(fun scope_map stmt ->
L.debug Capture Verbose "@;" ; visit_stmt stmt scope_map )
let empty_scope = {current= []; current_kind= InitialScope; outers= []} let empty_scope = {current= []; current_kind= InitialScope; outers= []}
@ -213,7 +214,7 @@ module Variables = struct
end end
module CXXTemporaries = struct module CXXTemporaries = struct
let rec visit_stmt context stmt temporaries = let rec visit_stmt_aux context stmt temporaries =
match (stmt : Clang_ast_t.stmt) with match (stmt : Clang_ast_t.stmt) with
| MaterializeTemporaryExpr | MaterializeTemporaryExpr
( stmt_info ( stmt_info
@ -224,6 +225,7 @@ module CXXTemporaries = struct
the reference *) the reference *)
None } ) -> None } ) ->
let pvar, typ = CVar_decl.materialize_cpp_temporary context stmt_info expr_info in let pvar, typ = CVar_decl.materialize_cpp_temporary context stmt_info expr_info in
L.debug Capture Verbose "+%a@," (Pvar.pp Pp.text) pvar ;
let temporaries = (pvar, typ, expr_info.ei_qual_type) :: temporaries in let temporaries = (pvar, typ, expr_info.ei_qual_type) :: temporaries in
visit_stmt_list context stmt_list temporaries visit_stmt_list context stmt_list temporaries
| ExprWithCleanups _ -> | ExprWithCleanups _ ->
@ -242,15 +244,26 @@ module CXXTemporaries = struct
Example of tricky case: [foo(x?y:z, w)] or [cond && y] where [y] generates a C++ Example of tricky case: [foo(x?y:z, w)] or [cond && y] where [y] generates a C++
temporary. *) temporary. *)
temporaries temporaries
| LambdaExpr _ ->
(* do not analyze the code of another function *) temporaries
| _ -> | _ ->
let _, stmt_list = Clang_ast_proj.get_stmt_tuple stmt in let _, stmt_list = Clang_ast_proj.get_stmt_tuple stmt in
visit_stmt_list context stmt_list temporaries visit_stmt_list context stmt_list temporaries
and visit_stmt context stmt temporaries =
L.debug Capture Verbose "<@[<hv2>%a|@,"
(Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string)
stmt ;
let r = visit_stmt_aux context stmt temporaries in
L.debug Capture Verbose "@]@;/%a>" (Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string) stmt ;
r
and visit_stmt_list context stmt_list temporaries = and visit_stmt_list context stmt_list temporaries =
List.fold stmt_list List.fold stmt_list ~init:temporaries ~f:(fun temporaries stmt ->
~f:(fun temporaries stmt -> visit_stmt context stmt temporaries) L.debug Capture Verbose "@;" ;
~init:temporaries visit_stmt context stmt temporaries )
let get_destroyable_temporaries context stmt_list = visit_stmt_list context stmt_list [] let get_destroyable_temporaries context stmt_list = visit_stmt_list context stmt_list []

@ -2161,8 +2161,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let field_exps = let field_exps =
match Tenv.lookup tenv tname with match Tenv.lookup tenv tname with
| Some {fields} -> | Some {fields} ->
List.filter_map fields ~f:(fun (fieldname, fieldtype, _) -> List.map fields ~f:(fun (fieldname, fieldtype, _) ->
Some (Exp.Lfield (var_exp, fieldname, var_typ), fieldtype) ) (Exp.Lfield (var_exp, fieldname, var_typ), fieldtype) )
| None -> | None ->
assert false assert false
in in
@ -2180,7 +2180,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
"assuming initListExpr is initializing the whole struct %a in one go" Exp.pp var_exp ; "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)] [init_expr_trans trans_state (var_exp, var_typ) stmt_info (Some stmt)]
| _ -> | _ ->
(* This can happen with union initializers. Skip them for now *) (* This happens with some braced-init-list for instance; translate each sub-statement so
as not to lose instructions (we might even get the translation right) *)
L.debug Capture Medium L.debug Capture Medium
"couldn't translate initListExpr properly: list lengths do not match:@\n\ "couldn't translate initListExpr properly: list lengths do not match:@\n\
\ field_exps is %d: [%a]@\n\ \ field_exps is %d: [%a]@\n\
@ -2190,7 +2191,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
field_exps (List.length stmts) field_exps (List.length stmts)
(Pp.seq ~sep:"," (Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string)) (Pp.seq ~sep:"," (Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string))
stmts ; stmts ;
[] ) let control, _ = instructions trans_state stmts in
[mk_trans_result (var_exp, var_typ) control] )
and initListExpr_builtin_trans trans_state stmt_info stmts var_exp var_typ = and initListExpr_builtin_trans trans_state stmt_info stmts var_exp var_typ =
@ -2283,12 +2285,11 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
match init_expr_opt with match init_expr_opt with
| None -> ( | None -> (
match match
Option.map ~f:(fun qt -> qt.Clang_ast_t.qt_type_ptr) qual_type Option.bind qual_type ~f:(fun qt -> CAst_utils.get_type qt.Clang_ast_t.qt_type_ptr)
|> Option.find_map ~f:CAst_utils.get_type
with with
| Some (Clang_ast_t.VariableArrayType (_, _, stmt_pointer)) -> | Some (Clang_ast_t.VariableArrayType (_, _, stmt_pointer)) ->
(* Set the dynamic length of the variable length array. Variable length array cannot (* Set the dynamic length of the variable length array. Variable length array cannot
have an initialization expression. *) have an initialization expression. *)
init_dynamic_array trans_state var_exp_typ var_stmt_info stmt_pointer init_dynamic_array trans_state var_exp_typ var_stmt_info stmt_pointer
| _ -> | _ ->
(* Nothing to do if no init expression and not a variable length array *) (* Nothing to do if no init expression and not a variable length array *)

@ -0,0 +1,53 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <variant>
#include <vector>
namespace std_visit {
struct A {
int s_;
~A() {}
A() {}
};
// See https://en.cppreference.com/w/cpp/utility/variant/visit for more details
using var_t = std::variant<float, int, A>;
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};
template <class... Ts>
overloaded(Ts...)->overloaded<Ts...>;
void visit_ok(var_t x) {
std::visit(overloaded{
[](float a) {},
[](int i) {},
[](const A& a) {},
},
x);
}
void visit_all_ok(std::vector<var_t>& vec) {
for (auto& x : vec) {
// the overloaded { .. } construct appears as an InitListExpr in
// the AST that the frontend needs to translate. Otherwise, since
// children of that InitListExpr create C++ temporaries, pulse
// will complain that they get destroyed because it never sees
// them being created (this is only a problem in a loop where the
// same temporary is re-used without having been re-initialized).
std::visit(overloaded{
[](float a) {},
[](int i) {},
[](const A& a) {},
},
x);
}
}
} // namespace std_visit
Loading…
Cancel
Save