Added operator overloading for unary operators, post-increment, and
post-decrement, including support for generating all of the built-in
operator candidates for these operators. 

C++ and C have different rules for the arguments to the builtin unary
'+' and '-'. Implemented both variants in Sema::ActOnUnaryOp.

In C++, pre-increment and pre-decrement return lvalues. Update
Expr::isLvalue accordingly.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59638 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index dbd2126..869fcc9 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1843,8 +1843,7 @@
   }
 
   // Add builtin overload candidates (C++ [over.built]).
-  if (NumArgs == 2)
-    return AddBuiltinBinaryOperatorCandidates(Op, Args, CandidateSet);
+  AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
 }
 
 /// AddBuiltinCandidate - Add a candidate for a built-in
@@ -2053,16 +2052,15 @@
   }
 }
 
-/// AddBuiltinCandidates - Add the appropriate built-in operator
-/// overloads to the candidate set (C++ [over.built]), based on the
-/// operator @p Op and the arguments given. For example, if the
-/// operator is a binary '+', this routine might add
-///   "int operator+(int, int)"
-/// to cover integer addition.
+/// AddBuiltinOperatorCandidates - Add the appropriate built-in
+/// operator overloads to the candidate set (C++ [over.built]), based
+/// on the operator @p Op and the arguments given. For example, if the
+/// operator is a binary '+', this routine might add "int
+/// operator+(int, int)" to cover integer addition.
 void
-Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, 
-                                         Expr **Args, 
-                                         OverloadCandidateSet& CandidateSet) {
+Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, 
+                                   Expr **Args, unsigned NumArgs,
+                                   OverloadCandidateSet& CandidateSet) {
   // The set of "promoted arithmetic types", which are the arithmetic
   // types are that preserved by promotion (C++ [over.built]p2). Note
   // that the first few of these types are the promoted integral
@@ -2090,10 +2088,11 @@
   BuiltinCandidateTypeSet CandidateTypes(Context);
   if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
       Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
-      Op == OO_Plus || Op == OO_Minus || Op == OO_Equal ||
+      Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal ||
       Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
-      Op == OO_ArrowStar) {
-    for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx)
+      Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
+      (Op == OO_Star && NumArgs == 1)) {
+    for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
       CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
   }
 
@@ -2104,24 +2103,184 @@
     assert(false && "Expected an overloaded operator");
     break;
 
+  case OO_Star: // '*' is either unary or binary
+    if (NumArgs == 1) 
+      goto UnaryStar;
+    else
+      goto BinaryStar;
+    break;
+
+  case OO_Plus: // '+' is either unary or binary
+    if (NumArgs == 1)
+      goto UnaryPlus;
+    else
+      goto BinaryPlus;
+    break;
+
+  case OO_Minus: // '-' is either unary or binary
+    if (NumArgs == 1)
+      goto UnaryMinus;
+    else
+      goto BinaryMinus;
+    break;
+
+  case OO_Amp: // '&' is either unary or binary
+    if (NumArgs == 1)
+      goto UnaryAmp;
+    else
+      goto BinaryAmp;
+
+  case OO_PlusPlus:
+  case OO_MinusMinus:
+    // C++ [over.built]p3:
+    //
+    //   For every pair (T, VQ), where T is an arithmetic type, and VQ
+    //   is either volatile or empty, there exist candidate operator
+    //   functions of the form
+    //
+    //       VQ T&      operator++(VQ T&);
+    //       T          operator++(VQ T&, int);
+    //
+    // C++ [over.built]p4:
+    //
+    //   For every pair (T, VQ), where T is an arithmetic type other
+    //   than bool, and VQ is either volatile or empty, there exist
+    //   candidate operator functions of the form
+    //
+    //       VQ T&      operator--(VQ T&);
+    //       T          operator--(VQ T&, int);
+    for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); 
+         Arith < NumArithmeticTypes; ++Arith) {
+      QualType ArithTy = ArithmeticTypes[Arith];
+      QualType ParamTypes[2] 
+        = { Context.getReferenceType(ArithTy), Context.IntTy };
+
+      // Non-volatile version.
+      if (NumArgs == 1)
+        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+      else
+        AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
+
+      // Volatile version
+      ParamTypes[0] = Context.getReferenceType(ArithTy.withVolatile());
+      if (NumArgs == 1)
+        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+      else
+        AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
+    }
+
+    // C++ [over.built]p5:
+    //
+    //   For every pair (T, VQ), where T is a cv-qualified or
+    //   cv-unqualified object type, and VQ is either volatile or
+    //   empty, there exist candidate operator functions of the form
+    //
+    //       T*VQ&      operator++(T*VQ&);
+    //       T*VQ&      operator--(T*VQ&);
+    //       T*         operator++(T*VQ&, int);
+    //       T*         operator--(T*VQ&, int);
+    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+         Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+      // Skip pointer types that aren't pointers to object types.
+      if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType())
+        continue;
+
+      QualType ParamTypes[2] = { 
+        Context.getReferenceType(*Ptr), Context.IntTy 
+      };
+      
+      // Without volatile
+      if (NumArgs == 1)
+        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+      else
+        AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+
+      if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
+        // With volatile
+        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile());
+        if (NumArgs == 1)
+          AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+        else
+          AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+      }
+    }
+    break;
+
+  UnaryStar:
+    // C++ [over.built]p6:
+    //   For every cv-qualified or cv-unqualified object type T, there
+    //   exist candidate operator functions of the form
+    //
+    //       T&         operator*(T*);
+    //
+    // C++ [over.built]p7:
+    //   For every function type T, there exist candidate operator
+    //   functions of the form
+    //       T&         operator*(T*);
+    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+         Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+      QualType ParamTy = *Ptr;
+      QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType();
+      AddBuiltinCandidate(Context.getReferenceType(PointeeTy), 
+                          &ParamTy, Args, 1, CandidateSet);
+    }
+    break;
+
+  UnaryPlus:
+    // C++ [over.built]p8:
+    //   For every type T, there exist candidate operator functions of
+    //   the form
+    //
+    //       T*         operator+(T*);
+    for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
+         Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+      QualType ParamTy = *Ptr;
+      AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+    }
+    
+    // Fall through
+
+  UnaryMinus:
+    // C++ [over.built]p9:
+    //  For every promoted arithmetic type T, there exist candidate
+    //  operator functions of the form
+    //
+    //       T         operator+(T);
+    //       T         operator-(T);
+    for (unsigned Arith = FirstPromotedArithmeticType; 
+         Arith < LastPromotedArithmeticType; ++Arith) {
+      QualType ArithTy = ArithmeticTypes[Arith];
+      AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
+    }
+    break;
+
+  case OO_Tilde:
+    // C++ [over.built]p10:
+    //   For every promoted integral type T, there exist candidate
+    //   operator functions of the form
+    //
+    //        T         operator~(T);
+    for (unsigned Int = FirstPromotedIntegralType; 
+         Int < LastPromotedIntegralType; ++Int) {
+      QualType IntTy = ArithmeticTypes[Int];
+      AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
+    }
+    break;
+
   case OO_New:
   case OO_Delete:
   case OO_Array_New:
   case OO_Array_Delete:
