forked from OSchip/llvm-project
Parsing, ASTs, and semantic analysis for the declaration of overloaded
operators in C++. Overloaded operators can be called directly via their operator-function-ids, e.g., "operator+(foo, bar)", but we don't yet implement the semantics of operator overloading to handle, e.g., "foo + bar". llvm-svn: 58817
This commit is contained in:
parent
193e4c025e
commit
11d0c4c098
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_AST_DECL_H
|
||||
#define LLVM_CLANG_AST_DECL_H
|
||||
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/Parse/AccessSpecifier.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
@ -542,6 +543,14 @@ public:
|
|||
StorageClass getStorageClass() const { return StorageClass(SClass); }
|
||||
bool isInline() const { return IsInline; }
|
||||
|
||||
/// isOverloadedOperator - Whether this function declaration
|
||||
/// represents an C++ overloaded operator, e.g., "operator+".
|
||||
bool isOverloadedOperator() const {
|
||||
return getOverloadedOperator() != OO_None;
|
||||
};
|
||||
|
||||
OverloadedOperatorKind getOverloadedOperator() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
|
||||
|
|
|
@ -1288,6 +1288,28 @@ DIAG(err_duplicate_base_class, ERROR,
|
|||
DIAG(err_ambiguous_derived_to_base_conv, ERROR,
|
||||
"ambiguous conversion from derived class '%0' to base class '%1':%2")
|
||||
|
||||
// C++ operator overloading
|
||||
DIAG(err_expected_operator, ERROR,
|
||||
"expected 'operator' keyword")
|
||||
DIAG(err_operator_overload_needs_class_or_enum, ERROR,
|
||||
"non-member overloaded operator '%0' must have at least one parameter of class or enumeration type (or reference thereof)")
|
||||
DIAG(err_operator_overload_variadic, ERROR,
|
||||
"overloaded operator cannot be variadic")
|
||||
DIAG(err_operator_overload_static, ERROR,
|
||||
"overloaded operator '%0' cannot be a static member function")
|
||||
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)")
|
||||
DIAG(err_operator_overload_must_be_binary, ERROR,
|
||||
"overloaded operator '%0' must be a binary operator (has %1 parameter%2)")
|
||||
DIAG(err_operator_overload_must_be_unary_or_binary, ERROR,
|
||||
"overloaded operator '%0' must be a unary or binary operator (has %1 parameter%2)")
|
||||
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(warn_not_compound_assign, WARNING,
|
||||
"use of unary operator that may be intended as compound assignment (%0=)")
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
|
||||
#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
|
||||
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
@ -49,11 +50,12 @@ class IdentifierInfo {
|
|||
// First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values
|
||||
// are for builtins.
|
||||
unsigned ObjCOrBuiltinID :10;
|
||||
unsigned OperatorID : 6; // C++ overloaded operator.
|
||||
bool HasMacro : 1; // True if there is a #define for this.
|
||||
bool IsExtension : 1; // True if identifier is a lang extension.
|
||||
bool IsPoisoned : 1; // True if identifier is poisoned.
|
||||
bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
|
||||
// 10 bits left in 32-bit word.
|
||||
// 4 bits left in 32-bit word.
|
||||
void *FETokenInfo; // Managed by the language front-end.
|
||||
IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE.
|
||||
void operator=(const IdentifierInfo&); // NONASSIGNABLE.
|
||||
|
@ -120,6 +122,16 @@ public:
|
|||
&& "ID too large for field!");
|
||||
}
|
||||
|
||||
/// getOverloadedOperatorID - Get the C++ overloaded operator that
|
||||
/// corresponds to this identifier.
|
||||
OverloadedOperatorKind getOverloadedOperatorID() const {
|
||||
return OverloadedOperatorKind(OperatorID);
|
||||
}
|
||||
void setOverloadedOperatorID(OverloadedOperatorKind ID) {
|
||||
OperatorID = ID;
|
||||
assert(OperatorID == (unsigned)ID && "ID too large for field!");
|
||||
}
|
||||
|
||||
/// get/setExtension - Initialize information about whether or not this
|
||||
/// language token is an extension. This controls extension warnings, and is
|
||||
/// only valid if a custom token ID is set.
|
||||
|
@ -161,6 +173,11 @@ class IdentifierTable {
|
|||
// BumpPtrAllocator!
|
||||
typedef llvm::StringMap<IdentifierInfo, llvm::BumpPtrAllocator> HashTableTy;
|
||||
HashTableTy HashTable;
|
||||
|
||||
/// OverloadedOperators - Identifiers corresponding to each of the
|
||||
/// overloadable operators in C++.
|
||||
IdentifierInfo *OverloadedOperators[NUM_OVERLOADED_OPERATORS];
|
||||
|
||||
public:
|
||||
/// IdentifierTable ctor - Create the identifier table, populating it with
|
||||
/// info about the language keywords for the language specified by LangOpts.
|
||||
|
@ -180,7 +197,12 @@ public:
|
|||
const char *NameBytes = &Name[0];
|
||||
return get(NameBytes, NameBytes+Name.size());
|
||||
}
|
||||
|
||||
|
||||
/// getOverloadedOperator - Retrieve the identifier
|
||||
IdentifierInfo &getOverloadedOperator(OverloadedOperatorKind Op) {
|
||||
return *OverloadedOperators[Op];
|
||||
}
|
||||
|
||||
typedef HashTableTy::const_iterator iterator;
|
||||
typedef HashTableTy::const_iterator const_iterator;
|
||||
|
||||
|
@ -194,6 +216,7 @@ public:
|
|||
void PrintStats() const;
|
||||
|
||||
void AddKeywords(const LangOptions &LangOpts);
|
||||
void AddOverloadedOperators();
|
||||
|
||||
/// Emit - Serialize this IdentifierTable to a bitstream. This should
|
||||
/// be called AFTER objects that externally reference the identifiers in the
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
//===--- OperatorKinds.def - C++ Overloaded Operator Database ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the OverloadedOperator database, which includes
|
||||
// all of the overloadable C++ operators.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef OVERLOADED_OPERATOR
|
||||
# define OVERLOADED_OPERATOR(Name,Spelling,Token)
|
||||
#endif
|
||||
|
||||
#ifndef OVERLOADED_OPERATOR_MULTI
|
||||
# define OVERLOADED_OPERATOR_MULTI(Name,Spelling) \
|
||||
OVERLOADED_OPERATOR(Name,Spelling,unknown)
|
||||
#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[]")
|
||||
|
||||
#undef OVERLOADED_OPERATOR_MULTI
|
||||
#undef OVERLOADED_OPERATOR
|
|
@ -0,0 +1,31 @@
|
|||
//===--- OperatorKinds.h - C++ Overloaded Operators -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines C++ overloaded operators.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_OPERATOR_KINDS_H
|
||||
#define LLVM_CLANG_BASIC_OPERATOR_KINDS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// OverloadedOperatorKind - Enumeration specifying the different kinds of
|
||||
/// C++ overloaded operators.
|
||||
enum OverloadedOperatorKind {
|
||||
OO_None, //< Not an overloaded operator
|
||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token) OO_##Name,
|
||||
#include "clang/Basic/OperatorKinds.def"
|
||||
NUM_OVERLOADED_OPERATORS
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines interfaces used for Declaration Specifiers and Declarators.
|
||||
// This file defines interfaces used for C++ access specifiers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
|
|
@ -728,6 +728,10 @@ private:
|
|||
void ParseBaseClause(DeclTy *ClassDecl);
|
||||
BaseResult ParseBaseSpecifier(DeclTy *ClassDecl);
|
||||
AccessSpecifier getAccessSpecifierIfPresent() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 13.5: Overloaded operators [over.oper]
|
||||
IdentifierInfo *MaybeParseOperatorFunctionId();
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -210,6 +210,15 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
|
|||
return NumRequiredArgs;
|
||||
}
|
||||
|
||||
/// getOverloadedOperator - Which C++ overloaded operator this
|
||||
/// function represents, if any.
|
||||
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
|
||||
if (getIdentifier())
|
||||
return getIdentifier()->getOverloadedOperatorID();
|
||||
else
|
||||
return OO_None;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TagdDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -28,6 +28,7 @@ using namespace clang;
|
|||
IdentifierInfo::IdentifierInfo() {
|
||||
TokenID = tok::identifier;
|
||||
ObjCOrBuiltinID = 0;
|
||||
OperatorID = 0;
|
||||
HasMacro = false;
|
||||
IsExtension = false;
|
||||
IsPoisoned = false;
|
||||
|
@ -46,6 +47,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts)
|
|||
// Populate the identifier table with info about keywords for the current
|
||||
// language.
|
||||
AddKeywords(LangOpts);
|
||||
AddOverloadedOperators();
|
||||
}
|
||||
|
||||
// This cstor is intended to be used only for serialization.
|
||||
|
@ -160,6 +162,15 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
|
|||
#include "clang/Basic/TokenKinds.def"
|
||||
}
|
||||
|
||||
/// AddOverloadedOperators - Register the name of all C++ overloadable
|
||||
/// operators ("operator+", "operator[]", etc.)
|
||||
void IdentifierTable::AddOverloadedOperators() {
|
||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token) \
|
||||
OverloadedOperators[OO_##Name] = &get(Spelling); \
|
||||
OverloadedOperators[OO_##Name]->setOverloadedOperatorID(OO_##Name);
|
||||
#include "clang/Basic/OperatorKinds.def"
|
||||
}
|
||||
|
||||
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
|
||||
// We use a perfect hash function here involving the length of the keyword,
|
||||
// the first and third character. For preprocessor ID's there are no
|
||||
|
|
|
@ -1305,6 +1305,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
|
||||
if (TypeTy *Type = ParseClassName())
|
||||
D.SetDestructor(Type, II, TildeLoc);
|
||||
} else if (Tok.is(tok::kw_operator)) {
|
||||
SourceLocation OperatorLoc = Tok.getLocation();
|
||||
|
||||
// First try the name of an overloaded operator
|
||||
if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
|
||||
D.SetIdentifier(II, OperatorLoc);
|
||||
} else {
|
||||
// This must be a user-defined conversion.
|
||||
}
|
||||
} else if (Tok.is(tok::l_paren)) {
|
||||
// direct-declarator: '(' declarator ')'
|
||||
// direct-declarator: '(' attributes declarator ')'
|
||||
|
|
|
@ -356,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
|
|||
/// [GNU] '__extension__' '__real' '__imag'
|
||||
///
|
||||
/// primary-expression: [C99 6.5.1]
|
||||
/// identifier
|
||||
/// [C99] identifier
|
||||
// [C++] id-expression
|
||||
/// constant
|
||||
/// string-literal
|
||||
/// [C++] boolean-literal [C++ 2.13.5]
|
||||
|
@ -390,6 +391,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
|
|||
/// enumeration-constant -> identifier
|
||||
/// character-constant
|
||||
///
|
||||
/// id-expression: [C++ 5.1]
|
||||
/// unqualified-id
|
||||
/// qualified-id [TODO]
|
||||
///
|
||||
/// unqualified-id: [C++ 5.1]
|
||||
/// identifier
|
||||
/// operator-function-id
|
||||
/// conversion-function-id [TODO]
|
||||
/// '~' class-name [TODO]
|
||||
/// template-id [TODO]
|
||||
Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
|
||||
ExprResult Res;
|
||||
tok::TokenKind SavedKind = Tok.getKind();
|
||||
|
@ -461,6 +472,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
|
|||
}
|
||||
|
||||
// primary-expression: identifier
|
||||
// unqualified-id: identifier
|
||||
// constant: enumeration-constant
|
||||
|
||||
// Consume the identifier so that we can see if it is followed by a '('.
|
||||
|
@ -589,6 +601,17 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
|
|||
return ParsePostfixExpressionSuffix(Res);
|
||||
}
|
||||
|
||||
case tok::kw_operator: {
|
||||
SourceLocation OperatorLoc = Tok.getLocation();
|
||||
if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
|
||||
Res = Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II,
|
||||
Tok.is(tok::l_paren));
|
||||
// These can be followed by postfix-expr pieces.
|
||||
return ParsePostfixExpressionSuffix(Res);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case tok::at: {
|
||||
SourceLocation AtLoc = ConsumeToken();
|
||||
return ParseObjCAtExpression(AtLoc);
|
||||
|
|
|
@ -291,3 +291,78 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
|
|||
ConsumeToken();
|
||||
DS.Finish(Diags, PP.getSourceManager(), getLang());
|
||||
}
|
||||
|
||||
/// MaybeParseOperatorFunctionId - Attempts to parse a C++ overloaded
|
||||
/// operator name (C++ [over.oper]). If successful, returns the
|
||||
/// predefined identifier that corresponds to that overloaded
|
||||
/// operator. Otherwise, returns NULL and does not consume any tokens.
|
||||
///
|
||||
/// operator-function-id: [C++ 13.5]
|
||||
/// 'operator' operator
|
||||
///
|
||||
/// operator: one of
|
||||
/// new delete new[] delete[]
|
||||
/// + - * / % ^ & | ~
|
||||
/// ! = < > += -= *= /= %=
|
||||
/// ^= &= |= << >> >>= <<= == !=
|
||||
/// <= >= && || ++ -- , ->* ->
|
||||
/// () []
|
||||
IdentifierInfo *Parser::MaybeParseOperatorFunctionId() {
|
||||
if (Tok.isNot(tok::kw_operator))
|
||||
return 0;
|
||||
|
||||
OverloadedOperatorKind Op = OO_None;
|
||||
switch (NextToken().getKind()) {
|
||||
case tok::kw_new:
|
||||
ConsumeToken(); // 'operator'
|
||||
ConsumeToken(); // 'new'
|
||||
if (Tok.is(tok::l_square)) {
|
||||
ConsumeBracket(); // '['
|
||||
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
|
||||
Op = OO_Array_New;
|
||||
} else {
|
||||
Op = OO_New;
|
||||
}
|
||||
return &PP.getIdentifierTable().getOverloadedOperator(Op);
|
||||
|
||||
case tok::kw_delete:
|
||||
ConsumeToken(); // 'operator'
|
||||
ConsumeToken(); // 'delete'
|
||||
if (Tok.is(tok::l_square)) {
|
||||
ConsumeBracket(); // '['
|
||||
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
|
||||
Op = OO_Array_Delete;
|
||||
} else {
|
||||
Op = OO_Delete;
|
||||
}
|
||||
return &PP.getIdentifierTable().getOverloadedOperator(Op);
|
||||
|
||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token) \
|
||||
case tok::Token: Op = OO_##Name; break;
|
||||
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling)
|
||||
#include "clang/Basic/OperatorKinds.def"
|
||||
|
||||
case tok::l_paren:
|
||||
ConsumeToken(); // 'operator'
|
||||
ConsumeParen(); // '('
|
||||
ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
|
||||
return &PP.getIdentifierTable().getOverloadedOperator(OO_Call);
|
||||
|
||||
case tok::l_square:
|
||||
ConsumeToken(); // 'operator'
|
||||
ConsumeBracket(); // '['
|
||||
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
|
||||
return &PP.getIdentifierTable().getOverloadedOperator(OO_Subscript);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (Op == OO_None)
|
||||
return 0;
|
||||
else {
|
||||
ExpectAndConsume(tok::kw_operator, diag::err_expected_operator);
|
||||
ConsumeAnyToken(); // the operator itself
|
||||
return &PP.getIdentifierTable().getOverloadedOperator(Op);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -863,6 +863,12 @@ public:
|
|||
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
|
||||
SourceLocation Loc, SourceRange Range);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Overloaded Operators [C++ 13.5]
|
||||
//
|
||||
|
||||
bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl);
|
||||
|
||||
// Objective-C declarations.
|
||||
virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
|
|
|
@ -932,6 +932,11 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
|||
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
|
||||
return ActOnDestructorDeclarator(Destructor);
|
||||
|
||||
// Extra checking for C++ overloaded operators (C++ [over.oper]).
|
||||
if (NewFD->isOverloadedOperator() &&
|
||||
CheckOverloadedOperatorDeclaration(NewFD))
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
// Merge the decl with the existing one if appropriate. Since C functions
|
||||
// are in a flat namespace, make sure we consider decls in outer scopes.
|
||||
if (PrevDecl &&
|
||||
|
|
|
@ -1576,3 +1576,242 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
|
|||
return PerformImplicitConversion(Init, T1);
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckOverloadedOperatorDeclaration - Check whether the declaration
|
||||
/// of this overloaded operator is well-formed. If so, returns false;
|
||||
/// otherwise, emits appropriate diagnostics and returns true.
|
||||
bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
|
||||
assert(FnDecl && FnDecl->getOverloadedOperator() != OO_None &&
|
||||
"Expected an overloaded operator declaration");
|
||||
|
||||
bool IsInvalid = false;
|
||||
|
||||
OverloadedOperatorKind Op = FnDecl->getOverloadedOperator();
|
||||
|
||||
// C++ [over.oper]p5:
|
||||
// The allocation and deallocation functions, operator new,
|
||||
// operator new[], operator delete and operator delete[], are
|
||||
// described completely in 3.7.3. The attributes and restrictions
|
||||
// found in the rest of this subclause do not apply to them unless
|
||||
// explicitly stated in 3.7.3.
|
||||
// FIXME: Write a separate routine for checking this. For now, just
|
||||
// allow it.
|
||||
if (Op == OO_New || Op == OO_Array_New ||
|
||||
Op == OO_Delete || Op == OO_Array_Delete)
|
||||
return false;
|
||||
|
||||
// C++ [over.oper]p6:
|
||||
// An operator function shall either be a non-static member
|
||||
// function or be a non-member function and have at least one
|
||||
// parameter whose type is a class, a reference to a class, an
|
||||
// enumeration, or a reference to an enumeration.
|
||||
CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl);
|
||||
if (MethodDecl) {
|
||||
if (MethodDecl->isStatic()) {
|
||||
Diag(FnDecl->getLocation(),
|
||||
diag::err_operator_overload_static,
|
||||
FnDecl->getName(),
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
|
||||
// Pretend this isn't a member function; it'll supress
|
||||
// additional, unnecessary error messages.
|
||||
MethodDecl = 0;
|
||||
}
|
||||
} else {
|
||||
bool ClassOrEnumParam = false;
|
||||
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
|
||||
Param != FnDecl->param_end(); ++Param) {
|
||||
QualType ParamType = (*Param)->getType();
|
||||
if (const ReferenceType *RefType = ParamType->getAsReferenceType())
|
||||
ParamType = RefType->getPointeeType();
|
||||
if (ParamType->isRecordType() || ParamType->isEnumeralType()) {
|
||||
ClassOrEnumParam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ClassOrEnumParam) {
|
||||
Diag(FnDecl->getLocation(),
|
||||
diag::err_operator_overload_needs_class_or_enum,
|
||||
FnDecl->getName(),
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [over.oper]p8:
|
||||
// An operator function cannot have default arguments (8.3.6),
|
||||
// except where explicitly stated below.
|
||||
//
|
||||
// Only the function-call operator allows default arguments
|
||||
// (C++ [over.call]p1).
|
||||
if (Op != OO_Call) {
|
||||
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
|
||||
Param != FnDecl->param_end(); ++Param) {
|
||||
if (Expr *DefArg = (*Param)->getDefaultArg()) {
|
||||
Diag((*Param)->getLocation(),
|
||||
diag::err_operator_overload_default_arg,
|
||||
DefArg->getSourceRange());
|
||||
IsInvalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// C++ [over.oper]p8:
|
||||
// [...] Operator functions cannot have more or fewer parameters
|
||||
// than the number required for the corresponding operator, as
|
||||
// described in the rest of this subclause.
|
||||
unsigned NumParams = FnDecl->getNumParams() + (MethodDecl? 1 : 0);
|
||||
if (Op != OO_Call &&
|
||||
((NumParams == 1 && !CanBeUnaryOperator) ||
|
||||
(NumParams == 2 && !CanBeBinaryOperator) ||
|
||||
(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
|
||||
assert(false && "All non-call overloaded operators are unary or binary!");
|
||||
|
||||
Diag(FnDecl->getLocation(), DK,
|
||||
FnDecl->getName(), NumParamsStr, NumParamsPlural,
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
}
|
||||
|
||||
// Overloaded operators cannot be variadic.
|
||||
if (FnDecl->getType()->getAsFunctionTypeProto()->isVariadic()) {
|
||||
Diag(FnDecl->getLocation(),
|
||||
diag::err_operator_overload_variadic,
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
}
|
||||
|
||||
// Some operators must be non-static member functions.
|
||||
if (MustBeMemberOperator && !MethodDecl) {
|
||||
Diag(FnDecl->getLocation(),
|
||||
diag::err_operator_overload_must_be_member,
|
||||
FnDecl->getName(),
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
}
|
||||
|
||||
// C++ [over.inc]p1:
|
||||
// The user-defined function called operator++ implements the
|
||||
// prefix and postfix ++ operator. If this function is a member
|
||||
// function with no parameters, or a non-member function with one
|
||||
// parameter of class or enumeration type, it defines the prefix
|
||||
// increment operator ++ for objects of that type. 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.
|
||||
if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) {
|
||||
ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1);
|
||||
bool ParamIsInt = false;
|
||||
if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType())
|
||||
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"),
|
||||
Context.getCanonicalType(LastParam->getType()).getAsString(),
|
||||
SourceRange(FnDecl->getLocation()));
|
||||
IsInvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return IsInvalid;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
struct X {
|
||||
X();
|
||||
X(int);
|
||||
};
|
||||
|
||||
X operator+(X, X);
|
||||
X operator-(X, X) { X x; return x; }
|
||||
|
||||
struct Y {
|
||||
Y operator-() const;
|
||||
void operator()(int x = 17) const;
|
||||
int operator[](int);
|
||||
|
||||
static int operator+(Y, Y); // expected-error{{overloaded operator 'operator+' cannot be a static member function}}
|
||||
};
|
||||
|
||||
|
||||
void f(X x) {
|
||||
x = operator+(x, x);
|
||||
}
|
||||
|
||||
X operator+(int, float); // expected-error{{non-member overloaded operator 'operator+' must have at least one parameter of class or enumeration type (or reference thereof)}}
|
||||
|
||||
X operator*(X, X = 5); // expected-error{{a parameter of an overloaded operator cannot have a default argument}}
|
||||
|
||||
X operator/(X, X, ...); // expected-error{{overloaded operator cannot be variadic}}
|
||||
|
||||
X operator%(Y); // expected-error{{overloaded operator 'operator%' must be a binary operator (has 1 parameter)}}
|
||||
|
||||
void operator()(Y&, int, int); // expected-error{{overloaded operator 'operator()' must be a non-static member function}}
|
||||
|
||||
typedef int INT;
|
||||
typedef float FLOAT;
|
||||
Y& operator++(Y&);
|
||||
Y operator++(Y&, INT);
|
||||
X operator++(X&, FLOAT); // expected-error{{second parameter of overloaded post-increment operator must have type 'int' (not 'float')}}
|
|
@ -810,14 +810,70 @@ welcome!</p>
|
|||
<td></td>
|
||||
</tr>
|
||||
<tr><td> 13.4 [over.over]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5 [over.oper]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.1 [over.unary]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.2 [over.binary]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.3 [over.ass]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.4 [over.call]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.5 [over.sub]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.6 [over.ref]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> 13.5.7 [over.inc]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr>
|
||||
<td> 13.5 [over.oper]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td>Overloaded operators can only be called with function syntax, e.g., <code>operator+(x, y)</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.1 [over.unary]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.2 [over.binary]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.3 [over.ass]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.4 [over.call]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.5 [over.sub]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.6 [over.ref]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 13.5.7 [over.inc]</td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#347C17" align="center"></td>
|
||||
<td bgcolor="#FDD017" align="center"></td>
|
||||
<td bgcolor="#C11B17" 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>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>
|
||||
|
|
Loading…
Reference in New Issue