extern tree cp_build_range_for_decls (location_t, tree, tree *, bool);
extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool,
tree, bool);
-extern tree build_range_temp (tree);
+extern tree build_range_temp (tree, bool = false);
extern tree cp_perform_range_for_lookup (tree, tree *, tree *,
tsubst_flags_t = tf_warning_or_error);
extern void cp_convert_omp_range_for (tree &, tree &, tree &,
builds up the range temporary. */
tree
-build_range_temp (tree range_expr)
+build_range_temp (tree range_expr, bool expansion_stmt_p /* = false */)
{
- /* Find out the type deduced by the declaration
- `auto &&__range = range_expr'. */
- tree auto_node = make_auto ();
- tree range_type = cp_build_reference_type (auto_node, true);
+ tree range_type, auto_node;
+
+ if (expansion_stmt_p)
+ {
+ /* Build const decltype(auto) __range = range_expr;
+ - range_expr provided by the caller already is (range_expr). */
+ auto_node = make_decltype_auto ();
+ range_type = cp_build_qualified_type (auto_node, TYPE_QUAL_CONST);
+ }
+ else
+ {
+ /* Find out the type deduced by the declaration
+ `auto &&__range = range_expr'. */
+ auto_node = make_auto ();
+ range_type = cp_build_reference_type (auto_node, true);
+ }
range_type = do_auto_deduction (range_type, range_expr, auto_node);
/* Create the __range variable. */
range_temp = range_expr;
else
{
- range_temp = build_range_temp (range_expr);
if (expansion_stmt_p)
{
- /* Depending on CWG3044 resolution, we might want to remove
- these 3 sets of TREE_STATIC (on range_temp, begin and end).
- Although it can only be done when P2686R4 is fully
- implemented. */
+ /* 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));
+ range_temp = build_range_temp (range_expr, true);
+
+ /* When P2686R4 is fully implemented, these 3 sets of TREE_STATIC
+ (on range_temp, begin and end) should be removed as per
+ CWG3044. */
TREE_STATIC (range_temp) = 1;
TREE_PUBLIC (range_temp) = 0;
DECL_COMMON (range_temp) = 0;
DECL_DECLARED_CONSTEXPR_P (range_temp) = 1;
TREE_READONLY (range_temp) = 1;
}
+ else
+ /* Build auto &&__for_range = range_expr; */
+ range_temp = build_range_temp (range_expr);
+
pushdecl (range_temp);
cp_finish_decl (range_temp, range_expr,
/*is_constant_init*/false, NULL_TREE,
namespace N
{
struct B { constexpr B () {} };
- constexpr A begin (B &) { return A (0); }
- constexpr A end (B &) { return A (6); }
+ constexpr A begin (const B &) { return A (0); }
+ constexpr A end (const B &) { return A (6); }
}
namespace O
{
struct D { constexpr D () {} };
- constexpr C begin (D &) { return C (0, 42, 5); }
- constexpr C end (D &) { return C (6, 36, 11); }
+ constexpr C begin (const D &) { return C (0, 42, 5); }
+ constexpr C end (const D &) { return C (6, 36, 11); }
}
long long
{
B c = { 3 };
template for (constexpr auto g : c) // { dg-warning "'template for' only available with" "" { target c++23_down } }
- ; // { dg-error "'c' is not a constant expression" "" { target *-*-* } .-1 }
+ ; // { dg-error "'c' is not a constant expression" "" { target c++14 } .-1 }
+ // { dg-error "the value of 'c' is not usable in a constant expression" "" { target c++11_down } .-1 }
C d = { 3 };
template for (constexpr auto g : d) // { dg-warning "'template for' only available with" "" { target c++23_down } }
- ; // { dg-error "'d' is not a constant expression" "" { target *-*-* } .-1 }
+ ; // { dg-error "'d' is not a constant expression" "" { target c++14 } .-1 }
// { dg-error "call to non-'constexpr' function 'const A\\\* C::begin\\\(\\\) const'" "" { target c++11_down } .-1 }
// { dg-error "call to non-'constexpr' function 'const A\\\* C::end\\\(\\\) const'" "" { target c++11_down } .-2 }
+ // { dg-error "the type 'const C' of 'constexpr' variable '__for_range ' is not literal" "" { target c++11_down } .-3 }
constexpr D e = { 3 };
template for (constexpr auto g : e) // { dg-warning "'template for' only available with" "" { target c++23_down } }
- ; // { dg-error "'e' is not a constant expression" "" { target *-*-* } .-1 }
+ ; // { dg-error "'e' is not a constant expression" "" { target c++14 } .-1 }
// { dg-error "call to non-'constexpr' function 'const A\\\* D::end\\\(\\\) const'" "" { target *-*-* } .-1 }
constexpr E f = { 3 };
template for (constexpr auto g : f) // { dg-warning "'template for' only available with" "" { target c++23_down } }
- ; // { dg-error "'f' is not a constant expression" "" { target *-*-* } .-1 }
+ ; // { dg-error "'f' is not a constant expression" "" { target c++14 } .-1 }
// { dg-error "call to non-'constexpr' function 'const A\\\* E::begin\\\(\\\) const'" "" { target *-*-* } .-1 }
constexpr G h = { 3 };
template for (constexpr auto g : h) // { dg-warning "'template for' only available with" "" { target c++23_down } }
- ; // { dg-error "'h' is not a constant expression" "" { target *-*-* } .-1 }
+ ; // { dg-error "'h' is not a constant expression" "" { target c++14 } .-1 }
+ // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target c++11_down } .-2 }
template for (constexpr auto g : { 1, 2, F { 3 }, 4L }) // { dg-warning "'template for' only available with" "" { target c++23_down } }
; // { dg-error "the type 'const F' of 'constexpr' variable 'g' is not literal" "" { target *-*-* } .-1 }
template for (constexpr auto g : H {})// { dg-warning "'template for' only available with" "" { target c++23_down } }
namespace N
{
struct B { constexpr B () {} };
- constexpr A begin (B &) { return A (0); }
- constexpr A end (B &) { return A (6); }
+ constexpr A begin (const B &) { return A (0); }
+ constexpr A end (const B &) { return A (6); }
}
void
namespace N
{
struct B { constexpr B () {} };
- constexpr A begin (B &) { return A (0); }
- constexpr A end (B &) { return A (6); }
+ constexpr A begin (const B &) { return A (0); }
+ constexpr A end (const B &) { return A (6); }
}
namespace O
{
struct D { constexpr D () {} };
- constexpr C begin (D &) { return C (0, 42, 5); }
- constexpr C end (D &) { return C (6, 36, 11); }
+ constexpr C begin (const D &) { return C (0, 42, 5); }
+ constexpr C end (const D &) { return C (6, 36, 11); }
}
#if __cpp_nontype_template_parameter_class >= 201806L
namespace N
{
struct B { constexpr B () {} };
- constexpr A begin (B &) { return A (0); }
- constexpr A end (B &) { return A (6); }
+ constexpr A begin (const B &) { return A (0); }
+ constexpr A end (const B &) { return A (6); }
}
void
--- /dev/null
+// C++26 P1306R5 - Expansion statements
+// { dg-do run { target c++23 } }
+// { dg-options "" }
+
+#include <span>
+
+constexpr int arr[3] = { 1, 2, 3 };
+consteval std::span <const int> foo () { return std::span <const int> (arr); }
+
+int
+main ()
+{
+ int r = 0;
+ template for (constexpr auto m : foo ()) // { dg-warning "'template for' only available with" "" { target c++23_down } }
+ r += m;
+ if (r != 6)
+ __builtin_abort ();
+}
namespace N
{
struct B { constexpr B () {} };
- constexpr A begin (B &) { return A (0); }
- constexpr A end (B &) { return A (6); }
+ constexpr A begin (const B &) { return A (0); }
+ constexpr A end (const B &) { return A (6); }
}
namespace O
{
struct D { constexpr D () {} };
- constexpr C begin (D &) { return C (0, 42, 5); }
- constexpr C end (D &) { return C (6, 36, 11); }
+ constexpr C begin (const D &) { return C (0, 42, 5); }
+ constexpr C end (const D &) { return C (6, 36, 11); }
}
template <int N>
consteval void bar() {
template for (constexpr int I : foo()) {
// doesn't work
- } // { dg-error "modification of '<temporary>' from outside current evaluation is not a constant expression" }
+ } // { dg-error "'foo\\\(\\\)' is not a constant expression because it refers to a result of 'operator new'" }
}
consteval int baz() {
int r = 0;
-#if 0
- // TODO: This doesn't work yet.
template for (constexpr int I : std::define_static_array(foo())) {
r += I;
}
-#else
- // Ugly workaround for that.
- template for (constexpr int I : (const std::span<const int>)std::define_static_array(foo())) {
- r += I;
- }
-#endif
return r;
}
return (... + m);
}
+consteval int garply() {
+ int r = 0;
+ template for (constexpr int I : (const std::span<const int>)std::define_static_array(foo())) {
+ r += I;
+ }
+ return r;
+}
+
static_assert (baz() == 6);
static_assert (qux() == 6);
static_assert (fred<int>() == 6);
+static_assert (garply() == 6);