[cfe-commits] r66923 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/Type.h lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiate.cpp

Douglas Gregor dgregor at apple.com
Fri Mar 13 11:40:32 PDT 2009


Author: dgregor
Date: Fri Mar 13 13:40:31 2009
New Revision: 66923

URL: http://llvm.org/viewvc/llvm-project?rev=66923&view=rev
Log:
Refactor the way we handle operator overloading and template
instantiation for binary operators. This change moves most of the
operator-overloading code from the parser action ActOnBinOp to a new,
parser-independent semantic checking routine CreateOverloadedBinOp. 

Of particular importance is the fact that CreateOverloadedBinOp does
*not* perform any name lookup based on the current parsing context (it
doesn't take a Scope*), since it has to be usable during template
instantiation, when there is no scope information. Rather, it takes a
pre-computed set of functions that are visible from the context or via
argument-dependent lookup, and adds to that set any member operators
and built-in operator candidates. The set of functions is computed in
the parser action ActOnBinOp based on the current context (both
operator name lookup and argument-dependent lookup). Within a
template, the set computed by ActOnBinOp is saved within the
type-dependent AST node and is augmented with the results of
argument-dependent name lookup at instantiation time (see
TemplateExprInstantiator::VisitCXXOperatorCallExpr).

Sadly, we can't fully test this yet. I'll follow up with template
instantiation for sizeof so that the real fun can begin.


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=66923&r1=66922&r2=66923&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Mar 13 13:40:31 2009
@@ -1245,6 +1245,14 @@
   /// corresponds to, e.g. "<<=".
   static const char *getOpcodeStr(Opcode Op);
 
+  /// \brief Retrieve the binary opcode that corresponds to the given
+  /// overloaded operator.
+  static Opcode getOverloadedOpcode(OverloadedOperatorKind OO);
+
+  /// \brief Retrieve the overloaded operator kind that corresponds to
+  /// the given binary opcode.
+  static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
+
   /// predicates to categorize the respective opcodes.
   bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
   bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=66923&r1=66922&r2=66923&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Mar 13 13:40:31 2009
@@ -40,14 +40,19 @@
 /// function templates that were found by name lookup at template
 /// definition time.
 class CXXOperatorCallExpr : public CallExpr {
+  /// \brief The overloaded operator.
+  OverloadedOperatorKind Operator;
+
 public:
-  CXXOperatorCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
-                      QualType t, SourceLocation operatorloc)
-    : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc){}
+  CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, 
+                      Expr **args, unsigned numargs, QualType t, 
+                      SourceLocation operatorloc)
+    : CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc),
+      Operator(Op) {}
 
   /// getOperator - Returns the kind of overloaded operator that this
   /// expression refers to.
-  OverloadedOperatorKind getOperator() const;
+  OverloadedOperatorKind getOperator() const { return Operator; }
 
   /// getOperatorLoc - Returns the location of the operator symbol in
   /// the expression. When @c getOperator()==OO_Call, this is the

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=66923&r1=66922&r2=66923&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Fri Mar 13 13:40:31 2009
@@ -361,7 +361,7 @@
   /// that its definition somehow depends on a template parameter 
   /// (C++ [temp.dep.type]).
   bool isDependentType() const { return Dependent; }
-  bool isOverloadType() const;                  // C++ overloaded function
+  bool isOverloadableType() const;
 
   /// hasPointerRepresentation - Whether this type is represented
   /// natively as a pointer; this includes pointers, references, block
@@ -1860,8 +1860,10 @@
   return false;
 }
 
