Index: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
index 2d221d7667a858c0d1ff8ec4bf1c7ca5b79f919b..764217f5f09fa138a482097836bda4e540a836cd 100644 |
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
@@ -17,6 +17,7 @@ |
#include "clang/AST/RecursiveASTVisitor.h" |
#include "clang/Frontend/CompilerInstance.h" |
#include "clang/Frontend/FrontendPluginRegistry.h" |
+#include "clang/Sema/Sema.h" |
using namespace clang; |
using std::string; |
@@ -144,6 +145,23 @@ const char kClassMustDeclareGCMixinTraceMethod[] = |
"[blink-gc] Class %0 which inherits from GarbageCollectedMixin must" |
" locally declare and override trace(Visitor*)"; |
+// Use a local RAV implementation to simply collect all FunctionDecls marked for |
+// late template parsing. This happens with the flag -fdelayed-template-parsing, |
+// which is on by default in MSVC-compatible mode. |
+std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) { |
+ struct Visitor : public RecursiveASTVisitor<Visitor> { |
+ bool VisitFunctionDecl(FunctionDecl* function_decl) { |
+ if (function_decl->isLateTemplateParsed()) |
+ late_parsed_decls.insert(function_decl); |
+ return true; |
+ } |
+ |
+ std::set<FunctionDecl*> late_parsed_decls; |
+ } v; |
+ v.TraverseDecl(decl); |
+ return v.late_parsed_decls; |
+} |
+ |
struct BlinkGCPluginOptions { |
BlinkGCPluginOptions() |
: enable_oilpan(false) |
@@ -1017,6 +1035,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
if (diagnostic_.hasErrorOccurred()) |
return; |
+ ParseFunctionTemplates(context.getTranslationUnitDecl()); |
+ |
CollectVisitor visitor; |
visitor.TraverseDecl(context.getTranslationUnitDecl()); |
@@ -1063,6 +1083,36 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
} |
} |
+ void ParseFunctionTemplates(TranslationUnitDecl* decl) { |
+ std::set<FunctionDecl*> late_parsed_decls = |
+ GetLateParsedFunctionDecls(decl); |
Reid Kleckner
2015/05/15 22:44:32
Traversing the whole AST might be expensive. Maybe
Nico
2015/05/15 22:57:26
We always build with asserts enabled, so that woul
|
+ clang::Sema& sema = instance_.getSema(); |
+ |
+ // If we have any late-parsed functions, make sure the |
+ // -fdelayed-template-parsing flag is on. Otherwise we don't know where |
+ // they came from. |
+ assert((instance_.getLangOpts().DelayedTemplateParsing || |
+ late_parsed_decls.empty()) && |
+ "Should not have late-parsed decls without " |
+ "-fdelayed-template-parsing."); |
+ |
+ for (const FunctionDecl* fd : late_parsed_decls) { |
+ assert(fd->isLateTemplateParsed()); |
+ |
+ if (!Config::IsTraceMethod(fd)) |
+ continue; |
+ |
+ if (instance_.getSourceManager().isInSystemHeader( |
+ instance_.getSourceManager().getSpellingLoc(fd->getLocation()))) |
+ continue; |
+ |
+ // Force parsing and AST building of the yet-uninstantiated function |
+ // template trace method bodies. |
+ clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd]; |
+ sema.LateTemplateParser(sema.OpaqueParser, *lpt); |
+ } |
+ } |
+ |
// Main entry for checking a record declaration. |
void CheckRecord(RecordInfo* info) { |
if (IsIgnored(info)) |