From 163c58502abf01db880cefb8a6c0b55c88142446 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 18 Nov 2008 14:39:36 +0000 Subject: [PATCH] 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 --- clang/docs/InternalsManual.html | 21 ++++-- clang/include/clang/AST/DeclarationName.h | 63 +++++++++++++----- clang/include/clang/Basic/IdentifierTable.h | 40 ++++------- clang/include/clang/Parse/Action.h | 15 ++++- clang/include/clang/Parse/DeclSpec.h | 27 ++++++-- clang/include/clang/Parse/Parser.h | 2 +- clang/lib/AST/Decl.cpp | 4 +- clang/lib/AST/DeclSerialization.cpp | 14 +++- clang/lib/AST/DeclarationName.cpp | 66 ++++++++++++++++++- clang/lib/AST/ExprCXX.cpp | 4 +- clang/lib/Basic/IdentifierTable.cpp | 22 ------- clang/lib/Parse/ParseDecl.cpp | 4 +- clang/lib/Parse/ParseExprCXX.cpp | 20 +++--- clang/lib/Sema/Sema.h | 5 ++ clang/lib/Sema/SemaDecl.cpp | 5 ++ clang/lib/Sema/SemaExpr.cpp | 2 +- clang/lib/Sema/SemaExprCXX.cpp | 46 +++++++++++++ .../test/SemaCXX/overloaded-operator-decl.cpp | 5 +- 18 files changed, 260 insertions(+), 105 deletions(-) diff --git a/clang/docs/InternalsManual.html b/clang/docs/InternalsManual.html index d9c2701f6e13..2e44640c9896 100644 --- a/clang/docs/InternalsManual.html +++ b/clang/docs/InternalsManual.html @@ -469,7 +469,7 @@ malloc'd objects are at least 8 byte aligned.

Given a DeclarationName N, N.getNameKind() will produce a value that describes what kind of name N - stores. There are 7 options (all of the names are inside + stores. There are 8 options (all of the names are inside the DeclarationName class)

Identifier
@@ -514,11 +514,19 @@ malloc'd objects are at least 8 byte aligned.

const *". Use N.getCXXNameType() to retrieve the type that this conversion function converts to. This type is always a canonical type. + +
CXXOperatorName
+
The name is a C++ overloaded operator name. Overloaded operators + are named according to their spelling, e.g., + "operator+" or "operator new + []". Use N.getCXXOverloadedOperator() to + retrieve the overloaded operator (a value of + type OverloadedOperatorKind).

DeclarationNames 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 DeclarationNames can be compared for @@ -532,16 +540,15 @@ malloc'd objects are at least 8 byte aligned.

DeclarationName instances can be created in different ways depending on what kind of name the instance will store. Normal - identifiers (IdentifierInfo pointers), including - overloaded operator names, and Objective-C selectors + identifiers (IdentifierInfo pointers) and Objective-C selectors (Selector) can be implicitly converted to DeclarationNames. Names for C++ constructors, - destructors, and conversion functions can be retrieved from + destructors, conversion functions, and overloaded operators can be retrieved from the DeclarationNameTable, an instance of which is available as ASTContext::DeclarationNames. The member functions getCXXConstructorName, getCXXDestructorName, - and getCXXConversionFunctionName, respectively, - return DeclarationName instances for the three kinds of + getCXXConversionFunctionName, and getCXXOperatorName, respectively, + return DeclarationName instances for the four kinds of C++ special function names.

diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 877d23566bc1..4c7a17096ee3 100644 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -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(Ptr & ~PtrMask); } @@ -105,12 +106,28 @@ private: return 0; } + /// getAsCXXOperatorIdName + CXXOperatorIdName *getAsCXXOperatorIdName() const { + if (getNameKind() == CXXOperatorName) + return reinterpret_cast(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(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(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(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 * + 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 diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 58ad133e3bac..cbd27547ac38 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -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 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. diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 215893e2e627..8e1a23f6e743 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -463,9 +463,22 @@ public: const CXXScopeSpec *SS = 0) { 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. diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index 46629637bc35..4ec9c5501257 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -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,10 +678,16 @@ private: /// AsmLabel - The asm label, if specified. Action::ExprTy *AsmLabel; - // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the - // type associated with the constructor, destructor, or conversion - // operator. - Action::TypeTy *Type; + 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) @@ -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; } diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 3beb36c7af99..ad6244fe4c3f 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -789,7 +789,7 @@ private: //===--------------------------------------------------------------------===// // C++ 13.5: Overloaded operators [over.oper] - IdentifierInfo *TryParseOperatorFunctionId(); + OverloadedOperatorKind TryParseOperatorFunctionId(); TypeTy *ParseConversionFunctionId(); }; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index eee934bebba2..194f47f96c49 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -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; } diff --git a/clang/lib/AST/DeclSerialization.cpp b/clang/lib/AST/DeclSerialization.cpp index 5137b720c5be..8a4612b6745b 100644 --- a/clang/lib/AST/DeclSerialization.cpp +++ b/clang/lib/AST/DeclSerialization.cpp @@ -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(D.ReadInt()); + Name = C.DeclarationNames.getCXXOperatorName(Op); + break; + } } } diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index d58016a44cc7..3a9e7c84e3d5 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -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(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; + + // 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*>(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]); +} + diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 22f30f451e50..1155a4b9c6be 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -90,10 +90,10 @@ OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const { return OO_None; if (const FunctionDecl *FDecl = dyn_cast(DRE->getDecl())) - return FDecl->getIdentifier()->getOverloadedOperatorID(); + return FDecl->getDeclName().getCXXOverloadedOperator(); else if (const OverloadedFunctionDecl *Ovl = dyn_cast(DRE->getDecl())) - return Ovl->getIdentifier()->getOverloadedOperatorID(); + return Ovl->getDeclName().getCXXOverloadedOperator(); else return OO_None; } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 38bdb7e630c3..1bef76688c5e 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -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 diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b73ee61a862e..112e2bcde762 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -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()) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 006c79158a84..90caa859a1cf 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -149,9 +149,9 @@ Parser::ExprResult Parser::ParseCXXIdExpression() { case tok::kw_operator: { SourceLocation OperatorLoc = Tok.getLocation(); - if (IdentifierInfo *II = TryParseOperatorFunctionId()) { - return Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II, - Tok.is(tok::l_paren), &SS); + 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, Type, Tok.is(tok::l_paren), @@ -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, diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 317cd6587eb9..03099956b07d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fdc4aff031cd..5ad1429c35d3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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"); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d113d6b6db9c..accdc32d45b8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index e49ef27af776..f2c6c3b35b17 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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(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(D); + + // check if referencing a declaration with __attribute__((deprecated)). + if (VD->getAttr()) + 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, diff --git a/clang/test/SemaCXX/overloaded-operator-decl.cpp b/clang/test/SemaCXX/overloaded-operator-decl.cpp index 7b05c38274b1..3af9592d2535 100644 --- a/clang/test/SemaCXX/overloaded-operator-decl.cpp +++ b/clang/test/SemaCXX/overloaded-operator-decl.cpp @@ -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}}