Fix several issues in checking of address-of expressions.
 - clang was erroneously accepting address-of applied to lvalue
   expressions involving pointer arithmetic.
 - clang was erroneously rejecting address-of applied to deref
   expressions of pointer-typed variables.
 - Improved existing test case.
 - Fixes: <rdar://problem/6113867>, <rdar://problem/6080158>


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54326 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1f54492..8896f43 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1968,8 +1968,16 @@
 
 /// getPrimaryDecl - Helper function for CheckAddressOfOperand().
 /// This routine allows us to typecheck complex/recursive expressions
-/// where the declaration is needed for type checking. Here are some
-/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+/// where the declaration is needed for type checking. We only need to
+/// handle cases when the expression references a function designator
+/// or is an lvalue. Here are some examples:
+///  - &(x) => x
+///  - &*****f => f for f a function designator.
+///  - &s.xx => s
+///  - &s.zz[1].yy -> s, if zz is an array
+///  - *(x + 1) -> x, if x is an array
+///  - &"123"[2] -> 0
+///  - & __real__ x -> x
 static ValueDecl *getPrimaryDecl(Expr *E) {
   switch (E->getStmtClass()) {
   case Stmt::DeclRefExprClass:
@@ -1981,7 +1989,7 @@
       return 0;
     return getPrimaryDecl(cast<MemberExpr>(E)->getBase());
   case Stmt::ArraySubscriptExprClass: {
-    // &X[4] and &4[X] is invalid if X is invalid and X is not a pointer.
+    // &X[4] and &4[X] refers to X if X is not a pointer.
   
     ValueDecl *VD = getPrimaryDecl(cast<ArraySubscriptExpr>(E)->getBase());
     if (!VD || VD->getType()->isPointerType())
@@ -1989,8 +1997,42 @@
     else
       return VD;
   }
-  case Stmt::UnaryOperatorClass:
-    return getPrimaryDecl(cast<UnaryOperator>(E)->getSubExpr());
+  case Stmt::UnaryOperatorClass: {
+    UnaryOperator *UO = cast<UnaryOperator>(E);
+    
+    switch(UO->getOpcode()) {
+    case UnaryOperator::Deref: {
+      // *(X + 1) refers to X if X is not a pointer.
+      ValueDecl *VD = getPrimaryDecl(UO->getSubExpr());
+      if (!VD || VD->getType()->isPointerType())
+        return 0;
+      return VD;
+    }
+    case UnaryOperator::Real:
+    case UnaryOperator::Imag:
+    case UnaryOperator::Extension:
+      return getPrimaryDecl(UO->getSubExpr());
+    default:
+      return 0;
+    }
+  }
+  case Stmt::BinaryOperatorClass: {
+    BinaryOperator *BO = cast<BinaryOperator>(E);
+
+    // Handle cases involving pointer arithmetic. The result of an
+    // Assign or AddAssign is not an lvalue so they can be ignored.
+
+    // (x + n) or (n + x) => x
+    if (BO->getOpcode() == BinaryOperator::Add) {
+      if (BO->getLHS()->getType()->isPointerType()) {
+        return getPrimaryDecl(BO->getLHS());
+      } else if (BO->getRHS()->getType()->isPointerType()) {
+        return getPrimaryDecl(BO->getRHS());
+      }
+    }
+
+    return 0;
+  }
   case Stmt::ParenExprClass:
     return getPrimaryDecl(cast<ParenExpr>(E)->getSubExpr());
   case Stmt::ImplicitCastExprClass: