[clang] [Clang] [C++26] Implement P1306R5 Expansion Statements (PR #165195)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 3 08:32:34 PST 2025


Sirraide wrote:

[[stmt.expand]p3](https://eel.is/c++draft/stmt.expand#3) is confusing me a bit at the moment:
> For an expression E, let the expressions begin-expr and end-expr be determined as specified in [[stmt.ranged]](https://eel.is/c++draft/stmt.ranged)[.](https://eel.is/c++draft/stmt.expand#3.sentence-1) An expression is [expansion-iterable](https://eel.is/c++draft/stmt.expand#def:expansion-iterable) if it does not have array type and either
> - begin-expr and end-expr are of the form E.begin() and E.end(), or
> - argument-dependent lookups for begin(E) and for end(E) each find at least one function or function template[.](https://eel.is/c++draft/stmt.expand#3.sentence-2)

The sentence ‘begin-expr and end-expr are of the form E.begin() and E.end()’ to me presupposes that those expressions are well-formed, but what happens if they aren’t? 

Similarly, regarding the second clause, ‘argument-dependent lookups for begin(E) and for end(E) each find at least one function or function template’, perhaps my standardese is lacking here, but does e.g. ‘finding a function’ require that that function be viable (and the single best candidate)? Does finding a e.g. deleted function count? Because if you do e.g. ADL for `begin()` on a `std::tuple<>`, it’ll find quite a few `begin()`/`end()` functions, but none of them actually work for `std::tuple<>`.

Specifically, what happens if e.g.
1. only member `begin()` (or `end()`) exists; or
2. only member `begin()` (or `end()`) exists but is inaccessible (e.g. private, deleted, etc.); or
3. member `begin()` and `end()` exist; either (or both) is inaccessible, and we have a valid ADL `begin()`/`end()` pair; or
4. only ADL `begin()` (or `end()`) exists; or
5. only ADL `begin()` (or `end()`) exists but is inaccassible; or
6. some mixture of member and ADL `begin()`/`end()` exist, but we don’t have a proper `begin()`/`end()` pair; or
7. we have a proper pair but either function (or both) is inaccessible?

For range-based for loops, this is a lot simpler: if anything goes wrong, the program is ill-formed; but here, we *sometimes* need to pivot to building a destructuring expansion instead. It’s not entirely clear to me which of the conditions I listed above constitute an ill-formed program, and which are grounds for switching to destructuring instead. GCC and the experimental fork also don’t seem to agree with each other on this (https://godbolt.org/z/hzfh1x67G).

CC @cor3ntin, @katzdm You probably have a better idea than me what the intent behind that paragraph is.

https://github.com/llvm/llvm-project/pull/165195


More information about the cfe-commits mailing list