-  case OO_Tilde:
-  case OO_Exclaim:
-  case OO_PlusPlus:
-  case OO_MinusMinus:
-  case OO_Arrow:
   case OO_Call:
-    assert(false && "Expected a binary operator");
+    assert(false && "Special operators don't use AddBuiltinOperatorCandidates");
     break;
 
   case OO_Comma:
+  UnaryAmp:
+  case OO_Arrow:
     // C++ [over.match.oper]p3:
     //   -- For the operator ',', the unary operator '&', or the
     //      operator '->', the built-in candidates set is empty.
-    // We don't check '&' or '->' here, since they are unary operators.
     break;
 
   case OO_Less:
@@ -2156,8 +2315,8 @@
     // Fall through.
     isComparison = true;
 
-  case OO_Plus:
-  case OO_Minus:
+  BinaryPlus:
+  BinaryMinus:
     if (!isComparison) {
       // We didn't fall through, so we must have OO_Plus or OO_Minus.
 
@@ -2201,8 +2360,8 @@
     }
     // Fall through
 
-  case OO_Star:
   case OO_Slash:
+  BinaryStar:
     // C++ [over.built]p12:
     //
     //   For every pair of promoted arithmetic types L and R, there
@@ -2235,7 +2394,7 @@
     break;
 
   case OO_Percent:
-  case OO_Amp:
+  BinaryAmp:
   case OO_Caret:
   case OO_Pipe:
   case OO_LessLess:
@@ -2285,10 +2444,12 @@
       ParamTypes[1] = *Enum;
       AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
 
-      // volatile T& operator=(volatile T&, T)
-      ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
-      ParamTypes[1] = *Enum;
-      AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+      if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
+        // volatile T& operator=(volatile T&, T)
+        ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
+        ParamTypes[1] = *Enum;
+        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+      }
     }
     // Fall through.
 
@@ -2319,9 +2480,11 @@
       ParamTypes[0] = Context.getReferenceType(*Ptr);
       AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
 
-      // volatile version
-      ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile());
-      AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+      if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
+        // volatile version
+        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile());
+        AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+      }
     }
     // Fall through.
 
@@ -2396,13 +2559,26 @@
     }
     break;
 
+  case OO_Exclaim: {
+    // C++ [over.operator]p23:
+    //
+    //   There also exist candidate operator functions of the form
+    //
+    //        bool        operator!(bool);            
+    //        bool        operator&&(bool, bool);     [BELOW]
+    //        bool        operator||(bool, bool);     [BELOW]
+    QualType ParamTy = Context.BoolTy;
+    AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+    break;
+  }
+
   case OO_AmpAmp:
   case OO_PipePipe: {
     // C++ [over.operator]p23:
     //
     //   There also exist candidate operator functions of the form
     //
-    //        bool        operator!(bool);            [In Unary version]
+    //        bool        operator!(bool);            [ABOVE]
     //        bool        operator&&(bool, bool);
     //        bool        operator||(bool, bool);
     QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };