Some cleanups to the declaration/checking of overloaded operators in C++. Thanks to Sebastian for the review

llvm-svn: 58986
This commit is contained in:
Douglas Gregor 2008-11-10 13:38:07 +00:00
parent bba5c7c629
commit 6cf0806e75
6 changed files with 142 additions and 146 deletions

View File

@ -1316,15 +1316,27 @@ DIAG(err_operator_overload_static, ERROR,
DIAG(err_operator_overload_default_arg, ERROR,
"a parameter of an overloaded operator cannot have a default argument")
DIAG(err_operator_overload_must_be_unary, ERROR,
"overloaded operator '%0' must be a unary operator (has %1 parameter%2)")
"overloaded operator '%0' must be a unary operator (has %1 parameter)")
DIAG(err_operator_overload_must_be_binary, ERROR,
"overloaded operator '%0' must be a binary operator (has %1 parameter%2)")
"overloaded operator '%0' must be a binary operator (has %1 parameter)")
DIAG(err_operator_overload_must_be_unary_or_binary, ERROR,
"overloaded operator '%0' must be a unary or binary operator (has %1 parameter%2)")
"overloaded operator '%0' must be a unary or binary operator (has %1 parameter)")
DIAG(err_operator_overload_must_be_unary_plural, ERROR,
"overloaded operator '%0' must be a unary operator (has %1 parameters)")
DIAG(err_operator_overload_must_be_binary_plural, ERROR,
"overloaded operator '%0' must be a binary operator (has %1 parameters)")
DIAG(err_operator_overload_must_be_unary_or_binary_plural, ERROR,
"overloaded operator '%0' must be a unary or binary operator (has %1 parameters)")
DIAG(err_operator_overload_must_be_member, ERROR,
"overloaded operator '%0' must be a non-static member function")
DIAG(err_operator_overload_post_incdec_must_be_int, ERROR,
"%0parameter of overloaded post-%1 operator must have type 'int' (not '%2')")
DIAG(err_operator_overload_post_inc_must_be_int, ERROR,
"second parameter of overloaded post-increment operator must have type 'int' (not '%0')")
DIAG(err_operator_overload_post_dec_must_be_int, ERROR,
"second parameter of overloaded post-decrement operator must have type 'int' (not '%0')")
DIAG(err_operator_overload_post_inc_must_be_int_member, ERROR,
"parameter of overloaded post-increment operator must have type 'int' (not '%0')")
DIAG(err_operator_overload_post_dec_must_be_int_member, ERROR,
"parameter of overloaded post-decrement operator must have type 'int' (not '%0')")
DIAG(err_operator_missing_type_specifier, ERROR,
"missing type specifier after 'operator'")

View File

