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..2d6eff256817f7b2c897a7a851329e47a54fd382 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,31 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
} |
} |
+ void ParseFunctionTemplates(TranslationUnitDecl* decl) { |
+ if (!instance_.getLangOpts().DelayedTemplateParsing) |
+ return; // Nothing to do. |
+ |
+ std::set<FunctionDecl*> late_parsed_decls = |
+ GetLateParsedFunctionDecls(decl); |
+ clang::Sema& sema = instance_.getSema(); |
+ |
+ 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)) |