aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSimon Martin <simon@nasilyan.com>2025-03-12 20:15:39 +0100
committerSimon Martin <simon@nasilyan.com>2025-03-12 20:16:01 +0100
commit90e53ecdbfcc482ad3d0090658427de6d44a5d49 (patch)
treea76977ab64b67bd1efdee42b0be5abe965fb891a /gcc
parent9ee6c2619b256878d43800a16f7b98b3ddf59e52 (diff)
downloadgcc-90e53ecdbfcc482ad3d0090658427de6d44a5d49.zip
gcc-90e53ecdbfcc482ad3d0090658427de6d44a5d49.tar.gz
gcc-90e53ecdbfcc482ad3d0090658427de6d44a5d49.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/lambda.cc14
-rw-r--r--gcc/cp/semantics.cc8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C46
4 files changed, 62 insertions, 7 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a839ad6..07500fa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index da075b9..ed70bb0 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -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;
}
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7c7d3e3..6e10893 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
new file mode 100644
index 0000000..aced567
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested10.C
@@ -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);
+ };
+ } ();
+}