Don't build identifiers for C++ constructors, destructors, or
conversion functions. Instead, we just use a placeholder identifier
for these (e.g., "<constructor>") and override NamedDecl::getName() to
provide a human-readable name.
This is one potential solution to the problem; another solution would
be to replace the use of IdentifierInfo* in NamedDecl with a different
class that deals with identifiers better. I'm also prototyping that to
see how it compares, but this commit is better than what we had
previously.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59193 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d008544..1de6407 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Basic/IdentifierTable.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -26,11 +27,20 @@
return new (Mem) CXXFieldDecl(RD, L, Id, T, BW);
}
+CXXRecordDecl::CXXRecordDecl(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id)
+ : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
+ UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
+ Aggregate(true), Polymorphic(false), Bases(0), NumBases(0),
+ Constructors(DC, &C.Idents.getConstructorId()),
+ Destructor(0),
+ Conversions(DC, &C.Idents.getConversionFunctionId()) { }
+
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl) {
void *Mem = C.getAllocator().Allocate<CXXRecordDecl>();
- CXXRecordDecl* R = new (Mem) CXXRecordDecl(TK, DC, L, Id);
+ CXXRecordDecl* R = new (Mem) CXXRecordDecl(C, TK, DC, L, Id);
C.getTypeDeclType(R, PrevDecl);
return R;
}
@@ -232,6 +242,10 @@
(getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0);
}
+const char *CXXConstructorDecl::getName() const {
+ return getParent()->getName();
+}
+
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
@@ -242,6 +256,34 @@
isImplicitlyDeclared);
}
+CXXDestructorDecl::~CXXDestructorDecl() {
+ delete [] Name;
+}
+
+const char *CXXDestructorDecl::getName() const {
+ if (!Name) {
+ std::string Builder = "~";
+ Builder += getParent()->getName();
+ Name = new char[Builder.size()+1];
+ strcpy(Name, Builder.c_str());
+ }
+ return Name;
+}
+
+CXXConversionDecl::~CXXConversionDecl() {
+ delete [] Name;
+}
+
+const char *CXXConversionDecl::getName() const {
+ if (!Name) {
+ std::string Builder = "operator ";
+ Builder += getConversionType().getAsString();
+ Name = new char[Builder.size()+1];
+ strcpy(Name, Builder.c_str());
+ }
+ return Name;
+}
+
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 2b9d7e3..b868475 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -42,7 +42,8 @@
IdentifierTable::IdentifierTable(const LangOptions &LangOpts)
// Start with space for 8K identifiers.
- : HashTable(8192) {
+ : HashTable(8192),
+ ConstructorId(0), DestructorId(0), ConversionFunctionId(0) {
// Populate the identifier table with info about keywords for the current
// language.
@@ -51,7 +52,33 @@
}
// This cstor is intended to be used only for serialization.
-IdentifierTable::IdentifierTable() : HashTable(8192) {}
+IdentifierTable::IdentifierTable()
+ : HashTable(8192),
+ ConstructorId(0), DestructorId(0), ConversionFunctionId(0) { }
+
+/// getConstructorId - Return a placeholder identifier for a C++
+/// constructor.
+IdentifierInfo &IdentifierTable::getConstructorId() {
+ if (!ConstructorId)
+ ConstructorId = &get("<constructor>");
+ return *ConstructorId;
+}
+
+/// getDestructorId - Return a placeholder identifier for a C++
+/// destructor.
+IdentifierInfo &IdentifierTable::getDestructorId() {
+ if (!DestructorId)
+ DestructorId = &get("<destructor>");
+ return *DestructorId;
+}
+
+/// getConversionFunctionId - Return a placeholder identifier for a
+/// C++ conversion function.
+IdentifierInfo &IdentifierTable::getConversionFunctionId() {
+ if (!ConversionFunctionId)
+ ConversionFunctionId = &get("<conversion function>");
+ return *ConversionFunctionId;
+}
//===----------------------------------------------------------------------===//
// Language Keyword Implementation
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 70d65f3..0c1080a 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1437,7 +1437,8 @@
if (getLang().CPlusPlus &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
D.SetConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope),
- Tok.getIdentifierInfo(), Tok.getLocation());
+ &PP.getIdentifierTable().getConstructorId(),
+ Tok.getLocation());
else
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
@@ -1446,18 +1447,9 @@
// This should be a C++ destructor.
SourceLocation TildeLoc = ConsumeToken();
if (Tok.is(tok::identifier)) {
- // Use the next identifier and "~" to form a name for the
- // destructor. This is useful both for diagnostics and for
- // correctness of the parser, since we use presence/absence of the
- // identifier to determine what we parsed.
- // FIXME: We could end up with a template-id here, once we parse
- // templates, and will have to do something different to form the
- // name of the destructor.
- IdentifierInfo *II = Tok.getIdentifierInfo();
- II = &PP.getIdentifierTable().get(std::string("~") + II->getName());
-
if (TypeTy *Type = ParseClassName())
- D.SetDestructor(Type, II, TildeLoc);
+ D.SetDestructor(Type, &PP.getIdentifierTable().getDestructorId(),
+ TildeLoc);
else
D.SetIdentifier(0, TildeLoc);
} else {
@@ -1473,10 +1465,9 @@
} else {
// This must be a conversion function (C++ [class.conv.fct]).
if (TypeTy *ConvType = ParseConversionFunctionId()) {
- IdentifierInfo *II
- = &PP.getIdentifierTable().get(std::string("operator ") +
- Actions.getTypeAsString(ConvType));
- D.SetConversionFunction(ConvType, II, OperatorLoc);
+ D.SetConversionFunction(ConvType,
+ &PP.getIdentifierTable().getConversionFunctionId(),
+ OperatorLoc);
}
}
} else if (Tok.is(tok::l_paren) && SS.isEmpty()) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6a86a8a..efe481a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -284,7 +284,6 @@
//
virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS);
- virtual std::string getTypeAsString(TypeTy *Type);
virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
virtual void ActOnParamDefaultArgument(DeclTy *param,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index bf29bdf..8c3a5c1 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -45,11 +45,6 @@
return 0;
}
-std::string Sema::getTypeAsString(TypeTy *Type) {
- QualType Ty = QualType::getFromOpaquePtr(Type);
- return Ty.getAsString();
-}
-
DeclContext *Sema::getContainingDC(DeclContext *DC) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
// A C++ out-of-line method will return to the file declaration context.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 128df11..9bf10ce 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -705,7 +705,7 @@
CXXConstructorDecl *DefaultCon =
CXXConstructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(),
- ClassDecl->getIdentifier(),
+ &Context.Idents.getConstructorId(),
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
/*isExplicit=*/false,
@@ -771,7 +771,7 @@
CXXConstructorDecl *CopyConstructor
= CXXConstructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(),
- ClassDecl->getIdentifier(),
+ &Context.Idents.getConstructorId(),
Context.getFunctionType(Context.VoidTy,
&ArgType, 1,
false, 0),
@@ -795,12 +795,10 @@
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
- std::string DestructorName = "~";
- DestructorName += ClassDecl->getName();
CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(Context, ClassDecl,
ClassDecl->getLocation(),
- &PP.getIdentifierTable().get(DestructorName),
+ &Context.Idents.getConstructorId(),
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0),
/*isInline=*/true,