Extend DeclarationName to support C++ overloaded operators, e.g.,

operator+, directly, using the same mechanism as all other special
names.

Removed the "special" identifiers for the overloaded operators from
the identifier table and IdentifierInfo data structure. IdentifierInfo
is back to representing only real identifiers.

Added a new Action, ActOnOperatorFunctionIdExpr, that builds an
expression from an parsed operator-function-id (e.g., "operator
+"). ActOnIdentifierExpr used to do this job, but
operator-function-ids are no longer represented by IdentifierInfo's.

Extended Declarator to store overloaded operator names. 
Sema::GetNameForDeclarator now knows how to turn the operator
name into a DeclarationName for the overloaded operator. 

Except for (perhaps) consolidating the functionality of
ActOnIdentifier, ActOnOperatorFunctionIdExpr, and
ActOnConversionFunctionExpr into a common routine that builds an
appropriate DeclRefExpr by looking up a DeclarationName, all of the
work on normalizing declaration names should be complete with this
commit.

llvm-svn: 59526
This commit is contained in:
Douglas Gregor 2008-11-18 14:39:36 +00:00
parent 383ccc1e75
commit 163c58502a
18 changed files with 260 additions and 105 deletions

View File

@ -469,7 +469,7 @@ malloc'd objects are at least 8 byte aligned.</p>
<p>Given
a <code>DeclarationName</code> <code>N</code>, <code>N.getNameKind()</code>
will produce a value that describes what kind of name <code>N</code>
stores. There are 7 options (all of the names are inside
stores. There are 8 options (all of the names are inside
the <code>DeclarationName</code> class)</p>
<dl>
<dt>Identifier</dt>
@ -514,11 +514,19 @@ malloc'd objects are at least 8 byte aligned.</p>
const *</code>". Use <code>N.getCXXNameType()</code> to retrieve
the type that this conversion function converts to. This type is
always a canonical type.</dd>
<dt>CXXOperatorName</dt>
<dd>The name is a C++ overloaded operator name. Overloaded operators
are named according to their spelling, e.g.,
"<code>operator+</code>" or "<code>operator new
[]</code>". Use <code>N.getCXXOverloadedOperator()</code> to
retrieve the overloaded operator (a value of
type <code>OverloadedOperatorKind</code>).</dd>
</dl>
<p><code>DeclarationName</code>s are cheap to create, copy, and
compare. They require only a single pointer's worth of storage in
the common cases (identifiers, C++ overloaded operator names, zero-
the common cases (identifiers, zero-
and one-argument Objective-C selectors) and use dense, uniqued
storage for the other kinds of
names. Two <code>DeclarationName</code>s can be compared for
@ -532,16 +540,15 @@ malloc'd objects are at least 8 byte aligned.</p>
<p><code>DeclarationName</code> instances can be created in different
ways depending on what kind of name the instance will store. Normal
identifiers (<code>IdentifierInfo</code> pointers), including
overloaded operator names, and Objective-C selectors
identifiers (<code>IdentifierInfo</code> pointers) and Objective-C selectors
(<code>Selector</code>) can be implicitly converted
to <code>DeclarationName</code>s. Names for C++ constructors,
destructors, and conversion functions can be retrieved from
destructors, conversion functions, and overloaded operators can be retrieved from
the <code>DeclarationNameTable</code>, an instance of which is
available as <code>ASTContext::DeclarationNames</code>. The member
functions <code>getCXXConstructorName</code>, <code>getCXXDestructorName</code>,
and <code>getCXXConversionFunctionName</code>, respectively,
return <code>DeclarationName</code> instances for the three kinds of
<code>getCXXConversionFunctionName</code>, and <code>getCXXOperatorName</code>, respectively,
return <code>DeclarationName</code> instances for the four kinds of
C++ special function names.</p>
<!-- ======================================================================= -->

View File

@ -23,6 +23,7 @@ namespace llvm {
namespace clang {
class CXXSpecialName; // a private class used by DeclarationName
class CXXOperatorIdName; // a private class used by DeclarationName
class DeclarationNameExtra; // a private class used by DeclarationName
class IdentifierInfo;
class MultiKeywordSelector; // a private class used by Selector and DeclarationName
@ -43,7 +44,8 @@ public:
ObjCMultiArgSelector,
CXXConstructorName,
CXXDestructorName,
CXXConversionFunctionName
CXXConversionFunctionName,
CXXOperatorName
};
private:
@ -53,7 +55,7 @@ private:
StoredIdentifier = 0,
StoredObjCZeroArgSelector,
StoredObjCOneArgSelector,
StoredObjCMultiArgSelectorOrCXXName,
StoredDeclarationNameExtra,
PtrMask = 0x03
};
@ -62,22 +64,21 @@ private:
/// on the kind of name this is, the upper bits of Ptr may have one
/// of several different meanings:
///
/// Identifier - The name is a normal identifier, and Ptr is a
/// normal IdentifierInfo pointer.
/// StoredIdentifier - The name is a normal identifier, and Ptr is
/// a normal IdentifierInfo pointer.
///
/// ObjCZeroArgSelector - The name is an Objective-C selector with
/// zero arguments, and Ptr is an IdentifierInfo pointer pointing
/// to the selector name.
/// StoredObjCZeroArgSelector - The name is an Objective-C
/// selector with zero arguments, and Ptr is an IdentifierInfo
/// pointer pointing to the selector name.
///
/// ObjCOneArgSelector - The name is an Objective-C selector with
/// one argument, and Ptr is an IdentifierInfo pointer pointing to
/// the selector name.
/// StoredObjCOneArgSelector - The name is an Objective-C selector
/// with one argument, and Ptr is an IdentifierInfo pointer
/// pointing to the selector name.
///
/// ObjCMultiArgSelectorOrCXXName - This is either an Objective-C
/// selector with two or more arguments or it is a C++ name. Ptr
/// is actually a DeclarationNameExtra structure, whose first
/// value will tell us whether this is an Objective-C selector or
/// special C++ name.
/// StoredDeclarationNameExtra - Ptr is actually a pointer to a
/// DeclarationNameExtra structure, whose first value will tell us
/// whether this is an Objective-C selector, C++ operator-id name,
/// or special C++ name.
uintptr_t Ptr;
/// getStoredNameKind - Return the kind of object that is stored in
@ -89,7 +90,7 @@ private:
/// getExtra - Get the "extra" information associated with this
/// multi-argument selector or C++ special name.
DeclarationNameExtra *getExtra() const {
assert(getStoredNameKind() == StoredObjCMultiArgSelectorOrCXXName &&
assert(getStoredNameKind() == StoredDeclarationNameExtra &&
"Declaration name does not store an Extra structure");
return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask);
}
@ -105,12 +106,28 @@ private:
return 0;
}
/// getAsCXXOperatorIdName
CXXOperatorIdName *getAsCXXOperatorIdName() const {
if (getNameKind() == CXXOperatorName)
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
else
return 0;
}
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
DeclarationName(CXXSpecialName *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
Ptr |= StoredObjCMultiArgSelectorOrCXXName;
Ptr |= StoredDeclarationNameExtra;
}
// Construct a declaration name from the name of a C++ overloaded
// operator.
DeclarationName(CXXOperatorIdName *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
Ptr |= StoredDeclarationNameExtra;
}
// Construct a declaration name from a zero- or one-argument
@ -130,7 +147,7 @@ private:
DeclarationName(MultiKeywordSelector *SI)
: Ptr(reinterpret_cast<uintptr_t>(SI)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector");
Ptr |= StoredObjCMultiArgSelectorOrCXXName;
Ptr |= StoredDeclarationNameExtra;
}
/// Construct a declaration name from a raw pointer.
@ -186,6 +203,11 @@ public:
/// type associated with that name.
QualType getCXXNameType() const;
/// getCXXOverloadedOperator - If this name is the name of an
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
/// kind of overloaded operator.
OverloadedOperatorKind getCXXOverloadedOperator() const;
/// getObjCSelector - Get the Objective-C selector stored in this
/// declaration name.
Selector getObjCSelector() const;
@ -248,6 +270,7 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
/// getCXXConstructorName).
class DeclarationNameTable {
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
@ -285,6 +308,10 @@ public:
/// function.
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
QualType Ty);
/// getCXXOperatorName - Get the name of the overloadable C++
/// operator corresponding to Op.
DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
};
} // end namespace clang

