diff options
author | Nico Weber <nicolasweber@gmx.de> | 2015-05-17 01:07:16 +0000 |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2015-05-17 01:07:16 +0000 |
commit | 28e0f243cf521103f2c63e1a6b8ea5ff315d6da2 (patch) | |
tree | 748dbc65fa68b4e5108aee4b929462083b07feaa /clang/lib/Parse/Parser.cpp | |
parent | 3b6e51a73ffe202a4baa027f7ae40b12c43afaaa (diff) | |
download | bcm5719-llvm-28e0f243cf521103f2c63e1a6b8ea5ff315d6da2.tar.gz bcm5719-llvm-28e0f243cf521103f2c63e1a6b8ea5ff315d6da2.zip |
Don't leak TemplateIds when a plugin parses late-parsed templates at TU end.
In -fdelayed-template-parsing mode, templates that aren't used are not parsed
at all. For some diagnostic plugins, this is a problem since they want to
analyse the contents of the template function body. What has been suggested
on cfe-dev [1] is to explicitly parse interesting templates in
HandleTranslationUnit(); IWYU does this for example [2].
This is workable, but since the delayed parsing doesn't run below a call to
ParseTopLevelDecl(), no DestroyTemplateIdAnnotationsRAIIObj object is on the
stack to clean up TemplateIds that are created during parsing. To fix this,
let ~Parser() clean them up in delayed template parsing mode instead of
leaking (or asserting in +Assert builds).
(r219810, relanded in r220400, fixed the same problem in incremental processing
mode; the review thread of r219810 has a good discussion of the problem.)
To test this, give the PrintFunctionNames plugin a flag to force parsing
of a template and add a test that uses it in -fdelayed-template-parsing mode.
Without the Parser.cpp change, that test asserts.
1: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-August/038415.html
2: https://code.google.com/p/include-what-you-use/source/detail?r=566
llvm-svn: 237531
Diffstat (limited to 'clang/lib/Parse/Parser.cpp')
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 49 |
1 files changed, 29 insertions, 20 deletions
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a45eaa0e333..dea7a6998a2 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -38,6 +38,26 @@ public: return false; } }; + +/// \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(); + } +}; } // end anonymous namespace IdentifierInfo *Parser::getSEHExceptKeyword() { @@ -414,6 +434,15 @@ Parser::~Parser() { PP.clearCodeCompletionHandler(); + if (getLangOpts().DelayedTemplateParsing && + !PP.isIncrementalProcessingEnabled() && !TemplateIds.empty()) { + // If an ASTConsumer parsed delay-parsed templates in their + // HandleTranslationUnit() method, TemplateIds created there were not + // guarded by a DestroyTemplateIdAnnotationsRAIIObj object in + // ParseTopLevelDecl(). Destroy them here. + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); + } + assert(TemplateIds.empty() && "Still alive TemplateIdAnnotations around?"); } @@ -490,26 +519,6 @@ void Parser::Initialize() { ConsumeToken(); } -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(); - } - }; -} - void Parser::LateTemplateParserCleanupCallback(void *P) { // While this RAII helper doesn't bracket any actual work, the destructor will // clean up annotations that were created during ActOnEndOfTranslationUnit |