Patchwork [C++0x] PR c++/46056 range-based for loop does not destruct iterators

login
register
mail settings
Submitter Rodrigo Rivas
Date Oct. 20, 2010, 10:04 a.m.
Message ID <AANLkTinwjg3KTdyOrCxA1JTh6Z7u4MKFOpJANrdwsbhp@mail.gmail.com>
Download mbox | patch
Permalink /patch/68420/
State New
Headers show

Comments

Rodrigo Rivas - Oct. 20, 2010, 10:04 a.m.
Hi!

The attached patch solves the mentioned bug. Also, a new testcase is added.

Regards.
Rodrigo

--
gcc/cp

2010-10-20  Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>

       PR c++/46056
       * parser.c (cp_convert_range_for): Call cp_finish_decl
       instead of finish_expr_stmt.

gcc/testsuite/

2010-10-20  Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>

       PR c++/46056
       * g++.dg/cpp0x/range-for7.C: New.
Jason Merrill - Oct. 20, 2010, 2:15 p.m.
Applied, thanks.

Jason

Patch

Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 165681)
+++ gcc/cp/parser.c	(working copy)
@@ -8773,8 +8773,10 @@  cp_convert_range_for (tree statement, tree range_d
   TREE_USED (range_temp) = 1;
   DECL_ARTIFICIAL (range_temp) = 1;
   pushdecl (range_temp);
-  finish_expr_stmt (cp_build_modify_expr (range_temp, INIT_EXPR, range_expr,
-					  tf_warning_or_error));
+  cp_finish_decl (range_temp, range_expr, 
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+
   range_temp = convert_from_reference (range_temp);
 
   if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
@@ -8824,17 +8826,19 @@  cp_convert_range_for (tree statement, tree range_d
   TREE_USED (begin) = 1;
   DECL_ARTIFICIAL (begin) = 1;
   pushdecl (begin);
-  finish_expr_stmt (cp_build_modify_expr (begin, INIT_EXPR, begin_expr,
-					  tf_warning_or_error));
+  cp_finish_decl (begin, begin_expr, 
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
+
   end = build_decl (input_location, VAR_DECL,
 		    get_identifier ("__for_end"), iter_type);
   TREE_USED (end) = 1;
   DECL_ARTIFICIAL (end) = 1;
   pushdecl (end);
+  cp_finish_decl (end, end_expr, 
+		  /*is_constant_init*/false, NULL_TREE,
+		  LOOKUP_ONLYCONVERTING);
 
-  finish_expr_stmt (cp_build_modify_expr (end, INIT_EXPR, end_expr,
-					  tf_warning_or_error));
-
   finish_for_init_stmt (statement);
 
 /* The new for condition */
Index: gcc/testsuite/g++.dg/cpp0x/range-for7.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/range-for7.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/range-for7.C	(revision 0)
@@ -0,0 +1,117 @@ 
+// PR c++/46056
+// Check that range-based for loop calls destructors 
+// when required
+// { dg-options "-std=c++0x" }
+// { dg-do run }
+extern "C" void abort();
+
+int value_counter = 0, it_counter = 0, seq_counter = 0;
+
+struct Int
+{
+    int x;
+    Int(int v)
+        :x(v)
+    {
+        ++value_counter;
+    }
+    Int(const Int &o)
+        :x(o.x)
+    {
+        ++value_counter;
+    }
+    ~Int()
+    {
+        --value_counter;
+    }
+};
+
+struct iterator
+{
+    int x;
+    iterator(int v) 
+        :x(v) 
+    {
+        ++it_counter;
+    }
+    iterator(const iterator &o)
+        :x(o.x)
+    {
+        ++it_counter;
+    }
+    ~iterator() 
+    {
+        --it_counter;
+    }
+    iterator &operator ++() { ++x; return *this; }
+    int operator *() { return x; }
+    bool operator != (const iterator &o) { return x != o.x; }
+};
+
+struct container
+{
+    int min, max;
+    container(int a, int b) :min(a), max(b)
+    {
+        ++seq_counter;
+    }
+    container(const container &) = delete;
+    ~container()
+    {
+        --seq_counter;
+    }
+};
+
+iterator begin(container &c)
+{
+    return iterator(c.min);
+}
+
+iterator end(container &c)
+{
+    return iterator(c.max + 1);
+}
+
+int main()
+{
+    for (Int x : container(0, 10))
+    {
+        if (value_counter != 1) abort();
+        if (it_counter != 2) abort();
+        if (seq_counter != 1) abort();
+    }
+    if (value_counter != 0) abort();
+    if (it_counter != 0) abort();
+    if (seq_counter != 0) abort();
+
+    try
+    {
+        for (Int x : container(0, 10))
+        {
+            if (value_counter != 1) abort();
+            if (it_counter != 2) abort();
+            if (seq_counter != 1) abort();
+        }
+        if (value_counter != 0) abort();
+        if (it_counter != 0) abort();
+        if (seq_counter != 0) abort();
+
+        for (Int x : container(0, 10))
+        {
+            if (value_counter != 1) abort();
+            if (it_counter != 2) abort();
+            if (seq_counter != 1) abort();
+
+            if (x.x == 5)
+                throw 0;
+        }
+    }
+    catch (int)
+    {
+        if (value_counter != 0) abort();
+        if (it_counter != 0) abort();
+        if (seq_counter != 0) abort();
+    }
+
+    return 0;
+}