View File

@ -51,12 +51,11 @@ 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.
// 4 bits left in 32-bit word.
// 10 bits left in 32-bit word.
void *FETokenInfo; // Managed by the language front-end.
IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE.
void operator=(const IdentifierInfo&); // NONASSIGNABLE.
@ -123,16 +122,6 @@ 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.
@ -175,10 +164,6 @@ class IdentifierTable {
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.
@ -199,11 +184,6 @@ public:
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;
@ -217,7 +197,6 @@ 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
@ -342,9 +321,9 @@ public:
static SelectorTable* CreateAndRegister(llvm::Deserializer& D);
};
/// DeclarationNameExtra - Common base of the MultiKeywordSelector and
/// CXXSpecialName classes, both of which are private classes that can
/// be stored by the AST's DeclarationName class.
/// DeclarationNameExtra - Common base of the MultiKeywordSelector,
/// CXXSpecialName, and CXXOperatorIdName classes, all of which are
/// private classes that describe different kinds of names.
class DeclarationNameExtra {
public:
/// ExtraKind - The kind of "extra" information stored in the
@ -354,12 +333,17 @@ public:
CXXConstructor = 0,
CXXDestructor,
CXXConversionFunction,
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
CXXOperator##Name,
#include "clang/Basic/OperatorKinds.def"
NUM_EXTRA_KINDS
};
/// ExtraKindOrNumArgs - Either the kind of C++ special name (if the
/// value is one of the CXX* enumerators of ExtraKind), in which
/// case the DeclarationNameExtra is also a CXXSpecialName, or
/// ExtraKindOrNumArgs - Either the kind of C++ special name or
/// operator-id (if the value is one of the CXX* enumerators of
/// ExtraKind), in which case the DeclarationNameExtra is also a
/// CXXSpecialName (for CXXConstructor, CXXDestructor, or
/// CXXConversionFunction) or CXXOperatorIdName, otherwise it is
/// NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of
/// arguments in the Objective-C selector, in which case the
/// DeclarationNameExtra is also a MultiKeywordSelector.