-inline bool Type::isOverloadType() const {
-  return isSpecificBuiltinType(BuiltinType::Overload);
+/// \brief Determines whether this is a type for which one can define
+/// an overloaded operator.
+inline bool Type::isOverloadableType() const {
+  return isDependentType() || isRecordType() || isEnumeralType();
 }
 
 inline bool Type::hasPointerRepresentation() const {

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

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Mar 13 13:40:31 2009
@@ -227,6 +227,68 @@
   return "";
 }
 
+BinaryOperator::Opcode 
+BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
+  switch (OO) {
+  case OO_Plus: return Add;
+  case OO_Minus: return Sub;
+  case OO_Star: return Mul;
+  case OO_Slash: return Div;
+  case OO_Percent: return Rem;
+  case OO_Caret: return Xor;
+  case OO_Amp: return And;
+  case OO_Pipe: return Or;
+  case OO_Equal: return Assign;
+  case OO_Less: return LT;
+  case OO_Greater: return GT;
+  case OO_PlusEqual: return AddAssign;
+  case OO_MinusEqual: return SubAssign;
+  case OO_StarEqual: return MulAssign;
+  case OO_SlashEqual: return DivAssign;
+  case OO_PercentEqual: return RemAssign;
+  case OO_CaretEqual: return XorAssign;
+  case OO_AmpEqual: return AndAssign;
+  case OO_PipeEqual: return OrAssign;
+  case OO_LessLess: return Shl;
+  case OO_GreaterGreater: return Shr;
+  case OO_LessLessEqual: return ShlAssign;
+  case OO_GreaterGreaterEqual: return ShrAssign;
+  case OO_EqualEqual: return EQ;
+  case OO_ExclaimEqual: return NE;
+  case OO_LessEqual: return LE;
+  case OO_GreaterEqual: return GE;
+  case OO_AmpAmp: return LAnd;
+  case OO_PipePipe: return LOr;
+  case OO_Comma: return Comma;
+  case OO_ArrowStar: return PtrMemI;
+  default: assert(false && "Not an overloadable binary operator");
+  }
+}
+
+OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
+  static const OverloadedOperatorKind OverOps[] = {
+    /* .* Cannot be overloaded */OO_None, OO_ArrowStar,
+    OO_Star, OO_Slash, OO_Percent,
+    OO_Plus, OO_Minus,
+    OO_LessLess, OO_GreaterGreater,
+    OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
+    OO_EqualEqual, OO_ExclaimEqual,
+    OO_Amp,
+    OO_Caret,
+    OO_Pipe,
+    OO_AmpAmp,
+    OO_PipePipe,
+    OO_Equal, OO_StarEqual,
+    OO_SlashEqual, OO_PercentEqual,
+    OO_PlusEqual, OO_MinusEqual,
+    OO_LessLessEqual, OO_GreaterGreaterEqual,
+    OO_AmpEqual, OO_CaretEqual,
+    OO_PipeEqual,
+    OO_Comma
+  };
+  return OverOps[Opc];
+}
+
 InitListExpr::InitListExpr(SourceLocation lbraceloc, 
                            Expr **initExprs, unsigned numInits,
                            SourceLocation rbraceloc)

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

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Mar 13 13:40:31 2009
@@ -160,27 +160,6 @@
   }
 }
 
-OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
-  // All simple function calls (e.g. func()) are implicitly cast to pointer to
-  // function. As a result, we try and obtain the DeclRefExpr from the 
-  // ImplicitCastExpr.
-  const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
-  if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
-    return OO_None;
-  
-  const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
-  if (!DRE)
-    return OO_None;
-  
-  if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
-    return FDecl->getDeclName().getCXXOverloadedOperator();  
-  else if (const OverloadedFunctionDecl *Ovl 
-             = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()))
-    return Ovl->getDeclName().getCXXOverloadedOperator();
-  else
-    return OO_None;
-}
-
 SourceRange CXXOperatorCallExpr::getSourceRange() const {
   OverloadedOperatorKind Kind = getOperator();
   if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Mar 13 13:40:31 2009
@@ -523,10 +523,18 @@
     OR_Deleted              ///< Overload resoltuion refers to a deleted function.
   };
 
+  typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet;
+  typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
+  typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
+
   void AddOverloadCandidate(FunctionDecl *Function, 
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
                             bool SuppressUserConversions = false);
+  void AddFunctionCandidates(const FunctionSet &Functions,
+                             Expr **Args, unsigned NumArgs,
+                             OverloadCandidateSet& CandidateSet,
+                             bool SuppressUserConversions = false);
   void AddMethodCandidate(CXXMethodDecl *Method,
                           Expr *Object, Expr **Args, unsigned NumArgs,
                           OverloadCandidateSet& CandidateSet,
@@ -538,11 +546,16 @@
                              const FunctionProtoType *Proto,
                              Expr *Object, Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet);
-  bool AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+  void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
                              SourceLocation OpLoc,
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,
                              SourceRange OpRange = SourceRange());
+  void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
+                                   SourceLocation OpLoc,
+                                   Expr **Args, unsigned NumArgs,
+                                   OverloadCandidateSet& CandidateSet,
+                                   SourceRange OpRange = SourceRange());
   void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, 
                            Expr **Args, unsigned NumArgs,
                            OverloadCandidateSet& CandidateSet,
@@ -572,6 +585,12 @@
                                         SourceLocation *CommaLocs, 
                                         SourceLocation RParenLoc,
                                         bool &ArgumentDependentLookup);
+
+  OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
+                                         unsigned Opc,
+                                         FunctionSet &Functions,
+                                         Expr *LHS, Expr *RHS);
+
   ExprResult
   BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
                             SourceLocation LParenLoc, Expr **Args, 
@@ -930,10 +949,6 @@
                                 bool AllowBuiltinCreation = true,
                                 SourceLocation Loc = SourceLocation());
 
-  typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet;
-  typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
-  typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
-
   void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
                                     QualType T1, QualType T2, 
                                     FunctionSet &Functions);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Mar 13 13:40:31 2009
@@ -1694,7 +1694,7 @@
   // If the initializer is the address of an overloaded function, try
   // to resolve the overloaded function. If all goes well, T2 is the
   // type of the resulting function.
-  if (T2->isOverloadType()) {
+  if (Context.getCanonicalType(T2) == Context.OverloadTy) {
     FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, 
                                                           ICS != 0);
     if (Fn) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Mar 13 13:40:31 2009
@@ -1324,8 +1324,7 @@
 
     // Build the candidate set for overloading
     OverloadCandidateSet CandidateSet;
-    if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
-      return ExprError();
+    AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -1361,8 +1360,9 @@
         UsualUnaryConversions(FnExpr);
 
         Input.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
-                                                       ResultTy, OpLoc));
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, 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
@@ -1424,9 +1424,8 @@
     // to the candidate set.
     OverloadCandidateSet CandidateSet;
     Expr *Args[2] = { LHSExp, RHSExp };
-    if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
-                              SourceRange(LLoc, RLoc)))
-      return ExprError();
+    AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
+                          SourceRange(LLoc, RLoc));
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -1469,7 +1468,8 @@
 
         Base.release();
         Idx.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+                                                       FnExpr, Args, 2, 
                                                        ResultTy, LLoc));
       } else {
         // We matched a built-in operator. Convert the arguments, then
@@ -3977,32 +3977,6 @@
                                                       CompTy, OpLoc));
 }
 
-static OverloadedOperatorKind 
-getOverloadedOperator(BinaryOperator::Opcode Opc) {
-  static const OverloadedOperatorKind OverOps[] = {
-    // Overloading .* is not possible.
-    static_cast<OverloadedOperatorKind>(0), OO_ArrowStar,
-    OO_Star, OO_Slash, OO_Percent,
-    OO_Plus, OO_Minus,
-    OO_LessLess, OO_GreaterGreater,
-    OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
-    OO_EqualEqual, OO_ExclaimEqual,
-    OO_Amp,
-    OO_Caret,
-    OO_Pipe,
-    OO_AmpAmp,
-    OO_PipePipe,
-    OO_Equal, OO_StarEqual,
-    OO_SlashEqual, OO_PercentEqual,
-    OO_PlusEqual, OO_MinusEqual,
-    OO_LessLessEqual, OO_GreaterGreaterEqual,
-    OO_AmpEqual, OO_CaretEqual,
-    OO_PipeEqual,
-    OO_Comma
-  };
-  return OverOps[Opc];
-}
-
 // Binary Operators.  'Tok' is the token for the operator.
 Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
                                           tok::TokenKind Kind,
@@ -4013,139 +3987,27 @@
   assert((lhs != 0) && "ActOnBinOp(): missing left expression");
   assert((rhs != 0) && "ActOnBinOp(): missing right expression");
 
-  // If either expression is type-dependent, just build the AST.
-  if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
-    // .* cannot be overloaded.
-    if (Opc == BinaryOperator::PtrMemD)
-      return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
-                                                Context.DependentTy, TokLoc));
-    
-    // Find all of the overloaded operators visible from the template
-    // definition. We perform both an operator-name lookup from the
-    // local scope and an argument-dependent lookup based on the types
-    // of the arguments.
+  if (getLangOptions().CPlusPlus &&
+      (lhs->getType()->isOverloadableType() || 
+       rhs->getType()->isOverloadableType())) {
+    // Find all of the overloaded operators visible from this
+    // point. We perform both an operator-name lookup from the local
+    // scope and an argument-dependent lookup based on the types of
+    // the arguments.
     FunctionSet Functions;
-    OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
-    LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
-                                 Functions);
-    Expr *Args[2] = { lhs, rhs };
-    DeclarationName OpName 
-      = Context.DeclarationNames.getCXXOperatorName(OverOp);
-    ArgumentDependentLookup(OpName, Args, 2, Functions);
-
-    OverloadedFunctionDecl *Overloads 
-      = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
-    for (FunctionSet::iterator Func = Functions.begin(), 
-                            FuncEnd = Functions.end();
-         Func != FuncEnd; ++Func)
-      Overloads->addOverload(*Func);
-
-    DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
-                                                TokLoc, false, false);
-    
-    return Owned(new (Context) CXXOperatorCallExpr(Context, Fn,
-                                                   Args, 2, 
-                                                   Context.DependentTy,
-                                                   TokLoc));
-  }
-
-  if (getLangOptions().CPlusPlus && Opc != BinaryOperator::PtrMemD &&
-      (lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||
-       rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) {
-    // If this is one of the assignment operators, we only perform
-    // overload resolution if the left-hand side is a class or
-    // enumeration type (C++ [expr.ass]p3).
-    if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
-        !(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {
-      return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
-    }
-
-    // Determine which overloaded operator we're dealing with.
-
-    // Add the appropriate overloaded operators (C++ [over.match.oper])
-    // to the candidate set.
-    OverloadCandidateSet CandidateSet;
-    OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
-    Expr *Args[2] = { lhs, rhs };
-    if (AddOperatorCandidates(OverOp, S, TokLoc, Args, 2, CandidateSet))
-      return ExprError();
-
-    // 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(lhs, Method) ||
-              PerformCopyInitialization(rhs, FnDecl->getParamDecl(0)->getType(),
-                                        "passing"))
-            return ExprError();
-        } else {
-          // Convert the arguments.
-          if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
-                                        "passing") ||
-              PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
-                                        "passing"))
-            return ExprError();
-        }
-
-        // Determine the result type
-        QualType ResultTy
-          = FnDecl->getType()->getAsFunctionType()->getResultType();
-        ResultTy = ResultTy.getNonReferenceType();
-
-        // Build the actual expression node.
-        Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
-                                                 SourceLocation());
-        UsualUnaryConversions(FnExpr);
-
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
-                                                       ResultTy, TokLoc));
-      } 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 (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
-                                      Best->Conversions[0], "passing") ||
-            PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
-                                      Best->Conversions[1], "passing"))
-          return ExprError();
-
-        break;
-      }
+    OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
+    if (OverOp != OO_None) {
+      LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+                                   Functions);
+      Expr *Args[2] = { lhs, rhs };
+      DeclarationName OpName 
+        = Context.DeclarationNames.getCXXOperatorName(OverOp);
+      ArgumentDependentLookup(OpName, Args, 2, Functions);
     }
 
-    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(TokLoc,  diag::err_ovl_ambiguous_oper)
-          << BinaryOperator::getOpcodeStr(Opc)
-          << lhs->getSourceRange() << rhs->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
-      return ExprError();
-
-    case OR_Deleted:
-      Diag(TokLoc, diag::err_ovl_deleted_oper)
-        << Best->Function->isDeleted()
-        << BinaryOperator::getOpcodeStr(Opc)
-        << lhs->getSourceRange() << rhs->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
-      return ExprError();
-    }
-
-    // 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.
+    // Build the (potentially-overloaded, potentially-dependent)
+    // binary operation.
+    return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
   }
 
   // Build a built-in binary operation.
@@ -4178,9 +4040,8 @@
     // Add the appropriate overloaded operators (C++ [over.match.oper])
     // to the candidate set.
     OverloadCandidateSet CandidateSet;
-    if (OverOp != OO_None &&
-        AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
-      return ExprError();
+    if (OverOp != OO_None)
+      AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet);
 
     // Perform overload resolution.
     OverloadCandidateSet::iterator Best;
@@ -4216,8 +4077,9 @@
         UsualUnaryConversions(FnExpr);
 
         input.release();
