From d08452f60a2731c279f3b845d84a4a8940844d99 Mon Sep 17 00:00:00 2001
From: Douglas Gregor
Date: Wed, 19 Nov 2008 15:42:04 +0000
Subject: [PATCH] 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.
llvm-svn: 59638
---
clang/Driver/PrintParserCallbacks.cpp | 6 +-
clang/include/clang/Parse/Action.h | 6 +-
clang/lib/AST/Expr.cpp | 5 +
clang/lib/Parse/ParseExpr.cpp | 10 +-
clang/lib/Parse/ParseStmt.cpp | 3 +-
clang/lib/Sema/Sema.h | 12 +-
clang/lib/Sema/SemaExpr.cpp | 219 ++++++++++++++--
clang/lib/Sema/SemaOverload.cpp | 242 +++++++++++++++---
.../SemaCXX/overloaded-builtin-operators.cpp | 40 ++-
clang/test/SemaCXX/overloaded-operator.cpp | 28 ++
clang/www/cxx_status.html | 38 +--
11 files changed, 522 insertions(+), 87 deletions(-)
diff --git a/clang/Driver/PrintParserCallbacks.cpp b/clang/Driver/PrintParserCallbacks.cpp
index 0048a6d459b1..2a85f64646fa 100644
--- a/clang/Driver/PrintParserCallbacks.cpp
+++ b/clang/Driver/PrintParserCallbacks.cpp
@@ -436,7 +436,7 @@ namespace {
}
// 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 @@ namespace {
}
// 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;
}
diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h
index 8e1a23f6e743..e9e59257dfd3 100644
--- a/clang/include/clang/Parse/Action.h
+++ b/clang/include/clang/Parse/Action.h
@@ -509,7 +509,7 @@ public:
}
// 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 @@ public:
}
// 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
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 49a4d7778380..a179af8b1450 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -398,6 +398,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
cast(this)->getOpcode() == UnaryOperator::Imag ||
cast(this)->getOpcode() == UnaryOperator::Extension)
return cast(this)->getSubExpr()->isLvalue(Ctx); // GNU.
+
+ if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1
+ (cast(this)->getOpcode() == UnaryOperator::PreInc ||
+ cast(this)->getOpcode() == UnaryOperator::PreDec))
+ return LV_Valid;
break;
case ImplicitCastExprClass:
return cast(this)->isLvalueCast()? LV_Valid
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 2b803d9ad0c7..440393dac6bf 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/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/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 49b818090486..221ad90273dd 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 29994d41c30b..c60fd352f9db 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9a77e4f8e1d5..c7803722fe9f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/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(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(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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index dbd21264f3b5..869fcc93528d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/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 };
diff --git a/clang/test/SemaCXX/overloaded-builtin-operators.cpp b/clang/test/SemaCXX/overloaded-builtin-operators.cpp
index af328da212bd..29d721c45bbf 100644
--- a/clang/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/clang/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -25,6 +25,14 @@ yes& islong(unsigned long); // FIXME: shouldn't be needed
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(islong(s + l));
(void)static_cast(islong(s + s));
@@ -46,6 +54,12 @@ struct LongRef {
};
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 @@ struct ConstIntPtr {
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 @@ void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr) {
#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;
}
+
diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp
index c540c2dafcbb..29486568185d 100644
--- a/clang/test/SemaCXX/overloaded-operator.cpp
+++ b/clang/test/SemaCXX/overloaded-operator.cpp
@@ -69,3 +69,31 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) {
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;
+}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index c8b8d57ef0cf..7c51fb387d05 100644
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -826,8 +826,8 @@ welcome!
13.3.1.2 [over.match.oper] |
✓ |
- |
- |
+ |
+ |
|
|
@@ -943,27 +943,27 @@ welcome!
|
|
|
- Most overloaded operators can only be called with function syntax, e.g., operator+(x) . |
+ Some overloaded operators can only be called with function syntax, e.g., operator[](x) . |
13.5.1 [over.unary] |
- |
+ N/A |
+ |
|
- |
|
|
13.5.2 [over.binary] |
- |
+ N/A |
+ |
|
- |
|
|
13.5.3 [over.ass] |
- |
+ N/A |
|
|
|
@@ -971,7 +971,7 @@ welcome!
13.5.4 [over.call] |
- |
+ N/A |
|
|
|
@@ -979,7 +979,7 @@ welcome!
13.5.5 [over.sub] |
- |
+ N/A |
|
|
|
@@ -987,21 +987,29 @@ welcome!
13.5.6 [over.ref] |
- |
+ N/A |
+ |
|
- |
|
|
13.5.7 [over.inc] |
- |
+ N/A |
+ |
|
- |
|
|
- 13.6 [over.built] | | | | | |
+
+ 13.6 [over.built] |
+ N/A |
+ |
+ |
+ |
+ Missing pointer-to-member versions (p11, p16) and support for
+ the ternary operator (p24, p25). |
+
14 [temp] | | | | | |
14.1 [temp.param] | | | | | |
14.2 [temp.names] | | | | | |