@@ -4665,11 +4665,13 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
build_int_cst (TREE_TYPE (iterator), -1)),
for_stmt, false, 0);
- elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
- complain);
- if (elt_init == error_mark_node)
- errors = true;
- finish_for_expr (elt_init, for_stmt);
+ /* We used to pass this decrement to finish_for_expr; now we add it to
+ elt_init below so it's part of the same full-expression as the
+ initialization, and thus happens before any potentially throwing
+ temporary cleanups. */
+ tree decr = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
+ complain);
+
to = build1 (INDIRECT_REF, type, base);
@@ -4794,7 +4796,10 @@ build_vec_init (tree base, tree maxindex, tree init,
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
if (elt_init && !errors)
- finish_expr_stmt (elt_init);
+ elt_init = build2 (COMPOUND_EXPR, void_type_node, elt_init, decr);
+ else
+ elt_init = decr;
+ finish_expr_stmt (elt_init);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, false,
new file mode 100644
@@ -0,0 +1,43 @@
+// Test that we clean up the right number of array elements when
+// a temporary destructor throws.
+// { dg-do run }
+
+#if __cplusplus > 201100L
+#define THROWING noexcept(false)
+#else
+#define THROWING
+#endif
+
+extern "C" void abort ();
+
+int b;
+int d = -1;
+struct A {
+ A() { }
+ A(const A&);
+ ~A() THROWING {
+ if (b == d) throw b;
+ }
+};
+struct B {
+ B(const A& = A()) { ++b; }
+ B(const B&);
+ ~B() { --b; }
+};
+void f()
+{
+ b = 0;
+ try
+ {
+ B bs[3];
+ if (b != 3) abort ();
+ }
+ catch (int i) { }
+ if (b != 0) abort ();
+}
+
+int main()
+{
+ for (d = 0; d <= 3; ++d)
+ f();
+}