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/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9a77e4f..c780372 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -752,19 +752,112 @@
 
 
 
-Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc, 
+Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                              tok::TokenKind Kind,
                                              ExprTy *Input) {
+  Expr *Arg = (Expr *)Input;
+
   UnaryOperator::Opcode Opc;
   switch (Kind) {
   default: assert(0 && "Unknown unary op!");
   case tok::plusplus:   Opc = UnaryOperator::PostInc; break;
   case tok::minusminus: Opc = UnaryOperator::PostDec; break;
   }
-  QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+  
+  if (getLangOptions().CPlusPlus &&
+      (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) {
+    // Which overloaded operator?
+    OverloadedOperatorKind OverOp = 
+      (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus;
+
+    // C++ [over.inc]p1:
+    //
+    //     [...] If the function is a member function with one
+    //     parameter (which shall be of type int) or a non-member
+    //     function with two parameters (the second of which shall be
+    //     of type int), it defines the postfix increment operator ++
+    //     for objects of that type. When the postfix increment is
+    //     called as a result of using the ++ operator, the int
+    //     argument will have value zero.
+    Expr *Args[2] = { 
+      Arg, 
+      new IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, 
+                                     /*isSigned=*/true), 
+                         Context.IntTy, SourceLocation())
+    };
+
+    // Build the candidate set for overloading
+    OverloadCandidateSet CandidateSet;
+    AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet);
+
+    // Perform overload resolution.
+    OverloadCandidateSet::iterator Best;
+    switch (BestViableFunction(CandidateSet, Best)) {
+    case OR_Success: {
+      // We found a built-in operator or an overloaded operator.
+      FunctionDecl *FnDecl = Best->Function;
+
+      if (FnDecl) {
+        // We matched an overloaded operator. Build a call to that
+        // operator.
+
+        // Convert the arguments.
+        if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+          if (PerformObjectArgumentInitialization(Arg, Method))
+            return true;
+        } else {
+          // Convert the arguments.
+          if (PerformCopyInitialization(Arg, 
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing"))
+            return true;
+        }
+
+        // Determine the result type
+        QualType ResultTy 
+          = FnDecl->getType()->getAsFunctionType()->getResultType();
+        ResultTy = ResultTy.getNonReferenceType();
+        
+        // Build the actual expression node.
+        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), 
+                                       SourceLocation());
+        UsualUnaryConversions(FnExpr);
+
+        return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, OpLoc);
+      } else {
+        // We matched a built-in operator. Convert the arguments, then
+        // break out so that we will build the appropriate built-in
+        // operator node.
+        if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0],
+                                      "passing"))
+          return true;
+
+        break;
+      } 
+    }
+
+    case OR_No_Viable_Function:
+      // No viable function; fall through to handling this as a
+      // built-in operator, which will produce an error message for us.
+      break;
+
+    case OR_Ambiguous:
+      Diag(OpLoc,  diag::err_ovl_ambiguous_oper)
+          << UnaryOperator::getOpcodeStr(Opc)
+          << Arg->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return true;
+    }
+
+    // Either we found no viable overloaded operator or we matched a
+    // built-in operator. In either case, fall through to trying to
+    // build a built-in operation.
+  }
+
+  QualType result = CheckIncrementDecrementOperand(Arg, OpLoc);
   if (result.isNull())
     return true;
-  return new UnaryOperator((Expr *)Input, Opc, result, OpLoc);
+  return new UnaryOperator(Arg, Opc, result, OpLoc);
 }
 
 Action::ExprResult Sema::
@@ -2819,16 +2912,6 @@
         !(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {
       return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
     }
-
-    // C++ [over.binary]p1:
-    //   A binary operator shall be implemented either by a non-static
-    //   member function (9.3) with one parameter or by a non-member
-    //   function with two parameters. Thus, for any binary operator
-    //   @, x@y can be interpreted as either x.operator@(y) or
-    //   operator@(x,y). If both forms of the operator function have
-    //   been declared, the rules in 13.3.1.2 determines which, if
-    //   any, interpretation is used.
-    OverloadCandidateSet CandidateSet;
     
     // Determine which overloaded operator we're dealing with.
     static const OverloadedOperatorKind OverOps[] = {
@@ -2854,6 +2937,7 @@
 
     // Add the appropriate overloaded operators (C++ [over.match.oper]) 
     // to the candidate set.
+    OverloadCandidateSet CandidateSet;
     Expr *Args[2] = { lhs, rhs };
     AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet);
 
@@ -2893,7 +2977,6 @@
                                        SourceLocation());
         UsualUnaryConversions(FnExpr);
 
