Hi!
When implementing expansion statements, cp_perform_range_for_lookup
does for the non-method begin/end:
/* Use global functions with ADL. */
releasing_vec vec;
vec_safe_push (vec, range);
member_begin = perform_koenig_lookup (id_begin, vec,
complain);
if ((complain & tf_error) == 0 && member_begin == id_begin)
return error_mark_node;
*begin = finish_call_expr (member_begin, &vec, false, true,
complain);
member_end = perform_koenig_lookup (id_end, vec,
tf_warning_or_error);
if ((complain & tf_error) == 0 && member_end == id_end)
{
*begin = error_mark_node;
return error_mark_node;
}
*end = finish_call_expr (member_end, &vec, false, true,
complain);
}
/* Last common checks. */
if (*begin == error_mark_node || *end == error_mark_node)
{
/* If one of the expressions is an error do no more checks. */
*begin = *end = error_mark_node;
return error_mark_node;
}
and finish_expansion_stmt uses
iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
&end_expr, tf_none);
if (begin_expr != error_mark_node && end_expr != error_mark_node)
{
kind = esk_iterating;
gcc_assert (iter_type);
}
to select iterating over destructuring only if both are
non-error_mark_nodes.
This is not what the standard says right now, but is what
the proposed resolution of CWG 3123 says:
https://cplusplus.github.io/CWG/issues/3123.html
I think for the pre-CWG 3123 wording I'd need to propagate to the
caller whether perform_koenig_lookup was successfull but whether
finish_call_expr succeeded or not should then be done without tf_none
after choosing esk_iterating.
Anyway, with the hope that CWG 3123 is voted in, this patch adds
a testcase for it.
Regtested on x86_64-linux and i686-linux, ok for trunk?
2026-02-11 Jakub Jelinek <[email protected]>
* g++.dg/cpp26/expansion-stmt29.C: New test.
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt29.C.jj 2026-02-10
15:40:47.794903075 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt29.C 2026-02-10
15:40:41.132016293 +0100
@@ -0,0 +1,15 @@
+// CWG 3123
+// { dg-do run { target c++26 } }
+
+#include <tuple>
+
+int
+main ()
+{
+ long l = 0;
+ std::tuple <int, long, unsigned> t = { 1, 2L, 3U };
+ template for (auto &&x : t)
+ l += x;
+ if (l != 6L)
+ __builtin_abort ();
+}
Jakub