Commit 8112667c by Marek Polacek Committed by Marek Polacek

PR c++/87152 - range-based for loops with initializer broken in templates.

	* constexpr.c (potential_constant_expression_1) <case RANGE_FOR_STMT>:
	Recur into RANGE_FOR_INIT_STMT.
	* cp-tree.def: Add RANGE_FOR_INIT_STMT to RANGE_FOR_STMT.
	* cp-tree.h (RANGE_FOR_INIT_STMT): Define.
	* dump.c (cp_dump_tree) <case RANGE_FOR_STMT>: Also dump
	RANGE_FOR_INIT_STMT.
	* pt.c (tsubst_expr) <case RANGE_FOR_STMT>: Recur into
	RANGE_FOR_INIT_STMT.
	* semantics.c (begin_range_for_stmt): Adjust call to build_stmt.
	Do put the init statement in RANGE_FOR_INIT_STMT.
	(finish_range_for_decl): Pop it for templates.

	* g++.dg/cpp2a/range-for11.C: New test.
	* g++.dg/cpp2a/range-for12.C: New test.
	* g++.dg/cpp2a/range-for13.C: New test.
	* g++.dg/cpp2a/range-for14.C: New test.
	* g++.dg/cpp2a/range-for15.C: New test.
	* g++.dg/cpp2a/range-for16.C: New test.
	* g++.dg/cpp2a/range-for17.C: New test.
	* g++.dg/cpp2a/range-for18.C: New test.
	* g++.dg/parse/error61.C (foo): Adjust dg-error.

