diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/docs/InternalsManual.html | 21 | ||||
| -rw-r--r-- | clang/include/clang/AST/DeclarationName.h | 63 | ||||
| -rw-r--r-- | clang/include/clang/Basic/IdentifierTable.h | 40 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 15 | ||||
| -rw-r--r-- | clang/include/clang/Parse/DeclSpec.h | 27 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 2 | ||||
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/AST/DeclSerialization.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/AST/DeclarationName.cpp | 66 | ||||
| -rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 20 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 46 | ||||
| -rw-r--r-- | clang/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 d9c2701f6e1..2e44640c989 100644 --- a/clang/docs/InternalsManual.html +++ b/clang/docs/InternalsManual.html @@ -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> <!-- ======================================================================= --> diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 877d23566bc..4c7a17096ee 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<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 diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 58ad133e3ba..cbd27547ac3 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<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. diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 215893e2e62..8e1a23f6e74 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 46629637bc3..4ec9c550125 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 3beb36c7af9..ad6244fe4c3 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 eee934bebba..194f47f96c4 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 5137b720c5b..8a4612b6745 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<OverloadedOperatorKind>(D.ReadInt()); + Name = C.DeclarationNames.getCXXOperatorName(Op); + break; + } } } diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index d58016a44cc..3a9e7c84e3d 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<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]); +} + diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 22f30f451e5..1155a4b9c6b 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<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; } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 38bdb7e630c..1bef76688c5 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 b73ee61a862..112e2bcde76 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 006c79158a8..90caa859a1c 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 317cd6587eb..03099956b07 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 fdc4aff031c..5ad1429c35d 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 d113d6b6db9..accdc32d45b 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 e49ef27af77..f2c6c3b35b1 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<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, diff --git a/clang/test/SemaCXX/overloaded-operator-decl.cpp b/clang/test/SemaCXX/overloaded-operator-decl.cpp index 7b05c38274b..3af9592d253 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}} |