-        return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, &Input,
-                                                       1, ResultTy, OpLoc));
+        return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, 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

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Mar 13 13:40:31 2009
@@ -800,7 +800,7 @@
     break;
 
   case ICK_Function_To_Pointer:
-    if (FromType->isOverloadType()) {
+    if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
       FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
       if (!Fn)
         return true;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Mar 13 13:40:31 2009
@@ -468,7 +468,7 @@
   Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
   if (argIsLvalue == Expr::LV_Valid && 
       !FromType->isFunctionType() && !FromType->isArrayType() &&
-      !FromType->isOverloadType()) {
+      Context.getCanonicalType(FromType) != Context.OverloadTy) {
     SCS.First = ICK_Lvalue_To_Rvalue;
 
     // If T is a non-class type, the type of the rvalue is the
@@ -2064,6 +2064,19 @@
   }
 }
 
+/// \brief Add all of the function declarations in the given function set to
+/// the overload canddiate set.
+void Sema::AddFunctionCandidates(const FunctionSet &Functions,
+                                 Expr **Args, unsigned NumArgs,
+                                 OverloadCandidateSet& CandidateSet,
+                                 bool SuppressUserConversions) {
+  for (FunctionSet::const_iterator F = Functions.begin(), 
+                                FEnd = Functions.end();
+       F != FEnd; ++F)
+    AddOverloadCandidate(*F, Args, NumArgs, CandidateSet, 
+                         SuppressUserConversions);
+}
+
 /// AddMethodCandidate - Adds the given C++ member function to the set
 /// of candidate functions, using the given function call arguments
 /// and the object argument (@c Object). For example, in a call
@@ -2308,17 +2321,43 @@
   }
 }
 
-/// AddOperatorCandidates - Add the overloaded operator candidates for
-/// the operator Op that was used in an operator expression such as "x
-/// Op y". S is the scope in which the expression occurred (used for
-/// name lookup of the operator), Args/NumArgs provides the operator
-/// arguments, and CandidateSet will store the added overload
-/// candidates. (C++ [over.match.oper]).
-bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+// FIXME: This will eventually be removed, once we've migrated all of
+// the operator overloading logic over to the scheme used by binary
+// operators, which works for template instantiation.
+void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
                                  SourceLocation OpLoc,
                                  Expr **Args, unsigned NumArgs,
                                  OverloadCandidateSet& CandidateSet,
                                  SourceRange OpRange) {
+
+  FunctionSet Functions;
+
+  QualType T1 = Args[0]->getType();
+  QualType T2;
+  if (NumArgs > 1)
+    T2 = Args[1]->getType();
+
+  DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+  LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
+  ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
+  AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet);
+  AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
+  AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
+}
+
+/// \brief Add overload candidates for overloaded operators that are
+/// member functions.
+///
+/// Add the overloaded operator candidates that are member functions
+/// for the operator Op that was used in an operator expression such
+/// as "x Op y". , Args/NumArgs provides the operator arguments, and
+/// CandidateSet will store the added overload candidates. (C++
+/// [over.match.oper]).
+void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
+                                       SourceLocation OpLoc,
+                                       Expr **Args, unsigned NumArgs,
+                                       OverloadCandidateSet& CandidateSet,
+                                       SourceRange OpRange) {
   DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
 
   // C++ [over.match.oper]p3:
@@ -2338,6 +2377,7 @@
   //        result of the qualified lookup of T1::operator@
   //        (13.3.1.1.1); otherwise, the set of member candidates is
   //        empty.
+  // FIXME: Lookup in base classes, too!
   if (const RecordType *T1Rec = T1->getAsRecordType()) {
     DeclContext::lookup_const_iterator Oper, OperEnd;
     for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(OpName);
@@ -2346,38 +2386,6 @@
                          Args+1, NumArgs - 1, CandidateSet,
                          /*SuppressUserConversions=*/false);
   }
