+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>
* decl.c (check_initializer): Call cp_complete_array_type.
return true;
case RANGE_FOR_STMT:
+ if (!RECUR (RANGE_FOR_INIT_STMT (t), any))
+ return false;
if (!RECUR (RANGE_FOR_EXPR (t), any))
return false;
if (!RECUR (RANGE_FOR_BODY (t), any))
DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5)
/* 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_UNROLL respectively. Only used in templates. */
-DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 5)
+ RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
+ RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
+ templates. */
+DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
/* Used to represent a 'while' statement. The operands are WHILE_COND
and WHILE_BODY, respectively. */
#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_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 SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
case RANGE_FOR_STMT:
dump_stmt (di, t);
+ dump_child ("init", RANGE_FOR_INIT_STMT (t));
dump_child ("decl", RANGE_FOR_DECL (t));
dump_child ("expr", RANGE_FOR_EXPR (t));
dump_child ("body", RANGE_FOR_BODY (t));
stmt = (processing_template_decl
? begin_range_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 = tsubst (decl, args, complain, in_decl);
maybe_push_decl (decl);
{
begin_maybe_infinite_loop (boolean_false_node);
- tree r = build_stmt (input_location, RANGE_FOR_STMT,
- NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+ tree r = build_stmt (input_location, RANGE_FOR_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
if (scope == NULL_TREE)
{
scope = begin_for_scope (&init);
}
- /* RANGE_FOR_STMTs do not use nor save the init tree, so we
- pop it now. */
- if (init)
- pop_stmt_list (init);
+ /* Since C++20, RANGE_FOR_STMTs can use the init tree, so save it. */
+ RANGE_FOR_INIT_STMT (r) = init;
RANGE_FOR_SCOPE (r) = scope;
return r;
}
/* 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. */
void
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_EXPR (range_for_stmt) = expr;
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>
PR target/86731
--- /dev/null
+// 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 ();
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
--- /dev/null
+// 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>();
+}
template<int> void foo()
{
int x[8];
- for (int& i, j : x) // { dg-error "multiple" }
- i = 0; // { dg-error "local variable" }
+ for (int& i, j : x) // { dg-error "multiple|reference" }
+ i = 0;
}
void bar()