]> granicus.if.org Git - clang/commitdiff
Implement template instantiation for the prefix unary operators. As
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 Mar 2009 23:49:33 +0000 (23:49 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 Mar 2009 23:49:33 +0000 (23:49 +0000)
always, refactored the existing logic to tease apart the parser action
and the semantic analysis shared by the parser and template
instantiation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66987 91177308-0d34-0410-b5e6-96231b3b80d8

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

index bfd8538788690e637ee7909435bce728a999b816..ed571fd6c4a8d36ee705808059038c3657538dfe 100644 (file)
@@ -660,6 +660,14 @@ public:
   /// 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);
index 4b99eefcd4f9b2341cee4158b3fba51dfffc2ee3..273b5ed72f797c761ab38634911f07fe992ad1af 100644 (file)
@@ -91,6 +91,36 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
   }
 }
 
+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.
 //===----------------------------------------------------------------------===//
index b29790e7b5c11ad0e9bb3cafa809511634cd1b56..a86aa65aff288ef1892c5580597071774f054f77 100644 (file)
@@ -586,6 +586,11 @@ public:
                                         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 @@ public:
                                               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,
index c04006cb1ca1a88994d05d2635606187ced1de54..c3ae4f7f675ae18975e8f561a5434db258bfbef4 100644 (file)
@@ -4036,114 +4036,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
   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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
   }
   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,
index 865034707d43d6568a50a1f1d5c8ca6e028a86bc..8943aa602eb1a60cb074ab540ec8319ba8db5740 100644 (file)
@@ -3623,6 +3623,153 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
   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 @@ 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);
@@ -3688,6 +3834,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
       !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);
index 4bd7ad4e83f24ca428070c975d9be61dbd805d9e..4c3f100d74d0d4fc7f3eee2337700a6122791f7a 100644 (file)
@@ -584,6 +584,7 @@ namespace {
     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);
@@ -633,6 +634,17 @@ TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) {
                                                (Expr *)SubExpr.release()));
 }
 
+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());
@@ -658,74 +670,116 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
 
 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);  
 }
 
index 869d558e33328d962878f3fd33f59333205b8b36..2ea0641b00771b883718aee2288915e6bebd3289 100644 (file)
@@ -53,3 +53,19 @@ void test_BitfieldDep() {
   (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}}
+}
index 81af5730def41fb955fae03d4591a6e04fa9044f..d90cef5a0b15132d044806c296994e4e4415b02e 100644 (file)
@@ -50,3 +50,18 @@ void test_bin_op_overload(A<1> *a1, A<2> *a2, A<4> *a4, A<8> *a8) {
   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;
+}