[clang] ignore `__attribute__((unused))` variable initialisations

Summary: When a `VarDecl` has the attribute `unused` then do not assign its initialisation result to the corresponding variable.

Reviewed By: ngorogiannis

Differential Revision: D13974497

fbshipit-source-id: 28029f995
master
Jules Villard 6 years ago committed by Facebook Github Bot
parent cfa33bd993
commit f8338d8faf

@ -172,11 +172,8 @@ let checker {Callbacks.tenv; summary; proc_desc} : Summary.t =
|> Option.exists ~f:(fun local -> local.ProcAttributes.is_constexpr) |> Option.exists ~f:(fun local -> local.ProcAttributes.is_constexpr)
in in
let should_report pvar typ live_vars captured_by_ref_vars = let should_report pvar typ live_vars captured_by_ref_vars =
(* T32000971: a temporay fix for dead store false positives until we support __unused__ attribute *)
let is_unused_tmp_var pvar = String.equal "__tmp" (Pvar.to_string pvar) in
not not
( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar || is_constexpr pvar ( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar || is_constexpr pvar
|| is_unused_tmp_var pvar
|| VarSet.mem (Var.of_pvar pvar) captured_by_ref_vars || VarSet.mem (Var.of_pvar pvar) captured_by_ref_vars
|| Domain.mem (Var.of_pvar pvar) live_vars || Domain.mem (Var.of_pvar pvar) live_vars
|| Procdesc.is_captured_pvar proc_desc pvar || Procdesc.is_captured_pvar proc_desc pvar

@ -2220,7 +2220,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
|> mk_trans_result ret_exp_typ |> mk_trans_result ret_exp_typ
and init_expr_trans trans_state var_exp_typ ?qual_type var_stmt_info init_expr_opt = and init_expr_trans ?(is_var_unused = false) trans_state var_exp_typ ?qual_type var_stmt_info
init_expr_opt =
match init_expr_opt with match init_expr_opt with
| None -> ( | None -> (
match match
@ -2254,8 +2255,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
in in
let assign_trans_control_opt = let assign_trans_control_opt =
if if
(* variable might be initialized already - do nothing in that case*) is_var_unused
List.exists ~f:(Exp.equal var_exp) res_trans_ie.control.initd_exps || (* variable might be initialized already - do nothing in that case*)
List.exists ~f:(Exp.equal var_exp) res_trans_ie.control.initd_exps
then None then None
else else
let sil_e1', ie_typ = res_trans_ie.return in let sil_e1', ie_typ = res_trans_ie.return in
@ -2292,18 +2294,21 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let context = trans_state.context in let context = trans_state.context in
let procdesc = context.CContext.procdesc in let procdesc = context.CContext.procdesc in
let procname = Procdesc.get_proc_name procdesc in let procname = Procdesc.get_proc_name procdesc in
let do_var_dec var_decl qual_type vdi next_node = let do_var_dec ~is_var_unused var_decl qual_type vdi next_node =
let pvar = CVar_decl.sil_var_of_decl context var_decl procname in let pvar = CVar_decl.sil_var_of_decl context var_decl procname in
let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in
CVar_decl.add_var_to_locals procdesc var_decl typ pvar ; CVar_decl.add_var_to_locals procdesc var_decl typ pvar ;
let trans_state' = {trans_state with succ_nodes= next_node} in let trans_state' = {trans_state with succ_nodes= next_node} in
init_expr_trans trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info init_expr_trans ~is_var_unused trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info
vdi.Clang_ast_t.vdi_init_expr vdi.Clang_ast_t.vdi_init_expr
in in
let has_unused_attr attributes =
List.exists attributes ~f:(function Clang_ast_t.UnusedAttr _ -> true | _ -> false)
in
let rec aux : decl list -> trans_result option = function let rec aux : decl list -> trans_result option = function
| [] -> | [] ->
None None
| (VarDecl (_, _, qt, vdi) as var_decl) :: var_decls' -> | (VarDecl ({di_attributes}, _, qt, vdi) as var_decl) :: var_decls' ->
(* Var are defined when procdesc is created, here we only take care of initialization *) (* Var are defined when procdesc is created, here we only take care of initialization *)
let res_trans_tl = aux var_decls' in let res_trans_tl = aux var_decls' in
let root_nodes_tl, instrs_tl, initd_exps_tl = let root_nodes_tl, instrs_tl, initd_exps_tl =
@ -2313,7 +2318,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
| Some {control= {root_nodes; instrs; initd_exps}} -> | Some {control= {root_nodes; instrs; initd_exps}} ->
(root_nodes, instrs, initd_exps) (root_nodes, instrs, initd_exps)
in in
let res_trans_tmp = do_var_dec var_decl qt vdi root_nodes_tl in let is_var_unused = has_unused_attr di_attributes in
let res_trans_tmp = do_var_dec ~is_var_unused var_decl qt vdi root_nodes_tl in
(* keep the last return and leaf_nodes from the list *) (* keep the last return and leaf_nodes from the list *)
let return, leaf_nodes = let return, leaf_nodes =
match res_trans_tl with match res_trans_tl with

@ -484,18 +484,17 @@ class Exceptions {
void init_in_binop_bad(int x) { x = -x & ~int{0}; } void init_in_binop_bad(int x) { x = -x & ~int{0}; }
void FN_unused_tmp_bad() { void unused_tmp_bad() { int __tmp = 1; }
// T32000971
int __tmp = 1;
}
#define UNUSED(a) __typeof__(&a) __attribute__((unused)) __tmp = &a; #define UNUSED(a) __typeof__(&a) __attribute__((unused)) __tmp = &a;
void unused_attribute_ok() { void unused_attribute_tmp_ok() {
int x; int x;
UNUSED(x); UNUSED(x);
} }
void unused_attribute_ok() { int __attribute__((unused)) x = 42; }
struct ChainedCalls { struct ChainedCalls {
ChainedCalls chained(int i); ChainedCalls chained(int i);
}; };

@ -18,6 +18,7 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus1_bad, 2, DEAD
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::reassign_param_bad, 0, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::reassign_param_bad, 0, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::unused_tmp_bad, 0, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::use_then_dead_bad, 3, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::use_then_dead_bad, 3, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores_constexpr.cpp, capture_const_bad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores_constexpr.cpp, capture_const_bad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/non_type_template_param.cpp, X<3>_isZeroBad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/non_type_template_param.cpp, X<3>_isZeroBad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value]

Loading…
Cancel
Save