diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-11-19 15:42:04 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-11-19 15:42:04 +0000 |
commit | 74253736184c0717a0649922551bf9d8b6815651 (patch) | |
tree | 49fde4054461edd0563407010d0c4619e2c7e8fa /lib | |
parent | 08b2c3743a29a2dddcf72e95f747760e213cdde7 (diff) |
Added operator overloading for unary operators, post-increment, and
post-decrement, including support for generating all of the built-in
operator candidates for these operators.
C++ and C have different rules for the arguments to the builtin unary
'+' and '-'. Implemented both variants in Sema::ActOnUnaryOp.
In C++, pre-increment and pre-decrement return lvalues. Update
Expr::isLvalue accordingly.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59638 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Expr.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 219 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 242 |
6 files changed, 426 insertions, 65 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 49a4d77783..a179af8b14 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -398,6 +398,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag || cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension) return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx); // GNU. + + if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1 + (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec)) + return LV_Valid; break; case ImplicitCastExprClass: return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 2b803d9ad0..440393dac6 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -515,7 +515,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(true); if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val); return Res; } case tok::amp: // unary-expression: '&' cast-expression @@ -529,7 +529,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val); return Res; } @@ -539,7 +539,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, Res.Val); return Res; } case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression @@ -724,8 +724,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid) - LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(), - LHS.Val); + LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(), + Tok.getKind(), LHS.Val); ConsumeToken(); break; } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 49b8180904..221ad90273 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -386,7 +386,8 @@ Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { } // Add the __extension__ node to the AST. - Res = Actions.ActOnUnaryOp(ExtLoc, tok::kw___extension__, Res.Val); + Res = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__, + Res.Val); if (Res.isInvalid) continue; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 29994d41c3..c60fd352f9 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -435,9 +435,9 @@ public: void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); - void AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, - Expr **Args, - OverloadCandidateSet& CandidateSet); + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet); void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -640,8 +640,8 @@ public: virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks); // Binary/Unary Operators. 'Tok' is the token for the operator. - virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, - ExprTy *Input); + virtual ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprTy *Input); virtual ExprResult ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, void *TyOrEx, const SourceRange &ArgRange); @@ -649,7 +649,7 @@ public: bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, const SourceRange &R, bool isSizeof); - virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, + virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, ExprTy *Input); virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9a77e4f8e1..c7803722fe 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -752,19 +752,112 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc) { -Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc, +Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, ExprTy *Input) { + Expr *Arg = (Expr *)Input; + UnaryOperator::Opcode Opc; switch (Kind) { default: assert(0 && "Unknown unary op!"); case tok::plusplus: Opc = UnaryOperator::PostInc; break; case tok::minusminus: Opc = UnaryOperator::PostDec; break; } - QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc); + + if (getLangOptions().CPlusPlus && + (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) { + // Which overloaded operator? + OverloadedOperatorKind OverOp = + (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus; + + // C++ [over.inc]p1: + // + // [...] If the function is a member function with one + // parameter (which shall be of type int) or a non-member + // function with two parameters (the second of which shall be + // of type int), it defines the postfix increment operator ++ + // for objects of that type. When the postfix increment is + // called as a result of using the ++ operator, the int + // argument will have value zero. + Expr *Args[2] = { + Arg, + new IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, + /*isSigned=*/true), + Context.IntTy, SourceLocation()) + }; + + // Build the candidate set for overloading + OverloadCandidateSet CandidateSet; + AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(Arg, Method)) + return true; + } else { + // Convert the arguments. + if (PerformCopyInitialization(Arg, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return true; + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, OpLoc); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0], + "passing")) + return true; + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Arg->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return true; + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + } + + QualType result = CheckIncrementDecrementOperand(Arg, OpLoc); if (result.isNull()) return true; - return new UnaryOperator((Expr *)Input, Opc, result, OpLoc); + return new UnaryOperator(Arg, Opc, result, OpLoc); } Action::ExprResult Sema:: @@ -2819,16 +2912,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, !(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) { return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs); } - - // C++ [over.binary]p1: - // A binary operator shall be implemented either by a non-static - // member function (9.3) with one parameter or by a non-member - // function with two parameters. Thus, for any binary operator - // @, x@y can be interpreted as either x.operator@(y) or - // operator@(x,y). If both forms of the operator function have - // been declared, the rules in 13.3.1.2 determines which, if - // any, interpretation is used. - OverloadCandidateSet CandidateSet; // Determine which overloaded operator we're dealing with. static const OverloadedOperatorKind OverOps[] = { @@ -2854,6 +2937,7 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, // Add the appropriate overloaded operators (C++ [over.match.oper]) // to the candidate set. + OverloadCandidateSet CandidateSet; Expr *Args[2] = { lhs, rhs }; AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet); @@ -2893,7 +2977,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, SourceLocation()); UsualUnaryConversions(FnExpr); - Expr *Args[2] = { lhs, rhs }; return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, TokLoc); } else { // We matched a built-in operator. Convert the arguments, then @@ -2933,10 +3016,98 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, } // Unary Operators. 'Tok' is the token for the operator. -Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, - ExprTy *input) { +Action::ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprTy *input) { Expr *Input = (Expr*)input; UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); + + if (getLangOptions().CPlusPlus && + (Input->getType()->isRecordType() + || Input->getType()->isEnumeralType())) { + // Determine which overloaded operator we're dealing with. + static const OverloadedOperatorKind OverOps[] = { + OO_None, OO_None, + OO_PlusPlus, OO_MinusMinus, + OO_Amp, OO_Star, + OO_Plus, OO_Minus, + OO_Tilde, OO_Exclaim, + OO_None, OO_None, + OO_None, + OO_None + }; + OverloadedOperatorKind OverOp = OverOps[Opc]; + + // Add the appropriate overloaded operators (C++ [over.match.oper]) + // to the candidate set. + OverloadCandidateSet CandidateSet; + if (OverOp != OO_None) + AddOperatorCandidates(OverOp, S, &Input, 1, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(Input, Method)) + return true; + } else { + // Convert the arguments. + if (PerformCopyInitialization(Input, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return true; + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + return new CXXOperatorCallExpr(FnExpr, &Input, 1, ResultTy, OpLoc); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformCopyInitialization(Input, Best->BuiltinTypes.ParamTypes[0], + "passing")) + return true; + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return true; + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + } + + QualType resultType; switch (Opc) { default: @@ -2956,10 +3127,18 @@ Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, case UnaryOperator::Minus: UsualUnaryConversions(Input); resultType = Input->getType(); - if (!resultType->isArithmeticType()) // C99 6.5.3.3p1 - return Diag(OpLoc, diag::err_typecheck_unary_expr, - resultType.getAsString()); - break; + if (resultType->isArithmeticType()) // C99 6.5.3.3p1 + break; + else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7 + resultType->isEnumeralType()) + break; + else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6 + Opc == UnaryOperator::Plus && + resultType->isPointerType()) + break; + + return Diag(OpLoc, diag::err_typecheck_unary_expr, + resultType.getAsString()); case UnaryOperator::Not: // bitwise complement UsualUnaryConversions(Input); resultType = Input->getType(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index dbd21264f3..869fcc9352 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1843,8 +1843,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, } // Add builtin overload candidates (C++ [over.built]). - if (NumArgs == 2) - return AddBuiltinBinaryOperatorCandidates(Op, Args, CandidateSet); + AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet); } /// AddBuiltinCandidate - Add a candidate for a built-in @@ -2053,16 +2052,15 @@ void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } } -/// AddBuiltinCandidates - Add the appropriate built-in operator -/// overloads to the candidate set (C++ [over.built]), based on the -/// operator @p Op and the arguments given. For example, if the -/// operator is a binary '+', this routine might add -/// "int operator+(int, int)" -/// to cover integer addition. +/// AddBuiltinOperatorCandidates - Add the appropriate built-in +/// operator overloads to the candidate set (C++ [over.built]), based +/// on the operator @p Op and the arguments given. For example, if the +/// operator is a binary '+', this routine might add "int +/// operator+(int, int)" to cover integer addition. void -Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, - Expr **Args, - OverloadCandidateSet& CandidateSet) { +Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet) { // The set of "promoted arithmetic types", which are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). Note // that the first few of these types are the promoted integral @@ -2090,10 +2088,11 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, BuiltinCandidateTypeSet CandidateTypes(Context); if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || - Op == OO_Plus || Op == OO_Minus || Op == OO_Equal || + Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal || Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript || - Op == OO_ArrowStar) { - for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) + Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus || + (Op == OO_Star && NumArgs == 1)) { + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType()); } @@ -2104,24 +2103,184 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, assert(false && "Expected an overloaded operator"); break; + case OO_Star: // '*' is either unary or binary + if (NumArgs == 1) + goto UnaryStar; + else + goto BinaryStar; + break; + + case OO_Plus: // '+' is either unary or binary + if (NumArgs == 1) + goto UnaryPlus; + else + goto BinaryPlus; + break; + + case OO_Minus: // '-' is either unary or binary + if (NumArgs == 1) + goto UnaryMinus; + else + goto BinaryMinus; + break; + + case OO_Amp: // '&' is either unary or binary + if (NumArgs == 1) + goto UnaryAmp; + else + goto BinaryAmp; + + case OO_PlusPlus: + case OO_MinusMinus: + // C++ [over.built]p3: + // + // For every pair (T, VQ), where T is an arithmetic type, and VQ + // is either volatile or empty, there exist candidate operator + // functions of the form + // + // VQ T& operator++(VQ T&); + // T operator++(VQ T&, int); + // + // C++ [over.built]p4: + // + // For every pair (T, VQ), where T is an arithmetic type other + // than bool, and VQ is either volatile or empty, there exist + // candidate operator functions of the form + // + // VQ T& operator--(VQ T&); + // T operator--(VQ T&, int); + for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); + Arith < NumArithmeticTypes; ++Arith) { + QualType ArithTy = ArithmeticTypes[Arith]; + QualType ParamTypes[2] + = { Context.getReferenceType(ArithTy), Context.IntTy }; + + // Non-volatile version. + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + + // Volatile version + ParamTypes[0] = Context.getReferenceType(ArithTy.withVolatile()); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + } + + // C++ [over.built]p5: + // + // For every pair (T, VQ), where T is a cv-qualified or + // cv-unqualified object type, and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // T*VQ& operator++(T*VQ&); + // T*VQ& operator--(T*VQ&); + // T* operator++(T*VQ&, int); + // T* operator--(T*VQ&, int); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + // Skip pointer types that aren't pointers to object types. + if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType()) + continue; + + QualType ParamTypes[2] = { + Context.getReferenceType(*Ptr), Context.IntTy + }; + + // Without volatile + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + + if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + // With volatile + ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } + } + break; + + UnaryStar: + // C++ [over.built]p6: + // For every cv-qualified or cv-unqualified object type T, there + // exist candidate operator functions of the form + // + // T& operator*(T*); + // + // C++ [over.built]p7: + // For every function type T, there exist candidate operator + // functions of the form + // T& operator*(T*); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTy = *Ptr; + QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType(); + AddBuiltinCandidate(Context.getReferenceType(PointeeTy), + &ParamTy, Args, 1, CandidateSet); + } + break; + + UnaryPlus: + // C++ [over.built]p8: + // For every type T, there exist candidate operator functions of + // the form + // + // T* operator+(T*); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTy = *Ptr; + AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + } + + // Fall through + + UnaryMinus: + // C++ [over.built]p9: + // For every promoted arithmetic type T, there exist candidate + // operator functions of the form + // + // T operator+(T); + // T operator-(T); + for (unsigned Arith = FirstPromotedArithmeticType; + Arith < LastPromotedArithmeticType; ++Arith) { + QualType ArithTy = ArithmeticTypes[Arith]; + AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); + } + break; + + case OO_Tilde: + // C++ [over.built]p10: + // For every promoted integral type T, there exist candidate + // operator functions of the form + // + // T operator~(T); + for (unsigned Int = FirstPromotedIntegralType; + Int < LastPromotedIntegralType; ++Int) { + QualType IntTy = ArithmeticTypes[Int]; + AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); + } + break; + case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: - case OO_Tilde: - case OO_Exclaim: - case OO_PlusPlus: - case OO_MinusMinus: - case OO_Arrow: case OO_Call: - assert(false && "Expected a binary operator"); + assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); break; case OO_Comma: + UnaryAmp: + case OO_Arrow: // C++ [over.match.oper]p3: // -- For the operator ',', the unary operator '&', or the // operator '->', the built-in candidates set is empty. - // We don't check '&' or '->' here, since they are unary operators. break; case OO_Less: @@ -2156,8 +2315,8 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, // Fall through. isComparison = true; - case OO_Plus: - case OO_Minus: + BinaryPlus: + BinaryMinus: if (!isComparison) { // We didn't fall through, so we must have OO_Plus or OO_Minus. @@ -2201,8 +2360,8 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, } // Fall through - case OO_Star: case OO_Slash: + BinaryStar: // C++ [over.built]p12: // // For every pair of promoted arithmetic types L and R, there @@ -2235,7 +2394,7 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Percent: - case OO_Amp: + BinaryAmp: case OO_Caret: case OO_Pipe: case OO_LessLess: @@ -2285,10 +2444,12 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, ParamTypes[1] = *Enum; AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); - // volatile T& operator=(volatile T&, T) - ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile()); - ParamTypes[1] = *Enum; - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + if (!Context.getCanonicalType(*Enum).isVolatileQualified()) { + // volatile T& operator=(volatile T&, T) + ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile()); + ParamTypes[1] = *Enum; + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + } } // Fall through. @@ -2319,9 +2480,11 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, ParamTypes[0] = Context.getReferenceType(*Ptr); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); - // volatile version - ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); - AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + // volatile version + ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile()); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + } } // Fall through. @@ -2396,13 +2559,26 @@ Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op, } break; + case OO_Exclaim: { + // C++ [over.operator]p23: + // + // There also exist candidate operator functions of the form + // + // bool operator!(bool); + // bool operator&&(bool, bool); [BELOW] + // bool operator||(bool, bool); [BELOW] + QualType ParamTy = Context.BoolTy; + AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + break; + } + case OO_AmpAmp: case OO_PipePipe: { // C++ [over.operator]p23: // // There also exist candidate operator functions of the form // - // bool operator!(bool); [In Unary version] + // bool operator!(bool); [ABOVE] // bool operator&&(bool, bool); // bool operator||(bool, bool); QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy }; |