[cfe-commits] r66987 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/instantiate-expr-1.cpp test/SemaTemplate/instantiate-expr-2.cpp

Douglas Gregor dgregor at apple.com
Fri Mar 13 16:49:34 PDT 2009


Author: dgregor
Date: Fri Mar 13 18:49:33 2009
New Revision: 66987

URL: http://llvm.org/viewvc/llvm-project?rev=66987&view=rev
Log:
Implement template instantiation for the prefix unary operators. As
always, refactored the existing logic to tease apart the parser action
and the semantic analysis shared by the parser and template
instantiation.


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp
    cfe/trunk/test/SemaTemplate/instantiate-expr-2.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Mar 13 18:49:33 2009
@@ -660,6 +660,14 @@
   /// corresponds to, e.g. "sizeof" or "[pre]++"
   static const char *getOpcodeStr(Opcode Op);
 
+  /// \brief Retrieve the unary opcode that corresponds to the given
+  /// overloaded operator.
+  static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix);
+
+  /// \brief Retrieve the overloaded operator kind that corresponds to
+  /// the given unary opcode.
+  static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
+
   virtual SourceRange getSourceRange() const {
     if (isPostfix())
       return SourceRange(Val->getLocStart(), Loc);

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

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Mar 13 18:49:33 2009
@@ -91,6 +91,36 @@
   }
 }
 
+UnaryOperator::Opcode 
+UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
+  switch (OO) {
+  case OO_PlusPlus: return Postfix? PostInc : PreInc;
+  case OO_MinusMinus: return Postfix? PostDec : PreDec;
+  case OO_Amp: return AddrOf;
+  case OO_Star: return Deref;
+  case OO_Plus: return Plus;
+  case OO_Minus: return Minus;
+  case OO_Tilde: return Not;
+  case OO_Exclaim: return LNot;
+  default: assert(false && "No unary operator for overloaded function");
+  }
+}
+
+OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
+  switch (Opc) {
+  case PostInc: case PreInc: return OO_PlusPlus;
+  case PostDec: case PreDec: return OO_MinusMinus;
+  case AddrOf: return OO_Amp;
+  case Deref: return OO_Star;
+  case Plus: return OO_Plus;
+  case Minus: return OO_Minus;
+  case Not: return OO_Tilde;
+  case LNot: return OO_Exclaim;
+  default: return OO_None;
+  }
+}
+
+
 //===----------------------------------------------------------------------===//
 // Postfix Operators.
 //===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Mar 13 18:49:33 2009
@@ -586,6 +586,11 @@
                                         SourceLocation RParenLoc,
                                         bool &ArgumentDependentLookup);
 
+  OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
+                                           unsigned Opc,
+                                           FunctionSet &Functions,
+                                           ExprArg input);
+
   OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
                                          unsigned Opc,
                                          FunctionSet &Functions,
@@ -1182,16 +1187,19 @@
                                               unsigned NumToks);
 
   // Binary/Unary Operators.  'Tok' is the token for the operator.
+  OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
+                                        unsigned OpcIn, 
+                                        ExprArg InputArg);
   virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
                                         tok::TokenKind Op, ExprArg Input);
-  virtual OwningExprResult
-    ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
-                           void *TyOrEx, const SourceRange &ArgRange);
 
   OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, 
                                            bool isSizeOf, SourceRange R);
   OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, 
                                            bool isSizeOf, SourceRange R);
+  virtual OwningExprResult
+    ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+                           void *TyOrEx, const SourceRange &ArgRange);
                                            
   bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
   bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Mar 13 18:49:33 2009
@@ -4036,114 +4036,22 @@
   return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
 }
 
