forked from OSchip/llvm-project
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:
parent
ffe7c7f4b2
commit
1e6b6060f9
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue