The patch fixes a bug in the detection of the usage of static variables inside generic lambdas. It does so by forcing the instantiation of generic lambdas within their enclosing scope. This ensures that the scope's static variables usage is computed correctly.
2026-01-15 Lucas Chollet <[email protected]> PR c++/114450 cp/ * decl2.cc (has_generic_lambda_param_p): New. (mark_used): Don't allow deferring template instantiations for generic lambdas. testsuite/ * g++.dg/warn/Wunused-var-42.C: New. --- gcc/cp/decl2.cc | 37 +++++++++++++++++++++- gcc/testsuite/g++.dg/warn/Wunused-var-42.C | 33 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wunused-var-42.C diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index c6449844965..bea083797cf 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -6546,6 +6546,37 @@ fn_template_being_defined (tree decl) return fn_being_defined (pattern); } +/* True if the function declaration DECL takes a generic lambda as one of its + template parameters. */ + +static bool +has_generic_lambda_param_p (tree decl) +{ + if (TREE_CODE (decl) != FUNCTION_DECL) + return false; + + tree tinfo = DECL_TEMPLATE_INFO (decl); + if (!tinfo) + return false; + + tree args = TI_ARGS (tinfo); + for (int i = 0; i < TREE_VEC_LENGTH (args); ++i) + { + tree arg = TREE_VEC_ELT (args, i); + if (TREE_CODE (arg) == RECORD_TYPE && LAMBDA_TYPE_P (arg)) + { + tree callop = lambda_function (arg); + tree call_type = TREE_TYPE (callop); + for (tree parms = TYPE_ARG_TYPES (call_type); + parms; + parms = TREE_CHAIN (parms)) + if (uses_template_parms (TREE_VALUE (parms))) + return true; + } + } + return false; +} + /* Mark DECL (either a _DECL or a BASELINK) as "used" in the program. If DECL is a specialization or implicitly declared class member, generate the actual definition. Return false if something goes @@ -6798,7 +6829,11 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */) need. Therefore, we always try to defer instantiation. */ { ++function_depth; - instantiate_decl (decl, /*defer_ok=*/true, + /* Generic lambdas need to be instantiated right away, when we + still know the parent scope. Otherwise, we won't be able to + see the usage of local static variable. See bug 114450. */ + bool defer_ok = !(warn_unused && has_generic_lambda_param_p (decl)); + instantiate_decl (decl, /*defer_ok=*/defer_ok, /*expl_inst_class_mem_p=*/false); --function_depth; } diff --git a/gcc/testsuite/g++.dg/warn/Wunused-var-42.C b/gcc/testsuite/g++.dg/warn/Wunused-var-42.C new file mode 100644 index 00000000000..f84fb94c334 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wunused-var-42.C @@ -0,0 +1,33 @@ +// { dg-do compile { target c14 } } +// { dg-options "-Wunused" } + +template <typename F> +void f (F &&d) +{ + static unsigned context; + d(context); +} + +void g () +{ + static int b; + f([](auto c) { return c <= b; }); +} + +void h () +{ + static int b = 0; // { dg-warning "unused variable" } + f([](auto c) { return c <= 0; }); +} + +void i () +{ + static int b = 0; // { dg-warning "set but not used" } + [](auto c) { return c <= b; }; +} + +void j () +{ + static int b = 0; // { dg-warning "unused variable" } + [](auto c) { return c <= 0; }; +} -- 2.51.0
