From: Douglas Gregor Date: Mon, 10 Nov 2008 13:38:07 +0000 (+0000) Subject: Some cleanups to the declaration/checking of overloaded operators in C++. Thanks... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=02bcd4cd1a19121da12884aa4943226f72a81e6c;p=clang Some cleanups to the declaration/checking of overloaded operators in C++. Thanks to Sebastian for the review git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58986 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 508f15633e..59c05fc20d 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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'") diff --git a/include/clang/Basic/OperatorKinds.def b/include/clang/Basic/OperatorKinds.def index 6226172c54..bce64a7b6a 100644 --- a/include/clang/Basic/OperatorKinds.def +++ b/include/clang/Basic/OperatorKinds.def @@ -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 diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h index 3d085dba75..da4f02b6fa 100644 --- a/include/clang/Basic/OperatorKinds.h +++ b/include/clang/Basic/OperatorKinds.h @@ -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 }; diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index e17f48ad3b..2b9d7e3845 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -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" diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 2fe3bcf2db..a1fd565822 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8bdb389f1f..c10fd8b3c2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1801,83 +1801,16 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { } } - bool CanBeUnaryOperator = false; - bool CanBeBinaryOperator = false; - bool MustBeMemberOperator = false; - - 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; + 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" + }; - // 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;