forked from OSchip/llvm-project
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
This commit is contained in:
parent
3462c8ecda
commit
d08452f60a
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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<yes&>(islong(s + l));
|
||||
(void)static_cast<no&>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -826,8 +826,8 @@ welcome!</p>
|
|||
<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 @@ welcome!</p>
|
|||
<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 @@ welcome!</p>
|
|||
</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 @@ welcome!</p>
|
|||
</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 @@ welcome!</p>
|
|||
</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>
|
||||
|
|
Loading…
Reference in New Issue