aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-08-30 00:57:29 +0000
committerJohn McCall <rjmccall@apple.com>2011-08-30 00:57:29 +0000
commit2148011bffc011f8e5f5b6dc1e312fa4afbc10a9 (patch)
tree0ebdb72742b2fda4b6b07cee2a3390729a2b103c
parentdad879a783f7cf055dd532883cd5efe12bcfd926 (diff)
Be sure to emit lvalue-to-rvalue casts for loads from x-values.
Doing this happens to disrupt the pattern that ARC was looking for for move optimizations, so we need to fix that simultaneously. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138789 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGObjC.cpp42
-rw-r--r--lib/Sema/SemaOverload.cpp8
-rw-r--r--test/CodeGenCXX/rvalue-references.cpp18
3 files changed, 40 insertions, 28 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 179dc75b31..f8f19285b3 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -1879,6 +1879,24 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
e = e->IgnoreParens();
QualType type = e->getType();
+ // If we're loading retained from a __strong xvalue, we can avoid
+ // an extra retain/release pair by zeroing out the source of this
+ // "move" operation.
+ if (e->isXValue() &&
+ !type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Emit the lvalue.
+ LValue lv = CGF.EmitLValue(e);
+
+ // Load the object pointer.
+ llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
+
+ // Set the source pointer to NULL.
+ CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
+
+ return TryEmitResult(result, true);
+ }
+
// As a very special optimization, in ARC++, if the l-value is the
// result of a non-volatile assignment, do a simple retain of the
// result of the call to objc_storeWeak instead of reloading.
@@ -1953,30 +1971,6 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// ultimate opaque expression.
llvm::Type *resultType = 0;
- // If we're loading retained from a __strong xvalue, we can avoid
- // an extra retain/release pair by zeroing out the source of this
- // "move" operation.
- if (e->isXValue() && !e->getType().isConstQualified() &&
- e->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
- // Emit the lvalue
- LValue lv = CGF.EmitLValue(e);
-
- // Load the object pointer and cast it to the appropriate type.
- QualType exprType = e->getType();
- llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
-
- if (resultType)
- result = CGF.Builder.CreateBitCast(result, resultType);
-
- // Set the source pointer to NULL.
- llvm::Value *null
- = llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(CGF.ConvertType(exprType)));
- CGF.EmitStoreOfScalar(null, lv);
-
- return TryEmitResult(result, true);
- }
-
while (true) {
e = e->IgnoreParens();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e3c5f83735..6f3b1aa7bf 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1113,10 +1113,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
return false;
}
}
- // Lvalue-to-rvalue conversion (C++ 4.1):
- // An lvalue (3.10) of a non-function, non-array type T can be
- // converted to an rvalue.
- bool argIsLValue = From->isLValue();
+ // Lvalue-to-rvalue conversion (C++11 4.1):
+ // A glvalue (3.10) of a non-function, non-array type T can
+ // be converted to a prvalue.
+ bool argIsLValue = From->isGLValue();
if (argIsLValue &&
!FromType->isFunctionType() && !FromType->isArrayType() &&
S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
diff --git a/test/CodeGenCXX/rvalue-references.cpp b/test/CodeGenCXX/rvalue-references.cpp
index e15172355e..f8e3eb29dd 100644
--- a/test/CodeGenCXX/rvalue-references.cpp
+++ b/test/CodeGenCXX/rvalue-references.cpp
@@ -83,3 +83,21 @@ C test_move_return() {
// CHECK: call void @_ZN1CD1Ev
//CHECK: ret void
}
+
+// PR10800: don't crash
+namespace test1 {
+ int &&move(int&);
+
+ struct A { A(int); };
+ struct B {
+ A a;
+ B(int i);
+ };
+
+ // CHECK: define void @_ZN5test11BC2Ei(
+ // CHECK: [[T0:%.*]] = call i32* @_ZN5test14moveERi(
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]]
+ // CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]])
+ // CHECK-NEXT: ret void
+ B::B(int i) : a(move(i)) {}
+}