diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 64e24ccd286d..3af207789c1e 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1245,6 +1245,14 @@ public: /// 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; } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index d18ffb3c8e95..37fead0cbf9b 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -40,14 +40,19 @@ namespace clang { /// 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 diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 2698a2e16a3d..13668569ca73 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -361,7 +361,7 @@ public: /// 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 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const { 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 { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 9612f7ff2afb..4b99eefcd4f9 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -227,6 +227,68 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) { 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) diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index d60ef39070b8..184c9fe49043 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -160,27 +160,6 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const { } } -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(getCallee()); - if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). - return OO_None; - - const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); - if (!DRE) - return OO_None; - - if (const FunctionDecl *FDecl = dyn_cast(DRE->getDecl())) - return FDecl->getDeclName().getCXXOverloadedOperator(); - else if (const OverloadedFunctionDecl *Ovl - = dyn_cast(DRE->getDecl())) - return Ovl->getDeclName().getCXXOverloadedOperator(); - else - return OO_None; -} - SourceRange CXXOperatorCallExpr::getSourceRange() const { OverloadedOperatorKind Kind = getOperator(); if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index d49efdddb193..c6fe6c164af8 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -523,10 +523,18 @@ public: OR_Deleted ///< Overload resoltuion refers to a deleted function. }; + typedef llvm::SmallPtrSet FunctionSet; + typedef llvm::SmallPtrSet AssociatedNamespaceSet; + typedef llvm::SmallPtrSet 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 @@ public: 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 @@ public: 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 @@ public: bool AllowBuiltinCreation = true, SourceLocation Loc = SourceLocation()); - typedef llvm::SmallPtrSet FunctionSet; - typedef llvm::SmallPtrSet AssociatedNamespaceSet; - typedef llvm::SmallPtrSet AssociatedClassSet; - void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, FunctionSet &Functions); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index daaedae103c0..f5d8f6b5e12a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1694,7 +1694,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, // 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) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4a314525bf21..0855932ac437 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1324,8 +1324,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, // 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 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, 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 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CompTy, OpLoc)); } -static OverloadedOperatorKind -getOverloadedOperator(BinaryOperator::Opcode Opc) { - static const OverloadedOperatorKind OverOps[] = { - // Overloading .* is not possible. - static_cast(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 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, 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); + 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); } - // 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(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; - } - } - - 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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, // 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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, 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 diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8453b4e88c30..501eda74438b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -800,7 +800,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 53174b68a132..865034707d43 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -468,7 +468,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, 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 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, } } +/// \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 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } -/// 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 @@ bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, // 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 @@ bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, 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 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, 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(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(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 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // owned. QualType ResultTy = Method->getResultType().getNonReferenceType(); ExprOwningPtr - 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 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, 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, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3f7756ef3edf..aea03cc580d8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -648,9 +648,11 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) { 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 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { 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(E->getCallee()); + OverloadedFunctionDecl *Overloads + = cast(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();