Patchwork C++0x PATCH for c++/46103 (wrong implicit move of class with array member)

login
register
mail settings
Submitter Jason Merrill
Date Oct. 22, 2010, 6:32 p.m.
Message ID <4CC1D8C7.9090307@redhat.com>
Download mbox | patch
Permalink /patch/68898/
State New
Headers show

Comments

Jason Merrill - Oct. 22, 2010, 6:32 p.m.
When doing a piecewise move of an array member, we need to preserve the 
xvalueness of the initializer; this was broken because we take the 
address and then dereference the resulting pointer, which produces an 
lvalue.  It would probably be better to avoid that and just use an 
ARRAY_REF rather than a pointer, but fixing the current strategy was 
pretty trivial.

Tested x86_64-pc-linux-gnu, applied to trunk.

Patch

commit b517d58d38264bb3c6deec5fd4dc31884b178f39
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Oct 22 09:57:27 2010 -0400

    	PR c++/46103
    	* init.c (build_vec_init): Handle memberwise move.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5091d4e..72fcf78 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2849,6 +2849,7 @@  build_vec_init (tree base, tree maxindex, tree init,
   tree try_block = NULL_TREE;
   int num_initialized_elts = 0;
   bool is_global;
+  bool xvalue = false;
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
     maxindex = array_type_nelts (atype);
@@ -2939,6 +2940,8 @@  build_vec_init (tree base, tree maxindex, tree init,
      checking.  Evaluate the initializer before entering the try block.  */
   if (from_array && init && TREE_CODE (init) != CONSTRUCTOR)
     {
+      if (lvalue_kind (init) & clk_rvalueref)
+	xvalue = true;
       base2 = decay_conversion (init);
       itype = TREE_TYPE (base2);
       base2 = get_temp_regvar (itype, base2);
@@ -3033,7 +3036,11 @@  build_vec_init (tree base, tree maxindex, tree init,
 	  tree from;
 
 	  if (base2)
-	    from = build1 (INDIRECT_REF, itype, base2);
+	    {
+	      from = build1 (INDIRECT_REF, itype, base2);
+	      if (xvalue)
+		from = move (from);
+	    }
 	  else
 	    from = NULL_TREE;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit10.C b/gcc/testsuite/g++.dg/cpp0x/implicit10.C
new file mode 100644
index 0000000..721a93d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/implicit10.C
@@ -0,0 +1,19 @@ 
+// PR c++/46103
+// { dg-options -std=c++0x }
+
+struct MoveOnly {
+  MoveOnly(const MoveOnly&) = delete;
+  MoveOnly(MoveOnly&&) { }
+  MoveOnly() = default;
+};
+
+struct A {
+  MoveOnly mo[1];
+  A() = default;
+  A(A&&) = default;
+};
+
+int main() {
+  A a;
+  A aa = static_cast<A&&>(a);
+}