Enhance GRExprEngine::VisitCallExpr() to be used in an lvalue context.  Uncovered a new failing test case along the way, but we're making progress on handling C++ references in the analyzer.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91710 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 9b00d1e..4295e9a 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -46,6 +46,23 @@
   return Ctx.Selectors.getSelector(0, &II);
 }
 
+static bool CalleeReturnsReference(const CallExpr *CE) { 
+  const Expr *Callee = CE->getCallee();
+  QualType T = Callee->getType();
+  
+  
+  if (const PointerType *PT = T->getAs<PointerType>()) {
+    const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
+    T = FT->getResultType();
+  }
+  else {
+    const BlockPointerType *BT = T->getAs<BlockPointerType>();
+    T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
+  }
+  
+  return T->isReferenceType();
+}
+
 //===----------------------------------------------------------------------===//
 // Batch auditor.  DEPRECATED.
 //===----------------------------------------------------------------------===//
@@ -228,7 +245,7 @@
       CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
       CurrSet->clear();
     }
-    
+
     void *tag = I->first;
     Checker *checker = I->second;
     
@@ -593,7 +610,7 @@
     case Stmt::CallExprClass:
     case Stmt::CXXOperatorCallExprClass: {
       CallExpr* C = cast<CallExpr>(S);
-      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false);
       break;
     }
 
@@ -745,6 +762,14 @@
       VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
       return;
       
+    case Stmt::CallExprClass:
+    case Stmt::CXXOperatorCallExprClass: {
+      CallExpr* C = cast<CallExpr>(Ex);
+      assert(CalleeReturnsReference(C));
+      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);      
+      break;
+    }
+      
     case Stmt::CompoundLiteralExprClass:
       VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
       return;      
@@ -1563,7 +1588,7 @@
 void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
                              CallExpr::arg_iterator AI,
                              CallExpr::arg_iterator AE,
-                             ExplodedNodeSet& Dst) {
+                             ExplodedNodeSet& Dst, bool asLValue) {
 
   // Determine the type of function we're calling (if available).
   const FunctionProtoType *Proto = NULL;
@@ -1577,7 +1602,7 @@
   WorkList.push_back(CallExprWLItem(AI, Pred));
   
   ExplodedNodeSet ArgsEvaluated;
-  
+
   while (!WorkList.empty()) {
     CallExprWLItem Item = WorkList.back();
     WorkList.pop_back();
@@ -1623,6 +1648,7 @@
   // Finally, evaluate the function call.  We try each of the checkers
   // to see if the can evaluate the function call.
   ExplodedNodeSet DstTmp3;
+
   
   for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
        DI != DE; ++DI) {
@@ -1664,7 +1690,28 @@
   
   // Finally, perform the post-condition check of the CallExpr and store
   // the created nodes in 'Dst'.
-  CheckerVisit(CE, Dst, DstTmp3, false);  
+  
+  if (!(!asLValue && CalleeReturnsReference(CE))) {
+    CheckerVisit(CE, Dst, DstTmp3, false);
+    return;
+  }
+  
+  // Handle the case where the called function returns a reference but
+  // we expect an rvalue.  For such cases, convert the reference to
+  // an rvalue.  
+  // FIXME: This conversion doesn't actually happen unless the result
+  //  of CallExpr is consumed by another expression.
+  ExplodedNodeSet DstTmp4;
+  CheckerVisit(CE, DstTmp4, DstTmp3, false);
+  QualType LoadTy = CE->getType();
+  
+  static int *ConvertToRvalueTag = 0;
+  for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
+       NI!=NE; ++NI) {
+    const GRState *state = GetState(*NI);
+    EvalLoad(Dst, CE, *NI, state, state->getSVal(CE),
+             &ConvertToRvalueTag, LoadTy);
+  }
 }
 
 //===----------------------------------------------------------------------===//