[cfe-commits] r59638 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/Parse/Action.h lib/AST/Expr.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseStmt.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/overloaded-builtin-operators.cpp test/SemaCXX/overloaded-operator.cpp www/cxx_status.html

Douglas Gregor doug.gregor at gmail.com
Wed Nov 19 07:42:07 PST 2008


Author: dgregor
Date: Wed Nov 19 09:42:04 2008
New Revision: 59638

URL: http://llvm.org/viewvc/llvm-project?rev=59638&view=rev
Log:
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.


Modified:
    cfe/trunk/Driver/PrintParserCallbacks.cpp
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Wed Nov 19 09:42:04 2008
@@ -436,7 +436,7 @@
     }
   
     // Postfix Expressions.
-    virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, 
+    virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                            tok::TokenKind Kind, ExprTy *Input) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
@@ -467,8 +467,8 @@
     }
   
     // 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) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Nov 19 09:42:04 2008
@@ -509,7 +509,7 @@
   }
   
   // Postfix Expressions.
-  virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, 
+  virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                          tok::TokenKind Kind, ExprTy *Input) {
     return 0;
   }
@@ -536,8 +536,8 @@
   }
   
   // 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) {
     return 0;
   }
   virtual ExprResult 

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Nov 19 09:42:04 2008
@@ -398,6 +398,11 @@
         cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag ||
         cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension)
       return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx);  // GNU.
+
+    if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1
+        (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc ||
+         cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec))
+      return LV_Valid;
     break;
   case ImplicitCastExprClass:
     return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid 

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Nov 19 09:42:04 2008
@@ -515,7 +515,7 @@
     SourceLocation SavedLoc = ConsumeToken();
     Res = ParseCastExpression(true);
     if (!Res.isInvalid)
-      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val);
+      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);
     return Res;
   }
   case tok::amp:           // unary-expression: '&' cast-expression
@@ -529,7 +529,7 @@
     SourceLocation SavedLoc = ConsumeToken();
     Res = ParseCastExpression(false);
     if (!Res.isInvalid)
-      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val);
+      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);
     return Res;
   }    
       
@@ -539,7 +539,7 @@
     SourceLocation SavedLoc = ConsumeToken();
     Res = ParseCastExpression(false);
     if (!Res.isInvalid)
-      Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val);
+      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val);
     return Res;
   }
   case tok::kw_sizeof:     // unary-expression: 'sizeof' unary-expression
@@ -724,8 +724,8 @@
     case tok::plusplus:    // postfix-expression: postfix-expression '++'
     case tok::minusminus:  // postfix-expression: postfix-expression '--'
       if (!LHS.isInvalid)
-        LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(),
-                                          LHS.Val);
+        LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(), 
+                                          Tok.getKind(), LHS.Val);
       ConsumeToken();
       break;
     }

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Wed Nov 19 09:42:04 2008
@@ -386,7 +386,8 @@
         }
         
         // Add the __extension__ node to the AST.
-        Res = Actions.ActOnUnaryOp(ExtLoc, tok::kw___extension__, Res.Val);
+        Res = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__, 
+                                   Res.Val);
         if (Res.isInvalid)
           continue;
         

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 19 09:42:04 2008
@@ -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,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 19 09:42:04 2008
@@ -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 at 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();

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 19 09:42:04 2008
@@ -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 };

Modified: cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp Wed Nov 19 09:42:04 2008
@@ -25,6 +25,14 @@
 no& islong(int);
 
 void f(Short s, Long l, Enum1 e1, Enum2 e2) {
+  // C++ [over.built]p8
+  int i1 = +e1;
+  int i2 = -e2;
+
+  // C++  [over.built]p10:
+  int i3 = ~s;
+  bool b1 = !s;
+
   // C++ [over.built]p12
   (void)static_cast<yes&>(islong(s + l));
   (void)static_cast<no&>(islong(s + s));
@@ -46,6 +54,12 @@
 };
 
 void g(ShortRef sr, LongRef lr) {
+  // C++ [over.built]p3
+  short s1 = sr++;
+
+  // C++ [over.built]p3
+  long l1 = lr--;
+
   // C++ [over.built]p18
   short& sr1 = (sr *= lr);
   volatile long& lr1 = (lr *= sr);
@@ -65,7 +79,16 @@
   operator int const *();
 };
 