-// Unary Operators.  'Tok' is the token for the operator.
-Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
-                                            tok::TokenKind Op, ExprArg input) {
-  // FIXME: Input is modified later, but smart pointer not reassigned.
-  Expr *Input = (Expr*)input.get();
-  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, OpLoc, &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 ExprError();
-        } else {
-          // Convert the arguments.
-          if (PerformCopyInitialization(Input,
-                                        FnDecl->getParamDecl(0)->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);
-
-        input.release();
-        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
-        // operator node.
-        if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
-                                      Best->Conversions[0], "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)
-          << UnaryOperator::getOpcodeStr(Opc)
-          << Input->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
-      return ExprError();
-
-    case OR_Deleted:
-      Diag(OpLoc, diag::err_ovl_deleted_oper)
-        << Best->Function->isDeleted()
-        << UnaryOperator::getOpcodeStr(Opc)
-        << Input->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.
-  }
-
+Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
+                                                    unsigned OpcIn, 
+                                                    ExprArg InputArg) {
+  UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+
+  // FIXME: Input is modified below, but InputArg is not updated
+  // appropriately.
+  Expr *Input = (Expr *)InputArg.get();
   QualType resultType;
   switch (Opc) {
-  default:
-    assert(0 && "Unimplemented unary expr!");
+  case UnaryOperator::PostInc:
+  case UnaryOperator::PostDec:
+  case UnaryOperator::OffsetOf:
+    assert(false && "Invalid unary operator");
+    break;
+
   case UnaryOperator::PreInc:
   case UnaryOperator::PreDec:
     resultType = CheckIncrementDecrementOperand(Input, OpLoc,
@@ -4211,10 +4119,38 @@
   }
   if (resultType.isNull())
     return ExprError();
-  input.release();
+
+  InputArg.release();
   return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
 }
 
+// Unary Operators.  'Tok' is the token for the operator.
+Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+                                            tok::TokenKind Op, ExprArg input) {
+  Expr *Input = (Expr*)input.get();
+  UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+
+  if (getLangOptions().CPlusPlus && Input->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 = UnaryOperator::getOverloadedOperator(Opc);
+    if (OverOp != OO_None) {
+      LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+                                   Functions);
+      DeclarationName OpName 
+        = Context.DeclarationNames.getCXXOperatorName(OverOp);
+      ArgumentDependentLookup(OpName, &Input, 1, Functions);
+    }
+
+    return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
+  }
+
+  return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
+}
+
 /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
 Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
                                       SourceLocation LabLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Mar 13 18:49:33 2009
@@ -3623,6 +3623,153 @@
   return 0;
 }
 
+/// \brief Create a unary operation that may resolve to an overloaded
+/// operator.
+///
+/// \param OpLoc The location of the operator itself (e.g., '*').
+///
+/// \param OpcIn The UnaryOperator::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 CreateOverloadedUnaryOp().
+///
+/// \param input The input argument.
+Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
+                                                     unsigned OpcIn,
+                                                     FunctionSet &Functions,
+                                                     ExprArg input) {  
+  UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+  Expr *Input = (Expr *)input.get();
+
+  OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
+  assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
+  DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+  Expr *Args[2] = { Input, 0 };
+  unsigned NumArgs = 1;
+    
+  // For post-increment and post-decrement, add the implicit '0' as
+  // the second argument, so that we know this is a post-increment or
+  // post-decrement.
+  if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) {
+    llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
+    Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, 
+                                           SourceLocation());
+    NumArgs = 2;
+  }
+
+  if (Input->isTypeDependent()) {
+    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);
+    
+    input.release();
+    return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
+                                                   &Args[0], NumArgs,
+                                                   Context.DependentTy,
+                                                   OpLoc));
+  }
+
+  // Build an empty overload set.
+  OverloadCandidateSet CandidateSet;
+
+  // Add the candidates from the given function set.
+  AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false);
+
+  // Add operator candidates that are member functions.
+  AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+
+  // Add builtin operator candidates.
+  AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, 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 ExprError();
+      } else {
+        // Convert the arguments.
+        if (PerformCopyInitialization(Input,
+                                      FnDecl->getParamDecl(0)->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);
+      
+      input.release();
+      return Owned(new (Context) CXXOperatorCallExpr(Context, Op, 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 (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+                                      Best->Conversions[0], "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)
+          << UnaryOperator::getOpcodeStr(Opc)
+          << Input->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
+
+    case OR_Deleted:
+      Diag(OpLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << UnaryOperator::getOpcodeStr(Opc)
+        << Input->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.
+  input.release();
+  return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input));
+}
+
 /// \brief Create a binary operation that may resolve to an overloaded
 /// operator.
 ///
@@ -3645,7 +3792,6 @@
                             unsigned OpcIn, 
                             FunctionSet &Functions,
                             Expr *LHS, Expr *RHS) {
-  OverloadCandidateSet CandidateSet;
   Expr *Args[2] = { LHS, RHS };
 
   BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
@@ -3688,6 +3834,8 @@
       !LHS->getType()->isOverloadableType())
     return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
 
+  // Build an empty overload set.
+  OverloadCandidateSet CandidateSet;
 
   // Add the candidates from the given function set.
   AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Mar 13 18:49:33 2009
@@ -584,6 +584,7 @@
     OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
     OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
     OwningExprResult VisitParenExpr(ParenExpr *E);
+    OwningExprResult VisitUnaryOperator(UnaryOperator *E);
     OwningExprResult VisitBinaryOperator(BinaryOperator *E);
     OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
     OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
@@ -634,6 +635,17 @@
 }
 
 Sema::OwningExprResult 
+TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) {
+  Sema::OwningExprResult Arg = Visit(E->getSubExpr());
+  if (Arg.isInvalid())
+    return SemaRef.ExprError();
+
+  return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(),
+                                      E->getOpcode(),
+                                      move(Arg));
+}
+
+Sema::OwningExprResult 
 TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
   Sema::OwningExprResult LHS = Visit(E->getLHS());
   if (LHS.isInvalid())
@@ -658,74 +670,116 @@
 
 Sema::OwningExprResult 
 TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