-
-  FunctionSet Functions;
-
-  //     -- The set of non-member candidates is the result of the
-  //        unqualified lookup of operator@ in the context of the
-  //        expression according to the usual rules for name lookup in
-  //        unqualified function calls (3.4.2) except that all member
-  //        functions are ignored. However, if no operand has a class
-  //        type, only those non-member functions in the lookup set
-  //        that have a first parameter of type T1 or “reference to
-  //        (possibly cv-qualified) T1”, when T1 is an enumeration
-  //        type, or (if there is a right operand) a second parameter
-  //        of type T2 or “reference to (possibly cv-qualified) T2”,
-  //        when T2 is an enumeration type, are candidate functions.
-  LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
-
-  // Since the set of non-member candidates corresponds to
-  // *unqualified* lookup of the operator name, we also perform
-  // argument-dependent lookup (C++ [basic.lookup.argdep]).
-  ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
-
-  // Add all of the functions found via operator name lookup and
-  // argument-dependent lookup to the candidate set.
-  for (FunctionSet::iterator Func = Functions.begin(),
-                          FuncEnd = Functions.end();
-       Func != FuncEnd; ++Func)
-    AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
-
-  // Add builtin overload candidates (C++ [over.built]).
-  AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
-
-  return false;
 }
 
 /// AddBuiltinCandidate - Add a candidate for a built-in
@@ -3615,6 +3623,161 @@
   return 0;
 }
 
+/// \brief Create a binary operation that may resolve to an overloaded
+/// operator.
+///
+/// \param OpLoc The location of the operator itself (e.g., '+').
+///
+/// \param OpcIn The BinaryOperator::Opcode that describes this
+/// operator.
+///
+/// \param Functions The set of non-member functions that will be
+/// considered by overload resolution. The caller needs to build this
+/// set based on the context using, e.g.,
+/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
+/// set should not contain any member functions; those will be added
+/// by CreateOverloadedBinOp().
+///
+/// \param LHS Left-hand argument.
+/// \param RHS Right-hand argument.
+Sema::OwningExprResult 
+Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
+                            unsigned OpcIn, 
+                            FunctionSet &Functions,
+                            Expr *LHS, Expr *RHS) {
+  OverloadCandidateSet CandidateSet;
+  Expr *Args[2] = { LHS, RHS };
+
+  BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
+  OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
+  DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+  // If either side is type-dependent, create an appropriate dependent
+  // expression.
+  if (LHS->isTypeDependent() || RHS->isTypeDependent()) {
+    // .* cannot be overloaded.
+    if (Opc == BinaryOperator::PtrMemD)
+      return Owned(new (Context) BinaryOperator(LHS, RHS, Opc,
+                                                Context.DependentTy, OpLoc));
+
+    OverloadedFunctionDecl *Overloads 
+      = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+    for (FunctionSet::iterator Func = Functions.begin(), 
+                            FuncEnd = Functions.end();
+         Func != FuncEnd; ++Func)
+      Overloads->addOverload(*Func);
+
+    DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
+                                                OpLoc, false, false);
+    
+    return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
+                                                   Args, 2, 
+                                                   Context.DependentTy,
+                                                   OpLoc));
+  }
+
+  // If this is the .* operator, which is not overloadable, just
+  // create a built-in binary operator.
+  if (Opc == BinaryOperator::PtrMemD)
+    return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+
+  // If this is one of the assignment operators, we only perform
+  // overload resolution if the left-hand side is a class or
+  // enumeration type (C++ [expr.ass]p3).
+  if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
+      !LHS->getType()->isOverloadableType())
+    return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+
+
+  // Add the candidates from the given function set.
+  AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
+
+  // Add operator candidates that are member functions.
+  AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
+
+  // Add builtin operator candidates.
+  AddBuiltinOperatorCandidates(Op, 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(LHS, Method) ||
+              PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(),
+                                        "passing"))
+            return ExprError();
+        } else {
+          // Convert the arguments.
+          if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(),
+                                        "passing") ||
+              PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(),
+                                        "passing"))
+            return ExprError();
+        }
+
+        // Determine the result type
+        QualType ResultTy
+          = FnDecl->getType()->getAsFunctionType()->getResultType();
+        ResultTy = ResultTy.getNonReferenceType();
+
+        // Build the actual expression node.
+        Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+                                                 SourceLocation());
+        UsualUnaryConversions(FnExpr);
+
+        return Owned(new (Context) CXXOperatorCallExpr(Context, Op, 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 (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
+                                      Best->Conversions[0], "passing") ||
+            PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
+                                      Best->Conversions[1], "passing"))
+          return ExprError();
+
+        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)
+          << BinaryOperator::getOpcodeStr(Opc)
+          << LHS->getSourceRange() << RHS->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
+
+    case OR_Deleted:
+      Diag(OpLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << BinaryOperator::getOpcodeStr(Opc)
+        << LHS->getSourceRange() << RHS->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
+    }
+
+  // Either we found no viable overloaded operator or we matched a
+  // built-in operator. In either case, try to build a built-in
+  // operation.
+  return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+}
+
 /// BuildCallToMemberFunction - Build a call to a member
 /// function. MemExpr is the expression that refers to the member
 /// function (and includes the object parameter), Args/NumArgs are the
