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/Sema.h b/lib/Sema/Sema.h
index 29994d4..c60fd35 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -435,9 +435,9 @@
   void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, 
                            Expr **Args, unsigned NumArgs,
                            OverloadCandidateSet& CandidateSet);
-  void AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, 
-                                          Expr **Args, 
-                                          OverloadCandidateSet& CandidateSet);
+  void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, 
+                                    Expr **Args, unsigned NumArgs, 
+                                    OverloadCandidateSet& CandidateSet);
   void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, 
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,
@@ -640,8 +640,8 @@
   virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);
     
   // Binary/Unary Operators.  'Tok' is the token for the operator.
-  virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
-                                  ExprTy *Input);
+  virtual ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, 
+                                  tok::TokenKind Op, ExprTy *Input);
   virtual ExprResult 
     ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
                            void *TyOrEx, const SourceRange &ArgRange);
@@ -649,7 +649,7 @@
   bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
                                  const SourceRange &R, bool isSizeof);
   
-  virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, 
+  virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                          tok::TokenKind Kind, ExprTy *Input);
   
   virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
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();
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 };