Correctly pass aggregates by reference when emitting thunks.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104778 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 0d6a70c..73cee3c 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -862,6 +862,36 @@
   }
 }
 
+RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) {
+  // StartFunction converted the ABI-lowered parameter(s) into a
+  // local alloca.  We need to turn that into an r-value suitable
+  // for EmitCall.
+  llvm::Value *Local = GetAddrOfLocalVar(Param);
+
+  QualType ArgType = Param->getType();
+ 
+  // For the most part, we just need to load the alloca, except:
+  // 1) aggregate r-values are actually pointers to temporaries, and
+  // 2) references to aggregates are pointers directly to the aggregate.
+  // I don't know why references to non-aggregates are different here.
+  if (const ReferenceType *RefType = ArgType->getAs<ReferenceType>()) {
+    if (hasAggregateLLVMType(RefType->getPointeeType()))
+      return RValue::getAggregate(Local);
+
+    // Locals which are references to scalars are represented
+    // with allocas holding the pointer.
+    return RValue::get(Builder.CreateLoad(Local));
+  }
+
+  if (ArgType->isAnyComplexType())
+    return RValue::getComplex(LoadComplexFromAddr(Local, /*volatile*/ false));
+
+  if (hasAggregateLLVMType(ArgType))
+    return RValue::getAggregate(Local);
+
+  return RValue::get(EmitLoadOfScalar(Local, false, ArgType));
+}
+
 RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
   if (ArgType->isReferenceType())
     return EmitReferenceBindingToExpr(E);