]> granicus.if.org Git - clang/commitdiff
When producing IR for a lvalue-to-rvalue cast *as an lvalue*, only
authorDouglas Gregor <dgregor@apple.com>
Thu, 27 Jan 2011 23:22:05 +0000 (23:22 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 27 Jan 2011 23:22:05 +0000 (23:22 +0000)
non-class prvalues actually require the realization of a
temporary. For everything else, we already have an lvalue (or class
prvalue) in the subexpression.

Note: we're missing some move elision in this case. I'll tackle that next.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124453 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExpr.cpp
test/CodeGenCXX/rvalue-references.cpp

index ca80d3dd38eb7379e097ae42086eeea250854c54..8bac4c0b02b776dd5b298e3d076bc57ffd7ea9d1 100644 (file)
@@ -1772,11 +1772,12 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   }
 
   case CK_NoOp:
-    if (!E->getSubExpr()->isRValue() || E->getType()->isRecordType())
+  case CK_LValueToRValue:
+    if (!E->getSubExpr()->Classify(getContext()).isPRValue() 
+        || E->getType()->isRecordType())
       return EmitLValue(E->getSubExpr());
     // Fall through to synthesize a temporary.
 
-  case CK_LValueToRValue:
   case CK_BitCast:
   case CK_ArrayToPointerDecay:
   case CK_FunctionToPointerDecay:
index 693e1431ddcab86fbccbe6fccb73922a57d9cc22..a7c74ae5c06d9e2e78891f950afbd78d0cb686b8 100644 (file)
@@ -34,3 +34,55 @@ int &&f1() { return static_cast<int&&>(getIntXValue()); }
 // CHECK-NEXT: store i32 {{.*}}, i32*
 // CHECK-NEXT: ret i32*
 int &&f2() { return static_cast<int&&>(getIntPRValue()); }
+
+bool ok;
+
+class C
+{
+   int* state_;
+
+   C(const C&) = delete;
+   C& operator=(const C&) = delete;
+public:
+  C(int state) : state_(new int(state)) { }
+  
+  C(C&& a) {
+    state_ = a.state_; 
+    a.state_ = 0;
+  }
+
+  ~C() {
+    delete state_; 
+    state_ = 0;
+  }
+};
+
+C test();
+
+// CHECK: define void @_Z15elide_copy_initv
+void elide_copy_init() {
+  ok = false;
+  // FIXME: We're doing an extra move here, when we shouldn't be!
+  // CHECK: call void @_Z4testv(%class.C* sret %ref.tmp)
+  // CHECK: call void @_ZN1CC1EOS_(%class.C* %a, %class.C* %ref.tmp)
+  // CHECK: call void @_ZN1CD1Ev(%class.C* %ref.tmp)
+  C a = test();
+  // CHECK: call void @_ZN1CD1Ev(%class.C* %a)
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z16test_move_returnv
+C test_move_return() {
+  // CHECK: call void @_ZN1CC1Ei
+  C a1(3);
+  // CHECK: call void @_ZN1CC1Ei
+  C a2(4);
+  if (ok)
+    // CHECK: call void @_ZN1CC1EOS_
+    return a1;
+  // CHECK: call void @_ZN1CC1EOS_
+  return a2;
+  // CHECK: call void @_ZN1CD1Ev
+  // CHECK: call void @_ZN1CD1Ev
+  //CHECK:  ret void
+}