diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-11-18 14:39:36 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-11-18 14:39:36 +0000 |
commit | e94ca9e4371c022329270436b3dd77adc4ddfa8f (patch) | |
tree | 88577be07029db31b21b7b0c8e3dbcf593dff4a4 /lib | |
parent | db0e15ae3e2b5e180541eec35e2bce54359ca7d8 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59526 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Decl.cpp | 4 | ||||
-rw-r--r-- | lib/AST/DeclSerialization.cpp | 14 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 66 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Basic/IdentifierTable.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 46 |
11 files changed, 150 insertions, 42 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index eee934bebb..194f47f96c 100644 --- a/lib/AST/Decl.cpp +++ b/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/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 5137b720c5..8a4612b674 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/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/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index d58016a44c..3a9e7c84e3 100644 --- a/lib/AST/DeclarationName.cpp +++ b/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/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 22f30f451e..1155a4b9c6 100644 --- a/lib/AST/ExprCXX.cpp +++ b/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/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 38bdb7e630..1bef76688c 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b73ee61a86..112e2bcde7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 006c79158a..90caa859a1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/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/lib/Sema/Sema.h b/lib/Sema/Sema.h index 317cd6587e..03099956b0 100644 --- a/lib/Sema/Sema.h +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fdc4aff031..5ad1429c35 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d113d6b6db..accdc32d45 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e49ef27af7..f2c6c3b35b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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, |