-        Expr *Args[2] = { lhs, rhs };
         return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, TokLoc);
       } else {
         // We matched a built-in operator. Convert the arguments, then
@@ -2933,10 +3016,98 @@
 }
 
 // Unary Operators.  'Tok' is the token for the operator.
-Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
-                                      ExprTy *input) {
+Action::ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, 
+                                      tok::TokenKind Op, ExprTy *input) {
   Expr *Input = (Expr*)input;
   UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+
+  if (getLangOptions().CPlusPlus &&
+      (Input->getType()->isRecordType() 
+       || Input->getType()->isEnumeralType())) {
+    // Determine which overloaded operator we're dealing with.
+    static const OverloadedOperatorKind OverOps[] = {
+      OO_None, OO_None,
+      OO_PlusPlus, OO_MinusMinus,
+      OO_Amp, OO_Star,
+      OO_Plus, OO_Minus,
+      OO_Tilde, OO_Exclaim,
+      OO_None, OO_None,
+      OO_None, 
+      OO_None
+    };
+    OverloadedOperatorKind OverOp = OverOps[Opc];
+
+    // Add the appropriate overloaded operators (C++ [over.match.oper]) 
+    // to the candidate set.
+    OverloadCandidateSet CandidateSet;
+    if (OverOp != OO_None)
+      AddOperatorCandidates(OverOp, S, &Input, 1, CandidateSet);    
+
+    // Perform overload resolution.
+    OverloadCandidateSet::iterator Best;
+    switch (BestViableFunction(CandidateSet, Best)) {
+    case OR_Success: {
+      // We found a built-in operator or an overloaded operator.
+      FunctionDecl *FnDecl = Best->Function;
+
+      if (FnDecl) {
+        // We matched an overloaded operator. Build a call to that
+        // operator.
+
+        // Convert the arguments.
+        if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+          if (PerformObjectArgumentInitialization(Input, Method))
+            return true;
+        } else {
+          // Convert the arguments.
+          if (PerformCopyInitialization(Input, 
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing"))
+            return true;
+        }
+
+        // Determine the result type
+        QualType ResultTy 
+          = FnDecl->getType()->getAsFunctionType()->getResultType();
+        ResultTy = ResultTy.getNonReferenceType();
+        
+        // Build the actual expression node.
+        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), 
+                                       SourceLocation());
+        UsualUnaryConversions(FnExpr);
+
+        return new CXXOperatorCallExpr(FnExpr, &Input, 1, ResultTy, OpLoc);
+      } else {
+        // We matched a built-in operator. Convert the arguments, then
+        // break out so that we will build the appropriate built-in
+        // operator node.
+        if (PerformCopyInitialization(Input, Best->BuiltinTypes.ParamTypes[0],
+                                      "passing"))
+          return true;
+
+        break;
+      } 
+    }
+
+    case OR_No_Viable_Function:
+      // No viable function; fall through to handling this as a
+      // built-in operator, which will produce an error message for us.
+      break;
+
+    case OR_Ambiguous:
+      Diag(OpLoc,  diag::err_ovl_ambiguous_oper)
+          << UnaryOperator::getOpcodeStr(Opc)
+          << Input->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return true;
+    }
+
+    // Either we found no viable overloaded operator or we matched a
+    // built-in operator. In either case, fall through to trying to
+    // build a built-in operation.    
+  }
+
+
   QualType resultType;
   switch (Opc) {
   default:
@@ -2956,10 +3127,18 @@
   case UnaryOperator::Minus:
     UsualUnaryConversions(Input);
     resultType = Input->getType();
-    if (!resultType->isArithmeticType())  // C99 6.5.3.3p1
-      return Diag(OpLoc, diag::err_typecheck_unary_expr, 
-                  resultType.getAsString());
-    break;
+    if (resultType->isArithmeticType()) // C99 6.5.3.3p1
+      break;
+    else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7
+             resultType->isEnumeralType())
+      break;
+    else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6
+             Opc == UnaryOperator::Plus &&
+             resultType->isPointerType())
+      break;
+
+    return Diag(OpLoc, diag::err_typecheck_unary_expr, 
+                resultType.getAsString());
   case UnaryOperator::Not: // bitwise complement
     UsualUnaryConversions(Input);
     resultType = Input->getType();