On 5/14/26 12:50 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?
-- >8 --
Thanks to DR 696 (r253266), this works:
int g;
void fn ()
{
int &c = g;
auto l = [] { c++; };
l();
}
because `c` in the lambda body is not an odr-use because we can
evaluate it to a constant and so there's no capture. But when
fn is a template, we reject the code and crash. This patch fixes
both.
Outside a template, the call to maybe_constant_value in mark_use
evaluates `c` to `(int&) &g` but in a template, it remains `c`.
Then we emit an error, and crash on the error_mark_node from
process_outer_var_ref. One of the reasons is
else if (TYPE_REF_P (TREE_TYPE (expression)))
/* FIXME cp_finish_decl doesn't fold reference initializers. */
return true;
in value_dependent_expression_p but even if that changed, we still
wouldn't get the referent because decl_really_constant_value wouldn't
give it to us; the DECL_INITIAL is not a TREE_CONSTANT yet.
So I stopped trying to make this work in a template, and instead
I'm delaying the processing to instantiating when we know that
maybe_constant_value wouldn't even try to evaluate.
But it sounds like maybe_constant_value is fine?
The is_capture_proxy change is due to lambda-scope10.C: we are
checking is_nondependent_constant_expression before the enclosing
function has been built up.
PR c++/123536
gcc/cp/ChangeLog:
* expr.cc (mark_use) <case VAR_DECL>: Check
is_nondependent_constant_expression before
process_outer_var_ref.
* lambda.cc (is_capture_proxy): Check DECL_CONTEXT.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/lambda/lambda-const12.C: New test.
---
gcc/cp/expr.cc | 3 +-
gcc/cp/lambda.cc | 1 +
.../g++.dg/cpp0x/lambda/lambda-const12.C | 48 +++++++++++++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index 4d017d530ef..15036cf7cad 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -131,7 +131,8 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
}
}
if (outer_automatic_var_p (expr)
- && decl_constant_var_p (expr))
+ && decl_constant_var_p (expr)
+ && is_nondependent_constant_expression (expr))
I think we want this condition to stay parallel with the one in
process_outer_var_ref:
/* Only an odr-use of an outer automatic variable causes an
error, and a constant variable can decay to a prvalue
constant without odr-use. So don't complain yet. */
else if (!odr_use && decl_constant_var_p (var))
return var;
...though that comment should refer to mark_use, and vice versa.
The idea is that first we try to process the ref from
finish_id_expression, and if that's going to fail we wait and try again
from mark_use.
Patrick's suggestion
Maybe we can make both testcases work if we instead give process_outer_var_ref
an early exit for when the outer variable is from a template?
makes sense to me.
Jason