@ -11,58 +11,93 @@
// all of the overloadable C++ operators.
//
//===----------------------------------------------------------------------===//
//
/// @file OperatorKinds.def
///
/// In this file, each of the overloadable C++ operators is enumerated
/// with either the OVERLOADED_OPERATOR or OVERLOADED_OPERATOR_MULTI
/// macro, each of which can be specified by the code including this
/// file. OVERLOADED_OPERATOR is used for single-token operators
/// (e.g., "+"), and has six arguments:
///
/// Name: The name of the token. OO_Name will be the name of the
/// corresponding enumerator in OverloadedOperatorKind in
/// OperatorKinds.h.
///
/// Spelling: A string that provides a canonical spelling for the
/// operator, e.g., "operator+".
///
/// Token: The name of the token that specifies the operator, e.g.,
/// "plus" for operator+ or "greatergreaterequal" for
/// "operator>>=". With a "kw_" prefix, the token name can be used as
/// an enumerator into the TokenKind enumeration.
///
/// Unary: True if the operator can be declared as a unary operator.
///
/// Binary: True if the operator can be declared as a binary
/// operator. Note that some operators (e.g., "operator+" and
/// "operator*") can be both unary and binary.
///
/// MemberOnly: True if this operator can only be declared as a
/// non-static member function. False if the operator can be both a
/// non-member function and a non-static member function.
///
/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token
/// overloaded operator names, e.g., "operator delete []". The macro
/// has all of the parameters of OVERLOADED_OPERATOR except Token,
/// which is omitted.
#ifndef OVERLOADED_OPERATOR
# define OVERLOADED_OPERATOR(Name,Spelling,Token)
# define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly)
#endif
#ifndef OVERLOADED_OPERATOR_MULTI
# define OVERLOADED_OPERATOR_MULTI(Name,Spelling) \
OVERLOADED_OPERATOR(Name,Spelling,unknown)
# define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) \
OVERLOADED_OPERATOR(Name,Spelling,unknown,Unary,Binary,MemberOnly)
#endif
OVERLOADED_OPERATOR_MULTI(New , "operator new")
OVERLOADED_OPERATOR_MULTI(Delete , "operator delete")
OVERLOADED_OPERATOR_MULTI(Array_New , "operator new[]")
OVERLOADED_OPERATOR_MULTI(Array_Delete , "operator delete[]")
OVERLOADED_OPERATOR(Plus , "operator+" , plus)
OVERLOADED_OPERATOR(Minus , "operator-" , minus)
OVERLOADED_OPERATOR(Star , "operator*" , star)
OVERLOADED_OPERATOR(Slash , "operator/" , slash)
OVERLOADED_OPERATOR(Percent , "operator%" , percent)
OVERLOADED_OPERATOR(Caret , "operator^" , caret)
OVERLOADED_OPERATOR(Amp , "operator&" , amp)
OVERLOADED_OPERATOR(Pipe , "operator|" , pipe)
OVERLOADED_OPERATOR(Tilde , "operator~" , tilde)
OVERLOADED_OPERATOR(Exclaim , "operator!" , exclaim)
OVERLOADED_OPERATOR(Equal , "operator=" , equal)
OVERLOADED_OPERATOR(Less , "operator<" , less)
OVERLOADED_OPERATOR(Greater , "operator>" , greater)
OVERLOADED_OPERATOR(PlusEqual , "operator+=" , plusequal)
OVERLOADED_OPERATOR(MinusEqual , "operator-=" , minusequal)
OVERLOADED_OPERATOR(StarEqual , "operator*=" , starequal)
OVERLOADED_OPERATOR(SlashEqual , "operator/=" , slashequal)
OVERLOADED_OPERATOR(PercentEqual , "operator%=" , percentequal)
OVERLOADED_OPERATOR(CaretEqual , "operator^=" , caretequal)
OVERLOADED_OPERATOR(AmpEqual , "operator&=" , ampequal)
OVERLOADED_OPERATOR(PipeEqual , "operator|=" , pipeequal)
OVERLOADED_OPERATOR(LessLess , "operator<<" , lessless)
OVERLOADED_OPERATOR(GreaterGreater , "operator>>" , greatergreater)
OVERLOADED_OPERATOR(LessLessEqual , "operator<<=" , lesslessequal)
OVERLOADED_OPERATOR(GreaterGreaterEqual , "operator>>=" , greatergreaterequal)
OVERLOADED_OPERATOR(EqualEqual , "operator==" , equalequal)
OVERLOADED_OPERATOR(ExclaimEqual , "operator!=" , exclaimequal)
OVERLOADED_OPERATOR(LessEqual , "operator<=" , lessequal)
OVERLOADED_OPERATOR(GreaterEqual , "operator>=" , greaterequal)
OVERLOADED_OPERATOR(AmpAmp , "operator&&" , ampamp)
OVERLOADED_OPERATOR(PipePipe , "operator||" , pipepipe)
OVERLOADED_OPERATOR(PlusPlus , "operator++" , plusplus)
OVERLOADED_OPERATOR(MinusMinus , "operator--" , minusminus)
OVERLOADED_OPERATOR(Comma , "operator," , comma)
OVERLOADED_OPERATOR(ArrowStar , "operator->*" , arrowstar)
OVERLOADED_OPERATOR(Arrow , "operator->" , arrow)
OVERLOADED_OPERATOR_MULTI(Call , "operator()")
OVERLOADED_OPERATOR_MULTI(Subscript , "operator[]")
OVERLOADED_OPERATOR_MULTI(New , "operator new" , true , true , false)
OVERLOADED_OPERATOR_MULTI(Delete , "operator delete" , true , true , false)
OVERLOADED_OPERATOR_MULTI(Array_New , "operator new[]" , true , true , false)
OVERLOADED_OPERATOR_MULTI(Array_Delete , "operator delete[]" , true , true , false)
OVERLOADED_OPERATOR(Plus , "operator+" , plus , true , true , false)
OVERLOADED_OPERATOR(Minus , "operator-" , minus , true , true , false)
OVERLOADED_OPERATOR(Star , "operator*" , star , true , true , false)
OVERLOADED_OPERATOR(Slash , "operator/" , slash , false, true , false)
OVERLOADED_OPERATOR(Percent , "operator%" , percent , false, true , false)
OVERLOADED_OPERATOR(Caret , "operator^" , caret , false, true , false)
OVERLOADED_OPERATOR(Amp , "operator&" , amp , true , true , false)
OVERLOADED_OPERATOR(Pipe , "operator|" , pipe , false, true , false)
OVERLOADED_OPERATOR(Tilde , "operator~" , tilde , true , false, false)
OVERLOADED_OPERATOR(Exclaim , "operator!" , exclaim , true , false, false)
OVERLOADED_OPERATOR(Equal , "operator=" , equal , false, true , true)
OVERLOADED_OPERATOR(Less , "operator<" , less , false, true , false)
OVERLOADED_OPERATOR(Greater , "operator>" , greater , false, true , false)
OVERLOADED_OPERATOR(PlusEqual , "operator+=" , plusequal , false, true , false)
OVERLOADED_OPERATOR(MinusEqual , "operator-=" , minusequal , false, true , false)
OVERLOADED_OPERATOR(StarEqual , "operator*=" , starequal , false, true , false)
OVERLOADED_OPERATOR(SlashEqual , "operator/=" , slashequal , false, true , false)
OVERLOADED_OPERATOR(PercentEqual , "operator%=" , percentequal , false, true , false)
OVERLOADED_OPERATOR(CaretEqual , "operator^=" , caretequal , false, true , false)
OVERLOADED_OPERATOR(AmpEqual , "operator&=" , ampequal , false, true , false)
OVERLOADED_OPERATOR(PipeEqual , "operator|=" , pipeequal , false, true , false)
OVERLOADED_OPERATOR(LessLess , "operator<<" , lessless , false, true , false)
OVERLOADED_OPERATOR(GreaterGreater , "operator>>" , greatergreater , false, true , false)
OVERLOADED_OPERATOR(LessLessEqual , "operator<<=" , lesslessequal , false, true , false)
OVERLOADED_OPERATOR(GreaterGreaterEqual , "operator>>=" , greatergreaterequal, false, true , false)
OVERLOADED_OPERATOR(EqualEqual , "operator==" , equalequal , false, true , false)
OVERLOADED_OPERATOR(ExclaimEqual , "operator!=" , exclaimequal , false, true , false)
OVERLOADED_OPERATOR(LessEqual , "operator<=" , lessequal , false, true , false)
OVERLOADED_OPERATOR(GreaterEqual , "operator>=" , greaterequal , false, true , false)
OVERLOADED_OPERATOR(AmpAmp , "operator&&" , ampamp , false, true , false)
OVERLOADED_OPERATOR(PipePipe , "operator||" , pipepipe , false, true , false)
OVERLOADED_OPERATOR(PlusPlus , "operator++" , plusplus , true , true , false)
OVERLOADED_OPERATOR(MinusMinus , "operator--" , minusminus , true , true , false)
OVERLOADED_OPERATOR(Comma , "operator," , comma , false, true , false)
OVERLOADED_OPERATOR(ArrowStar , "operator->*" , arrowstar , false, true , false)
OVERLOADED_OPERATOR(Arrow , "operator->" , arrow , true , false, true)
OVERLOADED_OPERATOR_MULTI(Call , "operator()" , true , true , true)
OVERLOADED_OPERATOR_MULTI(Subscript , "operator[]" , false, true , true)
#undef OVERLOADED_OPERATOR_MULTI
#undef OVERLOADED_OPERATOR