View File

@ -464,8 +464,21 @@ public:
return 0;
}
/// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator
/// name (e.g., @c operator+ ) as an expression. This is very
/// similar to ActOnIdentifierExpr, except that instead of providing
/// an identifier the parser provides the kind of overloaded
/// operator that was parsed.
virtual ExprResult ActOnOperatorFunctionIdExpr(Scope *S,
SourceLocation OperatorLoc,
OverloadedOperatorKind Op,
bool HasTrailingLParen,
const CXXScopeSpec *SS = 0) {
return 0;
}
/// ActOnConversionFunctionExpr - Parse a C++ conversion function
/// name (e.g., operator void const *) as an expression. This is
/// name (e.g., @c operator void const *) as an expression. This is
/// very similar to ActOnIdentifierExpr, except that instead of
/// providing an identifier the parser provides the type of the
/// conversion function.

View File

@ -647,6 +647,7 @@ public:
DK_Normal, // A normal declarator (has an identifier).
DK_Constructor, // A C++ constructor (identifier is the class name)
DK_Destructor, // A C++ destructor (identifier is ~class name)
DK_Operator, // A C++ overloaded operator name
DK_Conversion // A C++ conversion function (identifier is
// "operator " then the type name)
};
@ -677,11 +678,17 @@ private:
/// AsmLabel - The asm label, if specified.
Action::ExprTy *AsmLabel;
union {
// When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the
// type associated with the constructor, destructor, or conversion
// operator.
Action::TypeTy *Type;
/// When Kind is DK_Operator, this is the actual overloaded
/// operator that this declarator names.
OverloadedOperatorKind OperatorKind;
};
public:
Declarator(const DeclSpec &ds, TheContext C)
: DS(ds), Identifier(0), Context(C), Kind(DK_Abstract), InvalidType(false),
@ -802,7 +809,7 @@ public:
}
// setConversionFunction - Set this declarator to be a C++
// conversion function declarator.
// conversion function declarator (e.g., @c operator int const *).
void setConversionFunction(Action::TypeTy *Ty, SourceLocation Loc) {
Identifier = 0;
IdentifierLoc = Loc;
@ -810,6 +817,14 @@ public:
Type = Ty;
}
// setOverloadedOperator - Set this declaration to be a C++
// overloaded operator declarator (e.g., @c operator+).
void setOverloadedOperator(OverloadedOperatorKind Op, SourceLocation Loc) {
IdentifierLoc = Loc;
Kind = DK_Operator;
OperatorKind = Op;
}
void AddTypeInfo(const DeclaratorChunk &TI) {
DeclTypeInfo.push_back(TI);
}
@ -859,6 +874,8 @@ public:
Action::TypeTy *getDeclaratorIdType() const { return Type; }
OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; }
void setInvalidType(bool flag) { InvalidType = flag; }
bool getInvalidType() const { return InvalidType; }

View File

@ -789,7 +789,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 13.5: Overloaded operators [over.oper]
IdentifierInfo *TryParseOperatorFunctionId();
OverloadedOperatorKind TryParseOperatorFunctionId();
TypeTy *ParseConversionFunctionId();
};