@@ -3870,8 +4033,8 @@
   // owned.
   QualType ResultTy = Method->getResultType().getNonReferenceType();
   ExprOwningPtr<CXXOperatorCallExpr> 
-    TheCall(this, new (Context) CXXOperatorCallExpr(Context, NewFn, MethodArgs,
-                                                    NumArgs + 1,
+    TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, 
+                                                    MethodArgs, NumArgs + 1,
                                                     ResultTy, RParenLoc));
   delete [] MethodArgs;
 
@@ -3989,7 +4152,7 @@
   Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
                                            SourceLocation());
   UsualUnaryConversions(FnExpr);
-  Base = new (Context) CXXOperatorCallExpr(Context, FnExpr, &Base, 1, 
+  Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1, 
                                  Method->getResultType().getNonReferenceType(),
                                  OpLoc);
   return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Mar 13 13:40:31 2009
@@ -648,9 +648,11 @@
 
 Sema::OwningExprResult 
 TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
-  // FIXME: HACK HACK HACK. This is so utterly and completely wrong
-  // that I don't want to explain it here. I'll just fix it tomorrow
-  // instead.
+  // FIXME: Only handles binary operators at the moment.
+
+  // FIXME: Can we optimize this further if neither the left- nor the
+  // right-hand sides are type-dependent? It depends on whether we
+  // need to perform ADL again
   Sema::OwningExprResult LHS = Visit(E->getArg(0));
   if (LHS.isInvalid())
     return SemaRef.ExprError();
@@ -659,11 +661,56 @@
   if (RHS.isInvalid())
     return SemaRef.ExprError();
 
-  Sema::OwningExprResult Result
-    = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), 
-                                 BinaryOperator::Add,
-                                 (Expr *)LHS.get(),
-                                 (Expr *)RHS.get());
+  Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
+  Expr *Args[2] = { lhs, rhs };
+
+  if (!E->isTypeDependent()) { 
+    // Since our original expression was not type-dependent, we do not
+    // perform lookup again at instantiation time (C++ [temp.dep]p1).
+    // Instead, we just build the new overloaded operator call
+    // expression.
+    LHS.release();
+    RHS.release();
+    return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
+                                                       SemaRef.Context, 
+                                                       E->getOperator(),
+                                                       E->getCallee(), 
+                                                       Args, 2, E->getType(), 
+                                                       E->getOperatorLoc()));
+  }
+
+  BinaryOperator::Opcode Opc = 
+    BinaryOperator::getOverloadedOpcode(E->getOperator());
+  Sema::OwningExprResult Result(SemaRef);
+  if (!lhs->getType()->isOverloadableType() && 
+      !rhs->getType()->isOverloadableType()) {
+    // Neither LHS nor RHS is an overloadable type, so try create a
+    // built-in binary operation.
+    Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, 
+                                        lhs, rhs);
+  } else {
+    // Compute the set of functions that were found at template
+    // definition time.
+    Sema::FunctionSet Functions;
+    DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
+    OverloadedFunctionDecl *Overloads 
+      = cast<OverloadedFunctionDecl>(DRE->getDecl());
+    for (OverloadedFunctionDecl::function_iterator 
+           F = Overloads->function_begin(),
+           FEnd = Overloads->function_end();
+         F != FEnd; ++F)
+      Functions.insert(*F);
+
+    // Add any functions found via argument-dependent lookup.
+    DeclarationName OpName 
+      = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
+    SemaRef.ArgumentDependentLookup(OpName, Args, 2, Functions);
+
+    // Create the overloaded operator.
+    Result = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, 
+                                           Functions, lhs, rhs);
+  }
+
   if (Result.isInvalid())
     return SemaRef.ExprError();
 





More information about the cfe-commits mailing list