aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-01-27 23:22:05 +0000
committerDouglas Gregor <dgregor@apple.com>2011-01-27 23:22:05 +0000
commitb3d5e2f181269656c1b2dbc09eab1f449d5074aa (patch)
treebb5c7ce777b9c47957038011643627ac60d0f2a3
parent1e8011e2fcddc4a638d210ec2dcd21adcf7b1763 (diff)
When producing IR for a lvalue-to-rvalue cast *as an lvalue*, only
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
-rw-r--r--lib/CodeGen/CGExpr.cpp5
-rw-r--r--test/CodeGenCXX/rvalue-references.cpp52
2 files changed, 55 insertions, 2 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ca80d3dd38..8bac4c0b02 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -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:
diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp
index 693e1431dd..a7c74ae5c0 100644
--- a/test/CodeGenCXX/rvalue-references.cpp
+++ b/test/CodeGenCXX/rvalue-references.cpp
@@ -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
+}