On Sat, Nov 15, 2025 at 08:23:50AM +0100, Jakub Jelinek wrote: > Hi! > > For the https://gcc.gnu.org/pipermail/gcc/2025-November/246977.html > issues I've filed https://github.com/cplusplus/CWG/issues/805 > and got there some responses. One possibility is to change > the iterating expansion statement http://eel.is/c++draft/stmt.expand#5.2 > line from > constexpr auto&& range = expansion-initializer; > to > constexpr decltype(auto) range = (expansion-initializer); > (for our partly pre-CWG3044 implementation with static before it). > > The following patch on top of the 2 earlier expansion-stmt patches > attempts to implement it, though not sure if it should be committed > until at least a CWG is filed for it with some proposed resolution.
FWIW, I think we should wait a little. > It does affect some of our tests because they weren't using const > for the begin/end functions but bet real-world C++ code doesn't suffer > from that. > > Bootstrapped/regtested on x86_64-linux and i686-linux. > > BTW, I'd still like to understand which of the compilers is right for > static constexpr const auto && var = foo (); > where foo () is non-const prvalue like std::span<const int>, whether > the lifetime extended temporary is static std::span<const int> > in that case or static constexpr std::span<const int>, i.e. whether > what var refers to can be then used in constant expressions or not. > I think from reading [class.temp] and [conv.rval] I lean towards gcc > being right, but maybe I'm missing something important. This sounds like CWG 2126 which we partially implement (PR101588): "a temporary object of non-volatile const-qualified literal type whose lifetime is extended to that of a variable that is usable in constant expressions" is usable in a constant expression std::span<const int> is a literal type so it should work? > 2025-11-15 Jakub Jelinek <[email protected]> > > * parser.cc (cp_build_range_for_decls): For expansion stmts > build __for_range as > static constexpr decltype(auto) __for_range = (range_expr); > rather than static constexpr auto&& __for_range = range_expr; > as per https://github.com/cplusplus/CWG/issues/805. > > * g++.dg/cpp26/expansion-stmt1.C (N::begin, N::end, O::begin, > O::end): Change argument type from B & to const B & or from > D & to const D &. > * g++.dg/cpp26/expansion-stmt2.C (N::begin, N::end, O::begin, > O::end): Likewise. > * g++.dg/cpp26/expansion-stmt3.C (N::begin, N::end, O::begin, > O::end): Likewise. > * g++.dg/cpp26/expansion-stmt16.C: Expect different diagnostics > for C++11. > * g++.dg/cpp26/expansion-stmt18.C (N::begin, N::end): Change > argument type from B & to const B &. > * g++.dg/cpp26/expansion-stmt25.C (N::begin, N::end): Likewise. > * g++.dg/cpp26/expansion-stmt26.C: New test. > > --- gcc/cp/parser.cc.jj 2025-11-14 16:40:33.882192102 +0100 > +++ gcc/cp/parser.cc 2025-11-14 17:56:20.854087295 +0100 > @@ -15205,9 +15205,24 @@ cp_build_range_for_decls (location_t loc > range_temp = range_expr; > else > { > - range_temp = build_range_temp (range_expr); > if (expansion_stmt_p) > { > + /* Build constexpr decltype(auto) __for_range = (range_expr); */ > + location_t range_loc = cp_expr_loc_or_loc (range_expr, loc); > + range_expr > + = finish_parenthesized_expr (cp_expr (range_expr, range_loc)); > + tree auto_node = make_decltype_auto (); > + tree range_type > + = cp_build_qualified_type (auto_node, TYPE_QUAL_CONST); > + range_type = do_auto_deduction (range_type, range_expr, > + auto_node); > + > + /* Create the __range variable. */ > + range_temp = build_decl (input_location, VAR_DECL, > + for_range__identifier, range_type); > + TREE_USED (range_temp) = 1; > + DECL_ARTIFICIAL (range_temp) = 1; This is so close to build_range_temp that I think it should get a "bool expansion_stmt_p" parm so that we can reuse the do_auto_deduction and further code. Marek