View File

@ -20,7 +20,8 @@ namespace clang {
/// C++ overloaded operators.
enum OverloadedOperatorKind {
OO_None, //< Not an overloaded operator
#define OVERLOADED_OPERATOR(Name,Spelling,Token) OO_##Name,
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
OO_##Name,
#include "clang/Basic/OperatorKinds.def"
NUM_OVERLOADED_OPERATORS
};

View File

@ -165,7 +165,7 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
/// AddOverloadedOperators - Register the name of all C++ overloadable
/// operators ("operator+", "operator[]", etc.)
void IdentifierTable::AddOverloadedOperators() {
#define OVERLOADED_OPERATOR(Name,Spelling,Token) \
#define OVERLOADED_OPERATOR(Name,Spelling,Token, Unary, Binary, MemberOnly) \
OverloadedOperators[OO_##Name] = &get(Spelling); \
OverloadedOperators[OO_##Name]->setOverloadedOperatorID(OO_##Name);
#include "clang/Basic/OperatorKinds.def"

View File

@ -515,9 +515,9 @@ IdentifierInfo *Parser::MaybeParseOperatorFunctionId() {
}
return &PP.getIdentifierTable().getOverloadedOperator(Op);
#define OVERLOADED_OPERATOR(Name,Spelling,Token) \
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case tok::Token: Op = OO_##Name; break;
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling)
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
#include "clang/Basic/OperatorKinds.def"
case tok::l_paren:

View File

@ -1801,83 +1801,16 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
}
}
bool CanBeUnaryOperator = false;
bool CanBeBinaryOperator = false;
bool MustBeMemberOperator = false;
static const bool OperatorUses[NUM_OVERLOADED_OPERATORS][3] = {
{ false, false, false }
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
, { Unary, Binary, MemberOnly }
#include "clang/Basic/OperatorKinds.def"
};
switch (Op) {
case OO_New:
case OO_Delete:
case OO_Array_New:
case OO_Array_Delete:
assert(false && "Operators new, new[], delete, and delete[] handled above");
return true;
// Unary-only operators
case OO_Arrow:
MustBeMemberOperator = true;
// Fall through
case OO_Tilde:
case OO_Exclaim:
CanBeUnaryOperator = true;
break;
// Binary-only operators
case OO_Equal:
case OO_Subscript:
MustBeMemberOperator = true;
// Fall through
case OO_Slash:
case OO_Percent:
case OO_Caret:
case OO_Pipe:
case OO_Less:
case OO_Greater:
case OO_PlusEqual:
case OO_MinusEqual:
case OO_StarEqual:
case OO_SlashEqual:
case OO_PercentEqual:
case OO_CaretEqual:
case OO_AmpEqual:
case OO_PipeEqual:
case OO_LessLess:
case OO_GreaterGreater:
case OO_LessLessEqual:
case OO_GreaterGreaterEqual:
case OO_EqualEqual:
case OO_ExclaimEqual:
case OO_LessEqual:
case OO_GreaterEqual:
case OO_AmpAmp:
case OO_PipePipe:
case OO_Comma:
CanBeBinaryOperator = true;
break;
// Unary or binary operators
case OO_Amp:
case OO_Plus:
case OO_Minus:
case OO_Star:
case OO_PlusPlus:
case OO_MinusMinus:
case OO_ArrowStar:
CanBeUnaryOperator = true;
CanBeBinaryOperator = true;
break;
case OO_Call:
MustBeMemberOperator = true;
break;
case OO_None:
case NUM_OVERLOADED_OPERATORS:
assert(false && "Not an overloaded operator!");
return true;
}
bool CanBeUnaryOperator = OperatorUses[Op][0];
bool CanBeBinaryOperator = OperatorUses[Op][1];
bool MustBeMemberOperator = OperatorUses[Op][2];
// C++ [over.oper]p8:
// [...] Operator functions cannot have more or fewer parameters
@ -1890,23 +1823,30 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
(NumParams < 1) || (NumParams > 2))) {
// We have the wrong number of parameters.
std::string NumParamsStr = (llvm::APSInt(32) = NumParams).toString(10);
std::string NumParamsPlural;
if (NumParams != 1)
NumParamsPlural = "s";
diag::kind DK;
if (CanBeUnaryOperator && CanBeBinaryOperator)
DK = diag::err_operator_overload_must_be_unary_or_binary;
else if (CanBeUnaryOperator)
DK = diag::err_operator_overload_must_be_unary;
else if (CanBeBinaryOperator)
DK = diag::err_operator_overload_must_be_binary;
else
if (CanBeUnaryOperator && CanBeBinaryOperator) {
if (NumParams == 1)
DK = diag::err_operator_overload_must_be_unary_or_binary;
else
DK = diag::err_operator_overload_must_be_unary_or_binary;
} else if (CanBeUnaryOperator) {
if (NumParams == 1)
DK = diag::err_operator_overload_must_be_unary;
else
DK = diag::err_operator_overload_must_be_unary_plural;
} else if (CanBeBinaryOperator) {
if (NumParams == 1)
DK = diag::err_operator_overload_must_be_binary;
else
DK = diag::err_operator_overload_must_be_binary_plural;
} else {
assert(false && "All non-call overloaded operators are unary or binary!");
}
Diag(FnDecl->getLocation(), DK,
FnDecl->getName(), NumParamsStr, NumParamsPlural,
FnDecl->getName(), NumParamsStr,
SourceRange(FnDecl->getLocation()));
IsInvalid = true;
}
@ -1945,11 +1885,19 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
ParamIsInt = BT->getKind() == BuiltinType::Int;
if (!ParamIsInt) {
Diag(LastParam->getLocation(),
diag::err_operator_overload_post_incdec_must_be_int,
MethodDecl? std::string() : std::string("second "),
(Op == OO_PlusPlus)? std::string("increment")
: std::string("decrement"),
diag::kind DK;
if (Op == OO_PlusPlus) {
if (MethodDecl)
DK = diag::err_operator_overload_post_inc_must_be_int_member;
else
DK = diag::err_operator_overload_post_inc_must_be_int;
} else {
if (MethodDecl)
DK = diag::err_operator_overload_post_dec_must_be_int_member;
else
DK = diag::err_operator_overload_post_dec_must_be_int;
}
Diag(LastParam->getLocation(), DK,
Context.getCanonicalType(LastParam->getType()).getAsString(),
SourceRange(FnDecl->getLocation()));
IsInvalid = true;