[cfe-commits] r59638 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/Parse/Action.h lib/AST/Expr.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseStmt.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/overloaded-builtin-operators.cpp test/SemaCXX/overloaded-operator.cpp www/cxx_status.html
Douglas Gregor
doug.gregor at gmail.com
Wed Nov 19 07:42:07 PST 2008
Author: dgregor
Date: Wed Nov 19 09:42:04 2008
New Revision: 59638
URL: http://llvm.org/viewvc/llvm-project?rev=59638&view=rev
Log:
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.
Modified:
cfe/trunk/Driver/PrintParserCallbacks.cpp
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
cfe/trunk/test/SemaCXX/overloaded-operator.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Wed Nov 19 09:42:04 2008
@@ -436,7 +436,7 @@
}
// Postfix Expressions.
- virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,
+ virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprTy *Input) {
llvm::cout << __FUNCTION__ << "\n";
return 0;
@@ -467,8 +467,8 @@
}
// 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) {
llvm::cout << __FUNCTION__ << "\n";
return 0;
}
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Nov 19 09:42:04 2008
@@ -509,7 +509,7 @@
}
// Postfix Expressions.
- virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,
+ virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprTy *Input) {
return 0;
}
@@ -536,8 +536,8 @@
}
// 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) {
return 0;
}
virtual ExprResult
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Nov 19 09:42:04 2008
@@ -398,6 +398,11 @@
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
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Nov 19 09:42:04 2008
@@ -515,7 +515,7 @@
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 @@
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 @@
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 @@
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;
}
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Wed Nov 19 09:42:04 2008
@@ -386,7 +386,8 @@
}
// 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;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 19 09:42:04 2008
@@ -435,9 +435,9 @@
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 @@
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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 19 09:42:04 2008
@@ -752,19 +752,112 @@
-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 @@
!(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 at 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 @@
// 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 @@
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 @@
}
// 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 @@
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();
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 19 09:42:04 2008
@@ -1843,8 +1843,7 @@
}
// 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 @@
}
}
-/// 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 @@
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 @@
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 @@
// 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 @@
}
// 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 @@
break;
case OO_Percent:
- case OO_Amp:
+ BinaryAmp:
case OO_Caret:
case OO_Pipe:
case OO_LessLess:
@@ -2285,10 +2444,12 @@
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 @@
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 @@
}
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 };
Modified: cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp Wed Nov 19 09:42:04 2008
@@ -25,6 +25,14 @@
no& islong(int);
void f(Short s, Long l, Enum1 e1, Enum2 e2) {
+ // C++ [over.built]p8
+ int i1 = +e1;
+ int i2 = -e2;
+
+ // C++ [over.built]p10:
+ int i3 = ~s;
+ bool b1 = !s;
+
// C++ [over.built]p12
(void)static_cast<yes&>(islong(s + l));
(void)static_cast<no&>(islong(s + s));
@@ -46,6 +54,12 @@
};
void g(ShortRef sr, LongRef lr) {
+ // C++ [over.built]p3
+ short s1 = sr++;
+
+ // C++ [over.built]p3
+ long l1 = lr--;
+
// C++ [over.built]p18
short& sr1 = (sr *= lr);
volatile long& lr1 = (lr *= sr);
@@ -65,7 +79,16 @@
operator int const *();
};
-void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr) {
+struct VolatileIntPtrRef {
+ operator int volatile *&();
+};
+
+struct ConstIntPtrRef {
+ operator int const *&();
+};
+
+void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr,
+ VolatileIntPtrRef vipr, ConstIntPtrRef cipr) {
#if 0
// FIXME: Enable these tests once we have operator overloading for
// operator[].
@@ -76,4 +99,19 @@
#endif
bool b1 = (vip == cip);
long p1 = vip - cip;
+
+ // C++ [over.built]p5:
+ int volatile *vip1 = vipr++;
+ int const *cip1 = cipr++;
+ int volatile *&vipr1 = ++vipr;
+ int const *&cipr1 = --cipr;
+
+ // C++ [over.built]p6:
+ int volatile &ivr = *vip;
+
+ // C++ [over.built]p8:
+ int volatile *vip2 = +vip;
+ int i1 = +sr;
+ int i2 = -sr;
}
+
Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Wed Nov 19 09:42:04 2008
@@ -69,3 +69,31 @@
float &f3 = (e1 == enum2);
float &f4 = (enum1 == enum2); // expected-error{{non-const reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}
}
+
+
+struct PostInc {
+ PostInc operator++(int);
+ PostInc& operator++();
+};
+
+struct PostDec {
+ PostDec operator--(int);
+ PostDec& operator--();
+};
+
+void incdec_test(PostInc pi, PostDec pd) {
+ const PostInc& pi1 = pi++;
+ const PostDec& pd1 = pd--;
+ PostInc &pi2 = ++pi;
+ PostDec &pd2 = --pd;
+}
+
+struct SmartPtr {
+ int& operator*();
+ // FIXME: spurious error: long& operator*() const;
+};
+
+void test_smartptr(SmartPtr ptr, const SmartPtr cptr) {
+ int &ir = *ptr;
+ // FIXME: reinstate long &lr = *cptr;
+}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=59638&r1=59637&r2=59638&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Nov 19 09:42:04 2008
@@ -826,8 +826,8 @@
<tr>
<td> 13.3.1.2 [over.match.oper]</td>
<td class="complete" align="center">✓</td>
- <td class="broken" align="center"></td>
- <td class="broken" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="medium" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
@@ -943,27 +943,27 @@
<td class="advanced" align="center"></td>
<td class="medium" align="center"></td>
<td class="broken" align="center"></td>
- <td>Most overloaded operators can only be called with function syntax, e.g., <code>operator+(x)</code>.</td>
+ <td>Some overloaded operators can only be called with function syntax, e.g., <code>operator[](x)</code>.</td>
</tr>
<tr>
<td> 13.5.1 [over.unary]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
- <td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
<tr>
<td> 13.5.2 [over.binary]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
<tr>
<td> 13.5.3 [over.ass]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
@@ -971,7 +971,7 @@
</tr>
<tr>
<td> 13.5.4 [over.call]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
@@ -979,7 +979,7 @@
</tr>
<tr>
<td> 13.5.5 [over.sub]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
<td class="advanced" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
@@ -987,21 +987,29 @@
</tr>
<tr>
<td> 13.5.6 [over.ref]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
- <td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
<tr>
<td> 13.5.7 [over.inc]</td>
- <td class="advanced" align="center"></td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
- <td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td></td>
</tr>
-<tr><td> 13.6 [over.built]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+ <td> 13.6 [over.built]</td>
+ <td class="na" align="center">N/A</td>
+ <td class="advanced" align="center"></td>
+ <td class="medium" align="center"></td>
+ <td class="broken" align="center"></td>
+ <td>Missing pointer-to-member versions (p11, p16) and support for
+ the ternary operator (p24, p25).</td>
+</tr>
<tr><td>14 [temp]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 14.1 [temp.param]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td> 14.2 [temp.names]</td><td></td><td></td><td></td><td></td><td></td></tr>
More information about the cfe-commits
mailing list