-  // FIXME: Only handles binary operators at the moment.
-
-  Sema::OwningExprResult LHS = Visit(E->getArg(0));
-  if (LHS.isInvalid())
+  Sema::OwningExprResult First = Visit(E->getArg(0));
+  if (First.isInvalid())
     return SemaRef.ExprError();
 
-  Sema::OwningExprResult RHS = Visit(E->getArg(1));
-  if (RHS.isInvalid())
-    return SemaRef.ExprError();
+  Expr *Args[2] = { (Expr *)First.get(), 0 };
+
+  Sema::OwningExprResult Second(SemaRef);
+  if (E->getNumArgs() == 2) {
+    Second = Visit(E->getArg(1));
+
+    if (Second.isInvalid())
+      return SemaRef.ExprError();
 
-  Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
-  Expr *Args[2] = { lhs, rhs };
+    Args[1] = (Expr *)Second.get();
+  }
 
   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();
+    First.release();
+    Second.release();
     return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
                                                        SemaRef.Context, 
                                                        E->getOperator(),
                                                        E->getCallee(), 
-                                                       Args, 2, E->getType(), 
+                                                       Args, E->getNumArgs(),
+                                                       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);
+  bool isPostIncDec = E->getNumArgs() == 2 && 
+    (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus);
+  if (E->getNumArgs() == 1 || isPostIncDec) {
+    if (!Args[0]->getType()->isOverloadableType()) {
+      // The argument is not of overloadable type, so try to create a
+      // built-in unary operation.
+      UnaryOperator::Opcode Opc 
+        = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+
+      return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc,
+                                          move(First));
+    }
+
+    // Fall through to perform overload resolution
   } 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());
-
-    // FIXME: Do we have to check
-    // IsAcceptableNonMemberOperatorCandidate for each of these?
-    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);
+    assert(E->getNumArgs() == 2 && "Expected binary operation");
+
+    Sema::OwningExprResult Result(SemaRef);
+    if (!Args[0]->getType()->isOverloadableType() && 
+        !Args[1]->getType()->isOverloadableType()) {
+      // Neither of the arguments is an overloadable type, so try to
+      // create a built-in binary operation.
+      BinaryOperator::Opcode Opc = 
+        BinaryOperator::getOverloadedOpcode(E->getOperator());
+      Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, 
+                                          Args[0], Args[1]);
+      if (Result.isInvalid())
+        return SemaRef.ExprError();
+
+      First.release();
+      Second.release();
+      return move(Result);
+    }
+
+    // Fall through to perform overload resolution.
+  }
+
+  // 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());
+  
+  // FIXME: Do we have to check
+  // IsAcceptableNonMemberOperatorCandidate for each of these?
+  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, E->getNumArgs(), Functions);
+
+  // Create the overloaded operator invocation.
+  if (E->getNumArgs() == 1 || isPostIncDec) {
+    UnaryOperator::Opcode Opc 
+      = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+    return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc,
+                                           Functions, move(First));
   }
 
+  // FIXME: This would be far less ugly if CreateOverloadedBinOp took
+  // in ExprArg arguments!
+  BinaryOperator::Opcode Opc = 
+    BinaryOperator::getOverloadedOpcode(E->getOperator());
+  OwningExprResult Result 
+    = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, 
+                                    Functions, Args[0], Args[1]);
+
   if (Result.isInvalid())
     return SemaRef.ExprError();
 
-  LHS.release();
-  RHS.release();
+  First.release();
+  Second.release();
   return move(Result);  
 }
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp?rev=66987&r1=66986&r2=66987&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp Fri Mar 13 18:49:33 2009
@@ -53,3 +53,19 @@
   (void)sizeof(BitfieldDep<int, 1, 5>);
 }
 
+template<int I>
+struct BitfieldNeg {
+  int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+template<typename T, T I>
+struct BitfieldNeg2 {
+  int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+void test_BitfieldNeg() {
+  (void)sizeof(BitfieldNeg<-5>); // okay
+  (void)sizeof(BitfieldNeg<5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg<5>' requested here}}
+  (void)sizeof(BitfieldNeg2<int, -5>); // okay
+  (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}}
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-2.cpp?rev=66987&r1=66986&r2=66987&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-expr-2.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-expr-2.cpp Fri Mar 13 18:49:33 2009
@@ -50,3 +50,18 @@
   ZZ *zz = a8;
 }
 
+namespace N3 {
+  eight_bytes operator-(::N3::Z);
+}
+
+namespace N4 {
+  template<typename T>
+  struct UnaryOpOverload {
+    typedef A<sizeof(-T())> type;
+  };
+}
+
+void test_unary_op_overload(A<8> *a8) {
+  typedef N4::UnaryOpOverload<N3::Z>::type UZ;
+  UZ *uz = a8;
+}





More information about the cfe-commits mailing list