]> granicus.if.org Git - clang/commitdiff
Be sure to emit lvalue-to-rvalue casts for loads from x-values.
authorJohn McCall <rjmccall@apple.com>
Tue, 30 Aug 2011 00:57:29 +0000 (00:57 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 30 Aug 2011 00:57:29 +0000 (00:57 +0000)
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

lib/CodeGen/CGObjC.cpp
lib/Sema/SemaOverload.cpp
test/CodeGenCXX/rvalue-references.cpp

index 179dc75b31daa224eab1ad1df5a9e078f217a2eb..f8f19285b35f7ecc6c4bd160833ecaa03ede4494 100644 (file)
@@ -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();
 
index e3c5f83735309a4780ce8b8e83577fc439a8323a..6f3b1aa7bf598019d7a551a7bcb3390e74be7371 100644 (file)
@@ -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) {
index e15172355ebd19784822d731c370cac9015dbf51..f8e3eb29dd80346b2e6c4061d4d985a192a22fee 100644 (file)
@@ -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)) {}
+}