c++: Look through capture proxy from outer lambda instead of erroring out [PR110584]
We've been rejecting this valid code since r8-4571: === cut here === void foo (float); int main () { constexpr float x = 0; (void) [&] () { foo (x); (void) [] () { foo (x); }; }; } === cut here === The problem is that when processing X in the inner lambda, process_outer_var_ref errors out even though it does find the constant capture from the enclosing lambda. This patch makes sure that process_outer_var_ref properly looks through normal capture proxies, if any. PR c++/110584 gcc/cp/ChangeLog: * cp-tree.h (strip_normal_capture_proxy): Declare. * lambda.cc (strip_normal_capture_proxy): New function to look through normal capture proxies. (build_capture_proxy): Use it. * semantics.cc (process_outer_var_ref): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-nested10.C: New test.
This commit is contained in:
parent
9ee6c2619b
commit
90e53ecdbf
4 changed files with 62 additions and 7 deletions
|
@ -8114,6 +8114,7 @@ extern void insert_capture_proxy (tree);
|
|||
extern void insert_pending_capture_proxies (void);
|
||||
extern bool is_capture_proxy (tree);
|
||||
extern bool is_normal_capture_proxy (tree);
|
||||
extern tree strip_normal_capture_proxy (tree);
|
||||
extern bool is_constant_capture_proxy (tree);
|
||||
extern void register_capture_members (tree);
|
||||
extern tree lambda_expr_this_capture (tree, int);
|
||||
|
|
|
@ -295,6 +295,17 @@ is_normal_capture_proxy (tree decl)
|
|||
&& DECL_CAPTURED_VARIABLE (decl));
|
||||
}
|
||||
|
||||
/* If DECL is a normal capture proxy, return the variable it captures.
|
||||
Otherwise, just return DECL. */
|
||||
|
||||
tree
|
||||
strip_normal_capture_proxy (tree decl)
|
||||
{
|
||||
while (is_normal_capture_proxy (decl))
|
||||
decl = DECL_CAPTURED_VARIABLE (decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* Returns true iff DECL is a capture proxy for a normal capture
|
||||
of a constant variable. */
|
||||
|
||||
|
@ -469,8 +480,7 @@ build_capture_proxy (tree member, tree init)
|
|||
STRIP_NOPS (init);
|
||||
|
||||
gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
|
||||
while (is_normal_capture_proxy (init))
|
||||
init = DECL_CAPTURED_VARIABLE (init);
|
||||
init = strip_normal_capture_proxy (init);
|
||||
retrofit_lang_decl (var);
|
||||
DECL_CAPTURED_VARIABLE (var) = init;
|
||||
}
|
||||
|
|
|
@ -4528,6 +4528,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
|
|||
tree lambda_stack = NULL_TREE;
|
||||
tree lambda_expr = NULL_TREE;
|
||||
tree initializer = convert_from_reference (decl);
|
||||
tree var = strip_normal_capture_proxy (decl);
|
||||
|
||||
/* Mark it as used now even if the use is ill-formed. */
|
||||
if (!mark_used (decl, complain))
|
||||
|
@ -4539,9 +4540,6 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
|
|||
if (containing_function && LAMBDA_FUNCTION_P (containing_function))
|
||||
{
|
||||
/* Check whether we've already built a proxy. */
|
||||
tree var = decl;
|
||||
while (is_normal_capture_proxy (var))
|
||||
var = DECL_CAPTURED_VARIABLE (var);
|
||||
tree d = retrieve_local_specialization (var);
|
||||
|
||||
if (d && d != decl && is_capture_proxy (d))
|
||||
|
@ -4601,8 +4599,8 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
|
|||
/* 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 (decl))
|
||||
return decl;
|
||||
else if (!odr_use && decl_constant_var_p (var))
|
||||
return var;
|
||||
else if (lambda_expr)
|
||||
{
|
||||
if (complain & tf_error)
|
||||
|
|
46
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
Normal file
46
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
Normal file
|
@ -0,0 +1,46 @@
|
|||
// PR c++/110584
|
||||
// { dg-do "run" { target c++11 } }
|
||||
|
||||
void foo (int i) {
|
||||
if (i != 0)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
int main () {
|
||||
const int x = 0;
|
||||
|
||||
// We would error out on this.
|
||||
(void) [&] () {
|
||||
foo (x);
|
||||
(void) [] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
// As well as those.
|
||||
(void) [&] () {
|
||||
(void) [] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
(void) [&x] () {
|
||||
(void) [] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
// But those would work already.
|
||||
(void) [] () {
|
||||
(void) [&] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
(void) [&] () {
|
||||
(void) [&] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
(void) [=] () {
|
||||
(void) [] () {
|
||||
foo (x);
|
||||
};
|
||||
} ();
|
||||
}
|
Loading…
Add table
Reference in a new issue