[DEAD_STORE] Capture `constexpr`s in lambdas

Reviewed By: jvillard

Differential Revision: D9179442

fbshipit-source-id: 8df2769c6
master
Ezgi Çiçek 6 years ago committed by Facebook Github Bot
parent 797eedba8b
commit 0a668c2161

@ -50,7 +50,27 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
add_live_actuals_ actuals live_acc
let exec_instr astate _ _ = function
(* In C++14, for a lambda at block scope, constexpr variables in the
reaching scope may be used inside the lambda, even if they are
not captured. For further details:
https://timsong-cpp.github.io/cppwp/n4140/expr.prim.lambda#12 *)
let add_local_consts_for_lambdas pdesc call_exp astate =
let pname = Procdesc.get_proc_name pdesc in
match call_exp with
| Exp.Const (Cfun (Typ.Procname.ObjC_Cpp cpp_pname))
when Typ.Procname.ObjC_Cpp.is_cpp_lambda cpp_pname ->
Procdesc.get_locals pdesc
|> List.fold ~init:astate ~f:(fun acc var_data ->
let open ProcAttributes in
if Typ.is_const var_data.typ.quals then
let const_local_var = Pvar.mk var_data.name pname |> Var.of_pvar in
Domain.add const_local_var acc
else acc )
| _ ->
astate
let exec_instr astate {ProcData.pdesc} _ = function
| Sil.Load (lhs_id, _, _, _) when Ident.is_none lhs_id ->
(* dummy deref inserted by frontend--don't count as a read *)
astate
@ -68,7 +88,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
exp_add_live exp astate
| Sil.Call ((ret_id, _), call_exp, actuals, _, _) ->
Domain.remove (Var.of_id ret_id) astate |> exp_add_live call_exp
|> add_live_actuals actuals call_exp
|> add_live_actuals actuals call_exp |> add_local_consts_for_lambdas pdesc call_exp
| Sil.Declare_locals _ | Remove_temps _ | Abstract _ | Nullify _ ->
astate

@ -0,0 +1,53 @@
/*
* Copyright (c) 2016-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
int foo(int a);
// before, we were raising DEAD_STORE for x
void capture_constexpr_good() {
constexpr int x = 10;
[]() {
foo(x);
return;
}();
}
void call_it(void (*f)(void)) { f(); }
void FP_capture_constexpr_good() {
constexpr int x = 1;
auto lambda = []() {
foo(x);
return;
};
call_it(lambda);
}
// we always assume const exprs are captured in lambdas
void FN_capture_constexpr_good() {
constexpr int x = 10;
[]() {
foo(0);
return;
}();
}
void FN_init_capture_reassign_bad() {
constexpr int i = 1; // this is a dead store
return [i = 1]() { return i; }();
}
// expected DEAD_STORE
void capture_constexpr_bad() {
constexpr int x = 1;
foo(2);
}
// expected since dead stores to a "sentinel" value are ignored
void capture_constexpr_sentinel_good() {
constexpr int x = 0;
[]() { return; }();
}

@ -18,5 +18,7 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD
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::use_then_dead_bad, 3, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores_constexpr.cpp, FP_capture_constexpr_good, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores_constexpr.cpp, capture_constexpr_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, instanciateTemplateBad, 3, DEAD_STORE, no_bucket, ERROR, [Write of unused value]

Loading…
Cancel
Save