Parser: Don't manage TemplateAnnotationIds in a delayed cleanup pool.

Instead, make it the allocation function's responsibility to add them
to a list and clear it when a top-level decl is finished.

This plugs leakage of TemplateAnnotationIds. DelayedCleanupPool is
ugly and unused, remove it.

llvm-svn: 154743
This commit is contained in:
Benjamin Kramer 2012-04-14 12:14:03 +00:00
parent ffe7c7f4b2
commit 1e6b6060f9
6 changed files with 36 additions and 125 deletions

View File

@ -1,110 +0,0 @@
//=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- C++ -*===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a facility to delay calling cleanup methods until specific
// points.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
/// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function
/// allowing the cleanup functions to get called (with the pointer as parameter)
/// at specific points.
///
/// The use case is to simplify clean-up of certain resources that, while their
/// lifetime is well-known and restricted, cleaning them up manually is easy to
/// miss and cause a leak.
///
/// The same pointer can be added multiple times; its clean-up function will
/// only be called once.
class DelayedCleanupPool {
public:
typedef void (*CleanupFn)(void *ptr);
/// \brief Adds a pointer and its associated cleanup function to be called
/// at a later point.
///
/// \returns false if the pointer is already added, true otherwise.
bool delayCleanup(void *ptr, CleanupFn fn) {
assert(ptr && "Expected valid pointer to object");
assert(fn && "Expected valid pointer to function");
CleanupFn &mapFn = Ptrs[ptr];
assert((!mapFn || mapFn == fn) &&
"Adding a pointer with different cleanup function!");
if (!mapFn) {
mapFn = fn;
Cleanups.push_back(std::make_pair(ptr, fn));
return true;
}
return false;
}
template <typename T>
bool delayDelete(T *ptr) {
return delayCleanup(ptr, cleanupWithDelete<T>);
}
template <typename T, void (T::*Fn)()>
bool delayMemberFunc(T *ptr) {
return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>);
}
void doCleanup() {
for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I)
I->second(I->first);
Cleanups.clear();
Ptrs.clear();
}
~DelayedCleanupPool() {
doCleanup();
}
private:
llvm::DenseMap<void *, CleanupFn> Ptrs;
SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
template <typename T>
static void cleanupWithDelete(void *ptr) {
delete static_cast<T *>(ptr);
}
template <typename T, void (T::*Fn)()>
static void cleanupWithMemberFunc(void *ptr) {
(static_cast<T *>(ptr)->*Fn)();
}
};
/// \brief RAII object for triggering a cleanup of a DelayedCleanupPool.
class DelayedCleanupPoint {
DelayedCleanupPool &Pool;
public:
DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { }
~DelayedCleanupPoint() {
Pool.doCleanup();
}
};
} // end namespace clang
#endif

View File

@ -15,7 +15,6 @@
#define LLVM_CLANG_PARSE_PARSER_H
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/DelayedCleanupPool.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Sema/Sema.h"
@ -192,9 +191,9 @@ class Parser : public CodeCompletionHandler {
/// Factory object for creating AttributeList objects.
AttributeFactory AttrFactory;
/// \brief Gathers and cleans up objects when parsing of a top-level
/// declaration is finished.
DelayedCleanupPool TopLevelDeclCleanupPool;
/// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a
/// top-level declaration is finished.
SmallVector<TemplateIdAnnotation *, 16> TemplateIds;
IdentifierInfo *getSEHExceptKeyword();
@ -568,9 +567,7 @@ private:
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid);
/// \brief Get the TemplateIdAnnotation from the token and put it in the
/// cleanup pool so that it gets destroyed when parsing the current top level
/// declaration is finished.
/// \brief Get the TemplateIdAnnotation from the token.
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
/// TentativeParsingAction - An object that is used as a kind of "tentative

View File

@ -178,8 +178,11 @@ namespace clang {
ParsedTemplateArgument *getTemplateArgs() {
return reinterpret_cast<ParsedTemplateArgument *>(this + 1);
}
static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
/// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and
/// appends it to List.
static TemplateIdAnnotation *
Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) {
TemplateIdAnnotation *TemplateId
= (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
sizeof(ParsedTemplateArgument) * NumArgs);
@ -193,6 +196,7 @@ namespace clang {
for (unsigned I = 0; I != NumArgs; ++I)
new (TemplateArgs + I) ParsedTemplateArgument();
List.push_back(TemplateId);
return TemplateId;
}

View File

@ -1711,7 +1711,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Form a parsed representation of the template-id to be stored in the
// UnqualifiedId.
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
if (Id.getKind() == UnqualifiedId::IK_Identifier) {
TemplateId->Name = Id.Identifier;

View File

@ -838,7 +838,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// later.
Tok.setKind(tok::annot_template_id);
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
TemplateId->TemplateNameLoc = TemplateNameLoc;
if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
TemplateId->Name = TemplateName.Identifier;

View File

@ -397,6 +397,8 @@ Parser::~Parser() {
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
FPContractHandler.reset();
PP.clearCodeCompletionHandler();
assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?");
}
/// Initialize - Warm up the parser.
@ -470,10 +472,30 @@ void Parser::Initialize() {
}
}
namespace {
/// \brief RAIIObject to destroy the contents of a SmallVector of
/// TemplateIdAnnotation pointers and clear the vector.
class DestroyTemplateIdAnnotationsRAIIObj {
SmallVectorImpl<TemplateIdAnnotation *> &Container;
public:
DestroyTemplateIdAnnotationsRAIIObj(SmallVectorImpl<TemplateIdAnnotation *>
&Container)
: Container(Container) {}
~DestroyTemplateIdAnnotationsRAIIObj() {
for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I =
Container.begin(), E = Container.end();
I != E; ++I)
(*I)->Destroy();
Container.clear();
}
};
}
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
/// action tells us to. This returns true if the EOF was encountered.
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
// Skip over the EOF token, flagging end of previous input for incremental
// processing
@ -543,7 +565,7 @@ void Parser::ParseTranslationUnit() {
Parser::DeclGroupPtrTy
Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS) {
DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
if (PP.isCodeCompletionReached()) {
@ -1201,8 +1223,6 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
assert(tok.is(tok::annot_template_id) && "Expected template-id token");
TemplateIdAnnotation *
Id = static_cast<TemplateIdAnnotation *>(tok.getAnnotationValue());
TopLevelDeclCleanupPool.delayMemberFunc< TemplateIdAnnotation,
&TemplateIdAnnotation::Destroy>(Id);
return Id;
}