Updated IdentifierResolver to deal with DeclarationNames. The names of
C++ constructors, destructors, and conversion functions now have a
FETokenInfo field that IdentifierResolver can access, so that these
special names are handled just like ordinary identifiers. A few other
Sema routines now use DeclarationNames instead of IdentifierInfo*'s.
To validate this design, this code also implements parsing and
semantic analysis for id-expressions that name conversion functions,
e.g.,
return operator bool();
The new parser action ActOnConversionFunctionExpr takes the result of
parsing "operator type-id" and turning it into an expression, using
the IdentifierResolver with the DeclarationName of the conversion
function. ActOnDeclarator pushes those conversion function names into
scope so that the IdentifierResolver can find them, of course.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59462 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 82f95bf..cf0342f 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file implements the IdentifierResolver class, which is used for lexical
-// scoped lookup, based on identifier.
+// scoped lookup, based on declaration names.
//
//===----------------------------------------------------------------------===//
@@ -23,7 +23,7 @@
// IdDeclInfoMap class
//===----------------------------------------------------------------------===//
-/// IdDeclInfoMap - Associates IdDeclInfos with Identifiers.
+/// IdDeclInfoMap - Associates IdDeclInfos with declaration names.
/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each
/// individual IdDeclInfo to heap.
class IdentifierResolver::IdDeclInfoMap {
@@ -36,9 +36,9 @@
public:
IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
- /// Returns the IdDeclInfo associated to the IdentifierInfo.
+ /// Returns the IdDeclInfo associated to the DeclarationName.
/// It creates a new IdDeclInfo if one was not created before for this id.
- IdDeclInfo &operator[](IdentifierInfo *II);
+ IdDeclInfo &operator[](DeclarationName Name);
};
@@ -173,19 +173,19 @@
/// AddDecl - Link the decl to its shadowed decl chain.
void IdentifierResolver::AddDecl(NamedDecl *D) {
- IdentifierInfo *II = D->getIdentifier();
- void *Ptr = II->getFETokenInfo<void>();
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
if (!Ptr) {
- II->setFETokenInfo(D);
+ Name.setFETokenInfo(D);
return;
}
IdDeclInfo *IDI;
if (isDeclPtr(Ptr)) {
- II->setFETokenInfo(NULL);
- IDI = &(*IdDeclInfos)[II];
+ Name.setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[Name];
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
IDI->AddDecl(PrevD);
} else
@@ -198,18 +198,18 @@
/// after the decl that the iterator points to, thus the 'Shadow' decl will be
/// encountered before the 'D' decl.
void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) {
- assert(D->getIdentifier() == Shadow->getIdentifier() && "Different ids!");
+ assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!");
assert(LookupContext(D) == LookupContext(Shadow) && "Different context!");
- IdentifierInfo *II = D->getIdentifier();
- void *Ptr = II->getFETokenInfo<void>();
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
assert(Ptr && "No decl from Ptr ?");
IdDeclInfo *IDI;
if (isDeclPtr(Ptr)) {
- II->setFETokenInfo(NULL);
- IDI = &(*IdDeclInfos)[II];
+ Name.setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[Name];
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
assert(PrevD == Shadow && "Invalid shadow decl ?");
IDI->AddDecl(D);
@@ -225,29 +225,29 @@
/// The decl must already be part of the decl chain.
void IdentifierResolver::RemoveDecl(NamedDecl *D) {
assert(D && "null param passed");
- IdentifierInfo *II = D->getIdentifier();
- void *Ptr = II->getFETokenInfo<void>();
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
assert(Ptr && "Didn't find this decl on its identifier's chain!");
if (isDeclPtr(Ptr)) {
assert(D == Ptr && "Didn't find this decl on its identifier's chain!");
- II->setFETokenInfo(NULL);
+ Name.setFETokenInfo(NULL);
return;
}
return toIdDeclInfo(Ptr)->RemoveDecl(D);
}
-/// begin - Returns an iterator for decls of identifier 'II', starting at
+/// begin - Returns an iterator for decls with name 'Name', starting at
/// declaration context 'Ctx'. If 'LookInParentCtx' is true, it will walk the
/// decls of parent declaration contexts too.
IdentifierResolver::iterator
-IdentifierResolver::begin(const IdentifierInfo *II, const DeclContext *Ctx,
+IdentifierResolver::begin(DeclarationName Name, const DeclContext *Ctx,
bool LookInParentCtx) {
assert(Ctx && "null param passed");
- void *Ptr = II->getFETokenInfo<void>();
+ void *Ptr = Name.getFETokenInfo<void>();
if (!Ptr) return end();
LookupContext LC(Ctx);
@@ -284,7 +284,7 @@
void IdentifierResolver::iterator::PreIncIter() {
NamedDecl *D = **this;
LookupContext Ctx(D);
- void *InfoPtr = D->getIdentifier()->getFETokenInfo<void>();
+ void *InfoPtr = D->getDeclName().getFETokenInfo<void>();
assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?");
IdDeclInfo *Info = toIdDeclInfo(InfoPtr);
@@ -310,12 +310,11 @@
// IdDeclInfoMap Implementation
//===----------------------------------------------------------------------===//
-/// Returns the IdDeclInfo associated to the IdentifierInfo.
+/// Returns the IdDeclInfo associated to the DeclarationName.
/// It creates a new IdDeclInfo if one was not created before for this id.
IdentifierResolver::IdDeclInfo &
-IdentifierResolver::IdDeclInfoMap::operator[](IdentifierInfo *II) {
- assert (II && "null IdentifierInfo passed");
- void *Ptr = II->getFETokenInfo<void>();
+IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) {
+ void *Ptr = Name.getFETokenInfo<void>();
if (Ptr) return *toIdDeclInfo(Ptr);
@@ -327,7 +326,7 @@
CurIndex = 0;
}
IdDeclInfo *IDI = &IDIVecs.back()[CurIndex];
- II->setFETokenInfo(reinterpret_cast<void*>(
+ Name.setFETokenInfo(reinterpret_cast<void*>(
reinterpret_cast<uintptr_t>(IDI) | 0x1)
);
++CurIndex;
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
index e76bec6..5a0f746 100644
--- a/lib/Sema/IdentifierResolver.h
+++ b/lib/Sema/IdentifierResolver.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines the IdentifierResolver class, which is used for lexical
-// scoped lookup, based on identifier.
+// scoped lookup, based on declaration names.
//
//===----------------------------------------------------------------------===//
@@ -18,13 +18,14 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Parse/Scope.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclCXX.h"
namespace clang {
-/// IdentifierResolver - Keeps track of shadowed decls on enclosing scopes.
-/// It manages the shadowing chains of identifiers and implements efficent decl
-/// lookup based on an identifier.
+/// IdentifierResolver - Keeps track of shadowed decls on enclosing
+/// scopes. It manages the shadowing chains of declaration names and
+/// implements efficent decl lookup based on a declaration name.
class IdentifierResolver {
/// LookupContext - A wrapper for DeclContext. DeclContext is only part of
@@ -79,10 +80,10 @@
}
};
- /// IdDeclInfo - Keeps track of information about decls associated to a
- /// particular identifier. IdDeclInfos are lazily constructed and assigned
- /// to an identifier the first time a decl with that identifier is shadowed
- /// in some scope.
+ /// IdDeclInfo - Keeps track of information about decls associated
+ /// to a particular declaration name. IdDeclInfos are lazily
+ /// constructed and assigned to a declaration name the first time a
+ /// decl with that declaration name is shadowed in some scope.
class IdDeclInfo {
public:
typedef llvm::SmallVector<NamedDecl*, 2> DeclsTy;
@@ -123,7 +124,7 @@
public:
- /// iterator - Iterate over the decls of a specified identifier.
+ /// iterator - Iterate over the decls of a specified declaration name.
/// It will walk or not the parent declaration contexts depending on how
/// it was instantiated.
class iterator {
@@ -192,11 +193,11 @@
void PreIncIter();
};
- /// begin - Returns an iterator for decls of identifier 'II', starting at
+ /// begin - Returns an iterator for decls with the name 'Name', starting at
/// declaration context 'Ctx'. If 'LookInParentCtx' is true, it will walk the
/// decls of parent declaration contexts too.
/// Default for 'LookInParentCtx is true.
- static iterator begin(const IdentifierInfo *II, const DeclContext *Ctx,
+ static iterator begin(DeclarationName Name, const DeclContext *Ctx,
bool LookInParentCtx = true);
/// end - Returns an iterator that has 'finished'.
@@ -230,12 +231,12 @@
class IdDeclInfoMap;
IdDeclInfoMap *IdDeclInfos;
- /// Identifier's FETokenInfo contains a Decl pointer if lower bit == 0.
+ /// FETokenInfo contains a Decl pointer if lower bit == 0.
static inline bool isDeclPtr(void *Ptr) {
return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0;
}
- /// Identifier's FETokenInfo contains a IdDeclInfo pointer if lower bit == 1.
+ /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1.
static inline IdDeclInfo *toIdDeclInfo(void *Ptr) {
assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1
&& "Ptr not a IdDeclInfo* !");
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index efe481a..50a12f1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -282,7 +282,7 @@
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
- virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S,
+ virtual TypeTy *isTypeName(IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS);
virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
@@ -462,7 +462,7 @@
void CheckExtraCXXDefaultArguments(Declarator &D);
/// More parsing and symbol table subroutines...
- Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
+ Decl *LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
const DeclContext *LookupCtx = 0,
bool enableLazyBuiltinCreation = true);
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
@@ -614,6 +614,11 @@
IdentifierInfo &II,
bool HasTrailingLParen,
const CXXScopeSpec *SS = 0);
+ virtual ExprResult ActOnConversionFunctionExpr(Scope *S,
+ SourceLocation OperatorLoc,
+ TypeTy *Ty,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS);
virtual ExprResult ActOnPredefinedExpr(SourceLocation Loc,
tok::TokenKind Kind);
virtual ExprResult ActOnNumericConstant(const Token &);
@@ -820,7 +825,7 @@
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- const IdentifierInfo &II);
+ IdentifierInfo &II);
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 1480527..f22ca0c 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -20,9 +20,9 @@
namespace {
Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx,
- const IdentifierInfo &II, bool &IdIsUndeclared) {
+ DeclarationName Name, bool &IdIsUndeclared) {
IdentifierResolver::iterator
- I = IdentifierResolver::begin(&II, LookupCtx, LookInParentCtx),
+ I = IdentifierResolver::begin(Name, LookupCtx, LookInParentCtx),
E = IdentifierResolver::end();
if (I == E) {
@@ -67,15 +67,16 @@
const CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
- const IdentifierInfo &II) {
+ IdentifierInfo &II) {
DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
Decl *SD;
bool IdIsUndeclared;
if (DC)
- SD = LookupNestedName(DC, false/*LookInParentCtx*/, II, IdIsUndeclared);
+ SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared);
else
- SD = LookupNestedName(CurContext, true/*LookInParent*/, II, IdIsUndeclared);
+ SD = LookupNestedName(CurContext, true/*LookInParent*/, &II,
+ IdIsUndeclared);
if (SD) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 816d6fd..49c153d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -29,7 +29,12 @@
llvm::OwningPtr<CallExpr> TheCall(TheCallRaw);
// Get the IdentifierInfo* for the called function.
IdentifierInfo *FnInfo = FDecl->getIdentifier();
-
+
+ // None of the checks below are needed for functions that don't have
+ // simple names (e.g., C++ conversion functions).
+ if (!FnInfo)
+ return TheCall.take();
+
switch (FnInfo->getBuiltinID()) {
case Builtin::BI__builtin___CFStringMakeConstantString:
assert(TheCall->getNumArgs() == 1 &&
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 4807369..ea2a3ad 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -28,7 +28,7 @@
#include "llvm/ADT/StringExtras.h"
using namespace clang;
-Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S,
+Sema::TypeTy *Sema::isTypeName(IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS) {
DeclContext *DC = 0;
if (SS) {
@@ -113,7 +113,7 @@
// We are pushing the name of a function, which might be an
// overloaded name.
IdentifierResolver::iterator
- I = IdResolver.begin(FD->getIdentifier(),
+ I = IdResolver.begin(FD->getDeclName(),
FD->getDeclContext(), false/*LookInParentCtx*/);
if (I != IdResolver.end() &&
IdResolver.isDeclInScope(*I, FD->getDeclContext(), S) &&
@@ -126,7 +126,7 @@
// FunctionDecl and put it into an OverloadedFunctionDecl.
Ovl = OverloadedFunctionDecl::Create(Context,
FD->getDeclContext(),
- FD->getIdentifier());
+ FD->getDeclName());
Ovl->addOverload(dyn_cast<FunctionDecl>(*I));
// Remove the name binding to the existing FunctionDecl...
@@ -187,17 +187,17 @@
/// LookupDecl - Look up the inner-most declaration in the specified
/// namespace.
-Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
+Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
const DeclContext *LookupCtx,
bool enableLazyBuiltinCreation) {
- if (II == 0) return 0;
+ if (!Name) return 0;
unsigned NS = NSI;
if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
NS |= Decl::IDNS_Tag;
IdentifierResolver::iterator
- I = LookupCtx ? IdResolver.begin(II, LookupCtx, false/*LookInParentCtx*/) :
- IdResolver.begin(II, CurContext, true/*LookInParentCtx*/);
+ I = LookupCtx ? IdResolver.begin(Name, LookupCtx, false/*LookInParentCtx*/)
+ : IdResolver.begin(Name, CurContext, true/*LookInParentCtx*/);
// Scan up the scope chain looking for a decl that matches this identifier
// that is in the appropriate namespace. This search should not take long, as
// shadowing of names is uncommon, and deep shadowing is extremely uncommon.
@@ -209,13 +209,14 @@
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
if (NS & Decl::IDNS_Ordinary) {
- if (enableLazyBuiltinCreation &&
+ IdentifierInfo *II = Name.getAsIdentifierInfo();
+ if (enableLazyBuiltinCreation && II &&
(LookupCtx == 0 || isa<TranslationUnitDecl>(LookupCtx))) {
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID())
return LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S);
}
- if (getLangOptions().ObjC1) {
+ if (getLangOptions().ObjC1 && II) {
// @interface and @compatibility_alias introduce typedef-like names.
// Unlike typedef's, they can only be introduced at file-scope (and are
// therefore not scoped decls). They can, however, be shadowed by
@@ -1034,8 +1035,11 @@
return ActOnConstructorDeclarator(Constructor);
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
return ActOnDestructorDeclarator(Destructor);
- else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
- return ActOnConversionDeclarator(Conversion);
+
+ // Extra checking for conversion functions, including recording
+ // the conversion function in its class.
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+ ActOnConversionDeclarator(Conversion);
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e420ce5..e49ef27 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,56 @@
#include "clang/Basic/Diagnostic.h"
using namespace clang;
+/// ActOnConversionFunctionExpr - Parse a C++ conversion function
+/// name (e.g., 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.
+Sema::ExprResult Sema::ActOnConversionFunctionExpr(Scope *S,
+ SourceLocation OperatorLoc,
+ TypeTy *Ty,
+ bool HasTrailingLParen,
+ const CXXScopeSpec *SS) {
+ QualType ConvType = QualType::getFromOpaquePtr(Ty);
+ QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
+ DeclarationName ConvName
+ = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
+
+ // We only expect to find a CXXConversionDecl.
+ Decl *D;
+ if (SS && !SS->isEmpty()) {
+ DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
+ if (DC == 0)
+ return true;
+ D = LookupDecl(ConvName, Decl::IDNS_Ordinary, S, DC);
+ } else
+ D = LookupDecl(ConvName, 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,
+ ConvType.getAsString(), SS->getRange());
+ else
+ return Diag(OperatorLoc, diag::err_no_conv_function,
+ ConvType.getAsString());
+ }
+
+ assert(isa<CXXConversionDecl>(D) && "we had to find a conversion function");
+ CXXConversionDecl *Conversion = cast<CXXConversionDecl>(D);
+
+ // check if referencing a declaration with __attribute__((deprecated)).
+ if (Conversion->getAttr<DeprecatedAttr>())
+ Diag(OperatorLoc, diag::warn_deprecated, Conversion->getName());
+
+ // Only create DeclRefExpr's for valid Decl's.
+ if (Conversion->isInvalidDecl())
+ return true;
+
+ // Create a normal DeclRefExpr.
+ return new DeclRefExpr(Conversion, Conversion->getType(), OperatorLoc);
+}
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
Action::ExprResult