From: John McCall Date: Tue, 30 Aug 2011 00:57:29 +0000 (+0000) Subject: Be sure to emit lvalue-to-rvalue casts for loads from x-values. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2148011bffc011f8e5f5b6dc1e312fa4afbc10a9;p=clang 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 --- 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(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)) {} +}