diff options
author | John McCall <rjmccall@apple.com> | 2011-08-30 00:57:29 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-08-30 00:57:29 +0000 |
commit | 2148011bffc011f8e5f5b6dc1e312fa4afbc10a9 (patch) | |
tree | 0ebdb72742b2fda4b6b07cee2a3390729a2b103c | |
parent | dad879a783f7cf055dd532883cd5efe12bcfd926 (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.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 8 | ||||
-rw-r--r-- | test/CodeGenCXX/rvalue-references.cpp | 18 |
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)) {} +} |