-void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr) {
+struct VolatileIntPtrRef {
+  operator int volatile *&();
+};
+
+struct ConstIntPtrRef {
+  operator int const *&();
+};
+
+void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr,
+                    VolatileIntPtrRef vipr, ConstIntPtrRef cipr) {
 #if 0
   // FIXME: Enable these tests once we have operator overloading for
   // operator[].
@@ -76,4 +99,19 @@
 #endif
   bool b1 = (vip == cip);
   long p1 = vip - cip;
+
+  // C++ [over.built]p5:
+  int volatile *vip1 = vipr++;
+  int const *cip1 = cipr++;
+  int volatile *&vipr1 = ++vipr;
+  int const *&cipr1 = --cipr;
+
+  // C++ [over.built]p6:
+  int volatile &ivr = *vip;
+
+  // C++ [over.built]p8:
+  int volatile *vip2 = +vip;
+  int i1 = +sr;
+  int i2 = -sr;
 }
+

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Wed Nov 19 09:42:04 2008
@@ -69,3 +69,31 @@
   float &f3 = (e1 == enum2); 
   float &f4 = (enum1 == enum2);  // expected-error{{non-const reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}
 }
+
+
+struct PostInc {
+  PostInc operator++(int);
+  PostInc& operator++();
+};
+
+struct PostDec {
+  PostDec operator--(int);
+  PostDec& operator--();
+};
+
+void incdec_test(PostInc pi, PostDec pd) {
+  const PostInc& pi1 = pi++;
+  const PostDec& pd1 = pd--;
+  PostInc &pi2 = ++pi;
+  PostDec &pd2 = --pd;
+}
+
+struct SmartPtr {
+  int& operator*();
+  // FIXME: spurious error:  long& operator*() const;
+};
+
+void test_smartptr(SmartPtr ptr, const SmartPtr cptr) {
+  int &ir = *ptr;
+  // FIXME: reinstate long &lr = *cptr;
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=59638&r1=59637&r2=59638&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Nov 19 09:42:04 2008
@@ -826,8 +826,8 @@
 <tr>
   <td>      13.3.1.2 [over.match.oper]</td>
   <td class="complete" align="center">&#x2713;</td>  
-  <td class="broken" align="center"></td>
-  <td class="broken" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td class="medium" align="center"></td>
   <td class="broken" align="center"></td>  
   <td></td>
 </tr>
@@ -943,27 +943,27 @@
   <td class="advanced" align="center"></td>
   <td class="medium" align="center"></td>
   <td class="broken" align="center"></td>  
-  <td>Most overloaded operators can only be called with function syntax, e.g., <code>operator+(x)</code>.</td>
+  <td>Some overloaded operators can only be called with function syntax, e.g., <code>operator[](x)</code>.</td>
 </tr>
 <tr>
   <td>    13.5.1 [over.unary]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
+  <td class="advanced" align="center"></td>
   <td class="advanced" align="center"></td>
-  <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
   <td></td>
 </tr>
 <tr>
   <td>    13.5.2 [over.binary]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
+  <td class="advanced" align="center"></td>
   <td class="advanced" align="center"></td>
-  <td class="medium" align="center"></td>
   <td class="broken" align="center"></td>  
   <td></td>
 </tr>
 <tr>
   <td>    13.5.3 [over.ass]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
   <td class="advanced" align="center"></td>
   <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
@@ -971,7 +971,7 @@
 </tr>
 <tr>
   <td>    13.5.4 [over.call]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
   <td class="advanced" align="center"></td>
   <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
@@ -979,7 +979,7 @@
 </tr>
 <tr>
   <td>    13.5.5 [over.sub]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
   <td class="advanced" align="center"></td>
   <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
@@ -987,21 +987,29 @@
 </tr>
 <tr>
   <td>    13.5.6 [over.ref]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
+  <td class="advanced" align="center"></td>
   <td class="advanced" align="center"></td>
-  <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
   <td></td>
 </tr>
 <tr>
   <td>    13.5.7 [over.inc]</td>
-  <td class="advanced" align="center"></td>  
+  <td class="na" align="center">N/A</td>  
+  <td class="advanced" align="center"></td>
   <td class="advanced" align="center"></td>
-  <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>  
   <td></td>
 </tr>
-<tr><td>  13.6 [over.built]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>  13.6 [over.built]</td>
+  <td class="na" align="center">N/A</td>  
+  <td class="advanced" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td class="broken" align="center"></td>  
+  <td>Missing pointer-to-member versions (p11, p16) and support for
+  the ternary operator (p24, p25).</td>
+</tr>
 <tr><td>14 [temp]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  14.1 [temp.param]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  14.2 [temp.names]</td><td></td><td></td><td></td><td></td><td></td></tr>





More information about the cfe-commits mailing list