View File

@ -226,8 +226,8 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
/// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
if (getIdentifier())
return getIdentifier()->getOverloadedOperatorID();
if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
return getDeclName().getCXXOverloadedOperator();
else
return OO_None;
}

View File

@ -147,6 +147,10 @@ void NamedDecl::EmitInRec(Serializer& S) const {
case DeclarationName::CXXConversionFunctionName:
Name.getCXXNameType().Emit(S);
break;
case DeclarationName::CXXOperatorName:
S.EmitInt(Name.getCXXOverloadedOperator());
break;
}
}
@ -178,8 +182,16 @@ void NamedDecl::ReadInRec(Deserializer& D, ASTContext& C) {
break;
case DeclarationName::CXXConversionFunctionName:
Name = C.DeclarationNames.getCXXConversionFunctionName(QualType::ReadVal(D));
Name
= C.DeclarationNames.getCXXConversionFunctionName(QualType::ReadVal(D));
break;
case DeclarationName::CXXOperatorName: {
OverloadedOperatorKind Op
= static_cast<OverloadedOperatorKind>(D.ReadInt());
Name = C.DeclarationNames.getCXXOperatorName(Op);
break;
}
}
}

View File

@ -40,6 +40,15 @@ public:
}
};
/// CXXOperatorIdName - Contains extra information for the name of an
/// overloaded operator in C++, such as "operator+.
class CXXOperatorIdName : public DeclarationNameExtra {
public:
/// FETokenInfo - Extra information associated with this operator
/// name that can be used by the front end.
void *FETokenInfo;
};
bool operator<(DeclarationName LHS, DeclarationName RHS) {
if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo())
if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo())
@ -64,7 +73,7 @@ DeclarationName::DeclarationName(Selector Sel) {
default:
Ptr = Sel.InfoPtr & ~Selector::ArgFlags;
Ptr |= StoredObjCMultiArgSelectorOrCXXName;
Ptr |= StoredDeclarationNameExtra;
break;
}
}
@ -75,7 +84,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
case StoredObjCZeroArgSelector: return ObjCZeroArgSelector;
case StoredObjCOneArgSelector: return ObjCOneArgSelector;
case StoredObjCMultiArgSelectorOrCXXName:
case StoredDeclarationNameExtra:
switch (getExtra()->ExtraKindOrNumArgs) {
case DeclarationNameExtra::CXXConstructor:
return CXXConstructorName;
@ -87,6 +96,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
return CXXConversionFunctionName;
default:
// Check if we have one of the CXXOperator* enumeration values.
if (getExtra()->ExtraKindOrNumArgs <
DeclarationNameExtra::NUM_EXTRA_KINDS)
return CXXOperatorName;
return ObjCMultiArgSelector;
}
break;
@ -125,6 +139,23 @@ std::string DeclarationName::getAsString() const {
return Result;
}
case CXXOperatorName: {
static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = {
0,
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Spelling,
#include "clang/Basic/OperatorKinds.def"
};
const char *OpName = OperatorNames[getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
std::string Result = "operator";
if (OpName[0] >= 'a' && OpName[0] <= 'z')
Result += ' ';
Result += OpName;
return Result;
}
case CXXConversionFunctionName: {
std::string Result = "operator ";
QualType Type = getCXXNameType();
@ -147,6 +178,16 @@ QualType DeclarationName::getCXXNameType() const {
return QualType();
}
OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
unsigned value
= CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction;
return static_cast<OverloadedOperatorKind>(value);
} else {
return OO_None;
}
}
Selector DeclarationName::getObjCSelector() const {
switch (getNameKind()) {
case ObjCZeroArgSelector:
@ -175,6 +216,9 @@ void *DeclarationName::getFETokenInfoAsVoid() const {
case CXXConversionFunctionName:
return getAsCXXSpecialName()->FETokenInfo;
case CXXOperatorName:
return getAsCXXOperatorIdName()->FETokenInfo;
default:
assert(false && "Declaration name has no FETokenInfo");
}
@ -193,6 +237,10 @@ void DeclarationName::setFETokenInfo(void *T) {
getAsCXXSpecialName()->FETokenInfo = T;
break;
case CXXOperatorName:
getAsCXXOperatorIdName()->FETokenInfo = T;
break;
default:
assert(false && "Declaration name has no FETokenInfo");
}
@ -200,10 +248,19 @@ void DeclarationName::setFETokenInfo(void *T) {
DeclarationNameTable::DeclarationNameTable() {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
// Initialize the overloaded operator names.
CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
CXXOperatorNames[Op].ExtraKindOrNumArgs
= Op + DeclarationNameExtra::CXXConversionFunction;
CXXOperatorNames[Op].FETokenInfo = 0;
}
}
DeclarationNameTable::~DeclarationNameTable() {
delete static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
delete [] CXXOperatorNames;
}
DeclarationName
@ -249,3 +306,8 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
return DeclarationName(SpecialName);
}
DeclarationName
DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
}

View File

@ -90,10 +90,10 @@ OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
return OO_None;
if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
return FDecl->getIdentifier()->getOverloadedOperatorID();
return FDecl->getDeclName().getCXXOverloadedOperator();
else if (const OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()))
return Ovl->getIdentifier()->getOverloadedOperatorID();
return Ovl->getDeclName().getCXXOverloadedOperator();
else
return OO_None;
}

View File

@ -28,7 +28,6 @@ using namespace clang;
IdentifierInfo::IdentifierInfo() {
TokenID = tok::identifier;
ObjCOrBuiltinID = 0;
OperatorID = 0;
HasMacro = false;
IsExtension = false;
IsPoisoned = false;
@ -47,7 +46,6 @@ 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.
@ -163,26 +161,6 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
#include "clang/Basic/TokenKinds.def"
}
/// addOperatorPrefix - Add the prefix "operator" (possible with a
/// space after it) to the given operator symbol, and return the
/// result.
static std::string addOperatorPrefix(const char* Symbol) {
std::string result = "operator";
if (Symbol[0] >= 'a' && Symbol[0] <= 'z')
result += ' ';
result += Symbol;
return result;
}
/// AddOverloadedOperators - Register the name of all C++ overloadable
/// operators ("operator+", "operator[]", etc.)
void IdentifierTable::AddOverloadedOperators() {
#define OVERLOADED_OPERATOR(Name,Spelling,Token, Unary, Binary, MemberOnly) \
OverloadedOperators[OO_##Name] = &get(addOperatorPrefix(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

View File

@ -1460,8 +1460,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
SourceLocation OperatorLoc = Tok.getLocation();
// First try the name of an overloaded operator
if (IdentifierInfo *II = TryParseOperatorFunctionId()) {
D.SetIdentifier(II, OperatorLoc);
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
D.setOverloadedOperator(Op, OperatorLoc);
} else {
// This must be a conversion function (C++ [class.conv.fct]).
if (TypeTy *ConvType = ParseConversionFunctionId()) {

View File

@ -149,8 +149,8 @@ Parser::ExprResult Parser::ParseCXXIdExpression() {
case tok::kw_operator: {
SourceLocation OperatorLoc = Tok.getLocation();
if (IdentifierInfo *II = TryParseOperatorFunctionId()) {
return Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II,
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
return Actions.ActOnOperatorFunctionIdExpr(CurScope, OperatorLoc, Op,
Tok.is(tok::l_paren), &SS);
} else if (TypeTy *Type = ParseConversionFunctionId()) {
return Actions.ActOnConversionFunctionExpr(CurScope, OperatorLoc,
@ -534,7 +534,7 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
/// ^= &= |= << >> >>= <<= == !=
/// <= >= && || ++ -- , ->* ->
/// () []
IdentifierInfo *Parser::TryParseOperatorFunctionId() {
OverloadedOperatorKind Parser::TryParseOperatorFunctionId() {
assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
OverloadedOperatorKind Op = OO_None;
@ -549,7 +549,7 @@ IdentifierInfo *Parser::TryParseOperatorFunctionId() {
} else {
Op = OO_New;
}
return &PP.getIdentifierTable().getOverloadedOperator(Op);
return Op;
case tok::kw_delete:
ConsumeToken(); // 'operator'
@ -561,7 +561,7 @@ IdentifierInfo *Parser::TryParseOperatorFunctionId() {
} else {
Op = OO_Delete;
}
return &PP.getIdentifierTable().getOverloadedOperator(Op);
return Op;
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case tok::Token: Op = OO_##Name; break;
@ -572,21 +572,21 @@ IdentifierInfo *Parser::TryParseOperatorFunctionId() {
ConsumeToken(); // 'operator'
ConsumeParen(); // '('
ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
return &PP.getIdentifierTable().getOverloadedOperator(OO_Call);
return OO_Call;
case tok::l_square:
ConsumeToken(); // 'operator'
ConsumeBracket(); // '['
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
return &PP.getIdentifierTable().getOverloadedOperator(OO_Subscript);
return OO_Subscript;
default:
return 0;
return OO_None;
}
ConsumeToken(); // 'operator'
ConsumeAnyToken(); // the operator itself
return &PP.getIdentifierTable().getOverloadedOperator(Op);
return Op;
}
/// ParseConversionFunctionId - Parse a C++ conversion-function-id,

View File

@ -615,6 +615,11 @@ public:
IdentifierInfo &II,
bool HasTrailingLParen,
const CXXScopeSpec *SS = 0);
virtual ExprResult ActOnOperatorFunctionIdExpr(Scope *S,
SourceLocation OperatorLoc,
OverloadedOperatorKind Op,
bool HasTrailingLParen,
const CXXScopeSpec *SS = 0);
virtual ExprResult ActOnConversionFunctionExpr(Scope *S,
SourceLocation OperatorLoc,
TypeTy *Ty,

View File

@ -783,6 +783,11 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
Ty = Context.getCanonicalType(Ty);
return Context.DeclarationNames.getCXXConversionFunctionName(Ty);
}
case Declarator::DK_Operator:
assert(D.getIdentifier() == 0 && "operator names have no identifier");
return Context.DeclarationNames.getCXXOperatorName(
D.getOverloadedOperator());
}
assert(false && "Unknown name kind");

View File

@ -2839,7 +2839,7 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
OverloadedOperatorKind OverOp = OverOps[Opc];
// Lookup this operator.
Decl *D = LookupDecl(&PP.getIdentifierTable().getOverloadedOperator(OverOp),
Decl *D = LookupDecl(Context.DeclarationNames.getCXXOperatorName(OverOp),
Decl::IDNS_Ordinary, S);
// Add any overloaded operators we find to the overload set.

View File

@ -70,6 +70,52 @@ Sema::ExprResult Sema::ActOnConversionFunctionExpr(Scope *S,
return new DeclRefExpr(Conversion, Conversion->getType(), OperatorLoc);
}
/// ActOnOperatorFunctionIdExpr - Parse a C++ overloaded operator
/// name (e.g., @c operator+ ) as an expression. This is very
/// similar to ActOnIdentifierExpr, except that instead of providing
/// an identifier the parser provides the kind of overloaded
/// operator that was parsed.
Sema::ExprResult Sema::ActOnOperatorFunctionIdExpr(Scope *S,
SourceLocation OperatorLoc,
OverloadedOperatorKind Op,
bool HasTrailingLParen,
const CXXScopeSpec *SS) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op);
Decl *D;
if (SS && !SS->isEmpty()) {
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
if (DC == 0)
return true;
D = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
} else
D = LookupDecl(Name, Decl::IDNS_Ordinary, S);
if (D == 0) {
// If there is no conversion function that converts to this type,
// diagnose the problem.
if (SS && !SS->isEmpty())
return Diag(OperatorLoc, diag::err_typecheck_no_member,
Name.getAsString(), SS->getRange());
else
return Diag(OperatorLoc, diag::err_undeclared_var_use,
Name.getAsString());
}
ValueDecl *VD = cast<ValueDecl>(D);
// check if referencing a declaration with __attribute__((deprecated)).
if (VD->getAttr<DeprecatedAttr>())
Diag(OperatorLoc, diag::warn_deprecated, Name.getAsString());
// Only create DeclRefExpr's for valid Decl's.
if (VD->isInvalidDecl())
return true;
// Create a normal DeclRefExpr.
return new DeclRefExpr(VD, VD->getType(), OperatorLoc);
}
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
Action::ExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,

View File

@ -20,8 +20,7 @@ void f(X x) {
x = operator+(x, x);
}
X operator+(int, float); // expected-error{{overloaded 'operator+' must have at least one parameter of class or enumeration type}} \
// expected-error{{previous definition is here}}
X operator+(int, float); // expected-error{{overloaded 'operator+' must have at least one parameter of class or enumeration type}}
X operator*(X, X = 5); // expected-error{{parameter of overloaded 'operator*' cannot have a default argument}}
@ -37,4 +36,4 @@ Y& operator++(Y&);
Y operator++(Y&, INT);
X operator++(X&, FLOAT); // expected-error{{parameter of overloaded post-increment operator must have type 'int' (not 'float')}}
int operator+; // expected-error{{redefinition of 'operator+' as different kind of symbol}}
int operator+; // expected-error{{'operator+' cannot be the name of a variable or data member}}