From-SVN: r264158
parent 6bf9284f
2018-09-07 Marek Polacek <polacek@redhat.com>
PR c++/87152 - range-based for loops with initializer broken in templates.
* constexpr.c (potential_constant_expression_1) <case RANGE_FOR_STMT>:
Recur into RANGE_FOR_INIT_STMT.
* cp-tree.def: Add RANGE_FOR_INIT_STMT to RANGE_FOR_STMT.
* cp-tree.h (RANGE_FOR_INIT_STMT): Define.
* dump.c (cp_dump_tree) <case RANGE_FOR_STMT>: Also dump
RANGE_FOR_INIT_STMT.
* pt.c (tsubst_expr) <case RANGE_FOR_STMT>: Recur into
RANGE_FOR_INIT_STMT.
* semantics.c (begin_range_for_stmt): Adjust call to build_stmt.
Do put the init statement in RANGE_FOR_INIT_STMT.
(finish_range_for_decl): Pop it for templates.
2018-09-06 Bernd Edlinger <bernd.edlinger@hotmail.de> 2018-09-06 Bernd Edlinger <bernd.edlinger@hotmail.de>
* decl.c (check_initializer): Call cp_complete_array_type. * decl.c (check_initializer): Call cp_complete_array_type.
......
...@@ -5767,6 +5767,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, ...@@ -5767,6 +5767,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
return true; return true;
case RANGE_FOR_STMT: case RANGE_FOR_STMT:
if (!RECUR (RANGE_FOR_INIT_STMT (t), any))
return false;
if (!RECUR (RANGE_FOR_EXPR (t), any)) if (!RECUR (RANGE_FOR_EXPR (t), any))
return false; return false;
if (!RECUR (RANGE_FOR_BODY (t), any)) if (!RECUR (RANGE_FOR_BODY (t), any))
......
...@@ -301,9 +301,10 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4) ...@@ -301,9 +301,10 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5) DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5)
/* Used to represent a range-based `for' statement. The operands are /* Used to represent a range-based `for' statement. The operands are
RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, and RANGE_FOR_SCOPE, RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
RANGE_FOR_UNROLL respectively. Only used in templates. */ RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 5) templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
/* Used to represent a 'while' statement. The operands are WHILE_COND /* Used to represent a 'while' statement. The operands are WHILE_COND
and WHILE_BODY, respectively. */ and WHILE_BODY, respectively. */
......
...@@ -4923,6 +4923,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -4923,6 +4923,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define RANGE_FOR_BODY(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 2) #define RANGE_FOR_BODY(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 2)
#define RANGE_FOR_SCOPE(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 3) #define RANGE_FOR_SCOPE(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 3)
#define RANGE_FOR_UNROLL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4) #define RANGE_FOR_UNROLL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4)
#define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5)
#define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE))
#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) #define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
......
...@@ -301,6 +301,7 @@ cp_dump_tree (void* dump_info, tree t) ...@@ -301,6 +301,7 @@ cp_dump_tree (void* dump_info, tree t)
case RANGE_FOR_STMT: case RANGE_FOR_STMT:
dump_stmt (di, t); dump_stmt (di, t);
dump_child ("init", RANGE_FOR_INIT_STMT (t));
dump_child ("decl", RANGE_FOR_DECL (t)); dump_child ("decl", RANGE_FOR_DECL (t));
dump_child ("expr", RANGE_FOR_EXPR (t)); dump_child ("expr", RANGE_FOR_EXPR (t));
dump_child ("body", RANGE_FOR_BODY (t)); dump_child ("body", RANGE_FOR_BODY (t));
......
...@@ -16815,6 +16815,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, ...@@ -16815,6 +16815,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
stmt = (processing_template_decl stmt = (processing_template_decl
? begin_range_for_stmt (NULL_TREE, NULL_TREE) ? begin_range_for_stmt (NULL_TREE, NULL_TREE)
: begin_for_stmt (NULL_TREE, NULL_TREE)); : begin_for_stmt (NULL_TREE, NULL_TREE));
RECUR (RANGE_FOR_INIT_STMT (t));
decl = RANGE_FOR_DECL (t); decl = RANGE_FOR_DECL (t);
decl = tsubst (decl, args, complain, in_decl); decl = tsubst (decl, args, complain, in_decl);
maybe_push_decl (decl); maybe_push_decl (decl);
......
...@@ -1101,8 +1101,8 @@ begin_range_for_stmt (tree scope, tree init) ...@@ -1101,8 +1101,8 @@ begin_range_for_stmt (tree scope, tree init)
{ {
begin_maybe_infinite_loop (boolean_false_node); begin_maybe_infinite_loop (boolean_false_node);
tree r = build_stmt (input_location, RANGE_FOR_STMT, tree r = build_stmt (input_location, RANGE_FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
if (scope == NULL_TREE) if (scope == NULL_TREE)
{ {
...@@ -1110,22 +1110,23 @@ begin_range_for_stmt (tree scope, tree init) ...@@ -1110,22 +1110,23 @@ begin_range_for_stmt (tree scope, tree init)
scope = begin_for_scope (&init); scope = begin_for_scope (&init);
} }
/* RANGE_FOR_STMTs do not use nor save the init tree, so we /* Since C++20, RANGE_FOR_STMTs can use the init tree, so save it. */
pop it now. */ RANGE_FOR_INIT_STMT (r) = init;
if (init)
pop_stmt_list (init);
RANGE_FOR_SCOPE (r) = scope; RANGE_FOR_SCOPE (r) = scope;
return r; return r;
} }
/* Finish the head of a range-based for statement, which may /* Finish the head of a range-based for statement, which may
be given by RANGE_FOR_STMT. DECL must be the declaration be given by RANGE_FOR_STMT. DECL must be the declaration
and EXPR must be the loop expression. */ and EXPR must be the loop expression. */
void void
finish_range_for_decl (tree range_for_stmt, tree decl, tree expr) finish_range_for_decl (tree range_for_stmt, tree decl, tree expr)
{ {
if (processing_template_decl)
RANGE_FOR_INIT_STMT (range_for_stmt)
= pop_stmt_list (RANGE_FOR_INIT_STMT (range_for_stmt));
RANGE_FOR_DECL (range_for_stmt) = decl; RANGE_FOR_DECL (range_for_stmt) = decl;
RANGE_FOR_EXPR (range_for_stmt) = expr; RANGE_FOR_EXPR (range_for_stmt) = expr;
add_stmt (range_for_stmt); add_stmt (range_for_stmt);
......
2018-09-07 Marek Polacek <polacek@redhat.com>
PR c++/87152 - range-based for loops with initializer broken in templates.
* g++.dg/cpp2a/range-for11.C: New test.
* g++.dg/cpp2a/range-for12.C: New test.
* g++.dg/cpp2a/range-for13.C: New test.
* g++.dg/cpp2a/range-for14.C: New test.
* g++.dg/cpp2a/range-for15.C: New test.
* g++.dg/cpp2a/range-for16.C: New test.
* g++.dg/cpp2a/range-for17.C: New test.
* g++.dg/cpp2a/range-for18.C: New test.
* g++.dg/parse/error61.C (foo): Adjust dg-error.
2018-09-06 Will Schmidt <will_schmidt@vnet.ibm.com> 2018-09-06 Will Schmidt <will_schmidt@vnet.ibm.com>
PR target/86731 PR target/86731
......
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
template<typename>
int foo ()
{
int a[] = { 1, 2, 3, 4, 5 };
int j = 0;
for (int i = 0; auto x : a)
j += i++;
return j;
}
int
main ()
{
int j = foo<int>();
if (j != 10)
__builtin_abort ();
}
// PR c++/87152
// { dg-do compile }
// { dg-options "-std=c++2a" }
static const int a[] = { 1, 2, 3, 4, 5 };
extern void foo (int);
extern void bar (int, int);
constexpr int
baz ()
{
return 6;
}
template<typename T>
void
fn1 (T i)
{
for ((i += 2); auto x : a)
foo (i);
for (auto j = 0, k = 0; auto x : a)
bar (j + k, x);
for (constexpr int j = baz (); auto x : a)
bar (x, j);
}
void
do_fn1 ()
{
fn1<int>(10);
}
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
template<typename T>
void foo ()
{
int a[] = { 1, 2, 3, 4, 5 };
for (T i = 1; auto x : a)
if (i++ != x)
__builtin_abort ();
T i;
for (i = 1; auto x : a)
if (i++ != x)
__builtin_abort ();
i = 0;
for (i++; auto x : a)
if (i != 1)
__builtin_abort ();
for (T s[] = { 1, 1, 1 }; auto x : s)
if (x != 1)
__builtin_abort ();
}
int
main ()
{
foo<int>();
}
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
template<typename T>
void
fn ()
{
T a[] = { 1, 2, 3, 4, 5 };
for (T i = []{ return 3; }(); auto x : a)
if (i != 3)
__builtin_abort ();
for (T i = ({ 3; }); auto x : a)
if (i != 3)
__builtin_abort ();
}
int
main ()
{
fn<int>();
}
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
struct A { int i; long long j; } a[64];
template<typename T>
void foo ()
{
for (T i = 0; auto &x : a)
{
x.i = i;
x.j = 2 * i++;
}
for (auto & [ x, y ] : a)
{
x += 2;
y += 3;
}
for (T i = 0; const auto [ u, v ] : a)
{
if (u != i + 2 || v != 2 * i++ + 3)
__builtin_abort ();
}
for (T i = 0; auto [ x, y ] : a)
{
x += 4;
y += 5;
if (x != i + 6 || y != 2 * i++ + 8)
__builtin_abort ();
}
for (T i = 0; const auto x : a)
{
if (x.i != i + 2 || x.j != 2 * i++ + 3)
__builtin_abort ();
}
}
int
main ()
{
foo<int>();
}
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
struct A { int i, j; };
template<typename T>
void foo ()
{
A a = { .i = 2, .j = 3 };
T arr[] = { 1, 1, 1 };
for (auto & [ x, y ] = a; auto z : arr)
if (x + z != 3 || y + z != 4)
__builtin_abort ();
for (T d = 1; auto &z : arr)
z += d;
for (const auto [ x, y ] = a; auto z : arr)
if (x + z != 4 || y + z != 5)
__builtin_abort ();
for (T d = 1; auto &z : arr)
z += d;
for (auto [ x, y ] = a; auto z : arr)
if (x + z != 5 || y + z != 6)
__builtin_abort ();
}
int
main ()
{
foo<int>();
}
// PR c++/87152
// { dg-do run }
// { dg-options "-std=c++2a" }
struct A { int i; long long j; } a[64];
template<typename>
void foo ()
{
A b = { 1, 2 };
for (auto & [ u, v ] : a)
{
u = 2;
v = 3;
}
for (auto [x, y] = b; auto [ u, v ] : a)
if (y + u != x + v)
__builtin_abort ();
for (auto [x, y] = b; auto & [ u, v ] : a)
if (y + u != x + v)
__builtin_abort ();
}
int
main ()
{
foo<int>();
}
// PR c++/87152
// { dg-do compile }
// { dg-options "-std=c++2a" }
template<int> void foo()
{
int a[] = { 1, 1, 1 };
for (int i = 0; auto x : a);
int i;
}
void
bar ()
{
foo<0>();
}
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
template<int> void foo() template<int> void foo()
{ {
int x[8]; int x[8];
for (int& i, j : x) // { dg-error "multiple" } for (int& i, j : x) // { dg-error "multiple|reference" }
i = 0; // { dg-error "local variable" } i = 0;
} }
void bar() void bar()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment